Initialize Tizen 2.3 tizen_2.3 2.3a_release submit/tizen_2.3/20140531.115801 submit/tizen_2.3/20150202.105634 tizen_2.3_release
authorSehong Na <sehong.na@samsung.com>
Sat, 31 May 2014 04:21:47 +0000 (13:21 +0900)
committerSehong Na <sehong.na@samsung.com>
Sat, 31 May 2014 04:21:47 +0000 (13:21 +0900)
363 files changed:
BUGS [new file with mode: 0644]
Betas_Readme.txt [new file with mode: 0644]
CHANGES [new file with mode: 0644]
INSTALL [new file with mode: 0644]
LICENSE [new file with mode: 0644]
README [new file with mode: 0644]
README.CR [new file with mode: 0644]
TODO [new file with mode: 0644]
USexport.msg [new file with mode: 0644]
WHATSNEW [new file with mode: 0644]
WHERE [new file with mode: 0644]
acorn/GMakefile [new file with mode: 0644]
acorn/ReadMe [new file with mode: 0644]
acorn/ReadMe.GMakefile [new file with mode: 0644]
acorn/RunMe1st [new file with mode: 0644]
acorn/acornzip.c [new file with mode: 0644]
acorn/makefile [new file with mode: 0644]
acorn/match.s [new file with mode: 0644]
acorn/osdep.h [new file with mode: 0644]
acorn/riscos.c [new file with mode: 0644]
acorn/riscos.h [new file with mode: 0644]
acorn/sendbits.s [new file with mode: 0644]
acorn/srcrename [new file with mode: 0644]
acorn/swiven.h [new file with mode: 0644]
acorn/swiven.s [new file with mode: 0644]
acorn/zipsfx [new file with mode: 0644]
acorn/zipup.h [new file with mode: 0644]
amiga/LMKfile [new file with mode: 0644]
amiga/README [new file with mode: 0644]
amiga/amiga.c [new file with mode: 0644]
amiga/amiga.h [new file with mode: 0644]
amiga/amigazip.c [new file with mode: 0644]
amiga/crc_68.a [new file with mode: 0644]
amiga/deflate.a [new file with mode: 0644]
amiga/filedate.c [new file with mode: 0644]
amiga/makefile.azt [new file with mode: 0644]
amiga/match.a [new file with mode: 0644]
amiga/match_68.a [new file with mode: 0644]
amiga/osdep.h [new file with mode: 0644]
amiga/smakefile [new file with mode: 0644]
amiga/stat.c [new file with mode: 0644]
amiga/z-stat.h [new file with mode: 0644]
amiga/zipup.h [new file with mode: 0644]
aosvs/aosvs.c [new file with mode: 0644]
aosvs/make.cli [new file with mode: 0644]
api.c [new file with mode: 0644]
api.h [new file with mode: 0644]
atari/Makefile [new file with mode: 0644]
atari/README [new file with mode: 0644]
atari/atari.c [new file with mode: 0644]
atari/make_all.mup [new file with mode: 0644]
atari/make_zip.mup [new file with mode: 0644]
atari/osdep.h [new file with mode: 0644]
atari/zipup.h [new file with mode: 0644]
atheos/Makefile [new file with mode: 0644]
atheos/README [new file with mode: 0644]
atheos/atheos.c [new file with mode: 0644]
atheos/osdep.h [new file with mode: 0644]
atheos/zipup.h [new file with mode: 0644]
beos/Contents [new file with mode: 0644]
beos/Makefile [new file with mode: 0644]
beos/README [new file with mode: 0644]
beos/beos.c [new file with mode: 0644]
beos/osdep.h [new file with mode: 0644]
beos/zipup.h [new file with mode: 0644]
bzip2/install.txt [new file with mode: 0644]
cmsmvs/README.CMS [new file with mode: 0644]
cmsmvs/README.MVS [new file with mode: 0644]
cmsmvs/README.MVS.LE [new file with mode: 0644]
cmsmvs/cczip.exec [new file with mode: 0644]
cmsmvs/cms.c [new file with mode: 0644]
cmsmvs/cmsmvs.c [new file with mode: 0644]
cmsmvs/cmsmvs.h [new file with mode: 0644]
cmsmvs/cstat.h [new file with mode: 0644]
cmsmvs/mc.exec [new file with mode: 0644]
cmsmvs/mvs.c [new file with mode: 0644]
cmsmvs/mvs.h [new file with mode: 0644]
cmsmvs/mvs.mki [new file with mode: 0644]
cmsmvs/pipzip.rexx [new file with mode: 0644]
cmsmvs/zip.exec [new file with mode: 0644]
cmsmvs/zip.makefile [new file with mode: 0644]
cmsmvs/zipcloak.exec [new file with mode: 0644]
cmsmvs/zipmvsc.job [new file with mode: 0644]
cmsmvs/zipname.conven [new file with mode: 0644]
cmsmvs/zipnote.exec [new file with mode: 0644]
cmsmvs/zipsplit.exec [new file with mode: 0644]
cmsmvs/zipup.h [new file with mode: 0644]
cmsmvs/zipvmc.exec [new file with mode: 0644]
crc32.c [new file with mode: 0644]
crc32.h [new file with mode: 0644]
crc_i386.S [new file with mode: 0644]
crypt.c [new file with mode: 0644]
crypt.h [new file with mode: 0644]
deflate.c [new file with mode: 0644]
ebcdic.h [new file with mode: 0644]
file_id.diz [new file with mode: 0644]
fileio.c [new file with mode: 0644]
globals.c [new file with mode: 0644]
human68k/Makefile [new file with mode: 0644]
human68k/Makefile.gcc [new file with mode: 0644]
human68k/crc_68.s [new file with mode: 0644]
human68k/deflate.s [new file with mode: 0644]
human68k/human68k.c [new file with mode: 0644]
human68k/match.s [new file with mode: 0644]
human68k/osdep.h [new file with mode: 0644]
human68k/zipup.h [new file with mode: 0644]
macos/Contents [new file with mode: 0644]
macos/HISTORY.TXT [new file with mode: 0644]
macos/README.TXT [new file with mode: 0644]
macos/ZipLib.h [new file with mode: 0644]
macos/ZipSx.h [new file with mode: 0644]
macos/ZpPrj.hqx [new file with mode: 0644]
macos/osdep.h [new file with mode: 0644]
macos/readme.1st [new file with mode: 0644]
macos/source/VolWarn.h [new file with mode: 0644]
macos/source/charmap.h [new file with mode: 0644]
macos/source/extrafld.c [new file with mode: 0644]
macos/source/getenv.c [new file with mode: 0644]
macos/source/helpers.c [new file with mode: 0644]
macos/source/helpers.h [new file with mode: 0644]
macos/source/macglob.h [new file with mode: 0644]
macos/source/macopen.c [new file with mode: 0644]
macos/source/macopen.h [new file with mode: 0644]
macos/source/macos.c [new file with mode: 0644]
macos/source/macstuff.c [new file with mode: 0644]
macos/source/macstuff.h [new file with mode: 0644]
macos/source/mactime.c [new file with mode: 0644]
macos/source/mactime.h [new file with mode: 0644]
macos/source/pathname.c [new file with mode: 0644]
macos/source/pathname.h [new file with mode: 0644]
macos/source/recurse.c [new file with mode: 0644]
macos/source/recurse.h [new file with mode: 0644]
macos/source/unixlike.c [new file with mode: 0644]
macos/source/unixlike.h [new file with mode: 0644]
macos/source/zip_rc.hqx [new file with mode: 0644]
macos/zipup.h [new file with mode: 0644]
man/zip.1 [new file with mode: 0644]
man/zipcloak.1 [new file with mode: 0644]
man/zipnote.1 [new file with mode: 0644]
man/zipsplit.1 [new file with mode: 0644]
match.S [new file with mode: 0644]
msdos/README.DOS [new file with mode: 0644]
msdos/crc_i86.asm [new file with mode: 0644]
msdos/makebz2.dj2 [new file with mode: 0644]
msdos/makefile.bor [new file with mode: 0644]
msdos/makefile.dj1 [new file with mode: 0644]
msdos/makefile.dj2 [new file with mode: 0644]
msdos/makefile.emx [new file with mode: 0644]
msdos/makefile.msc [new file with mode: 0644]
msdos/makefile.tc [new file with mode: 0644]
msdos/makefile.wat [new file with mode: 0644]
msdos/match.asm [new file with mode: 0644]
msdos/msdos.c [new file with mode: 0644]
msdos/osdep.h [new file with mode: 0644]
msdos/zipup.h [new file with mode: 0644]
novell/MAKEINIT [new file with mode: 0644]
novell/Makefile [new file with mode: 0644]
novell/Netware.c [new file with mode: 0644]
novell/README [new file with mode: 0644]
novell/m.cmd [new file with mode: 0644]
novell/osdep.h [new file with mode: 0644]
novell/signal.c [new file with mode: 0644]
novell/zip.lnk [new file with mode: 0644]
novell/zipup.h [new file with mode: 0644]
os2/makefile.os2 [new file with mode: 0644]
os2/match32.asm [new file with mode: 0644]
os2/os2.c [new file with mode: 0644]
os2/os2acl.c [new file with mode: 0644]
os2/os2acl.h [new file with mode: 0644]
os2/os2zip.c [new file with mode: 0644]
os2/os2zip.h [new file with mode: 0644]
os2/osdep.h [new file with mode: 0644]
os2/zip.def [new file with mode: 0644]
os2/zipup.h [new file with mode: 0644]
packaging/zip.spec [new file with mode: 0644]
proginfo/3rdparty.bug [new file with mode: 0644]
proginfo/ZipPorts [new file with mode: 0644]
proginfo/algorith.txt [new file with mode: 0644]
proginfo/ebcdic.msg [new file with mode: 0644]
proginfo/extrafld.txt [new file with mode: 0644]
proginfo/fileinfo.cms [new file with mode: 0644]
proginfo/infozip.who [new file with mode: 0644]
proginfo/ntsd.txt [new file with mode: 0644]
proginfo/perform.dos [new file with mode: 0644]
proginfo/timezone.txt [new file with mode: 0644]
proginfo/txtvsbin.txt [new file with mode: 0644]
proginfo/ziplimit.txt [new file with mode: 0644]
qdos/IZREADME.SMS [new file with mode: 0644]
qdos/Makefile.qdos [new file with mode: 0644]
qdos/Makefile.qlzip [new file with mode: 0644]
qdos/config.s [new file with mode: 0644]
qdos/crc68.s [new file with mode: 0644]
qdos/match.s [new file with mode: 0644]
qdos/osdep.h [new file with mode: 0644]
qdos/qdos.c [new file with mode: 0644]
qdos/qfileio.c [new file with mode: 0644]
qdos/zipup.h [new file with mode: 0644]
revision.h [new file with mode: 0644]
tailor.h [new file with mode: 0644]
tandem/HISTORY [new file with mode: 0644]
tandem/README [new file with mode: 0644]
tandem/commacs [new file with mode: 0644]
tandem/doit [new file with mode: 0644]
tandem/macros [new file with mode: 0644]
tandem/make [new file with mode: 0644]
tandem/tandem.c [new file with mode: 0644]
tandem/tandem.h [new file with mode: 0644]
tandem/tannsk.h [new file with mode: 0644]
tandem/tanzip.c [new file with mode: 0644]
tandem/tanzip.h [new file with mode: 0644]
tandem/zipup.h [new file with mode: 0644]
theos/Makefile [new file with mode: 0644]
theos/README [new file with mode: 0644]
theos/_chmod.c [new file with mode: 0644]
theos/_fprintf.c [new file with mode: 0644]
theos/_isatty.c [new file with mode: 0644]
theos/_rename.c [new file with mode: 0644]
theos/_setargv.c [new file with mode: 0644]
theos/_stat.c [new file with mode: 0644]
theos/charconv.h [new file with mode: 0644]
theos/osdep.h [new file with mode: 0644]
theos/stat.h [new file with mode: 0644]
theos/theos.c [new file with mode: 0644]
theos/zipup.h [new file with mode: 0644]
timezone.c [new file with mode: 0644]
timezone.h [new file with mode: 0644]
tops20/make.mic [new file with mode: 0644]
tops20/osdep.h [new file with mode: 0644]
tops20/rename.mic [new file with mode: 0644]
tops20/tops20.c [new file with mode: 0644]
tops20/zipup.h [new file with mode: 0644]
trees.c [new file with mode: 0644]
ttyio.c [new file with mode: 0644]
ttyio.h [new file with mode: 0644]
unix/Makefile [new file with mode: 0644]
unix/Packaging/README [new file with mode: 0644]
unix/Packaging/pkginfo.in [new file with mode: 0644]
unix/Packaging/postinstall [new file with mode: 0644]
unix/Packaging/preinstall.in [new file with mode: 0644]
unix/Packaging/prototype [new file with mode: 0644]
unix/README.OS390 [new file with mode: 0644]
unix/configure [new file with mode: 0644]
unix/osdep.h [new file with mode: 0644]
unix/unix.c [new file with mode: 0644]
unix/zipup.h [new file with mode: 0644]
util.c [new file with mode: 0644]
vms/NOTES.TXT [new file with mode: 0644]
vms/VMS_ZIP.RNH [new file with mode: 0644]
vms/build_zip.com [new file with mode: 0644]
vms/bzlib.h [new file with mode: 0644]
vms/cmdline.c [new file with mode: 0644]
vms/collect_deps.com [new file with mode: 0644]
vms/cvthelp.tpu [new file with mode: 0644]
vms/descrip.mms [new file with mode: 0644]
vms/descrip_deps.mms [new file with mode: 0644]
vms/descrip_mkdeps.mms [new file with mode: 0644]
vms/descrip_src.mms [new file with mode: 0644]
vms/find_bzip2_lib.com [new file with mode: 0644]
vms/hlp_lib_next.com [new file with mode: 0644]
vms/install_vms.txt [new file with mode: 0644]
vms/mod_dep.com [new file with mode: 0644]
vms/osdep.h [new file with mode: 0644]
vms/stream_lf.fdl [new file with mode: 0644]
vms/unixio_gcc.h [new file with mode: 0644]
vms/unixlib_gcc.h [new file with mode: 0644]
vms/vms.c [new file with mode: 0644]
vms/vms.h [new file with mode: 0644]
vms/vms_im.c [new file with mode: 0644]
vms/vms_msg_gen.c [new file with mode: 0644]
vms/vms_pk.c [new file with mode: 0644]
vms/vmsdefs.h [new file with mode: 0644]
vms/vmsmunch.c [new file with mode: 0644]
vms/vmsmunch.h [new file with mode: 0644]
vms/vmszip.c [new file with mode: 0644]
vms/zip.opt [new file with mode: 0644]
vms/zip_cli.cld [new file with mode: 0644]
vms/zip_cli.help [new file with mode: 0644]
vms/zip_msg.msg [new file with mode: 0644]
vms/zipup.h [new file with mode: 0644]
win32/README.NT [new file with mode: 0644]
win32/README.TZ [new file with mode: 0644]
win32/README.txt [new file with mode: 0644]
win32/crc_i386.asm [new file with mode: 0644]
win32/crc_i386.c [new file with mode: 0644]
win32/crc_lcc.asm [new file with mode: 0644]
win32/gvmat64.asm [new file with mode: 0644]
win32/lm32_lcc.asm [new file with mode: 0644]
win32/makefile.a64 [new file with mode: 0644]
win32/makefile.bor [new file with mode: 0644]
win32/makefile.dj [new file with mode: 0644]
win32/makefile.emx [new file with mode: 0644]
win32/makefile.gcc [new file with mode: 0644]
win32/makefile.ibm [new file with mode: 0644]
win32/makefile.lcc [new file with mode: 0644]
win32/makefile.w10 [new file with mode: 0644]
win32/makefile.w32 [new file with mode: 0644]
win32/makefile.wat [new file with mode: 0644]
win32/makenoas.w32 [new file with mode: 0644]
win32/match32.asm [new file with mode: 0644]
win32/nt.c [new file with mode: 0644]
win32/nt.h [new file with mode: 0644]
win32/osdep.h [new file with mode: 0644]
win32/readme.a64 [new file with mode: 0644]
win32/rsxntwin.h [new file with mode: 0644]
win32/vc6/ReadmeVC.txt [new file with mode: 0644]
win32/vc6/zip.dsp [new file with mode: 0644]
win32/vc6/zip.dsw [new file with mode: 0644]
win32/vc6/zipcloak.dsp [new file with mode: 0644]
win32/vc6/zipnote.dsp [new file with mode: 0644]
win32/vc6/zipsplit.dsp [new file with mode: 0644]
win32/vc6bz2/ReadVCBZ.txt [new file with mode: 0644]
win32/vc6bz2/zip.dsp [new file with mode: 0644]
win32/vc6bz2/zip.dsw [new file with mode: 0644]
win32/win32.c [new file with mode: 0644]
win32/win32i64.c [new file with mode: 0644]
win32/win32zip.c [new file with mode: 0644]
win32/win32zip.h [new file with mode: 0644]
win32/zip.def [new file with mode: 0644]
win32/zip.rc [new file with mode: 0644]
win32/zipup.h [new file with mode: 0644]
windll/VBz64/VBZIP.VBP [new file with mode: 0644]
windll/VBz64/VBZIP.vbw [new file with mode: 0644]
windll/VBz64/VBZipBas.bas [new file with mode: 0644]
windll/VBz64/Vbzipfrm.frm [new file with mode: 0644]
windll/VBz64/readVB64.txt [new file with mode: 0644]
windll/Vb/VBZIP.vbw [new file with mode: 0644]
windll/Vb/VBZipBas.bas [new file with mode: 0644]
windll/Vb/Vbzip.vbp [new file with mode: 0644]
windll/Vb/Vbzipfrm.frm [new file with mode: 0644]
windll/Vb/readmeVB.txt [new file with mode: 0644]
windll/contents [new file with mode: 0644]
windll/example.c [new file with mode: 0644]
windll/example.h [new file with mode: 0644]
windll/structs.h [new file with mode: 0644]
windll/visualc/dll/zip32z64.dsp [new file with mode: 0644]
windll/visualc/dll/zip32z64.dsw [new file with mode: 0644]
windll/visualc/lib/zip32z64.dsp [new file with mode: 0644]
windll/visualc/lib/zip32z64.dsw [new file with mode: 0644]
windll/windll.aps [new file with mode: 0644]
windll/windll.c [new file with mode: 0644]
windll/windll.h [new file with mode: 0644]
windll/windll.rc [new file with mode: 0644]
windll/windll.txt [new file with mode: 0644]
windll/windll16.def [new file with mode: 0644]
windll/windll32.def [new file with mode: 0644]
windll/ziplib.def [new file with mode: 0644]
zbz2err.c [new file with mode: 0644]
zip.c [new file with mode: 0644]
zip.h [new file with mode: 0644]
zip.txt [new file with mode: 0644]
zip30.ann [new file with mode: 0644]
zip30f.ann [new file with mode: 0644]
zip30g.ann [new file with mode: 0644]
zip30h.ann [new file with mode: 0644]
zipcloak.c [new file with mode: 0644]
zipcloak.txt [new file with mode: 0644]
ziperr.h [new file with mode: 0644]
zipfile.c [new file with mode: 0644]
zipnote.c [new file with mode: 0644]
zipnote.txt [new file with mode: 0644]
zipsplit.c [new file with mode: 0644]
zipsplit.txt [new file with mode: 0644]
zipup.c [new file with mode: 0644]

diff --git a/BUGS b/BUGS
new file mode 100644 (file)
index 0000000..21a9013
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,6 @@
+- zip sometimes crashes on some versions of NetBSD (0.8, 0.9 and early
+  0.9-current), FreeBSD (<= 1.1) and BSDI (< 1.1) . This is due to a
+  bug in stdio.
+  Upgrading the stdio package in /usr/src/lib/libc/stdio should
+  fix the problem. See *BSD mirrors in src/lib/libc/stdio
+  You must at least replace setvbuf.o in all the libc's with a newer version.
diff --git a/Betas_Readme.txt b/Betas_Readme.txt
new file mode 100644 (file)
index 0000000..26e965e
--- /dev/null
@@ -0,0 +1,17 @@
+Betas are works in progress.  When a beta has a seemingly stable set
+of features, we may post a public beta so outside developers can see
+where the code is going and make contributions or comment.
+
+A Release Candidate is a beta that we believe has the full feature
+set that will be released.  It's still being tested, and things can
+still change, but we thought it close when we posted it.
+
+We take suggestions, bug fixes, and patches at any time, so send them in.
+
+We make no guarantees as to the state of betas so use at your own risk.
+All code, including releases, are released under the Info-ZIP license.
+
+Enjoy!
+
+Ed Gordon
+20 April 2008
diff --git a/CHANGES b/CHANGES
new file mode 100644 (file)
index 0000000..751695f
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,3460 @@
+------------------------- August 7th 1996 version 2.2a ------------------
+ 1. QDOS port (Jonathan Hudson)
+ 2. win32 volumelabel handling (Paul)
+ 3. VM/CMS clean up (Greg Hartwig)
+ 4. leading "../" in internal filenames are allowed (Paul)
+ 5. System V packages support (John Bush)
+ 6. Fix handling of atx in zipup() (Onno, Greg)
+ 7. Fixed typo that caused zip -R to dump core (Onno)
+ 8. msdos/makefile.dj2: fix for command line too long when linking zip.exe
+ 9. win95 long filename support with djgpp v2 (Onno, Kimio Itoh)
+------------------------- August 9th 1996 version 2.2b ------------------
+ 1. windll: use wiz instead of wizip (Mike)
+ 2. use z->name NOT z->zname to open files (Onno, Mike)
+------------------------ September 1st 1996 version 2.2c ------------------
+ 1. windll: use fprintf instead of putc to send data to std{out,err} (Mike)
+ 2. os2: make borlandc version detection equal to unzip 5.30d (Kai Uwe)
+ 3. use #elif constructions for msdos,os2 and win32 compiler detection (Onno)
+ 4. fix for incorrect free in zip.c (Onno, Mike, Steve)
+ 5. BeBox port from Chris
+ 6. unix/{configure,Makefile} fixes for SCO Xenix 286 (Tom Schmidt)
+ 7. remove zilog entry from unix/Makefile (Onno)
+ 8. man page fixes (Tom Schmidt)
+ 9. SCO ODT {3,5} fixes (Bill Davidsen)
+------------------------ October 8th 1996 version 2.2d ------------------
+ 1. Fix bug in QDOS patch that broke zipsplit.c (Onno, Paul)
+ 2. Fix a couple of warnings from BorlandC (Mike)
+ 3. msdos/makefile.wat: Delete some more files when cleaning up (Paul)
+ 4. store msdos volumelabels without a dot in them (Paul)
+ 5. clean up of unix/{Makefile,configure,packaging} (Tom Schmidt)
+ 6. make QDOS port case independent (Jonathan Hudson)
+ 7. new amiga SASC makefile (Walter Haidinger)
+ 8. don't truncate filenames in win32's in2ex() (Paul)
+ 9. os2/makefile.os2 update for emx 0.9c (Kai Uwe)
+10. password() function for QDOS (Jonathan)
+11. fix the last(?) free() related bug (Mike)
+12. win32: security descriptors operations (Scott Field)
+13. win32: FILE_SHARE_DELETE is not defined in some win32 compilers (Onno)
+14. win32: fix makefile.wat to include nt.c (Onno)
+------------------------ January 17th 1997 version 2.2e ------------------
+ 1. define USE_CASE_MAP in osdep.h for those ports that need it (Onno)
+ 2. define PROCNAME in osdep.h for those ports that need it (Onno)
+ 3. wild() prototype decl only if PROCNAME defined => delete MSVMS define (Onno)
+ 4. add DOS EMX makefile (E-Yen Tan)
+ 5. include <qdos.h> a little earlier in qdos/qdos.c (Jonathan)
+ 6. add ttyio.o to OBJZ in qdos/Makefile.qdos (Jonathan)
+ 7. remove unused fprintebc define from zip.c (Onno)
+ 8. use the right password routine in ttyio.c for unzip (Mike)
+ 9. BeOS update from Chris
+10. Fix for 'zip -r foo x:' (Paul)
+11. Fix library bug on beos (Chris)
+12. Fix calculating version number (kitoh_@mix.or.jp, Walter Haidinger)
+13. IsWinNT always returned TRUE (Mike)
+14. Windll update from Mike
+15. Improved crc routines for x86 from Scott Field
+16. Detect in unix/configure if we can use crc_i386.S (Onno)
+17. Fix spurious internal logic error (Paul)
+18. Fix to include directory names on the Acorn when needed (Sergio)
+19. include zip.h in mvs.h (Onno, George Carr)
+20. add workaround for AZTEC C compiler bug to revision.h (Paul, Walter)
+21. MVS doesn't have rmdir (George Carr)
+22. define and use USE_ZIPMAIN for WINDLL en VM_CMS (Onno)
+23. Fixes from Greg Hartwig to make CMS standalone versions possible.
+24. Move OS specific encryption stuff to the os specific directories (Christian)
+25. Change password fetching interface in ttyio and crypt (Christian)
+26. Update emx support for 0.9c (Christian)
+27. Define WINDLL instead of MSWIN (Christian)
+28. Extended time stamp extra field format support (Christian)
+29. Support for rsxnt-emx 0.9c win32 compiler (Christian)
+30. Use izshr017b (Christian)
+------------------------ March 11th 1997 version 2.2f ------------------
+ 1. Move makefile.emx, rsxwinnt.h and zip.def to win32 subdir (Kai Uwe)
+ 2. Add win32 target to makefile.os2 to allow cross compilation (Kai Uwe)
+ 3. Fix NTSD_EAS link time failures with win32 (Paul)
+ 4. Fix buffer freed too early in password verification code (Mike)
+ 5. Remove unix/zipgrep and man/zipgrep.1 (sanvila@ctv.es)
+ 6. Only use crc_i386.o when we're using an x86 (Onno, Mark)
+ 7. Remove carriage returns from amiga/crc_68.a (Paul)
+ 8. New windll from Mike
+ 9. Fix typo in os2/os2zip.c (Kai Uwe)
+10. Don't use ctime (last file status change) for unix and qdos cross compile
+    (Greg)
+11. added gccwin32 crosscompilation target (RSXNT) to os2/makefile.os2 (Kai Uwe)
+12. fixed the OS/2 file attribute and time stamp generation for zipping
+    stdin ("-") (Kai Uwe)
+13. fixed the atime and ctime stat fields for the OS/2 Watcom C library
+    (Kai Uwe)
+14. added atime and ctime support for the UT extra field when generated under
+    OS/2, the atime and ctime values are only stored when zipping (Kai Uwe)
+15. qdos patches from Jonathan Hudson mainly for extended time flag handling
+16. amiga aztec compiler bug workaround (Paul)
+17. fix -v output of zipcloak, zipnote and zipsplit (Paul)
+18. new amiga/makefile.azt with targets for debug versions (Paul)
+------------------------ March 31st 1997 version 2.2g ------------------
+ 1. remove -I/usr/local/include from unix/Makefile (Chris)
+ 2. Update versinfolines in revision.h (Greg)
+ 3. change 1U to 0x1 to accomodate non ANSI compilers (Onno, Rodney Brown)
+ 4. win32zip.c: cast buffer parameter in memcompress() to char * (Mike)
+ 5. remove beos/zipgrep (Chris)
+ 6. correct the -e password verification check in zip.c (Christian)
+ 7. use ZCONST instead of const in the generic code. (Christian)
+ 8. fix mktime timezone correction when time is near to daylight/nodaylight
+    switch points. (Christian)
+ 9. correct dependencies in makefile.os2 (Christian)
+10. use a more sensible default for iztime.ctime than "0" when system does not
+    not support creation time stamps. (Christian)
+11. fix VMS_PK_EXTRA function interface declarations. (Christian)
+12. implement atime/ctime support in win32. (Christian)
+13. win32/win32.c: replacement getch() for Watcom. (Paul)
+14. win32/makefile.wat: debug object files kept separate. (Paul)
+15. msdos/makefile.wat: debug object files kept separate. (Paul)
+16. Fix extended time defines for the acorn. (Sergio)
+17. Define PROCNAME() in acorn/osdep.h (Sergio)
+18. Ignore exit status of ${INSTALL_D} in unix/Makefile (Chris)
+19. Add Metroworks and BEOS info to version() in several files (Chris)
+20. Move defines for the password fetch to zip.h (Christian)
+21. Support the obsolete version rsxnt 1.1 / emx 0.9b (Christian)
+22. Remove obsolete "#define PROCNAME ..." from cmsmvs/cmsmvs.h (Christian)
+23. Fix extended time defines for qdos (Jonathan Hudson)
+24. Use watcom getch() from unz530q in win32/win32.c (Onno)
+25. Don't install zipgrep via the unix package tools (John Bush)
+26. use izshr021 (Onno)
+27. Fix zipnote: use iname not zname in zipnote.c (Onno)
+28. Create proginfo directory (Christian)
+------------------------ May 5th 1997 version 2.2h --------------------
+ 1. Fix vms/zipup.h: iztime --> iztimes  (Onno, Mike Freeman)
+ 2. Remove windll/wizdll.def (Mike)
+ 3. Add a couple of external variable declaration to windll.h (Mike)
+ 4. Remove zipgrep from install in unix/Makefile (Onno)
+ 5. Make updating .zip files with extended time fields possible (Kai Uwe)
+ 6. Delete beos/Makefile.gcc, beos/Makefiles handles both compilers (Chris)
+ 7. Fixes for unused variables (Chris)
+ 8. Added very simplistic example how to load and call the windll (Mike)
+ 9. Updated windll documentation to note this example (Mike)
+10. Removed an unused memeber of a structure in windll (Mike)
+11. Add BUGS instead of infozip.who and algorith.doc with the packaging
+    tools (John Bush)
+12. tailor.h: increment NUM_HOSTS to keep in sync with UnZip (Christian)
+13. win32/osdep.h: remove NO_SECURE_TESTS define (Christian)
+14. zip.h: add declaration for free_crc_table() (Christian)
+15. windll: move everything that's not windows specific into api.* (Mike)
+16. use iname when checking for directory names in zipfile.c (Sergio)
+17. improved mktime.c with better error checking (Christian)
+18. improved crc routines (Christian, Rodney Brown)
+19. get the -z option working again (Onno, Brad Clarke)
+20. define BROKEN_FSEEK and seekable() for those systems where fseek()
+    always returns 0 (== OK) (Onno, Jeffrey Altman)
+------------------------ May 10th 1997 version 2.2i --------------------
+ 1. win32's seekable should only check for FILE_TYPE_DISK (Onno, Jeffrey Altman)
+ 2. add (ulg) cast to zipbeg = ~0 in zipfile.c (Steve)
+ 3. seekable() *really* belongs in flush_block, keep it there (Onno)
+ 4. seekable() calls fseekable(FILE *) (Onno)
+ 5. define HAVE_FSEEKABLE if a port has their own fseekable (Onno)
+ 6. WatCom doesn't have _get_osfhandle, use _os_handle instead (Paul)
+ 7. upgrade to Mike's latest windll sources (Mike)
+ 8. add -P option so you can specify a password on the commandline (Onno)
+ 9. Get -@ working again (Onno)
+10. emx+RSXNT doesn't know about _get_osfhandle() (Kai Uwe)
+11. fix a couple of typos in the OS/2 makefiles (Kai Uwe)
+12. fix initialization bug in windll code (Mike)
+13. tweak deletedir for RISC OS (Sergio)
+14. RISCOS doesn't know about fstat() (Sergio)
+15. Remove acorn/acorn (Sergio)
+16. Delete debugging statements from version_local() in msdos.c (Greg)
+17. Fix huge bug in readzipfile() (Onno)
+------------------------ May 18th 1997 version 2.2j --------------------
+ 1. Add missing ';' after return ZE_PARMS in zip.c (Mike)
+ 2. Remove obsolete 'struct stat st' in zipfile.c (Onno)
+ 3. Get Amiga SFX handling working again (Paul)
+ 4. Get zip -A working again (Onno)
+ 5. Change an && to & in zipfile.c (Johnny)
+ 6. Fix handling of empty sfx archives (Onno, Mike)
+ 7. Remove experimental entries from the makefiles (Jean-loup)
+ 8. Add exit codes to the manual page (Onno)
+ 9. Remove lines from the help screen that contain lesser used options (Onno)
+------------------------ June 8th 1997 version 2.2k --------------------
+ 1. use zip -t ddmmyyyy for year 2000 stuff (Greg)
+ 2. zip -@ only handles ONE filename per line (Jean-loup)
+ 3. beos support for DR9 filesystem and symlinks (Chris)
+ 4. VB support for windll (Mike)
+------------------------ June 10th 1997 version 2.2l -------------------
+ 1. beos filetype support (Chris)
+ 2. fill the buffer in getnam() to get it working again (Onno)
+ 3. implement -x@filename and -i@filename (Onno)
+------------------------ June 22nd 1997 version 2.2m -------------------
+ 1. Add a ; after de nextarg label in main() (Onno, Erik Baatz)
+ 2. Initialize p to NULL in get_filters() (Onno, Frank Donahoe)
+ 3. Fix typo in first if statement in filetypes() (Johnny Lee)
+ 4. zip -A works again (Onno, Greg)
+ 5. don't free zipbuf for VMS and CMS_MVS in main() (Onno, Mike Freeman)
+ 6. fix make_zip.com, link_zip.com and vmsdefs.h for gcc 2.6.3 on VMS (Onno)
+ 7. clarify -g option in the man page (Jean-loup)
+------------------------ July 6th 1997 version 2.2n -------------------
+ 1. use local in readzipfile2() declaration (Onno, Mike Freeman)
+ 2. return values with windll in get_filters() (Mike)
+ 3. a couple of minor patches for BEOS (Chris)
+ 4. zip -g works again (Onno, Chris)
+ 5. Some more Visual Basic dll support (Mike)
+ 6. Fix stack overflow in readzipfile() for DOS (Onno, Michael Mauch)
+------------------------ August 19th 1997 version 2.2o -------------------
+ 1. beos README and Makefile tweaks from Chris.
+ 2. Syntax corrections for README and man/zip.1  (Frank Donahoe)
+ 3. Use name not iname when deleting directories in trash() (Christian)
+ 4. change several wkuvx1 to lists in e-mail addresses (Christian)
+ 5. default to PK style extra fields for VMS (Christian)
+ 6. use izshr023 (Christian)
+ 7. replace buggy time library functions (Walter Haidinger, Paul, Christian)
+ 8. in2ex() and stat() are needed also when UTIL isn't defined (Greg Hartwig)
+ 9. don't use type=record in fopen() for MVS and CMS (Greg Hartwig)
+10. Change P and K literals to hex for EBCDIC systems (Greg Hartwig)
+11. Add output path support for CMS and MVS (Greg Hartwig)
+12. Add memtoasc and memtoebc for EBCDIC systems (Greg Hartwig)
+13. Handle comments correctly to fix zipnote for CMS and MVS (Greg Hartwig)
+14. Add -tt option (do not operate on files after date mmddyy) (Christian)
+15. move alloc routines for DOS into the !UTIL block (Christian)
+16. move UTIL blocks and version_local() functions to a more logical place
+    (Christian)
+17. Handle -P, -R, -x@, -i@ and -tt for the VMS CLI (Christian)
+18. Update VMS help file with the new options (Christian)
+19. Use iname in MATCH, not zname (Jonathan Hudson)
+20. windll: more Visual Basic support (Mike)
+21. windll: more project makefiles (Mike)
+22. windll: insert Zip in front of global variable names (Mike)
+------------------------ August 25th 1997 version 2.2p -------------------
+ 1. Remove unused flags from LFLAGS2 in unix/Makefile (Onno)
+ 2. SunOS make bug: change unix_.o rule in unix/Makefile (Onno, Mike Freeman)
+ 3. ZipIsWinNT() instead of IsWinNT() in zip.h (Mike)
+ 4. Fix -t and -tt behaviour for windll (Mike)
+ 5. Remove windll makefiles that are now elsewhere (Mike)
+ 6. BEOS: preserve file attributes associated with symbolic links (Chris)
+ 7. No need to use in2ex() for ziputils (Christian)
+ 8. Fix comment handling for EBCDIC systems (Christian)
+ 9. EBCDIC conversion for entry names read from zipfile in UTIL mode (Christian)
+10. Fix "fatal" error messages on EBCDIC systems (Christian)
+11. zipnote.c: Fix handling of entry name changes for EBCDIC systems (Christian)
+12. removed a large part of "dead" code from ziputils version (Christian)
+13. use z->iname in comparison functions for sorting (Christian)
+14. new installation utils for the acorn (Sergio)
+15. use LSSTAT in set_extra_field for unix and beos (Onno)
+16. perror(z->zname) instead of perror("zip warning") (Onno, Geoff Pennington)
+17. Amiga SFX should work again (Paul)
+18. refer to zip22 in install.doc (Frank Donahoe)
+------------------------ September 10th 1997 version 2.2q -------------------
+ 1. Change .doc to .txt, these aren't MS-Word documents (John D. Mitchell)
+ 2. Change msdos$_(OBJ) to msdos_$(OBJ) (Kai Uwe)
+ 3. Fix a couple of amiga related glitches (Paul)
+ 4. Support for DOS packed .exe files in makefile.dj2 (Frank Donahoe)
+ 5. Change warning message for zip -A (Greg)
+------------------------ September 29th 1997 version 2.2r -------------------
+ 1. Fix make svr4package (Eric Baatz)
+ 2. Fix VMS warning (Mike Freeman, Christian)
+ 3. Clean up beos gcc port and beos README (Chris)
+-------------------------- October 6th 1997 version 2.2s --------------------
+ 1. Change lpPrint to lpZipPrint for windll (Mike)
+ 2. Change lpPassword to lpZipPassword for windll (Mike)
+ 3. Amiga timezone fixes (Paul)
+ 4. WatCom C 11.0 makefile fixes (Paul)
+ 5. Tandem port from Dave Smith
+ 6. Corrections and updates for install.txt (Christian)
+ 7. Minor VMS README update (Christian)
+-------------------------- October 12th 1997 version 2.2t --------------------
+ 1. qdos compiler bug workaround (Jonathan)
+ 2. prevent storing qdos specific filenames that exceed filesystem limits
+    (Jonathan)
+ 3. fix undelimited comment in fileio.c (Frank Donahoe)
+ 4. disable storing of symlinks in BEOS until OS support is available (Chris)
+ 5. Init hash_head to 0 in amiga/deflate.a (Paul)
+ 6. Upgrade to izshr025 (Christian)
+ 7. don't add ".zip" to ZIP name for TANDEM (Dave Smith)
+ 8. use zipup.h not tandem.h in zipup.c (Dave Smith)
+ 9. rename history to CHANGES (Onno)
+10. rename install.txt to INSTALL (Onno)
+11. rename zip.txt to ZIPMAN (Onno)
+12. create WHATSNEW (Onno)
+-------------------------- October 15th 1997 version 2.2u --------------------
+ 1. Use Info-ZIP instead of Info-Zip (Christian)
+ 2. Note recent filename changes in several files (Christian)
+ 3. Remove a couple of items from the TODO list (Christian, Onno)
+ 4. Add windll port, zip -t yyyymmdd and zip -R to WHATSNEW (Christian)
+ 5. VMS documentation cleanups and clarifications (Christian)
+ 6. dist entry in unix/Makefile (Onno)
+ 7. remove duplicate amiga/timezone.txt (Christian)
+ 8. rename ZIPMAN to MANUAL and update a couple of files regarding this (Onno)
+-------------------------- October 24th 1997 version 2.2v --------------------
+ 1. izshr026: in WHERE wiz40 instead of wiz30 (Christian)
+ 2. izshr026: another couple of Info-ZIP spelling fixes (Christian)
+ 3. Remove zipgrep from the makefiles that still had it (Christian)
+ 4. Update makefiles to handle the MANUAL renaming change (Christian)
+ 5. Fix the last daylight savings bug on the Amiga (Paul)
+ 6. Fix the SCO Unix specialty detection in unix/configure (Onno,
+    bug reported by Bo Kullmar for Solaris 2.6 and with uname -X output
+    for SCO Unix from ken@apisys.com and dgsmith@vnet.ibm.com)
+ 7. Update WHERE and amiga/time_lib.c from unzip 5.32g (Greg)
+-------------------------- October 26th 1997 version 2.2w --------------------
+ 1. Additional +Onolimit check in unix/configure (Onno, Peter Jones)
+ 2. Use ZIPERR macro instead of ziperr (Christian)
+ 3. initialize z->lflg for zip entries without extra field (Christian)
+ 4. "local (+ locextend)" vs. "central" header consistency check (Christian)
+ 5. Override local header values with central header values with -A
+    and differences between these headers (Christain)
+ 6. made "deltaoff" signed long; offset adjustment may be negative (Christian)
+ 7. fix a number of "wild" deallocation bugs (Christian)
+ 8. When zipping from a FAT drive (only 8.3 DOS names) under OS/2 or
+    WIN32, set z->vem to "OS_DOS | <real zip version number>".
+    Mark as "made by DOS PKZIP 2.0" only when dosify was requested. (Christian)
+ 9. DOS port should not store fake unix style external attributes. (Christian)
+10. amiga/time_lib.c from izshr028 (Christian)
+-------------------------- October 31st 1997 version 2.2y --------------------
+ 1. amiga/time_lib.c from izshr029 (Christian)
+ 2. Turbo C++ version code clarification (E-Yen Tan)
+ 3. Fix spelling in cmsvms/zipname.conven (Rodney Brown)
+ 4. Fix memset check in unix/configure for Unixware 2.1.1 (Rodney Brown)
+ 5. Forward declaration fixes for HP-UX bundled compiler (Rodney Brown)
+-------------------------- November 3rd 1997 version 2.2 --------------------
+ 1. Update WHERE (Greg).
+-------------------------- January 4th 1998 version 2.21a -------------------
+ 1. BSD friendly version of version_local() in unix/unix.c (Onno)
+ 2. No NT versions in DOS version_local() (Steve Salisbury)
+ 3. -t mmddyyyy instead of -t ddmmyyyy in WHATSNEW (Walter Haidinger)
+ 4. use generic fseekable() for rsxnt (Christian)
+ 5. Fix MSC 8.x warnings (Christian, Steve Salisbury)
+ 6. win32 Borland C++ makefile (E-Yen Tan)
+ 7. Tandem doesn't know about extensions like .zip,.arj, ... (Dave Smith)
+ 8. Use dosmatch for EMX and DJGPP too (Christian)
+ 9. dummy djgpp startup functions to remove command line globbing and
+    recognition of environment variables from djgpp.env (Christian)
+10. include DJGPP_MINOR in DOS version_local() (Christian)
+11. TC 2.0 doesn't have mktime() (Christian, mmp@earthling.net)
+12. VMS: rename opendir() to zopendir() so avoiding name clash with
+    VMS 7.x POSIX libraries (Christian, Martin Zinser)
+13. Add support for VMS DEC C V 5.6 features (Christian)
+14. Use iname for comparison in check_dup (Christian Spieler, Christian Michel)
+15. Fix access to uninitialized ioctx records in vms_get_attributes()
+    Christian, Robert Nielsen)
+16. Parenthesis around MAX_MATCH>>1 in match.S (Greg)
+17. Use strchr() not strrchr() for -i and -x to get -i@ and -x@ really
+    working (Onno, Kai Uwe)
+18. add chmod statements to unix/Makefile (Quentin Barnes)
+19. Windll: handle both -r and -R (Mike)
+20. Windll: general error handler in main() via setjmp/longjmp (Mike)
+21. Don't allow zip -i@x.lst foo.zip (Onno)
+22. vms/link_zip.com: use .eqs. not .nes. when checking with f$search
+    for the zip AXP object library (David Dachtera)
+23. rsxnt 1.3.1 fixes (E-Yen Tan)
+-------------------------- January 20th 1998 version 2.21b -------------------
+ 1. Bigger PATH_MAX for win32's windll (Mike)
+ 2. Update windll.txt w.r.t. PATH_MAX (Mike)
+ 3. Amiga SAS/C fixes (Walter, Paul)
+ 4. zip -i@ and -x@ should *really* work now ...... (Onno)
+-------------------------- February 20th 1998 version 2.21c -------------------
+ 1. make -f unix/Makefile qnx needs LN=ln in its options (Chris)
+ 2. Support Metroworks Codewarrior/x86 on BEOS (Chris)
+ 3. Add Norbert Pueschel to proginfo/infozip.who (Walter)
+ 4. Use big endian for Be types (Chris)
+ 5. zip -i and -x were broken by the -i@ fix last time around (Christian)
+ 6. win32 stat bandaid (Paul)
+ 7. acorn filetype and timestamp fixes (Sergio, D. Krumbholz)
+ 8. update to izshr30 (Christian)
+ 9. Support for NTSD in the RSXNT environment (Christian)
+10. restructure readzipfile() (Christian)
+11. Where needed define MATCH in osdep.h (Christian)
+12. version_local() fixes for RSXNT (Christian)
+13. New vmsmunch.c (Christian)
+-------------------------- March 15th 1998 version 2.3a -------------------
+ 1. Fixes for the windll API (Mike)
+ 2. Use CPUTYPE in BorlandC Makefile for DOS (E-Yen Tan)
+ 3. BEOS: -rostr not available for the x86 compiler (Chris)
+ 4. preserve file attributes of a symlink on BEOS (Chris)
+ 5. New VM/CMS README.CMS and version_local() (Ian Gorman)
+ 6. INSTALL fixes from Takahiro Watanabe
+ 7. OS/390 port from Paul von Behren
+ 8. new api.h from Mike
+-------------------------- April 19th 1998 version 2.3b -------------------
+ 1. Improve Tandem file I/O performance (Dave Smith)
+ 2. New VM/CMS README.CMS and version_local() (Ian Gorman)
+ 3. cygwin32 port from Cosmin Truta
+ 4. Workaround for tasm32 5.0 bug in win32/crc_i386.asm (Cosmin Truta)
+ 5. win32/match32.asm fixes for tasm 5.0 (Cosmin Truta)
+ 6. simplify OS/390 port (Christian)
+ 7. win32 timezone handling fixes (Christian)
+ 8. fix 40-bit time conversion on the acorn (Sergio and Christian)
+ 9. strip network part from UNC type filenames (Christian)
+10. Makefile for OpenMVS (Ian Gorman)
+11. Use the Watcom getch() for cygwin32 (Christian)
+12. Borland C++ 5.x added to win32's version_local() (Cosmin Truta)
+13. Borland C++ needs tzset() in win32 (Christian, Cosmin Truta)
+-------------------------- May 21st 1998 version 2.3c -------------------
+ 1. Better error messages for -i and -x (Christian)
+ 2. Win32 stat() wrapper needs dos2unixtime (Christian,Paul,Mike)
+ 3. DJGPP: use _chmod to handle LFN attributes correctly (Michael Mauch)
+ 4. Fix Borlandc warnings (Mike)
+ 5. win32/makefile.bor fixes from Michael Mauch
+ 6. win32/makefile.{dj,emx} fixes from E-Yen Tan
+ 7. Use izshr031 (Christian)
+ 8. CMS: use RECFM=V LRECL=32760 by adding "byteseek" (Greg Hartwig)
+ 9. Check external name for trailing "/" (Greg Hartwig)
+10. More specific info in CMS version_local() (Greg Hartwig)
+11. Changed usage info to refer to "fm" rather than "path" on CMS (Greg Hartwig)
+12. No more "extra data" messages when using the same OS (Greg Hartwig)
+13. Rewritten README.CMS, one version for ZIP and UNZIP (Greg Hartwig)
+14. DOS/OS2/WIN32/UNIX: ex2in() strips off "//host/share/" from UNC names (SPC)
+-------------------------- June 23rd 1998 version 2.3d -------------------
+ 1. Fixed Win32's stat() bandaid handling of time stamps (SPC)
+ 2. General fix of file selections for DELETE and FRESHEN action (SPC)
+ 3. CMS_MVS: Use ASCII coding for TIME extra field ID (SPC)
+ 4. EBCDIC: Repaired bogus CMS_MVS fix in zipup.c; check the internal
+    name for trailing (ASCII) '/' to detect directory entries (SPC)
+ 5. Use explicit ASCII coding when comparing or setting chars in iname (SPC)
+ 6. Fixed win32/makefile.bor, win32/makefile.dj (support NTSD),
+    win32/makefile.emx (SPC)
+ 7. Replaced win32/makefile.cyg by win32/makefile.gcc, containing new
+    support for mingw32 GCC environment (SPC)
+ 8. Use izshr032 (SPC)
+ 9. Modified zipup.c to hold (un)compressed lengths in "ulg" variables, in
+    an attempt to support handling of huge (>2GByte) files. (SPC)
+10. Removed some duplicate #defines from api.h, they are now in crypt.h (SPC)
+11. Reenabled "extra data size" info messages in noisy mode for all systems
+    except RISCOS and CMS_MVS (SPC)
+12. For EMX 0.9c, the runtime lib contains a working mktime(), use it (SPC)
+13. Miscellanous cosmetic changes (SPC)
+14. Move win32/makefile.emx to msdos (E-Yen Tan)
+15. make api.h work with zcrypt2.8 (Mike)
+16. define ydays differently in api.h to avoid linking problems (Mike)
+17. New windll.txt (Mike)
+18. win32 lcc patches  (E-Yen Tan)
+19. win32 lcc makefile (E-Yen Tan)
+20. Multiple inclusion bug: no malloc.h when using lcc-win32 (E-Yen Tan)
+21. New VB support files for windll (Mike Le Voi, Raymond King)
+22. MacOS port by Dirk Haase
+-------------------------- August 1st 1998 version 2.3e -------------------
+ 1. Generalized check for validy of TZ timezone setup info, similar to
+    UnZip; use it on AMIGA and MSDOS, as before. (SPC)
+ 2. Apply TZ validy check on OS/2 and enable creation of UT e.f. (SPC)
+ 3. BEOS: New Makefile, updates for README and Contents (Chris Herborth)
+ 4. beos/beos.c: declare some private functions as "local" (SPC)
+ 5. Include memcompress() code only for ports that make use of it, controlled
+    by preprocessor symbol ZP_NEED_MEMCOMPR (SPC)
+ 6. cmsmvs/README.CMS fix: Zip archive entries to be extracted into var-length
+    records CMS files should >>NOT<< contain binary data ... (SPC)
+ 7. crc32.c, crctab.c: the crc polynom table is ZCONST (SPC)
+ 8. trees.c: fixed a bug in the deflate algorithm that limited the compressed
+    size of an archive member to 512 MByte (SPC)
+ 9. deflate.c: Integrated the changes found in zlib that are neccessary to make
+    the deflate algorithm deterministic; modified msdos/match.asm to take
+    care of the "nice_match" global no longer being constant.  (SPC)
+10. deflate.c, trees.c, zipup.c: Reorganized and simplified deflate's
+    compressed output buffer handling. I/O and compression code are now
+    separated more cleanly. (SPC)
+11. Killed bits.c by moving its contents into trees.c resp. zipup.c;
+    synchronized all Makefiles and Make procedures with this change. (SPC)
+12. Integrated support for optionally replacement of deflate and crc32 by
+    public domain zlib code. (SPC)
+13. Synchronize the different variants (UNIX/GNU C, OS/2, WIN32) of i386
+    assembler replacement for deflate's longest_match() (SPC)
+14. Moved the EMX+rsxnt Makefile.emx from msdos/ back into win32/ (SPC)
+15. Restored a separate Makefile.emx for DOS; on DOS, some make programs may
+    have difficulties with recursive invokation (SPC)
+16. Fixed the "include header mess" of the new MACOS port and removed the
+    "work-around hacks" caused by these bad MACOS .h-file includes (SPC)
+17. Integrated Dirk Haase's beta4 (27-Jun-98) release of MacZIP (Dirk Haase)
+18. Added support for MS Quick C in the MSDOS version_local() report (SPC)
+19. Added WIN32 rsxnt targets linking against the emx crtl DLL to Makefile.emx
+    in os2/ and win32/ (SPC)
+20. Fixed typo in os2/os2.c wild() function. (Kai Uwe Rommel)
+21. Removed ChangeNameForFAT() from os2/os2.c in2ex() to fix problem with
+    long filename support. (Kai Uwe Rommel)
+22. os2/os2zip.[ch]: correct type of DOS-style timestamp data is "ulg" (SPC)
+23. vms/cmdline.c: Removed wrong ';' behind if condition (Johnny Lee)
+24. VMS: Preliminary preparations in C code for supporting GNU C on OpenVMS
+    Alpha (Onno van der Linden, Christian Spieler)
+25. VMS: Fixed check against adding zipfile to itself in fileio.c (SPC)
+26. WIN32: Added lcc-Win32 variants of i386 assembler code for crc32() and
+    longest_match(). (SPC)
+27. WIN32: Removed bogus type-cast in assignment to statb st_mode member (SPC)
+28. zip.c: Fixed MACOS-related typo that broke "-@" command option (SPC)
+29. zipup.c: Fixed messed-up expression for assignment to z->ver (SPC)
+30. MACOS extra fields: check realloc return values (Onno, Johnny Lee)
+31. Fix the PUTBYTE macro in trees.c: >= instead of < (Onno)
+-------------------------- September 6th 1998 version 2.3f -------------------
+ 1. Add zp_tz_is_valid to globals.c (Onno, Frank Donahoe)
+ 2. Updated tandem files from Dave Smith
+ 3. Windll: allow comments to zip archive with VB (Mike)
+ 4. Windll: add support for -b and update the documentation (Mike)
+ 5. win32: use wbS for FOPW to handle large zip files better (Steve Miller)
+ 6. MVS fix: use fseek();clearerr() instead of rewind() (Onno, Lee Burton)
+ 7. Updated VB examples for windll (Mike)
+ 8. Tandem: use UTC timestamps and GID/UID in extra field (Dave Smith)
+ 9. Tandem: handle -o option (Dave Smith)
+10. default for ZCONST is const in tailor.h, override in osdep.h (Onno)
+11. additional Macintosh options in zip.c (Dirk Haase)
+12. additional Macintosh options in zip.1 and MANUAL (Onno, Dirk Haase)
+13. Integrate Beta 5 of the Macintosh Port (Dirk Haase)
+-------------------------- October 27th 1998 version 2.3g -------------------
+ 1. zip_tz_is_valid should be zp_tz_is_valid (Kai Uwe)
+ 2. MVS native (not OE) beta fixes (Keith Owens)
+ 3. LynxOS support from Giuseppe Guerrini
+ 4. MVS already has stat() and fstat() so use 'em (Keith Owens)
+ 5. MVS fix in readzipfile() for new, unopened dataset without EOF marker
+    (Keith Owens)
+ 6. Remove 16-bit stuff from windll/windll.rc (Mike)
+ 7. Windll: Use hCurrentInst not hInst (Mike)
+ 8. In util.c compare strchr() return value with NULL (Onno, Frank Donahoe)
+ 9. unix/unix.c: initialize variable t in ex2in() (Onno, Frank Danahoe)
+10. Remove windll/borland subdirectory (Mike)
+11. Really fix extra field realloc() for BeOS and MacOS (Christian)
+12. Fix the dj2 LFN related access violation bug (Christian, Joe Forster)
+13. proginfo/3rdparty.bug: Added more info about other Zip clone's bugs.
+14. The global copyright definitions in revision.h now depend on DEFCPYRT
+    (Christian).
+15. tandem/macros: removed obsolete object file references (Christian)
+16. fix memory leak with the "filter" patterns (Christian, Leah Kramer)
+17. zip.c: completed the support for MacOS specific -N (Christian)
+18. reorganized the Mac specific help screen code (Christian)
+19. zipup.c: corrected the USE_ZLIB code to emit "stored" entries under
+    the same conditions as the "native deflate" code (Christian)
+20. A couple of vars that will never be negative should be unsigned (Christian)
+-------------------------- November 18th 1998 version 2.3h -------------------
+ 1. DJGPP: When compressing from stdin don't set binary mode if stdin is
+    a terminal (E-Yen Tan)
+ 2. Fix signed/unsigned comparisons in fileio.c, util.c and zipcloak.c
+    (Frank Donahoe)
+ 3. Move macgetch() prototype from macos/source/macos.c to macos/osdep.h
+    (Christian)
+ 4. _doserrno should have type int, not unsigned int (Christian)
+ 5. In zipfile.c init a file pointer with NULL to fix gcc warning (Christian)
+ 6. Upgrade to MacOS beta 7 (Dirk Haase)
+ 7. Move the #pragma statements from generic sources to cmsmvs.h (Christian)
+ 8. Support for QNX/Neutrino 2.0 (Chris)
+ 9. Default to -r in help screen add -R at the bottom (Chris)
+10. Clean up Makefile for BeOS R4 on x86 (Chris)
+11. Beos: If not storing symlinks store attributes of symlink target (Chris)
+12. Use izshr037 (Christian)
+13. Remove ZIPERR() macro from in {msdos,win32}/osdep.h (Christian)
+14. win32/win32.c: Fix 1-day offset in non-64bit FileTime2utime() (Christian)
+15. win32: enable 64-bit FileTime2utime() for MS VC++ >= 5.0 (Christian)
+16. cygwin32 only has _P_WAIT (Thomas Klausner)
+17. msname() should *really* ignore illegal characters (Thomas Klausner)
+18. Fix a missing ')' in Opendir() from win32zip.c (Thomas Klausner)
+-------------------------- December 5th 1998 version 2.3i -------------------
+ 1. Remove the #pragma statements that were forgotten the first time (Ian)
+ 2. Remove obsolete macos/source/CharMap.h (Steve Salisbury)
+ 3. isatty(fileno(zstdin)) in zipup.c should be isatty(zstdin)
+    (Onno, E-Yen Tan)
+ 4. several "shut up warnings from compiler" fixes (Christian)
+ 5. several cosmetic source changes (Christian)
+ 6. win32: make NTSD handling to be robust against alignment and structure
+    padding problems (Christian)
+ 7. Apply don't set binary mode when stdin is a terminal in zipup.c for
+    MSDOS and human68k (Christian)
+ 8. Upgrade to MacOS beta 8 (Dirk Haase)
+ 9. Add callback for WINDLL to handle user termination (Mike)
+10. Fix typo in acornzip.c (Darren Salt)
+11. acorn/sendbits.s: pass correct parameters to flush_outbuf() (Darren Salt)
+12. Fixes for IBM C/C++ 3.6 where time_t is a double (Kai Uwe)
+13. Fixes for IBM Visual Age C++ for win32 (Douglas Hendrix)
+14. man/zip.1: some version numbers in the text were still "2.2" (Christian)
+15. win32/makefile.emx: added a compilation variant that generates
+    standalone executables (Christian)
+16. change __CYGWIN32__ into __CYGWIN__ and add compatiblity definition for
+    B19 and older (Cosmin Truta)
+17. create uniform win32 getch() replacement (Christian)
+18. put back in define of USE_EF_UT_TIME in tandem.h (Dave Smith)
+19. put back in define of USE_CASE_MAP in tandem.h (Dave Smith)
+20. updates to make/macros to allow the object to be licensed (Dave Smith)
+21. updates to macros/doit to remove mktime.c (Dave Smith)
+22. updates to tandem.c for in2ex/mapname/chmod amendments to match Unzip
+    (Dave Smith)
+23. Use izshr039.zip (Christian)
+24. Init filenotes to 0 for the amiga too (Onno)
+25. get_filters(): remove one flag=0 statement to make -R work again (Onno)
+-------------------------- December 17th 1998 version 2.3j ------------------
+ 1. FOPWT defines opening a temp file for writing (Ian)
+ 2. Remove handling of bits.c from a couple of tandem files (Christian)
+ 3. A couple of "shut up warnings from compiler" fixes (Christian)
+ 4. win32/osdep.h: removed duplicate "IZ_PACKED" definition (Christian)
+ 5. win32/zipup.h: remove invalid "elseif" preprocessor token (Christian)
+ 6. sync MacOS help screen with other ports (Christian)
+ 7. get_filters(): set flag to 0 when -R isn't used (Christian)
+ 8. "local extra != central extra" now has "info" status (Christian)
+ 9. use windll directory as "home" directory for builds (Mike)
+10. CMS/MVS: define FOPWT (Ian)
+11. Upgrade to MacOS beta 9 (Dirk Haase)
+-------------------------- January 17th 1999 version 2.3k ------------------
+ 1. Change FOPW into FOPW_TMP (Christian)
+ 2. win32: #include uses paths relative to the parent directory (Christian)
+ 3. Use forward slashes as path separator in #include statements (Christian)
+ 4. windll: fix descriptions of f{In,Ex}cludeDate (Christian)
+ 5. win32/makefile.lcc: add some -I<path> options to find files in the
+    right places (Christian)
+ 6. Supply default empty IZ_PACKED define (Christian)
+ 7. windll: Fix some typos, descriptions (Christian)
+ 8. windll project files: use relative paths, no specific root directory
+    (Christian)
+ 9. windll project files: remove link references to import libraries that
+    are not used by the zip library (Christian)
+10. windll: fix potential infinite loop in a VB sample (Mike)
+11. windll/windll.txt: remove "may not work with VB" statement (Mike)
+12. Multibyte character set support from Yoshioka Tsuneo
+13. Theos port from Jean-Michel Dubois
+14. Tandem: added simple handling of Enscribe files by converting them into
+    text type files (Dave Smith)
+15. Tandem Extra Field ("TA") containing Tandem File Attributes (Dave Smith)
+16. Tandem history file showing background info to (UN)ZIP ports (Dave Smith)
+17. create ZIP file on tandem with special file code (1001) (Dave Smith)
+18. made tandem.c & tandem.h code completely the same as UNZIP (Dave Smith)
+19. unix/configure: move +Onolimit and -Olimit into the machine specific
+    section (Onno, John Wiersba)
+-------------------------- February 21st 1999 version 2.3l ------------------
+ 1. Fix qdos Makefile (Jonathan Hudson)
+ 2. fgets instead of gets in zipnote to fix linker warnings (Jonathan Hudson)
+ 3. Theos: remove _setargv.c and a reference in zip.c (Jean-Michel Dubois)
+ 4. Theos README (Jean-Michel Dubois)
+ 5. interchanged the fRecurse flag values for "-R" and "-r" (Christian)
+ 6. add "z" pr prefix to MBCS functions to avoid name clashes (Christian)
+ 7. Whenever the position of the increment operator does not matter, the
+    INCSTR variant is used, which has been mapped to the {PRE|POS}INCSTR
+    variant that is more efficient. (Christian)
+ 8. fixed the "-R" handling in fileio.c, filter() function (Christian)
+ 9. simplified some THEOS specific code additions (Christian)
+10. changed the line break of the compiler version message in version_local()
+    for MSDOS and Win32 to take into account some verbose compilers (Christian)
+11. removed the THEOS changes from ttyio.c. Instead, a THEOS specific
+    setup was added to ttyio.h (Christian)
+12. sync vms/link_zip.com with the corresponding make_zip.com (Christian)
+13. added compatibility settings for support of MBCS on Win32 with all tested
+    compilers to win32/osdep.h
+14. added type-casts to isalpha() macro calls (Christian)
+15. fixed win32's wild_match which was clobbered by the MBCS addition
+    (Christian)
+16. finished up the "potential infinite loop" problems in the VB sample
+    that Mike started to repair (Christian)
+17. in ziperr.h, AZTEK C might require the false comma that was removed
+    to satisfy THEOS C (Christian)
+18. removed the bogus THEOS specific isdir check in zipup.c (Christian)
+19. modified the code for line ending translation to be independent
+    of the local system's convention for '\n' and '\r'; this allowed
+    the removal of the THEOS specialities (Christian)
+20. Tandem: -B option to zip Enscribe files with no record delimiters
+    (Dave Smith)
+21. Tandem: attempt to catch Large Transfer mode failure (Dave Smith)
+22. Theos: Fixed keyboard entry functions. (Jean-Michel Dubois)
+23. Theos: workaround for the argument wild card expansion that is bugged
+    in the standard library. Managed by MAINWA_BUG flag. (Jean-Michel Dubois)
+24. Theos: support for filenames and notes with accented characters.
+    (Jean-Michel Dubois)
+25. Upgrade to MacOS final (Dirk Haase)
+-------------------------- March 31st 1999 version 2.3m -------------------
+ 1. Theos: for relative paths to root directory cause open, fopen and stat
+    failure, workaround this. (Jean-Michel Dubois)
+ 2. Theos: when no path is indicated in a file or directory name and the
+    file or directory doesn't exist in the current directory it looks for
+    the file or directory in the root directory, workaround this.
+    (Jean-Michel Dubois)
+ 3. Corrected some typos and spelling error in macos/HISTORY.TXT; skipped
+    off invisible trailing whitespace (Christian)
+ 4. proginfo/extra.fld: added documentation for Tandem and Theos extra
+    field layout (Christian with Dave D Smith resp. Jean-Michel Dubois)
+ 5. qdos/Makefile.qdos: The build of ZipCloak requires inclusion of
+    the crctab object module; qfileio_.o compilation requires the -DUTIL
+    flag (Christian)
+ 6. win32: fix incorrect MB_CUR_MAX macro for mingw32 and lcc (Christian)
+ 7. theos/_fprintf.c, theos/_rename.c, theos/osdep.h: Some function
+    parameters require the "const" attribute to achieve compatibility
+    with ANSI C requirements (Christian)
+ 8. theos/theos.c: map Theos' (No)Hidden file attribute to MSDOS Hidden
+    bit in the MSDOS part of zipentry header's external attribute field;
+ 9. theos/stat.h: prevent multiple inclusions
+10. Theos: Fixed wild card management for options other than adding
+    (Jean-Michel Dubois)
+11. Theos: Removed modifications of const strings (Jean-Michel Dubois)
+12. Split tandem.c up into separate zip/unzip parts (Dave Smith, Christian)
+13. Move inclusion of OS specific zipup.h files to tailor.h (Onno)
+-------------------------- August 14th 1999 version 2.3n -------------------
+ 1. Move inclusion of OS specific zipup.h files back to zipup.c (Onno)
+ 2. Remove getline() from zipnote.c and use gets() again (Onno)
+ 3. BeOS PowerPC R4.1 support (Chris)
+ 4. New DOIT and MACROS files for the tandem port (Dave Smith)
+ 5. Don't switch the console to binary mode (Michel de Ruiter)
+ 6. In some circumstances undosm could be freed twice (Mike)
+ 7. Also define const in tailor.h for ultrix (Onno, Foppa Uberti Massimo)
+ 8. Tandem: Change zopen in TANZIPC to allow opening of files with missing
+    alt keys (err 4) (Dave Smith)
+ 9. Tandem: Assume not DST if can't resolve time (no DST table available)
+    (Dave Smith)
+10. WIN32: skip trailing dots and spaces in getnam (Onno, Dan Kegel)
+11. Use ZE_NONE when nothing to freshen or update (Onno, Yuri Sidorenko)
+12. Remove tabs from files that don't need them (Onno)
+13. Remove tabs and spaces from the end of a text line (Onno)
+14. Upgrade macos to 1.04b2 (Dirk)
+15. Add -Q documentation to manual page (Jonathan Hudson)
+16. Copy hiperspace files instead of renaming them (Keith Owens)
+17. Disallow some more characters to appear in DOS filenames when using -k
+    (Onno, Thomas Klausner)
+18. Document missing options and environment variables in the manual (Onno)
+19. New acorn/GMakefile to compile with gcc on RISCOS (Darren Salt)
+20. ISO 8601 date format support for -t and -tt (Rodney Brown)
+-------------------------- September 21st 1999 version 2.3o -------------------
+ 1. Sync zip.h license with LICENSE (Onno)
+ 2. Add copyright notice to README, os2zip.c and os2.zip.h (Onno, Greg)
+ 3. Fix the ASM variable in acorn/GMakefile (Darren Salt)
+ 4. Add another requirement to acorn/ReadMe.GMakefile (Darren Salt)
+ 5. Fix unbalanced parenthesis in vms_get_attributes declaration in zip.h
+    and move it to vms/zipup.h (Onno, Mike Freeman)
+ 6. Make a couple of os2 files public domain (Kai Uwe)
+ 7. Change and rename disclaimer array in revision.h (Onno)
+ 8. Change copyright array in revision.h (Onno)
+ 9. macstuff.c copyright is the same as macstuff.h (Christian)
+10. WHATSNEW: add ISO 8601 dates supported (Christian)
+11. fileio.c - msname(): strip off leading dots, these are illegal for
+    MSDOS compatible names (Christian)
+13. fileio.c - replace(): deactivate "dead" code for CMS_MVS (Christian)
+14. man/zip.1: "-$" option is also used for WIN32 ports
+15. msdos/msdos.c - version_local(): break the version line for
+    GNU compilers too (Christian)
+16. tailor.h: added typecasts to MBCS macros, to suppress "type mismatch"
+    warnings (Christian)
+17. util.c, zip.h, zipfile.c: ZCONSTify several pointers (Christian)
+18. util.c - recmatch(), zip.c - version_info(): add compile time option
+    WILD_STOP_AT_DIR (Christian, Darren Salt)
+19. util.c - envargs(): MBCS related fixes (Christian)
+20. win32/lm32_lcc.asm: add TAB characters that are required by the lcc
+    assembler source parser (Christian)
+21. zip.c: fix the "is a console" check (Christian)
+22. zipnote.c: use getline() (Christian)
+23. zipup.c: use zclose() in case of I/O errors (Christian)
+24. zipup.c: use ZE_WRITE when a write error occurs (Christian)
+25. win32/win32.c: HAVE_INT64 is used by mingw32 (Cosmin Truta)
+26. update shared sources to match izshr041 (Christian)
+-------------------------- November 29th 1999 version 2.3 ------------------
+ 1. Missing parenthesis in win32/win32.c (Steve Salisbury)
+ 2. Add Cosmin Truta to proginfo/infozip.who (Onno)
+ 3. Remove one parenthesis pair too many from vms_get_attributes() declaration
+    in vms/zipup.h (Mike Freeman)
+ 4. qdos .s are expected to start with a #, work around it (Jonathan Hudson)
+ 5. tandem: -B0 should be deflating not storing (Dave Smith)
+ 6. human68k updates from Shimazaki Ryo
+ 7. beos Makefile cleanup (Chris)
+ 8. workaround for fseek to negativate offset behaviour of the RISC OS
+    SharedCLibrary (Darren Salt)
+ 9. set file type for RISC OS in zipcloak.c (Darren Salt)
+10. change tandem zgetch() to allow crypt version to work (Dave Smith)
+11. fix a comment typo in acorn/riscos.c (Christian)
+12. fileio.c: two type-cast to shut up noisy compilers (Christian)
+13. human68k: fix missing case_flag argmument (Christian)
+14. win32/win32.c: remove HAVE_INT64 completely (Christian)
+15. zip.c: raise "cannot zip to console" error when stdout IS a tty (Christian)
+16. zip.h: don't use dummy argument names in declarations (Christian)
+17. Add missing semicolon in fileio.c (Shimazaki Ryo)
+18. win32.c: IBMC compiler >= 3.50 have int64 (Kai Uwe)
+19. Handle initialization error return value from MVS stat() in procname()
+    (Keith Owens)
+20. Use RISC OS instead of RiscOS in the manual (Darren Salt)
+21. Use # instead of ? as single character wildcard on RISC OS (Darren Salt)
+22. New windll example.c (Mike)
+23. Correct storage of 8-bit char filenames with RSXNT (Burkhard Hirzinger)
+24. fix install in unix/Makefile (Santiago Vila, Onno)
+25. Fix zip -L output (Santiago Vila, Onno)
+26. Ignore unix special files (Jonathan O'Brien)
+27. Upgrade to izshr042 (Onno)
+28. Make copyright notice the same as in izshr042 (Onno)
+29. Make copyright notice in zip.h the same as LICENSE (Christian)
+30. Set tempzf to NULL _after_ it has been closed (Chris Kacher)
+31. Change email address for Jonathan Hudson (Jonathan Hudson)
+32. Remove win32/winzip.c.orig (Steve Salisbury)
+33. Use 'Steve Salisbury' throughout the documentation (Steve Salisbury)
+34. Change email address for Steve Salisbury (Steve Salisbury)
+35. Change email address for Chris Herborth (Chris Herborth)
+36. Use zip23 in INSTALL (Roger Cornelius)
+37. Use zcrypt28 in INSTALL (Onno)
+38. New acorn/srcrename (Darren Salt)
+39. amiga/makefile.azt: make clean should remove some more items (Paul)
+40. Change email address for Cosmin Truta (Cosmin Truta)
+-------------------------- February 11th 2001 version 2.4a ------------------
+ 1. Identify newer Borland compilers (Brad Clarke)
+ 2. Detect Turbo C 2.01 which doesn't have mktime (Brian Lindholm)
+ 3. Fix the use of -@ together with -i -x (Christian)
+ 4. Update msdos/README.DOS to match reality (Christian)
+ 5. win32: use assembler crc32 code (Christian)
+ 6. windll: _CRTIMP is needed in several function declarations (Christian)
+ 7. back to zip 2.2 memcompress() behaviour  (Kelly Anderson)
+ 8. new amiga time code based on nih public domain code  (Paul Kienitz)
+ 9. Detect some more Borland C++ builder versions (Brad Clarke)
+10. Fix OS/2's extended file attributes compression code (Christian, Kai Uwe)
+11. Correct translation of EBCDIC passwords to ASCII (Christian)
+12. Attempt at integrating novell patches from Roger Foss (Onno)
+13. Use izshr043 (Christian)
+-------------------------- July 3rd 2001 version 2.4b ------------------
+ 1. Fix OS/2's ACL compression code (Christian, Kai Uwe)
+ 2. Rename netware subdir to novell (Christian)
+ 3. Remove -dNETWARE -dDOS from novell Makefile (Christian)
+ 4. Remove defined(NETWARE) from the sources (Christian)
+ 5. printf is a macro in glibc 2.2, fix version_local function
+    (Christian, Matthew Wilcox)
+-------------------------- January 13th 2002 version 2.4c ------------------
+ 1. Use klist_items when initilizating koff[] in tandem.c (Dave Smith)
+ 2. Only call NLMsignals() in zip.c when NLM is defined (Mike, Onno)
+ 3. include riscos.h instead of acorn/riscos.h in acorn/osdep.h (Andy Wingate)
+ 4. Use izshr044 (Christian)
+-------------------------- January 13th 2002 version 2.4d ------------------
+ 1. Don't use mmap for stored entries (Christian)
+ 2. BIG_MEM and MMAP cannot be defined at the same time (Christian)
+ 3. Allow redirection of version screen to file (Christian)
+ 4. Fix for OS/2 output redirection bug (Christian, Kai Uwe)
+ 5. Acorn script for creating self extracting zips (Darren Salt)
+ 6. Update amiga makefiles to support revised timezone routines (Christian)
+ 7. Correct memcompress calculation for allocation size (Christian)
+ 8. Fix FORCE_METHOD debug option for level 1 and 2 (Christian)
+ 9. Whitespace cleanup in man/zip.1 (Christian)
+10. Define IZ_IMP to specify compiler declaration prefixes (Christian)
+11. make win32 and msdos version_local() "stdio-macro-safe" (Christian)
+12. move tandem's zip specific zipopen to tanzip.c (Christian)
+13. first parm is void * in external scope of vms_get_attributes() (Christian)
+14. use right novell subdirectory in zipup.c (Christian)
+15. update copyright for files modified in 2002 (Onno)
+-------------------------- January 19th 2002 version 2.4e ------------------
+ 1. Add MacOS X to version_local() (Mark)
+ 2. unix/configure: Init LFLAGS1 to "", MacOS X doesn't like -s (Onno, Mark)
+ 3. rename errors array to ziperrors to avoid MacOS X library clash (Mark)
+ 4. Support for the upx executable packer in DOS makefiles (Christian)
+ 5. remove obsolete -m486 switch from dos djgpp makefile (Christian)
+ 6. When using DOS, force the use of msdos style external attributes when
+    updating zip entries created under another OS (Christian)
+ 7. os2/makefile.os2: fixed ASFLAGS for watcom16dos (Christian)
+ 8. Update copyright and ftp address in several files (Christian)
+ 9. The RISCOS port uses '.' as directory separator, not '/' (Christian)
+10. win32/makefile.bor: more options to compile the asm CRC code (Christian)
+11. win32: use registry to handle timezones with MS C rtl (Christian)
+12. acorn: use recommended practice for calling the linker (Andy Wingate)
+13. unix/configure: check if CPP works else use ${CC} -E (Onno, Mark)
+14. update versioninfolines in revision.h to match reality (Onno)
+-------------------------- February 10th 2002 version 2.4f ------------------
+ 1. vms: Zip -V is now able to handle file sizes up to 4Gb (Christian)
+ 2. vms: Include target environment detection for MMS/MMK (Christian)
+ 3. Change dummy message from zipcloak (Christian)
+ 4. acorn: add riscos specific -/ option (Darren)
+ 5. Update acorn's WILD_STOP_AT_DIR feature (Christian)
+ 6. acorn: Fix buffer allocation for -/ option (Christian, Darren)
+ 7. acorn: fix make clean (Andy Wingate)
+ 8. acorn: use tabs for GMakefile to make GNU make happy (Andy Wingate)
+ 9. tandem: use nskopen not zipopen (Dave Smith)
+10. tandem: allow passing of CRYPT define (Dave Smith)
+11. use izshr045 (Christian)
+-------------------------- April 1st 2002 version 2.4g ------------------
+ 1. acorn: fix assembler and compiler options in makefile (Darren)
+ 2. use izshr046 (Christian)
+ 3. MVS: define isatty to 1 to fix screen output (Christian)
+ 4. tandem: encryption really works now (Dave Smith)
+ 5. win32: detect Borland C++ builder 6 (Brad Clarke)
+-------------------------- April 30th 2003 version 2.4h ------------------
+ 1. tandem: fix temporary file contention (Dave Smith)
+ 2. cmsmvs: generate better filenames with -j (Owen Leibman)
+ 3. tandem: fix temporary file leftovers (Dave Smith)
+ 4. solaris: enable large file I/O to break 2G barrier (Rick Moakley, Onno)
+
+Note:  Zip 2.4 was never released.  That code was the start of the Zip 3.0
+effort below.  Some changes and fixes also made it to the Zip 2.3x releases.
+
+---------------------- January 21st 2004 version 3.0a ----------------------
+Initial work on Zip 3.0 by Ed Gordon and Rainer Nausedat
+ 1. Changed some comments to update copyrights (Ed)
+ 2. Changed text in command line messages from zip 2.4 to zip 3.0 (Ed)
+ 3. Changes to many files for Zip64 wrapped in ifdef ZIP64_SUPPORT (Rainer)
+ 4. Attempt to fix buggy Win32 buffered 64-bit calls (Ed)
+ 5. Add functions to zipfile.c for Little-Endian memory writes (Rainer)
+ 6. Add functions to zipfile.c for writing Zip64 extra fields (Rainer)
+ 7. Major changes to putlocal, putcentral, and putend (Rainer)
+ 8. Fixing -F and -FF for Zip64 postponed (Ed and Rainer)
+ 9. Command line code replaced.  Global table sets options, long options now
+    supported.  Permutes so order of arguments can vary (Ed)
+10. Fix bug where not allowed to use -@ with stdout but was with stdin.
+    Now can read filenames from stdin using -@ and output to stdout and
+    no longer am allowed to use -@ if reading from stdin (Ed)
+11. Replace stat() with zstat(), fstat() with zfstat() and struct
+    stat with z_stat in Zip64 blocks.  Put 64-bit file calls in ifdef
+    LARGE_FILE_SUPPORT blocks.  Can implement Zip64 without > 4 GB
+    file support but for now need large files for Zip64 support (Ed)
+12. Move port-specific code to osdep.h and win32.c (port specific) and
+    tailor.h (generic) and remove temporary os_io.c.  As OF() is
+    not defined until after osdep.h includes in tailor.h function
+    prototypes for zfseeko, zftello, and zstat after that in tailor.h (Ed)
+13. Settings of ZIP64_SUPPORT and LARGE_FILE_SUPPORT automatic based on
+    port and version of compiler.  Defining NO_ZIP64_SUPPORT or
+    NO_LARGE_FILE_SUPPORT overrides this (Ed)
+14. Bugs compiling scanzipf_fix(...) in zipfile.c and the fix functions could
+    use rewrite (Rainer and Ed)
+15. Add prototype for zfopen for mapping to 64-bit fopen on ports using
+    inodes but not implemented (Ed)
+16. More work on extended local headers and encypted archives (Rainer)
+17. Fix DLL files so now compiles (Ed)
+18. File size in dll limited to 32-bit in structure.  A new DLL api is needed
+    to return 64-bit file sizes.  Current api fixed to return max 32-bit if
+    more than that (Ed)
+19. Add local header Zip64 support and local extra field.  Fixed cast
+    to ulg missed previously that forced zstat to return value mod 4 GB in
+    zipup.c which kept local header code from seeing actual file size (Ed)
+20. Add new option --force-zip64 to force use of zip64 fields.  Could
+    be temporary (Ed)
+21. Fix for VB added to api.c that just store the passed strings internally.
+    Should update api to optionally return file sizes as 64-bit in call back
+    and to accept RootDir and other strings in same call that zips (Ed)
+22. Readme updated to describe new features and mention updated mail group
+    web links (Ed)
+23. Minor bugs in output format found and fixed.  Now can add
+    files > 4 GB to archive and unzip using major unzippers (Ed)
+24. If zip used as filter (zip - -) and sizes exceed limits of extended
+    local header (data descriptor) then set max 32-bit values there.  Major
+    unzippers ignore and use central directory values which are correct.  Can
+    create Zip64 data descriptor using --force-zip64 option but seems no need
+    for it (Ed)
+25. A few bugs in how headers are handled prevented zipping large numbers
+    of files.  Fixed (Rainer)
+26. A bit of an attempt to fix -F and -FF.  Seems to work but not that
+    robust.  More work needed (Ed)
+27. After some cast and other fixes zip compiles on Linux Red Hat 9 using Unix
+    generic.  Added automatic detection of fseeko64 and if detected
+    sets LARGE_FILE_SUPPORT and setting that sets ZIP64_SUPPORT.  Works but
+    could not test large files on the small system (Ed)
+28. Tried to fix bug that prevents zipnotes from compiling when ZIP64_SUPPORT
+    is set.  Still broke.  This crashes the Unix Makefile but after
+    zip is compiled (Ed)
+---------------------- May 8th 2004 version 3.0b ----------------------
+ 1. Update license headers on more files (Ed)
+ 2. Change many ZIP64_SUPPORT ifdefs to LARGE_FILE_SUPPORT where appropriate.
+    Now can test ports using three stages, compile with NO_LARGE_FILE_SUPPORT
+    (which disables ZIP64_SUPPORT) to test base code, compile with
+    NO_ZIP64_SUPPORT to test the 64-bit file calls (assuming port sets
+    LARGE_FILE_SUPPORT) but otherwise use the base code, and without either
+    to test Zip64 if enabled on port (Ed)
+ 3. Fix zipnotes bug by moving a ZIP64_SUPPORT block in zipfile.c (Ed)
+ 4. Add Large File Summit (LFS) code to Unix port to enable 64-bit calls.
+    Update configure to include test for all needed 64-bit file calls before
+    enabling LARGE_FILE_SUPPORT for unix port (Ed)
+ 5. Merge encryption code from zcrypt29 (files from unzip) into zip and
+    enable by default (Ed)
+ 6. New man pages for zipnote, zipsplit, and zipcloak (Greg, Ed)
+ 7. Add encryption notice to crypt.c comments and to version information
+    in zip.c (Greg, Ed)
+ 8. Add Russian OEM EBCDIC support when OEM_RUSS defined in ebcdic.h but
+    Dmitri reports that 0x2F not '/' so make recommended change in cutpath
+    call in zipfile.c used by -D option (Dmitri - Nov 10 2003 email)
+ 9. ToDo30 file added to list what's left to do in this release (Ed)
+10. Change fopen to zfopen for large file code and map to fopen64 for
+    Unix (Ed)
+11. ftello64 seems broken in zipup.c on Linux (kernel 2.4), returning
+    negatives past the 2 GB barrier, though ftello64 works in a test program.
+    Likely error in defines.  For now skip ftello64 check for Unix with
+    LARGE_FILE_SUPPORT.
+12. A few updates in Readme.  Needs overhaul likely.  Also verified mxserver
+    is gone and replaced with list addresses (Ed)
+13. First iterations at updating WinDLL for Zip64 (Mike)
+14. Decide to drop backward dll compatibility in favor of a cleaner
+    dll interface.  Decide to add string interfaces for VB (Ed, Mike)
+15. Add string interfaces to dll interface to bypass array limitations
+    imposed by VB and add -x and -i to interface (Mike)
+16. Create new VB example using new Zip64 dll interface (Ed)
+17. Add O_LARGEFILE define for zopen in unix/zipup.h to enable reading
+    large files in unix (Ed)
+18. Combine ZpSetOptions and ZpArchive dll calls to allow removing all VB kluges
+    in api.c to work around VB garbage collecting passed strings (Mike)
+19. Change new VBz64 example to use updated interface.  All works without
+    kluges (Ed)
+---------------------- August 15th 2004 version 3.0c ----------------------
+ 1. Add date formats in -t and -tt date errors (Ed)
+ 2. Add -so to display all available options (Ed)
+ 3. Many fixes from Dan Nelson to fix some large file support problems and
+    add large file support to a few ports.  Main change is rather than use
+    explicit 64-bit calls like fopen64 now set 64-bit environment and use
+    standard calls.  Also add a define for 64-bit printf format used to
+    print 64-bit stats (Dan, Ed)
+ 4. Changes to Unix config based on suggestions from Dan Nelson.  Check
+    if off_t is at least 64 bit (Dan, Ed)
+ 5. Add -- to get_option.  Any arguments after -- on command line now
+    read as paths and not options (Ed)
+ 6. Add extended help (Ed)
+ 7. Change add_filter flag parameter from char to int as some compilers have
+    problems with char arguments (Ed)
+ 8. Changed filter() to do R and i separately so i has precedence over R (Ed)
+ 9. Split variable t in zip.c into t (off_t) and tf (ulg) (Ed)
+10. Add quotes to zipname in check_zipfile for MSDOS to allow spaces in
+    archive path given to unzip to test ( , Ed)
+11. Move zip.h include before ctype.h include in trees.c and zipup.c as
+    when ctype.h is first and using 64-bit environment at least on unix port
+    found it defines off_t as 4 bytes in those files as off_t is defined as
+    8 bytes in other files and this changes the size of the zlist structure
+    which is not good (Ed)
+12. Add default 64-bit file environment to tailor.h if LARGE_FILE_SUPPORT
+    is set but no port 64-bit file defines are set up earlier in the file.
+    Should allow other ports to set LARGE_FILE_SUPPORT on the compiler
+    command line to test if the standard defines work (Ed)
+13. Adjust binary detection in trees.c by changing 20% binary (4 out of 5
+    ascii) that used >> 2 to 2% (64 out of 65) using >> 6 instead.
+    trees.c  (Ed)
+---------------------- November 12th 2004 version 3.0d ----------------------
+ 1. Add global variable for EncryptionPassword in VBz64 example and
+    some other password callback cleanup (Ed)
+ 2. Add -W option to turn on WILD_STOP_AT_DIR where wildcards will not
+    include directory boundaries in matches (Ed)
+ 3. Add -nw option "no wild" to completely disable wildcards in MATCH
+    function.  Allows a list of files to be read in without worrying about
+    wildcards or escapes (Ed)
+ 4. Add -s option split-size but not implemented (Ed)
+ 5. Add -sp option split-pause but not implemented (Ed)
+ 6. Add changes for WiZ including moving Win32 64-bit wrappers into
+    win32i64.c to avoid naming conflict between libraries in WiZ (Mike, Ed)
+ 7. Some large file fixes in crypt.c (Ed)
+ 8. Add new error code ZE_UNSUP for unsupported compiler options.  Add
+    check of size of zoff_t in zip.c when LARGE_FILE_SUPPORT enabled (Ed)
+ 9. Changed ZE_UNSUP to ZE_COMPERR to avoid conflict with unzip (Ed)
+10. On VMS (sufficiently recent, non-VAX), DECC$ARGV_PARSE_STYLE is set
+    automatically to preserve case of the command line if the user has
+    SET PROCESS /PARSE = EXTEND.  This obviates quoting upper-case
+    options, like -V, when enabled.  VMS.C (Steven Schweda (SMS))
+11. On VMS, building with macro VMS_PRESERVE_CASE defined preserves case
+    of names in archive, instead of forcing lower-case (the former and
+    current default behavior).  VMSZIP.C (SMS)
+12. On VMS, in some of the simplest cases, ODS5 extended file name
+    escape characters ("^") are removed from names in archive.
+    VMSZIP.C (SMS)
+13. On VMS, fixed a problem in some cases with mixed-case directory
+    names, where too much of the directory hierarchy was included in the
+    path names in the archive.  VMSZIP.C (SMS)
+14. On VMS, minor changes for large file support (long -> zoff_t).
+    VMSZIP.C (SMS)
+15. On VMS, changed some structure declarations to typedefs, and
+    rearranged to simplify #if's and reduce potential name conflicts.
+    VMS.H, VMS_IM.C, VMS_PK.C (SMS)
+16. On VMS, reformed -V (/VMS) processing.  Added -VV (/VMS=ALL).
+    Removed some sign bits to accomodate files bigger than 2GB.
+    CMDLINE.C, VMS_IM.C, VMS_PK.C, ZIP.C, ZIP_CLI.CLD, ZIP_CLI.HELP,
+    ZIPUP.H (SMS)
+17. Update command line options to support -VV as distinct option (Ed)
+18. More VMS changes (SMS)
+19. Add zoff_t format function (SMS)
+20. On VMS, when -b was not used, temporary archive files were always
+    created in the current default directory, rather than in the archive
+    file destination directory.  VMS now uses its own tempname()
+    function.  FILEIO.C, VMS.C (SMS)
+21. Remove using FNMAX for path size in a few places including filetime.c
+    to avoid exceeding limit (based on fixes from Greg and others) (Ed)
+22. Add port atheos (Ruslan Nickolaev, Ed)
+23. Bug fix adds different extra fields for local and central in VMS (SMS)
+24. Now short options also take optional values as next argument (Ed)
+25. Change -dd to control -v dots (SMS, Ed)
+26. On VMS, a new open callback function senses (where supported) the
+    process RMS_DEFAULT values for file extend quantity (deq),
+    multi-block count (mbc), and multi-buffer count (mbf), and sets the
+    FAB/RAB parameters accordingly.  The default deq is now much larger
+    than before (16384, was none), and the default mbc is now 127
+    (up from 64), speeding creation of a large archive file.  Explicitly
+    set RMS_DEFAULT values override built-in defaults.  OSDEP.H, VMS.C
+    (SMS)
+27. VMS CLI definitions and CLI help have been updated, and may be
+    approximately correct.  CMDLINE.C, ZIP_CLI.CLD, ZIP_CLI.HELP (SMS)
+28. The man file zip.1 updated and Makefile updated to generate manual
+    pages for zipcloak.1, zipnote.1, and zipsplit.1 (Ed)
+---------------------- July 23rd 2005 version 3.0e ----------------------
+ 1. Debian patch 004 - apply 2.4i configure changes from Onno to remove
+    need for -fno-builtin in unix/configure (Onno, Ed)
+ 2. Debian patch 005 for bug 279867 - fix bug that could crash on large paths
+    and create security problem.  Apply patch changes from Greg (Greg, Ed)
+ 3. SourceForge patch 1074363 - add win32i64.c to win32/makefile.w32 (Ed)
+ 4. Add check when not ZIP64_SUPPORT in scanzipf_reg() in zipfile.c if
+    Zip64 archive being read (Ed)
+ 5. Renamed fzofft() used to format zoff_t values to zip_fzofft() to remove
+    conflict when combined with UnZip in WiZ (Mike)
+ 6. Add check in scanzipf_reg() in zipfile.c if Zip64 archive being read (Ed)
+ 7. Fixes for amiga/makefile.azt to define directory for object files (Paul)
+ 8. Define prototypes for local functions optionerr, get_shortopt and
+    get_longopt in fileio.c.  Define err argument of optionerr as ZCONST (Paul)
+ 9. Add help_extended and DisplayRunningStats prototypes, fix other prototypes
+    in zip.c (Paul)
+10. Split int kk off of k for argument types (Paul)
+11. Aztec #endif quirk fix in zip.c for Amiga (Paul)
+12. Add detection of binary in first buffer read from file in zipup.c to avoid
+    a -l or -ll translation on binary file.  Not perfect but at least should
+    catch some binary files (Ed)
+13. Remove check for >= 128 from binary check in zipup.c as <= 6 enough for
+    signed char (SMS, Ed)
+14. SF Bug 1074368 - check for empty zip file in readzipfile() in zipfile.c
+    (Christian d'Heureuse, Ed)
+15. Add error exit to prevent archive corruption when updating a large-file
+    archive with a small-file program.  Add ZE_ZIP64 error.
+    ziperr.h, zipfile.c (SMS)
+16. Change percent() in zipup.c to do rounding better, handle cases near limits
+    while rounding, and allow negative percent returns (SMS, Ed)
+17. Add function ffile_size() in zipfile.c but in #if 0 block until determine
+    if works on all ports under all conditions.  Currently only used for size
+    check for Zip64 archive detection if compiled without ZIP64_SUPPORT and
+    this check may already be handled in scanzipf_reg() and should be added to
+    scanzipf_fix() when that is updated (SMS, Ed)
+18. Change >>1 to /2 in zipsplit.c to allow for negative percent returns (SMS)
+19. Add type uzoff_t for unsigned zoff_t things.  Should clean up some casting
+    (Ed)
+20. Based on discussions with other development groups, when data descriptors
+    (extended local headers) are used, force to Zip64.  This is compatible
+    with other unzips and does not require a change of the AppNote, but the
+    resulting archive requires Zip64 to read.  Using standard data descriptors
+    would mean that the zip operation would fail if a Zip64 entry was
+    encountered.  See zipfile.c (Ed)
+21. Add define SPLIT_SUPPORT to enable splits.  The command line options are
+    done and the globals are set up but nothing more.  globals.c, zip.h, and
+    zip.c mainly (Ed)
+22. Create spanning signature at beginning of archive when splitting enabled.
+    If reading a split archive skip the spanning signature unless creating a
+    split archive.  zip.c, globals.c (Ed)
+23. Start implementing split archives.  Define two methods. split_method = 1
+    updates local headers and is the most compatible but requires updating
+    previous splits.  split_method = 2 uses data descriptors and should work
+    for streams and removable media but may not be as compatible with other
+    zip applications.  (In part based on previous discussions with Rainer.)
+    Updated global variables to include bytes written to just the current
+    entry in the current split.  zipfile.c (Ed)
+24. Add note about output redirection to zip.1 (?, Ed)
+25. Remove num < 0 check as num now unsigned.  util.c (SMS, Ed)
+26. Change lastchar to lastchr in fileio.c in places to avoid function by same
+    name (SMS, Ed)
+27. Moved #endif /* !WINDLL */ in zip.c (Mike)
+28. Account for vms directory version being ;1.  vmszip.c (SMS)
+29. Fix Zip64 check in scanzipf_reg to use the buffer.  zipfile.c (Ed)
+30. Default define size_t (for use by Steve's ffile_size() function).  tailor.h (Ed)
+31. Enable Steve's ffile_size() function and enable large file check.  It
+    currently does not allow file sizes over 2 GB but the code is not supporting
+    it anyway without large file support.  Should remove that part of the check
+    when the casts are fixed.  zipfile.c (Ed)
+32. Fixes for djgpp.  Now compiles with djgpp 2 (Ed)
+33. Add new VC6 projects for win32 and windll (Cosmin)
+34. Convert some variables in zipsplit.c from ulg to zoff_t so compiles (Ed)
+35. Add wildcards to extended help.  zip.c (Ed)
+36. For optional option value now '-' is same as missing value.  fileio.c (Ed)
+37. Remove extra free() from -dd option switch.  zip.c (Ed)
+38. Change write_unsigned_to_mem() to write_ulong_to_mem() and write_short_to_mem()
+    to write_ushort_to_mem().  zipfile.c (Ed)
+39. Create new append to mem functions.  zipfile.c (Ed)
+40. Change zlist nam and ext from extent to ushort as that is what gets written.
+    zipfile.c (Ed)
+41. Change GetSD to use ush instead of size_t.  win32/win32zip.c (Ed)
+42. Change PutLocal(), PutExtended(), PutCentral(), and PutEnd() to write to
+    memory and then write the block at once to the file.  zipfile.c (Ed)
+43. Change zcomlen from extent to ush, other extent conversions.  zipfile.c,
+    globals.c, zip.h (Ed)
+44. Add is_seekable() and global output_is_seekable.  Do seekable check
+    when output file is opened.  zipup.c, globals.c, zip.h, zip.c (Ed)
+45. Do not increment files_so_far and bytes_so_far if file could not be read.
+    zip.c (Ed)
+46. If force_zip64 set, only force compressed size in central directory to Zip64
+    instead of all entries (csize, usize, off, disk) in Zip64 extra field.  This
+    fixes inconsistent handling of disk numbers.  zipfile.c (Ed)
+47. Add end status if displaying running stats and not all files were read.
+    zip.c (Ed)
+48. Change force_zip64 to zip64_archive in putend().  zipfile.c (Ed)
+49. Enable the i686-optimized code by default.  crc_i386.S,
+    win32/crc_i386.asm, win32/crc_i386.c (Cosmin)
+50. Document and implement a new text detection scheme provided by Cosmin in
+    set_file_type().  Should be able to handle UTF-8 and some other character sets.
+    proginfo/txtvsbin.txt, trees.c (Cosmin, Johnny, Christian)
+51. Update binary detection for -l and -ll to use Cosmin black list.  zipup.c (Ed)
+52. Change ZE_BIG to include read and write.  ziperr.h (Ed)
+53. If archive not seekable then use data descriptors.  If ZIP64_SUPPORT always
+    create Zip64 data descriptors and add a Zip64 extra field to flag it is
+    a Zip64 data descriptor.  This is klugy but should be compatible with other
+    unzips.  See the note in zipfile.c for details.  (Ed)
+54. Use ush for comment length in putend().  Instead of extent use ush for
+    zcount and fcount same as in zip file.  zip.h (Ed)
+55. Update VB readme.  windll/VB/readmeVB.txt (Ed)
+56. Change (INSTALL) to (INSTALL_PROGRAM).  unix/Makefile (, Ed)
+57. During update the file and byte status counts were off.  Fixed by not coun-
+    ting files copied from old to new as those are not in totals.  zip.c (Ed)
+58. Change from -b to -bx for nroff of manuals to text files.  unix/Makefile (Ed)
+59. Add cygwin to makefile.  unix/Makefile (, Ed)
+60. Fix bug where files to delete not added to list.  zip.c (Ed)
+61. Fix delete stats.  zip.c (Ed)
+62. Increment version of crypt to 2.10.  Update default behavior notes.
+    crypt.c, crypt.h (Paul, Christian)
+63. Format changes, add parentheses to zfseeko(), fix output bytes, add ifdef
+    blocks for ZIP10, fzofft formatting, casts.  crypt.c (Christian)
+64. Cast block_start to unsigned.  deflate.c (Christian)
+65. Let -R patterns match in subdirectories.  Update filter() to use switch,
+    use global icount and Rcount, handle subdirectories, update icount and
+    RCount in filterlist_to_patterns().  fileio.c, zip.c, zip.h, globals.c
+    (Christian)
+66. Enclose option -! and use_privileges under NTSD_EAS guard.  globals.c,
+    zip.c, zip.h (Cosmin)
+67. Updates to version, copyright, license.  [I did not split the copyright
+    to 2 lines as it already takes up space on the help screen.  Ed]
+    revision.h (Christian)
+68. Add ZCONST to some read-only string pointer arguments in function
+    declarations.  zipcloak.c, zipnote.c, zipsplit.c, zip.c, zip.h (Christian)
+69. Fix byte counts on exit in zipcloak() and zipbare() to fix zipcloak bug
+    (Christian)
+70. Modified zipnote.c to use WRBUFSIZ to handle line widths of at least 2047
+    characters in write mode (Christian)
+71. Change simple() and greedy() from zoff_t to uzoff_t.  zipsplit.c (Christian)
+72. Remove duplicate copyright notices.  zipsplit.c (Christian)
+73. Remove export notice from help page.  Move notice to bottom of license
+    page.  zipcloak.c (Ed)
+74. File USexport.msg export history added. (Greg)
+75. Added support for VMS ODS5 extended file names.  (Eight-bit only, no
+    Unicode.)  VMS name character "/" is mapped to Zip name character
+    "?".  New command-line options -C[2|5][-] (/PRESERVE_CASE[=opts])
+    control name case preservation and/or down-casing.  globals.c,
+    zip.c, zip.h, vms/cmdline.c, vms/vms_im.c, vms/vms_pk.c, vms/vms.c,
+    vms/vmszip.c, vms/vms.h  (SMS)
+76. New VMS option -ww (/DOT_VERSION) stores version numbers as ".nnn"
+    instead of ";nnn" [changed from -Y to -ww (Ed)].  zip.c (SMS)
+77. Changes to vms_open().  vms/vms_im.c, vms/vms_pk.c
+78. Changes to vms_read().  vms/vms_pk.c (SMS)
+79. Documentation updates.  vms/vms_zip.rnh (SMS)
+80. Minor updates.  vms/zip_cli.help, vms/cmdline.c, vms/vms_zip.rnh (Ed)
+81. Changes to vmsmunch().  vms/vmsmunch.c (SMS)
+82. Do some updating of VMS options.  vms/zip_cli.cld (SMS)
+83. Moved the VMS-specific ziptyp() function from zipfile.c to vms/vms.c
+    to segregate better the RMS stuff. (SMS)
+84. Put 64-bit calls in ZIP64_SUPPORT ifdef blocks, change some long parameters
+    for append to memory block functions to ulg, remove redundant includes,
+    add OFT protos to some functions with parameter types that get promoted
+    like ush to avoid warnings in VMS.  zipfile.c (SMS)
+85. Use zip_fzofft() to format number.  zipsplit.c (SMS)
+86. Add file_id.diz from Zip 2.31 (?, Ed)
+87. Update install from Zip 2.31 (?, Ed)
+88. Update license from Zip 2.31.  License (?, Ed)
+89. Update Readme.cr from Zip 2.31 (?, Ed)
+90. Add 64-bit assembler for Win32 from Zip 2.31.  win32/makefile.a64,
+    win32/readme.a64, win32/gvmat64.asm (?, Ed)
+91. Update Readme (Ed)
+92. Update headers.  crctab.c, crc32.c, deflate.c, ebcdic.h, fileio.h (Ed)
+93. Option for extra verbose VMS, change DIAG_FLAG from verbose to
+    (verbose >= 2).  vms/vms.c (SMS)
+94. Update copyright header.  qdos/qdos.c (Christian, Ed)
+95. Change exit(0) to exit(ZE_OK).  qdos/qdos.c (Christian)
+96. Change ulg to unsigned long.  tailor.h (, Christian)
+97. Default uzoff_t to unsigned long long if LARGE_FILE_SUPPORT manually
+    enabled for an otherwise unsupported port.  tailor.h (Ed)
+98. Update copyright header.  tailor.h (Ed)
+99. Change EXIT(0) to EXIT(ZE_LOGIC) for ziperr recursion.  zip.c (Christian)
+100. Change EXIT(0) to EXIT(ZE_OK) for successful returns.  zip.c,
+     zipcloak.c (Christian)
+101. Update license.  zip.h (Christian)
+102. Initialized mesg in zipcloak.c, zipnote.c, zipsplit.c to fix access
+     violation crashes.  (Christian)
+103. Added -q (Quiet mode) option to zipcloak, zipnote, zipsplit.  (Christian)
+104. Add proto of mb_clen().  fileio.c (Cosmin)
+105. Synchronize ttyio.c and ttyio.h with the unzip-5.52 source. (Cosmin)
+106. Control the POSIX emulation provided by some Unix-on-Windows compiler
+     distributions, such as Cygwin, via the FORCE_WIN32_OVER_UNIX macro.
+     tailor.h, win32/Makefile.gcc (Cosmin)
+107. Remove getenv() declaration.  util.c (Cosmin)
+108. Fix definitions of zopen and zstdin.  unix/zipup.h (Cosmin)
+109. Enable binary file operations for DJGPP and Cygwin.  unix/osdep.h (Cosmin)
+110. Remove -DMSDOS from CFLAGS; use correct dependency in target crc_i386.obj.
+     win32/makefile.w32, win32/makenoas.w32 (Cosmin)
+111. Update win32/makefile.bor and win32/makefile.gcc (Cosmin)
+112. Put mktemp() declaration inside the NO_PROTO guard.  tailor.h (Cosmin)
+113. Use the right type (DWORD) for volSerNo, maxCompLen and fileSysFlags
+     in FSusesLocalTime().  win32/win32.c (Cosmin)
+114. Set the "zip Debug" configuration as default.  win32/vc6/zip.dsp (Cosmin)
+115. Define ASM_CRC by default.  win32/osdep.h (Cosmin)
+116. Avoid using file names that are distinguished solely by letter case;
+     e.g. crc_i386.S and crc_i386.s.  unix/Makefile (Cosmin)
+117. Stylistic fix inside ex2in().  unix/unix.c (Cosmin)
+118. Change zlist dsk from ush to ulg to support Zip64 and added casts in
+     zipfile.c to write ush.  zip.h, zipfile.c (Christian, Ed)
+119. Conditionally apply S_IFLNK to support DJGPP.  unix/unix.c (Cosmin)
+120. Change -dd [siz] (display dots, set optional dot size) to the options
+     -dd (turn dots on, use 10 MB default) and -ds siz (set dot size).
+     Found that using -dd with an optional value got confusing as detection
+     of an optional argument, when the next argument was not either an option
+     or the end of the line, was easy to overlook.  Easier to avoid optional
+     values.  zip.c (Ed)
+121. Change text output of manual pages to zip.txt, zip.txt, zipcloak.txt,
+     zipnote.txt, zipsplit.txt.  unix/Makefile (Christian, Ed)
+122. Change comments using // to /* */ format.  api.c, zip.c   (Christian)
+123. Add support for signals SIGABRT, SIGBREAK, SIGBUS, SIGILL, and SIGSEGV
+     to utilities.  zipcloak.c, zipnote.c, zipsplit.c (Christian)
+124. Update ToDo30.txt file (Ed)
+125. Delete old Manual file (Ed)
+126. Update WHERE from Zip 2.32 (Ed)
+127. Change description of dot-size.  zip.c (Ed)
+128. Change VMS to use -ds to set dotsize.  vms/cmdline.c (Ed)
+129. Update manuals.  man/zip.1, man/zipsplit.1, man/zipnote.1,
+     man/zipcloak.1 (Ed)
+130. Detect i586, i686 and Cygwin in version_local().  unix/unix.c (Cosmin)
+131. Add clean target.  win32/makefile.w32, win32/makenoas.w32 (Cosmin)
+132. Changed most 64-bit size/offset variable declarations (like zoff_t)
+     into "unsigned" type (like uzoff_t), for better backward compatibility
+     with non-ZIP64_SUPPORT setups where "ulg" was used for these variables.
+     deflate.c, fileio.c, globals.c, trees.c, vms/vms_pk.c, win32zip.c,
+     zip.c, zip.h, zipfile.c, zipup.c (Christian)
+133. Add (ulg) cast to strstart in flush_block.  deflate.c (Christian)
+134. Updated Win32 LARGE_FILE_SUPPORT setup for Watcom and MinGW.
+     tailor.h, win32/osdep.h (Christian)
+135. Add attempt count to tempname().  fileio.c (Christian)
+136. Fixed size counter handling in debug code for Zip64. trees.c (Christian)
+137. Moved cryptnote display text definition into revision.h, like was done
+     in Zip 2.31.  zip.c, revision.h (Christian)
+138. Add ZCONST.  fileio.c (Christian)
+139. Removed earlier change in trash() where ASCII-containing iname was
+     searched for native-coded '/' characters.  [Added note but left as
+     changed 5/20/05 EG]  zipfile.c (Christian)
+140. Change zipup size error message to use zip_fzofft().  zipup.c (Christian)
+141. Updated win32/makefile.wat to enable Zip64 support and use directory
+     for intermediate files.  (Christian)
+142. Change fcount and zcount from ulg to extent as extent is used internally,
+     but Zip64 standard supports up to ulg.  Add note to zip.h.  globals.c,
+     zip.h (Christian)
+143. Define NO_W32TIMES_IZFIX in compile options when appropriate. Add
+     version information for USE_ZLIB compiler option.  zip.c (Christian)
+144. Add support for SIGABRT, SIGBREAK, SIGBUS, SIGILL, and SIGSEGV signals.
+     zip.c (Christian)
+145. Add display-usize option to show uncompressed size.  zip.c (Ed)
+146. Add many descriptions to options table.  zip.c (Ed)
+147. Remove -R from help screen as on extended help screen.  zip.c (Ed)
+148. Add basics to extended help.  zip.c (Ed)
+149. Fix checks in scanzipf_reg() for empty file since cenbeg now unsigned.
+     Change buffer from t to b in small big check.  Back up after small
+     zip big archive check.  zipfile.c (Ed)
+150. Change Zip64 not supported warning in scanzipf_reg().  zipfile.c (Ed)
+151. Fix bug where local and central headers were not matching when compiled
+     with NO_LARGE_FILE_SUPPORT.  Restored order of zlist structure elements
+     to match order of local header as scanzipf_reg() compares it as an
+     array of bytes to the local header.  Gag.  It needs fixing but at least
+     it works as intended now.  zip.h, zipfile.c (Ed)
+152. Minor fix from 10000 to 10 K for WriteNumString().  util.c (Ed)
+153. Add overflow check to file_read().  zipup.c (SMS)
+154. Add parameter p1 product specification.  vms/collect_deps.com (SMS)
+155. VMS changes.  vms/descrip_mkdeps.mms (SMS)
+156. Change zoff_t to uzoff_t and unsigned int to size_t.  vms/vms_im.c,
+     vms/vms_pk.c (SMS)
+157. Fix ; that was : at end of line.  Fix DisplayNumString() prototype.
+     zip.h (Ed)
+158. Get rid of leading blanks in DisplayNumString().  util.c (Ed)
+159. Reset dot_count each file.  zipup.c (Ed)
+160. Minor changes to extended help.  zip.c (Ed)
+161. Move defines into DEFINED_ONCE block.  api.h (Mike)
+162. Add Still Remaining And Planned For Zip 3.0 section.  WhatsNew (Ed)
+163. Delete quotes around CHANGES.  Readme (Ed)
+164. Add -lf, open file at path and use for logging, -la, append to
+     existing logfile, and -li, include informational messages, options.
+     globals.c, zip.h, zip.c (Ed)
+165. Update extended help to include logging.  zip.c (Ed)
+166. Add support for required short option value in form -o=value as optional
+     does.  fileio.c (Ed)
+167. If bytes_total is smaller than bytes_so_far for some reason then display
+     negative of bytes_to_go.  This can happen if files grow in size after all
+     the sizes are initially added up.  zip.c (Ed)
+168. Use usize from filetime for adding to bytes_total when updating instead
+     of size in old entry.  zip.c (Ed)
+169. Change status counts files_so_far and bytes_so_far to include bad files
+     so the status counts end at the end but add bad_files_so_far and
+     bad_bytes_so_far to track bad files.  After minor fixes it looks like
+     the counts remaining at the end are correct, even when some files are
+     not readable.  Update bad file warnings.  zip.c, zip.h, globals.c,
+     zipup.c (Ed)
+170. Add uq for unsigned q in zipup().  Initialize z->len in case an error
+     later so have a valid size.  zipup.c (Ed)
+171. Check noisy in DisplayRunningStats() so logging is independent of it.
+     zip.c (Ed)
+172. Add check in DOS for windows and if running DOS version on Windows warn
+     user.  zip.c, msdos/msdos.c, msdos/osdep.h (Johnny)
+173. Add errno.h for strerror(errno) call.  zip.c, zipup.c (SMS)
+174. Fix log problem if using -q option.  zipup.c (Ed)
+175. Change "Far char" to "char Far" as Far is a qualifier not for the char
+     type but the storage allocation of the array.  fileio.c (Christian)
+176. Update note on extent.  globals.c (Christian, Ed)
+177. Remove extra USE_ZLIB.  zip.c (Christian)
+178. Add note for the OEM_RUSS '/' bug.  Need to look at later as it seems
+     the Russian bug remains unfixed.  zipfile.c (Christian, Ed)
+180. So byte counts always come out even, create good_bytes_so_far to
+     count bytes read in and convert bytes_so_far to use the counts
+     from the initial scan.  If files change during the zip operation
+     good_bytes_so_far will change and not match bytes_so_far.
+     zip.h, globals.c, zip.c (Ed)
+181. Changes to extended help.  zip.c (Ed)
+182. Update WhatsNew (Ed)
+183. Update DLL resource copyright.  windll.rc, windll.aps (Ed)
+184. Add directory search improvements to Win32 (within recursion, reuse
+     attribs from directory lookup to avoid calling stat()).  Add
+     getd_attribs(), procname_win32().  win32/win32zip.c (Johnny)
+185. Cache result of IsFileSystemOldFAT() to avoid repetitive system calls
+     for identical information.  win32/win32.c  (Johnny)
+186. Add optimization to dosmatch(): apply alternate shortcut code when the
+     pattern to match consists of one multichar wildcard ('*') followed
+     by a fixed string.  util.c (Johnny)
+187. Move DOS check_for_windows() checks to Help and Version and errors
+     only.  Shorten message to one line.  zip.c, msdos/msdos.c (Ed)
+188. Define WIN32_OEM to enable oem ansi conversions for more than RSXNT.
+     Not yet fully implemented.  win32/win32.c, win32zip.c, zip.c,
+     zipfile.c (Ed)
+189. Directory search improvements for MSDOS.  msdos/msdos.c (Johnny)
+190. Add caching of directory information.  If pattern is just *string no
+     need to recurse.  win32/win32.c (Johnny)
+191. If wild_stop_at_dir then do recurse to handle cases like a/b/*.txt.
+     win32/win32.c (Ed)
+192. Additional improvements to directory search speedups, including
+     a) MSDOS port fixes for Turbo C++ compiler
+     b) In both Win32 and MSDOS, change getDirEntryAttr() into macro,
+        saving one function call overhead
+     e) Add explaining comment to optimized procname_{local} code
+     f) In util.c, move "*literal" pattern-matching optimization from
+        dosmatch() to recmatch(). Advantages:
+        - optimization used for all systems
+        - optimization applied to all occurences where a "*" is last wildcard
+          in pattern
+        - "dosmatch()" only preconditoning wrapper for matching workhorse
+          "recmatch()", it should not implement matching algorithms itself
+        - optimization not applied for WILD_STOP_AT_DIR option
+     g) >>>disabled<<< "*literal" optimization for all MBCS-aware environments,
+        because suspect that supplied optimization code is not MBCS-clean
+        (for details see the comment within the patch), so IS NOT USED for
+        win32 port!  Can force activation of match optimization by specifying
+        conditional compilation symbol TEST_FOR_MBCS_CLEAN.
+     (Christian)
+193. Add and move comments, implement changes for directory search improvements
+     in Zip 3.0 util.c (Ed)
+194. In win32/win32.c, IsFileSystemOldFAT(), add declarations of static caching
+     variables where missing to fix win32 port compilation bug (Christian)
+195. Correct changed arguments in RSXNT-only character set conversion
+     call.  win32/win32zip.c (Christian)
+196. Implement Directory Search improvements from Zip 2.32.  win32/win32zip.c
+     (Johnny, Ed)
+197. Debian Bug #312090 fix.  Reworded man page to give multiple examples of
+     recursion, not just zip -r foo foo.  man/zip.1 (Ed)
+198. Change "-Aa -D_HPUX_SOURCE +e" to -Ae for HP.  "HP-UX with the HP compiler
+     and on AIX 4.2.0. AIX 5.1 with gcc-3.4.3 (32-bit) and Darwin built fine
+     - though AIX 5.1 needed CC=gcc make -e ... to find gcc.  According to the
+     HP-UX man page -Ae is equivalent to -Aa -D_HPUX_SOURCE +e it seems the
+     +e is needed and -Ae is more terse anyway."  Expression generated before
+     was too long.  unix/configure (Rodney Brown)
+199. Add support for osf4.0f that does not have fseeko or ftello but has 64-bit
+     fseek and ftell though.  tailor.h (Rodney)
+200. Fix unsigned char to char in recmatch(), add casts for compares.  util.c
+     (Ed)
+201. Fix for alpha off_t long long.  unix/osdep.h (Rodney)
+202. Change shmatch() from uch to char and change parameters to recmatch().
+     Change dosmatch().  util.c (SMS, Rodney, Ed)
+203. Add local for DisplayRunningStats().  zip.c (Rodney, Ed)
+204. Disable unused append_ubyte_to_mem().  Fix error messages in other append.
+     zipfile.c (Rodney, Ed)
+205. Delete unused getDirEntryAttribs().  msdos/msdos.c (Christian)
+206. Change warning when running msdos version on Windows.  msdos/msdos.c (Ed)
+207. Change recmatch() to support MBCS matching.  util.c (Christian)
+208. Update WhatsNew (Ed)
+209. Update Readme (Ed)
+210. Format Readme to fit in 80 character lines (SMS, Ed)
+211. Rename install.vms to install_vms.txt.  vms/install_vms.txt (SMS)
+212. Add reference to vms/install_vms.txt in INSTALL (SMS)
+213. Update INSTALL (Ed)
+214. Remove ALT_NEXTBYTE and Building UnZip sections as no longer needed.
+     vms/notes.txt (SMS, Ed)
+215. Add note to TODO (Ed)
+216. Update Makefile message to suggest using generic.  unix/Makefile (Ed)
+217. Update text output of manual.  zip.txt (Ed)
+218. Update VMS section.  INSTALL (SMS, Ed)
+219. Minor changes in vms/install_vms.txt (SMS, Ed)
+220. Update VMS install information.  INSTALL, vms/install_vms.txt (SMS, Ed)
+221. Do not use _stati64 under Cygwin.  win32/osdep.h (Cosmin)
+222. Add note to Makefile to use generic first.  unix/Makefile (Ed)
+223. Add Test option for VMS CLI.  vms/cmdline.c (SMS, ?)
+224. Add noconfirm to deletes, define symbol edit.  vms/descrip.mms (SMS)
+225. Changes to vms/install_vms.txt (SMS)
+226. Add note on symbols to VMS.  INSTALL (SMS)
+227. Update license headers.  vms/osdep.h, vms/vms.h, vms/vmsmunch.c,
+     vms/zipup.h, vms/vmszip.c, vms/vms.c, vms/vms_im.c, vms/vms_pk.c,
+     vms/command.c (Ed)
+228. Add stsdef.h include for VMS and convert unzip test return to VMS
+     result for VMS.  zip.c (SMS)
+229. Add const to ziperr().  amiga/amiga.c (Paul)
+230. Clean up makefile.  amiga/makefile.azt (Paul)
+231. Don't try Amiga large file support.  amiga/osdep.h (Paul)
+232. Add note on -V and -VV.  vms/notes.txt (SMS)
+233. Small update.  vms/zip_cli.help (SMS)
+234. Format Windows warning message.  msdos/msdos.c (Christian)
+235. Format changes.  util.c (Christian)
+236. Update VMS.  INSTALL (SMS)
+237. Add creation of intermediate object directories.  msdos/makefile.wat
+     (Christian)
+238. Add void * cast.  msdos/msdos.c (Christian)
+239. Add include for mktemp().  msdos/osdep.h (Christian)
+240. Fix __RSXNT__ and WIN32_OEM define blocks.  win32/win32.c (Christian)
+241. Fix __RSXNT__ and WIN32_OEM define blocks.  win32/win32zip.c (Christian)
+242. Add != NULL to check.  zip.c (Christian)
+243. Fix WIN32_OEM.  zipfile.c (Christian)
+---------------------- October 11th 2005 version 3.0f01 ----------------------
+(the internal betas may be merged later)
+ 1. Add DSEG for Watcom data segment.  msdos/makefile.wat (Christian)
+ 2. Add -zq and use assembler.  os2/makefile.os2 (Christian)
+ 3. Update header.  os2/match32.asm (Christian)
+ 4. Change len from int to unsigned int.  os2/os2.c (Christian)
+ 5. In GetLongPathEA() limit tempbuf to CCHMAXPATH.  os2/os2.c (Christian)
+ 6. Add DWATCOM_DSEG to use data segment.  win32/makefile.wat (Christian)
+ 7. Update header and add DGROUP.  win32/match32.asm (Christian)
+ 8. Add UNICODE_SUPPORT define.  zip.h, zip.c (Ed)
+ 9. Add oname to f and z structs for the display name to use in messages.
+    Change z->zname to z->oname in messages.  fileio.c, zip.c, win32zip.c,
+    zipup.c, zipfile.c, zip.h (Ed)
+10. Move multi-byte defines to make global (they were needed with wide
+    characters but that was taken out and left them where they are).
+    fileio.c, zip.h
+11. Add copy_args(), free_args(), and insert_arg() to create copy of argv
+    that can free() and to support inserting "@" in get_option for lists.
+    fileio.c, zip.h
+12. Insert arg "@" after list if not followed by option.  fileio.c
+13. Add args variable and copy argv to args so can use insert_arg(). zip.c
+14. Add MKS Korn Shell note.  zip.c
+15. Change cast of option in add_filter() calls from char to int. zip.c
+16. Implement multi-byte version of Unicode support.  To support Win32 NT
+    wide calls will require additional work not planned for this release.
+    Changes include (Ed):
+    - Add use_wide_to_mb_default flag.  globals.c, zip.h
+    - Add compiler UNICODE_SUPPORT version information.  zip.c
+    - Add uname to f and z structs for UTF-8 name. zip.c
+    - Moved some defines out of ZIP64 section.  zipfile.c
+    - Add define UTF8_PATH_EF_TAG for Unicode Path extra field.  Currently
+      the tag is 0x7075 which is 'u' 'p' for Unicode path and seems
+      free according to the AppNote.  The extra field is
+        tag (2 bytes 'u' 'p')
+        size (2 bytes)
+        Unicode Path size (2 bytes)
+        unused (2 bytes set to 0)
+        unused (2 bytes set to 0)
+        Unicode path (variable)
+      The unused locations also serve as a check in case the tag is in
+      use already.
+    - Add add_Unicode_Path_local_extra_field() and
+      add_Unicode_Path_cen_extra_field() functions. zipfile.c
+    - Add read_Unicode_Path_entry() function. zipfile.c
+    - Set uname and oname in scanzipf_ref(). zipfile.c
+    - Add define wide_to_mb_default.  Add zchar but not used. win32/osdep.h
+    - Add wide command line reading but don't use. win32/win32.c
+    - Add port functions for Unicode, including local_to_utf8_string(),
+      wide_to_escape_string() (for converting a wide character that can't be
+      converted to mb in the local character set to a reversable escape string),
+      escape_string_to_wide(), wide_to_local_string(), local_to_display_string()
+      (for creating the display version of name), utf8_to_local_string(),
+      local_to_wide_string(), wide_to_utf8_string() (NOT IMPLEMENTED), and
+      utf8_to_wide_string() (NOT IMPLEMENTED).  win32/win32.c
+    - Implement attempt at escape function.  Whenever a wide character can't
+      be mapped to the local character set, this function gets called.
+      Currently the wide character is converted to a string of hex digits.
+      If the wide can fit in 2 bytes then the form #1234 is used.  If not,
+      the 4-byte form #L12345678 is used.
+    It compiles but needs the utf8 functions implemented.  Also needs testing
+    in a multi-byte environment and only Windows is implemented so need to at
+    least do Unix. (Ed)
+17. Update freeup() to include uname and oname.  zip.c
+18. Move define wide_to_mb_default so default for all is '_'. zip.h (Ed)
+19. No changes needed to osdep.h and update unix/unix.c but not tested. (Ed)
+---------------------- October 19th 2005 version 3.0f02 ----------------------
+ 1. Remove null value check for split_size as get_option() already checks.
+    zip.c (Ed)
+ 2. Update f$search().  vms/descrip.mms (SMS)
+ 3. Save parse name before search and use that on failure.  Change name parsing
+    in ziptyp() to solve a problem with search-list logical name device directory
+    specs.  vms/vms.c (SMS)
+ 4. Compile in UNICODE_SUPPORT if have wchar_t and mbstowcs().  unix/configure (Ed)
+ 5. Move Unicode defines to zip.h and functions to fileio.c so generic.  Create
+    a new OEM function for Windows.  fileio.c, zip.h, tailor.h, win32/win32.c (Ed)
+ 6. Add UTF-8 functions.  fileio.c (Paul)
+ 7. Convert Unicode functions to use zwchar defined as unsigned long for wide
+    char.  fileio.c, zip.h (Ed)
+ 8. Add wchar_t check for Unix.  unix/configure (Ed)
+ 9. Add default when zwchar (4 bytes) is too big for wchar_t (2 bytes).  zip.h (Ed)
+10. Allow for states for wide characters but surrogates not done.  fileio.c (Ed)
+11. Update WhatsNew (Ed)
+---------------------- December 16th 2005 version 3.0f03 ----------------------
+ 1. Fix broke encryption when ZIP64_SUPPORT enabled by accounting for need for
+    data description when encrypting.  Data description is not required for
+    encryption (WinZip does not use one) but seems needed by Zip for some reason.
+    zipfile.c (Ed)
+ 2. Add function bfwrite() to do buffered fwrite().  Most output already is
+    written by zfwrite used by crypt.c which now calls bfwrite.  All splitting
+    and new byte counts are done in bfwrite.  fileio.c (Ed)
+ 3. Move some functions out of ZIP64_SUPPORT defines for use with UNICODE_SUPPORT.
+    zipfile.c, zip.h (Ed)
+ 4. Add is_ascii_string() and only create Unicode extra field if z->iname is
+    not ascii.  zipfile.c, zip.h, fileio.c,  (Ed)
+ 5. Add parameter rewrite to putlocal() to note when rewriting bytes so the bytes
+    rewritten are not counted in output totals.  zipfile.c, zip.h (Ed)
+ 6. Handle VMS ... wildcard.  util.c (SMS)
+ 7. Make tempzip file name global.  zip.c, globals.c, zip.h (Ed)
+ 8. Add out_path global and -O path option to allow the output archive to have a
+    different name than the input archive, if there is one.  This allows
+    updating a split archive, since output to the same split name would otherwise
+    be complicated and not user friendly.  Use out_path for output.  zip.h,
+    zip.c, globals.c (Ed)
+ 9. Many output functions that had output file y as parameter, such as zipup(),
+    zipcopy(), putlocal(), putcentral(), and putend(), now do not as y is
+    now global.  This allows changing y as splits are created.  zip.c (Ed)
+10. Add function zipmessage() for writing messages like zipwarn() but are
+    informational.  zip.c (Ed)
+11. Minor changes to help.  zip.c (Ed)
+12. Add SPLIT_SUPPORT to version output.  zip.c (Ed)
+13. Add rename_split() to rename and set attributes for a split.  zip.c (Ed)
+14. Add set_filetype() to set attributes of split.  zip.c (Ed)
+15. Change variable a (holds attributes) to zipfile_attributes and make global.
+    zip.c, zip.h, globals.c (Ed)
+16. Add key_needed flag for encryption and move setting key to after
+    command line processed.  zip.c (SMS)
+17. Initialize dot size using default only if dot_size not set.  zip.c (Ed)
+18. Change command line processing so that last -P or -e is used.  zip.c
+    (Ed)
+19. Fix broke writing of 4-byte spanning signature at the beginning of the archive
+    if splitting.  zip.c (Ed)
+20. Use bfcopy() instead of fcopy() to copy archive beginning.  bfcopy() uses
+    global y.  zip.c (Ed)
+21. It looks like tempzf is no longer used.  zip.c (Ed)
+22. Account for SUNPRO_C and DECC_VER.  Change SPARC to Sparc.  unix/unix.c (SMS)
+23. Remove GNUC.  vms/cmdline.c (SMS)
+24. Change case of system calls.  vms/vms.c (SMS)
+25. Add fix for VMS ... matching, but may change Zip to avoid ex2in() and in2ex()
+    for pattern matching in future.  vms/vmszip.c (SMS)
+26. Remove /NODIRNAMES and /DIRNAMES from VMS help.  vms/zip_cli.help (SMS)
+27. Define new globals zip64_eocd_disk, zip64_eocd_offset, current_local_tempname,
+    bytes_this_split, and bytes_this_entry for splits.  globals.c, zip.h (Ed)
+28. Add SUNPRO C and DEC C compile checks.  unix/configure (SMS)
+29. Add CFLAGS_NOOPT for removing optimization for configure.  unix/Makefile (SMS)
+30. Modify crypthead() to use bfwrite().  crypt.h, crypt.c (Ed)
+31. Modify zfwrite() to use global output file.  crypt.h, crypt.c (Ed)
+32. Modify zfwrite() when no encryption to use bfwrite().  crypt.h (Ed)
+33. Add bfcopy() to copy to y.  fileio.c (Ed)
+34. Add close_split() and bfwrite() for splits.  fileio.c (Ed)
+35. Add is_ascii_string() to check if UTF-8 extra field is needed.  fileio.c (Ed)
+36. Change Unicode escape of 2-byte wide from #1234 to #U1234.  fileio.c (Ed)
+37. Add read_Unicode_Path_entry() to read the UTF-8 path extra field.  zipfile.c (Ed)
+38. Latest Unicode Path extra field format is
+      1 byte     Version of Unicode Path Extra Field
+      2 bytes    Name Field Checksum
+      variable   UTF-8 Version of Name
+39. Use CRC-32 for Unicode Path Checksum and AND halves.  zipfile.c (Paul)
+40. Add Unicode Path Checksum check to make sure extra field applies to Name field
+    still.  zipfile.c (Christian)
+41. Move get_extra_field() out of Zip64 block and make available for splits.
+    zipfile.c (Ed)
+42. Check in putlocal() using is_ascii_string() and don't create Unicode path
+    extra field if name is ASCII characters.  zipfile.c (Ed)
+43. If local header for split is on another disk and using split method 1, close
+    that split in putlocal() after rewrite local header.  zipfile.c (Ed)
+44. Fix data descriptor bug when encrypting where putextended() did not handle the
+    not Zip64 case, which mostly only happens now for encryption.  zipfile.c (Ed)
+45. Check for ASCII name using is_ascii_string() in putcentral() for Unicode path
+    extra field.  zipfile.c (Ed)
+46. Instead of single disk values, update putend() to use real split values for
+    current_disk, cd-start_disk, cd_entries_this_disk, cd_start_offset,
+    zip64_eocd_disk, zip64_eocd_offset, and current_disk and allow for
+    needing Zip64 if exceed standard max values for current_disk, cd_start_disk,
+    cd_entries_this_disk, total_cd_entries, and cd_start_offset.  zipfile.c (Ed)
+47. Use current_local_offset and current_local_disk for z->off and z->dsk in
+    zipup().  zipup.c (Ed)
+48. Fix bug where force_zip64 was used to determine descriptor size but can have
+    Zip64 entry without force_zip64 so use zip64_entry.  zipup.c (Ed)
+49. Change the p - o != s compression size test for splits to bytes_this_entry
+    != (key ? s + 12 : s) and avoid ftell() in split.  zipup.c (Ed)
+50. If local header is on a previous split and split method 1 do the seek on that
+    split to update header.  zipup.c (Ed)
+51. For streaming, only force Zip64 if reading stdin and writing a non-seekable
+    device.  In other cases can detect either the input file size and set Zip64
+    if needed or seek in the output to update the local headers.  zipup.c,
+    zipfile.c, zipup.c (Ed)
+52. Allow creation of stored archives with descriptors for testing.  Currently
+    they can't reliably be read but this is planned.  zipup.c, zipfile.c, zip.c
+    (Ed)
+53. Update help, adding in -e, -P, -s splitsize, -sp, and -sv options.  zip.c (Ed)
+54. Spelling fix in zipsplit man page.  man/zipsplit.1, zipsplit.txt (Ed)
+55. New option -sv and variable noisy_splits to enable verbose splitting.
+    Default is to quietly create splits, unless -sp set to pause between splits.
+    zip.h, zip.c, globals.c, fileio.c (Ed)
+---------------------- December 23rd 2005 version 3.0f04 ----------------------
+ 1. Move inlined text-vs-binary checks from file_read() into a separate,
+    new function named is_text_buf().  zipup.c, util.c, zip.h (Cosmin)
+ 2. Fix calls to putlocal to remove the removed dest parameter.  crypt.c (Ed)
+ 3. Add get_split_path() to get the path for a split given the disk number.
+    fileio.c, zip.h (Ed)
+ 4. Change formatting of zipmessage() to remove tabbing and add formatting
+    to call to zipmessage().  fileio.c, zip.c (Ed)
+ 5. Initialize many variables such as y and tempzip.  zip.c, fileio.c,
+    zipfile.c (Ed)
+ 6. Add loop to pause during split method 2 to allow changing disk or changing
+    the path for the next split.  fileio.c (Ed)
+ 7. If after starting new split there is not enough room for the remaining buffer
+    for split method 1 display error and exit and for split method 2 we can
+    display a warning and user can replace disk or change path.  fileio.c (Ed)
+ 8. Add list to store input file arguments using add_name() to add the name to
+    filelist_struc filelist and then process the names after the input archive
+    is read.  zip.c (Ed)
+ 9. Fix infinite loop when opening a log file whose name contains multiple '/'.
+    zip.c (Cosmin)
+10. Move split size message lower and only output if option sv sets
+    noisy splits.  zip.c (Ed)
+11. Set y to output file, remove output file from zipcopy(), putlocal(),
+    putcentral(), and putend().  zipsplit.c, zipnote.c, zipcloak.c (Ed)
+12. Add code for not SPLIT_SUPPORT case.  zipfile.c, zipup.c (Ed)
+13. Prepend '-' to commands from target clean.
+    win32/makefile.w32, win32/makenoas.w32, win32/makefile.bor (Cosmin)
+14. Must not call putenv() in iz_w32_prepareTZenv() under Cygwin.
+    win32/osdep.h (Cosmin)
+15. Add browse info in Visual C++ 6 project.  win32/vc6/zip*.dsp (Cosmin)
+---------------------- December 27th 2005 version 3.0f05 ----------------------
+ 1. Add proposed changes to License (Ed)
+ 2. Fix -l corruption bug by using memcpy() instead of wrongly changing the
+    buffer pointer.  Fix was left out of last beta.  zipup.c (Cosmin)
+ 3. Fix get_split_path() parameter.  zip.h (SMS, Ed)
+ 4. Add -dg and display_globaldots to display dots globally for entire archive
+    instead of for each file.  Is not affected by noisy flag.  globals.c,
+    zip.h, zip.c, zipup.c, fileio.c (Ed)
+ 5. Make dot_count and dot_size uzoff_t, dot_count because with global dots
+    dot_count does not reset and with terabyte files the number of buffers
+    could exceed 2G, dot_size to allow use of ReadNumString() to read number.
+    zip.c, zip.h, globals.c (Ed)
+ 6. Add Deletion to help.  zip.c (Ed)
+ 7. Fix delete date.  zip.c (Ed)
+ 8. For streaming, need to assume Zip64 if writing a non-seekable device so
+    extra field for Zip64 is created if needed.  zipup.c, zipfile.c, zipup.c (Ed)
+ 9. Add remove_local_extra_field() and remove_central_extra_field().
+    zipfile.c (Ed)
+10. Remove disabled copyright from license().  zip.c (Ed)
+11. Clean up recent changes.  zip.c, zipfile.c, fileio.c, zip.h, zipup.c (Ed)
+12. Create scanzipf_regnew() for new file scan.  zipfile.c (Ed)
+---------------------- December 29th 2005 version 3.0f06 ----------------------
+ 1. Change dot_size and dot_count from uzoff_t to zoff_t to allow use of
+    negative flag values.  globals.c, zip.h (SMS, Ed)
+ 2. Remove file parameter to bfwrite() in putend().  zipfile.c (SMS, Ed)
+ 3. Add back code for not SPLIT_SUPPORT to putend().  zipfile.c (SMS, Ed)
+ 4. Change tag from ush to ulg in remove_local_extra_field() and
+    remove_central_extra_field() to avoid parameter problems.  zipfile.c (Ed)
+ 5. Add allow_empty_archive to flag when want to create an empty archive.
+    globals.c, zip.h (Ed)
+ 6. Set allow_empty_archive when using -i and expecting an archive to be
+    created.  This is in response to the 2/14/05 email.  zip.c (Ed)
+ 7. Make before and after variables that hold the dates of files to
+    process or delete global so can use them in scanzipf_regnew().  zip.h,
+    zip.c, globals.c (Ed)
+ 8. Change scanzipf_regnew() to be based on scanzipf_fix() which seems closer.
+    Still have not coded the new regular zipfile reader.  zipfile.c (Ed)
+ 9. For new reader first get add list and then read old archive and filter
+    as reading old entries.  zip.c, zipfile.c (Ed)
+10. Define USE_NEW_READ to turn on using new reader, which is being
+    created.  This allows all to work while the new reader is being worked
+    on.  zip.c, zipfile.c (Ed)
+---------------------- January 9th 2006 version 3.0f07 ----------------------
+ 1. Remove dest parameter from crypthead() and zipcopy().  crypt.c (SMS, Ed)
+ 2. Change -ds to handle dots for as small as every 32 KB.  zip.c (Ed)
+ 3. Add ask_for_split_write_path() and ask_for_split_read_path()  for
+    asking where to put the next write split and for locating the next
+    read split.  zip.h, fileio.c (Ed)
+ 4. Add in_path to track where reading splits from. zip.h, globals.c, zip.c (Ed)
+ 5. Update copyright date on changed files to include 2006 (Ed)
+ 6. Replace stderr with mesg for most output messages.  deflate.c, fileio.c,
+    trees.c, util.c, zip.c, zipcloak.c, zipfile.c, zipnote.c, zipsplit.c
+ 7. Add mesg_line_started to track if need new line on mesg output and update
+    zipmessage() and zipwarn() to use it.  Set mesg_line_started to 1 when
+    newline not last character written to mesg and 0 when it is.  deflate.c,
+    zip.h, zip.c, globals.c, zipup(), fileio.c (Ed)
+ 8. Include base_path as parameter for get_split_path().  fileio.c (Ed)
+ 9. Account for VMS version in split path.  Add vms_file_version().  fileio.c,
+    zip.c, vms/vms.c, vms/vms.h (SMS)
+10. Create crc16f() to create ANDed halves crc32 for Unicode using copy
+    of crc32() but may change to use main copy.  zipfile.c, zip.h,
+    fileio.c (Ed)
+11. Close in_path and out_path in finish() and ziperr().  zip.c (Ed)
+12. Change perror() to strerror() and print to mesg in ziperr().  zip.c (Ed)
+13. Add find_next_signature() to find the next signature when reading a
+    zip file.  zipfile.c (Ed)
+14. Add find_signature() to find a given signature from current point in
+    archive.  zipfile.c (Ed)
+15. Add at_signature() to check if at a given signature in archive.
+    zipfile.c (Ed)
+16. Changes to scanzipf_regnew() but far from done.  zipfile.c (Ed)
+17. Changes to readzipfile() to close input archive file and allow new
+    zipfile reader to open and close files as goes through splits.
+    zipfile.c (Ed)
+18. Change -s to default to MB and set minimum split size to 64k.
+    zip.c (Ed)
+19. Add link to user32.lib for CharToOem().  makefile.w32, makenoas.w32
+    (Cosmin)
+20. Remove unused Z64_EFPos.  globals.c (Ed)
+---------------------- February 13th 2006 version 3.0f08 ----------------------
+ 1. Move option checks before any work is done.  zip.c (Ed)
+ 2. Update bfcopy() to handle reading splits and remove input file
+    parameter and use global in_file.  fileio.c (Ed)
+ 3. Change ask_for_split_read_path() to allow user aborting.  fileio.c (Ed)
+ 4. Change get_split_path() to use standard file extensions from most
+    recent AppNote of .z01, .z02, ..., .z99, .z100, .z101, ... fileio.c (Ed)
+ 5. Change is_ascii_string to use 0x7F for ASCII detection.  fileio.c (Ed)
+ 6. Add copy_only global for when -O is used to change the format of an
+    archive without changing the contents.  This allows for converting an
+    archive to a split archive for instance.  The global copy_only is used
+    to output status information for copies when normally copied files
+    have no status messages.  globals.c (Ed)
+ 7. Add in_file, split_path, total_disks, current_in_disk, and
+    current_in_offset as globals to track reading splits.  zip.h,
+    globals.c (Ed)
+ 8. Update copyright date.  revision.h (Ed)
+ 9. Close in_file if open in finish().  zip.c (Ed)
+10. Add -O (big o) to extended help.  zip.c (Ed)
+11. Remove readzipfile() from zipstdout() and use main call later down.
+    zip.c (Ed)
+12. Move archive reading and file scanning after command line checks.
+    zip.c (Ed)
+13. If -O out_zip and so have_out is set then set copy_only and allow
+    copying instead of error message *Nothing to do*.  zip.c (Ed)
+14. If zipbeg is just 4 bytes and spanning then assume is spanning
+    signature and set zipbeg to 0 to ignore.  zip.c (Ed)
+15. Don't open initial write test as modify if have_out is set and so have
+    a separate output file.  zip.c (Ed)
+16. If zipbeg is 0 and nothing at beginning of archive to copy then don't
+    open input file until zipcopy() does.  zip.c (Ed)
+17. If stuff at beginning then copy and close input file.  Should be able
+    to keep it open but easier to close it and let zipcopy() reopen it.
+    zip.c (Ed)
+18. Add status message when copy_only set so something is displayed.
+    zip.c (Ed)
+19. Instead of closing x at bottom close in_file.  The variable x was used
+    inconsistently and it seemed easier to make in_file global instead.
+    Then again y remains the global output variable.  zip.c (Ed)
+20. Update copyright.  zipnote.c, zipsplit.c, zipcloak.c (Ed)
+21. Change adjust_zip_local_entry() to return 1 if the entry is Zip64 and
+    0 if not.  This is needed to know how large the extended local header
+    is later.  zipfile.c (Ed)
+22. Add read_Unicode_Path_local_entry() to read the local version of the
+    Unicode Path extra field.  zipfile.c (Ed)
+23. Handle disk in adjust_zip_central_entry().  zipfile.c (Ed)
+24. Change USE_NEW_READ to SPLIT_SUPPORT as splits seems to be stable more
+    or less.  zipfile.c (Ed)
+25. Add is_signature() to compate signatures.  zipfile.c (Ed)
+26. Create scanzipf_fixnew().  It should look like scanzipf_regnew().
+    zipfile.c (Ed)
+27. Change scanzipf_regnew() to read the central directory and create zlist
+    and handle reading traditionally.  Allows using central directory
+    information, in particular file sizes, in zipcopy() while reading
+    entries.  Use global in_file instead of f for input file and set to NULL
+    when not a valid file so finish() only tries to close it if needed.
+    Check to make sure the End Of Central Directory record found is infact
+    the last one in case a stored archive is in the last 64 KB.  Refuse
+    to update a split archive but recommend using -O instead.  zipfile.c (Ed)
+28. Change readable check in readzipfile() to require input archive to exist
+    if using -O out_archive.  zipfile.c (Ed)
+29. Change putlocal() to not create a Zip64 extra field unless needed and
+    on rewriting the local header to remove Zip64 extra field if was created
+    but not needed.  Add check if assumed entry does not need Zip64 but does,
+    meaning probably the uncompressed size is less than 4 GB but the
+    compressed size is over 4 GB.  zipfile.c (Ed)
+30. Change zipcopy() to use the global in_file and y files and to open and
+    close read splits as needed.  Checks the local header against the
+    central directory header to verify same file, which should be as using
+    the disk and offset values from the central directory.  Update disk and
+    offset in central directory.  zipfile.c (Ed)
+31. Change out_path and out_len to base_path and base_len in
+    get_split_path().  fileio.c (SMS)
+32. Update command line options for VMS to include verbose splitting.
+    vms/zip_cli.cmd, vms/cmdline.c (SMS)
+33. Handle HP.  unix/unix.c (SMS)
+34. Add adler16() checksum function.  util.c (Cosmin)
+35. Use FILE_FLAG_BACKUP_SEMANTICS and a less demanding access mode
+    in CreateFile() when retrieving file attributes.  Fixes a problem
+    when adding a directory entry from an NTFS or a CDFS partition
+    (i.e. one that stores timestamps using universal time), and the
+    directory timestamp is not the same daylight savings time setting.
+    The effect is an offset in the timestamp by one hour, if zip is
+    built using NT_TZBUG_WORKAROUND. The problem is not exposed,
+    however, if NO_W32TIMES_IZFIX is defined.  win32/win32.c (Cosmin)
+---------------------- March 19th 2006 version 3.0f09 ----------------------
+ 1. Fix encryption problem where a large file with uncompressable data
+    can cause deflate to store bad data.  See crypt.c for details.
+    Thanks to the nice people at WinZip for finding and providing the
+    details of this problem.  crypt.c (Ed)
+ 2. Add note at top of Extended Help to refer to the Zip Manual.  zip.c
+    (Ed)
+ 3. Update extended help for delete.  zip.c (Ed)
+ 4. Change crypthead() to use buffer and bfwrite() which is split aware.
+    crypt.c (Ed)
+ 5. Create SPLIT_SUPPORT version of zipcloak() and zipbare() and read
+    local header rather than assume data using central header.  crypt.c (Ed)
+ 6. Change zfwrite() to use global output file y.  crypt.c (Ed)
+ 7. Remove in and out parameters from zipcloak() and zipbare() for
+    splits.  crypt.h, zipcloak.c (Ed)
+ 8. Change get_split_path() to get_in_split_path() and get_out_split_path().
+    zipfile.c, fileio.c, zip.h (Ed)
+ 9. Change crc32f() to crc32u().  fileio.c, zip.h (Ed)
+10. Add encryption overwrite fix to copy_block() and remove from zfwrite().
+    crypt.c, tree.c (Ed, Christian)
+11. Add note on bug fix.  WhatsNew (Ed)
+12. Add copy_only mode.  zip.c (Ed)
+13. Make SPLIT_SUPPORT the default.  zip.h (Ed)
+14. Add set_filetype(), rename_split(), and zipmessage().  zipcloak.c,
+    zipnote.c, zipsplit.c (Ed)
+15. Add long option support.  zipcloak.c (Ed)
+16. Set in_path.  zipcloak.c, zipnote.c, zipsplit.c (Ed)
+17. Use SPLIT_SUPPORT calls.  zipcloak.c, zipnote.c, zipsplit.c (Ed)
+18. Set current_disk, cd_start_disk, and cd_entries_this_disk for use
+    by putend() and bytes_this_split for putcentral().  zipsplit.c (Ed)
+19. Include ctype.h for toupper().  zipfile.c (Ed)
+20. Add readlocal() for utilities to read local header.  zipfile.c (Ed)
+21. Put Zip64 variables and code in ZIP64_SUPPORT ifdef in scanzipf_regnew().
+    zipfile.c (Ed, SMS)
+22. Use zip_fzofft() for converting offset.  zipfile.c (Ed, SMS)
+23. Add casts to many append to memory calls.  zipfile.c (Ed)
+24. Move handling of .zip split to get_in_split_path() and
+    get_out_split_path().  zipfile.c (Ed)
+25. Handle fix = 3 case for ZipNote that renames entries in zipcopy().
+    zipfile.c (Ed)
+26. Restore clearing of extended local header bit when not encrypting.  When
+    encrypting need to output extended local header using putextended() in
+    zipcopy().  zipfile.c (Ed)
+27. Add notes on using file time for encrypting.  zipup.c (Ed)
+28. Remove extended local header bit separately for z->lflg (local flags)
+    and z->flg (central directory flags).  These should be the same but
+    could be different.  zipup.c (Ed)
+29. Suppress command line globbing for MINGW.  win32/win32.c (Christian)
+30. Add EF UT time fix for delete.  zip.c (Christian)
+---------------------- April 28th 2006 version 3.0f10 ----------------------
+ 1. Add note to extended help to escape [ as [[] or use -nw.  zip.c (Ed)
+ 2. Remove local declaration of tempfile as now global.  zipnote.c,
+    zipcloak.c (SMS)
+ 3. Add zip_fzofft() for outputting uzoff_t bin size c.  zipsplit.c (SMS)
+ 4. Add only_archive_set and clear_archive_bits to do Window archive bit
+    selection and clearing.  Add -AS option to require DOS Archive bit
+    be set and -AC to clear archive bits of included files.  Add
+    ClearArchiveBit() to clear archive bits after archive created.
+    Only Win32.  globals.c, zip.h, zip.c, win32zip.c, win32.c (Ed)
+ 5. Change procname_win32() and readd() to check archive bit.
+    win32/win32zip.c (Ed)
+ 6. Update copyright.  win32/win32zip.h (Ed)
+ 7. Add mesg_line_started = 0 to stats to remove blank line when clearing
+    archive bits.  zipup.c (Ed)
+ 8. Add zip_fzofft() to format split size.  zipsplit.c (SMS)
+ 9. Update help for splits and archive bit and add note on escaping [.
+    zip.c (Ed)
+10. Add -M option and bad_open_is_error to exit with error if any input
+    file unreadable.  Also error if -M and would get "name not matched"
+    warning.  zip.c (Ed)
+11. Copy Zip 2.32 csharp example, though it is designed for zip32.dll and
+    not zip32z64.dll from Zip 3.0.  Updated note.  windll/csharp (Ed)
+12. Change -M to -MM and define -mm to avoid accidental use of -m.
+    zip.c (Ed)
+13. Define split_method -1 to not allow splitting, mainly used when reading
+    a split archive to stop automatic splitting of output with same
+    split size.  Now -s=0 or -s- disables splitting.  zip.h, globals.c,
+    zip.c (Ed)
+14. Add fflush() after dots displayed.  deflate.c, fileio.c, zipup.c (Ed)
+15. Instead of assuming buffer size as 32 KB for dots, use WSIZE for
+    compressing and SBSZ for storing and calculate as dots are counted.
+    Now dot_count and dot_size are bytes instead of buffers.  Add dots
+    to Delete and Archive modes.  zip.c, zipup.c, deflate.c, fileio.c (Ed)
+16. If reading a split archive and split size has not been given, get
+    size of first split read by zipcopy(), which should be the first
+    split, and set split size to that, making the output archive the same
+    split size as the input archive.  Delay -sv split size message
+    if split size is 0 at first but then changed.  zipfile.c (Ed)
+17. Add proc_archive_name() for new archive mode to process names in old
+    archive only and skip looking on the file system.  Easier than modifying
+    the various port codes.  fileio.c (Ed)
+18. Fix cd_start_offset bug.  fileio.c (Ed)
+19. Create new action ARCHIVE that looks for matches only in old archive
+    for Copy Mode.  If no input paths and there is an output archive,
+    Copy Mode is assumed even without ARCHIVE.  Old default Copy Mode
+    when no input files updated to work like -U mode and allow filters.
+    New global copy_only currently only used to control global dots.
+    zip.c, fileio.c, globals.c, zip.h (Ed)
+20. Update help.  Change extended help to more help.  Update more help
+    to include internal modes delete and new Archive.  Update help for
+    formatting options.  Update help for wildcards.  Remove streaming
+    examples from top basic section.  Indent examples.  Help for new
+    --out and Copy Mode.  Add warnings that output using data descriptors
+    may not be compatible with some unzips.  Update dots help and add
+    warning that dot size is approximate.  Add help for new DOS archive
+    bit options.  More help for -b and -MM.  zip.c (Ed)
+21. Add support for Unix FIFO (named pipe).  Add set_extra_field() stat
+    name ending in '/' fix found in Zip 2.32.  unix/unix.c (Ed)
+22. Add check to not allow setting -U (internal copy) in similar cases to
+    -d (delete).  zip.c (Ed)
+23. Add counts for internal modes Delete and Archive.  Byte counts for -db
+    remain uncompressed size for external modes, but internal modes Delete
+    and Archive now use compressed sizes as these copy that many bytes.
+    zip.c (Ed)
+24. Add check for when ftell() wraps. zipup.c (Ed)
+25. Add mesg_line_started = 0 to result percentage message.  zipup.c (Ed)
+26. Update contact information.  unix/packaging/preinstall.in (SMS, Ed)
+27. A few Zip64 fixes to set Zip64 correctly and fix disk and offset of
+    Zip64 End Of Central Directory.  zipsplit.c (Ed)
+28. Update comments for get_option().  fileio.c (Ed)
+29. Update DLL version.  windll/windll.rc (SMS, Ed)
+30. New option -sf shows files that would be operated on.  zip.c (Ed)
+---------------------- May 5th 2006 version 3.0f11 ----------------------
+ 1. Use C prototypes for Unicode functions.  fileio.c (SMS)
+ 2. Change constant for mask in set_file_type from unsigned to signed.
+    trees.c (SMS)
+ 3. Use C prototypes for zip_fzofft() and zip_fuzofft() signed and
+    unsigned zoff_t formatting functions.  util.c (SMS)
+ 4. Remove U from constants in Adler16 code.  util.c, zip.h (SMS)
+ 5. Add spaces to VMS usage to avoid misinterpretation.  zip.c (SMS)
+ 6. Add OF() to at_signature().  zipfile.c (SMS)
+ 7. Use zip_zofft() for entries error.  zipfile.c (SMS)
+ 8. Remove U in constants in percent().  zipup.c (SMS)
+ 9. VMS command line updates.  vms/cmdline.c, vms/descrip_deps.mms,
+    vms/vms_zip.rnh, zip_cli.cld, vms/zip_cli.help (SMS)
+10. Update to VMS help.  vms/zip_cli.help (Ed)
+11. Check for memmove() and strerror().  Remove specific 64-bit support
+    for SunOS, as large file support now does.  unix/configure (SMS)
+12. Add emergency replacements for memmove() and strerror().
+    unix/unix.c (SMS)
+13. Remove old not SPLIT_SUPPORT code.  globals.c, zipnote.c, fileio.c,
+    crypt.h, crypt.c, zipcloak.c, zip.h, zip.c, zipup.c, zipsplit.c,
+    zipfile.c (Ed)
+---------------------- May 12th 2006 version 3.0f12 ----------------------
+ 1. Add UNICODE_SUPPORT ifdef around uname in zipup().  zip.c (SMS)
+ 2. Change size from uzoff_t to zoff_t in zipcopy().  zipfile.c (SMS, Ed)
+ 3. Fix a bug where filetime() returns -1 for device but not handled in
+    byte counts.  zip.c (Ed)
+ 4. Add check for UnZip version and exit if not 6.00 or later if
+    a Zip64 archive.  Define popen() and pclose() in Win32 to native
+    _popen() and _pclose().  ziperr.h, zip.c, win32/osdep.h (Ed)
+ 5. Add -sb option to ring bell when pause to change disk.  Use new
+    global split_bell.  global.c, zip.h, zip.c, fileio.c (Ed)
+ 6. Enable crc32u() and use for Unicode extra field.  fileio.c (Ed)
+ 7. Add -dv to display volume being written to.  zip.c, zip.h,
+    globals.c (Ed)
+ 8. Update WhatsNew.  WhatsNew (Ed)
+ 9. Help updates.  zip.c (Ed)
+10. Create option -X- (negated -X) to keep old extra fields and remove
+    -XX which is now -X.  Make get_extra_field() global.  Add
+    copy_nondup_extra_fields()to copy old extra fields not already
+    in new extra fields.  zipup.c, zip.c, zipfile.c (Ed)
+11. Use output name oname for -sf option to show files that would be
+    worked on.  zip.c (Ed)
+12. When updating or freshening old entries, read the old local header
+    with readlocal() to get local flags and extra fields.  zip.c (Ed)
+13. Add UNICODE_SUPPORT ifdefs around uname code.  zip.c (SMS, Ed)
+14. If WIN32_OEM set then on WIN32 store OEM name in archive.  As read
+    DOS or WIN32 archives convert assumed OEM paths to ANSI.  Remove old
+    WIN32_OEM code.  Make oem_to_local_string() global for WIN32_OEM and
+    local_to_oem_string() global for WIN32_OEM and UNICODE_SUPPORT.
+    zip.h, zipfile.c, zipup.c, win32/win32.c, win32/win32zip.c (Ed)
+15. Update error 8 to include wrong unzip.  ziperr.h (Ed)
+16. Change checksum for Unicode extra field to standard crc32 using
+    C version crc32u().  Add crctab.c.  win32/vc6/zipnote.dsp,
+    win32/vc6/zipsplit.dsp, zipfile.c
+17. Update readlocal() to handle multi-disk archives if not UTIL.
+    zipfile.c (Ed)
+18. Convert size to signed zoff_t in zipcopy().  Update note.
+    zipfile.c (Ed)
+19. Update Readme.  Readme (Ed)
+20. Add crctab.o to zipsplit and zipnote.  unix/Makefile (Ed)
+21. Proposed update to license.  License (Ed)
+---------------------- May 20th 2006 version 3.0f13 ----------------------
+ 1. Reformat License file.  License (Cosmin)
+ 2. Change %d to %lu for disk number and add cast.  zip.c (Cosmin, Ed)
+ 3. Display Scanning files message after delay at start based on
+    suggestion from Greg.  Currently the time is checked every 100
+    entries processed.  After 100 entries the start time is saved.
+    After 5 seconds or 100 entries after that, whichever takes
+    longer, the Scanning files message is displayed and every 2 seconds
+    or 100 entries, whichever takes longer, after that a dot is displayed.
+    fileio.c, zip.c, globals.c, zip.h (Greg, Ed)
+ 4. Add Unicode mismatch flag and option -UN.  Default is now a Unicode
+    mismatch is an error.  -UN=warn outputs warnings and continues,
+    -UN=ignore disables warnings, and -UN=no ignores the Unicode extra
+    fields.  globals.c, zip.h, zipfile.c (Ed)
+ 5. Add options for VMS.  vms/cmdline.c, vms/zip_cld.cld (SMS)
+ 6. Add casts to percent().  zipup.c (Ed)
+ 7. Minor changes to logfile formatting.  zip.c (Ed)
+ 8. Update help.  zip.c (Ed)
+ 9. Add -Z=compression-method option.  zip.c (Ed)
+10. Add sd: to -sd status messages.  zip.c (Ed)
+11. Instead of original argv[] use args[] for -sc show command line
+    to show final command line.  zip.c (Ed)
+12. Change argv[] to args[] for logfile.  zip.c (Ed)
+13. Put results of -sf show files in log file if open.  zip.c (Ed)
+14. Add Johnny's bzip2 patch but not tested.  win32/makefile, zip.c,
+    zip.h, zipup.c (Johnny)
+15. Minor tweeks to bzip2 to work with latest beta.  zip.c, zipup.c (Ed)
+16. Add -sf- to list files that would be included only in log file
+    and not on stdout as list can be long.  Only list totals on stdout.
+    zip.c (Ed)
+17. Create check_unzip_version().  Fix Unix check.  Zip still creates
+    the temporary archive then does the check, and if it fails
+    the archive is deleted, even if the check fails because of the wrong
+    verion of UnZip.  On Unix only 'unzip' the system version of UnZip
+    is checked, not './unzip' which would allow putting a local more
+    up to date version of UnZip in the current directory for the check.
+    There should be a way to override the system version of UnZip for
+    the -T test.  zip.c (Ed)
+---------------------- July 12th 2006 version 3.0f14 ----------------------
+ 1. Change crypt version from 2.10 to 2.91 to match Zip 2.32 and avoid
+    confusion.  crypt.h (Cosmin)
+ 2. Add abbrevmatch() to handle option values that can be abbreviated
+    like compression method.  util.c, zip.h, zip.c (Ed)
+ 3. Change USE_BZIP2 to BZIP2_SUPPORT as USE_BZIP2 implies it replaces
+    deflation maybe.  zip.c, zip.h, zipup.c (Ed)
+ 4. Update man page.  man/zip.1, zip.txt (Ed)
+ 5. Add bzip2 to VMS.  vms/build_zip.com, vms/bzlib.h, vms/cmdline.c,
+    vms/descrip.mms, vms/descrip_src.mms, vms/find_bzip2_lib.com,
+    vms/install_vms.txt, vms/zip_cli.cld (SMS)
+ 6. Remove zipfile parameter from bzfilecompress().  Add unsigned
+    cast for EOF in bzip2 code.  Add bzip2 version information.
+    zipup.c, zip.c (SMS)
+ 7. Add bzip2 to Unix.  unix/configure (SMS)
+ 8. Add and update bzip2 descriptions.  INSTALL, README, WhatsNew,
+    bzip2/install.txt (SMS, Ed)
+ 9. Add vc6bz2 projects for compiling bzip2 code into zip (not the
+    best approach perhaps).  win32/vc6/readmevc.txt,
+    win32/vc6bz2/readvcbz.txt, win32/vc6bz2/zip.dsp, win32/vc6bz2/zip.dsw,
+    win32/vc6bz2/zipcloak.dsp, win32/vc6bz2/zipnote.dsp,
+    win32/vc6bz2/zipsplit.dsp (Ed)
+10. Add support for VC++ 2005 by disabling deprecation.  win32/osdep.h
+    (Cosmin)
+11. Update instructions for makefile.  unix/Makefile (Ed)
+12. Update todo list.  todo30.txt (Ed)
+13. Reduce #if 0 block to now allow extra data message.  zipfile.c (Ed)
+14. Add note that readlocal() reads local headers.  zipfile.c (Ed)
+15. Archive comment was not being read by new scanzipf_regew().  Added.
+    zipfile.c (Ed)
+16. Handle reading and writing OEM comments.  zipfile.c (Ed)
+17. Update Zip64 data descriptor note.  zipfile.c (Ed)
+18. Format filetypes() check.  zipup.c (Ed)
+19. Update note to remember to force deflation for descriptors by
+    release.  zipup.c (Ed)
+20. In compression code using libraries, enable dots for noisy also.
+    zipup.c (Ed)
+21. Update extended help to add more of the basic options and
+    compression method.  zip.c (Ed)
+22. Add additional lines bz_opt_ver2 and bz_opt_ver3 to bzip2
+    version to give credit to bzip2.  zip.c (Ed)
+23. Add descriptions to version information for USE_EF_UT_TIME,
+    NTSD_EAS, WILD_STOP_AT_DIR, WIN32_OEM, LARGE_FILE_SUPPORT,
+    ZIP64_SUPPORT, and UNICODE_SUPPORT similar to how UnZip does.
+    zip.c (Ed)
+24. Add note that crypt is modified in Zip 3.  zip.c (Ed)
+25. Use abbrevmatch() and update warnings for compression
+    method selection.  zip.c (Ed)
+26. Update config to handle either using IZ_BZIP2 to define
+    the location of the bzip2 files or the bzip2 directory.
+    unix/configure, zipup.c, zip.c (SMS, Ed)
+---------------------- July 14th 2006 version 3.0f15 ----------------------
+ 1. Change USE_BZIP2 to BZIP2_SUPPORT in VMS.  vms/descrip_src.mms,
+    vms/build_zip.com (SMS)
+ 2. Add SYS$DISK:.  vms/descrip.mms, vms/build_zip.com (SMS)
+ 3. Change vms/install.txt to [.vms]install.txt.  bzip2/install.txt (SMS)
+ 4. Change VMS files to lower case.  vms/mod_dep.com, vms/install_vms.txt,
+    vms/zip.opt, vms/hlp_lib_next.com, vms/notes.txt, vms/unixlib_gcc.h,
+    vms/unixio_gcc.h (SMS)
+ 5. Remove old VMS files.  vms/descrip-old.mms (removed),
+    vms/link_zip.com (removed), vms/make_zip.com (removed),
+    vms/makefile.vms (removed) (SMS)
+---------------------- July 24th 2006 version 3.0f16 ----------------------
+ 1. Fix global dots so can set with dot size.  deflate.c, fileio.c (Ed)
+ 2. Update License top line to refer only to license.  License (Cosmin)
+ 3. Update License.  License (Ed)
+ 4. Implement zero length UTF-8 path length as flag standard path is UTF-8
+    and should use that.  This allows Zip to use the standard path as
+    UTF-8 when the local character set is UTF-8.  zipfile.c (Ed)
+ 5. Update WhatsNew.  WhatsNew (Ed)
+ 6. Change case of bzip2/install.txt.  INSTALL (Ed)
+ 7. Change MANUAL.txt to ZIP.txt and update ftp site.  README (Ed)
+ 8. Update announcement.  zip30f.ann (Ed)
+ 9. Now also check if OS has bzip2 library and can use that.
+    unix/configure, zip.c (Mark Adler, Ed)
+10. Add fix from akt@m5.dion.ne.jp in Japan to recurse on doublebyte
+    characters without processing in recmatch().  This should not be needed
+    unless the rest of the code in there is broke for Japanese character
+    sets in some way.  Need to test.  util.c (Ed)
+11. Add note for bzip2.  zip.c (Ed)
+12. Do not do seek wrap test if ftell() returns -1 as from a pipe.  Add
+    output of last ftell() and current ftell() for zipfile too big seek
+    error.  zipup.c (Ed)
+13. Add version to the options table.  Remove the check to display version
+    before the command line is processed.  Add to option -v a check to
+    display the version if that is the only argument.  Can still enable
+    verbose with piping by using zip -v - - format.  zip.c (Ed)
+14. Add abbrevmatch() for -UN option.  zip.c (Ed)
+---------------------- August 7th 2006 version 3.0f17 ----------------------
+ 1. Change license modifications to retain intent of copyright holders, as
+    any major change in license conditions would require contacting all
+    copyright holders.  LICENSE (Greg, Ed)
+ 2. Move debugging statement after zipstdout() where mesg is set to stderr.
+    Add mesg and fflush() to sd messages where needed so that messages go
+    to stderr when piping.  zip.c (Ed)
+ 3. Update encryption comment.  zipup.c (Ed)
+ 4. Do not use data descriptors for directories.  zipup.c (Mark, Ed)
+ 5. Update Q & A to match license.  README (Ed)
+ 6. Update WhatsNew.  WHATSNEW (Ed)
+ 7. Add ifndef around version_info() for dll.  zip.c (Ed)
+ 8. Add -TT (--unzip-path) to allow setting the unzip command to use with
+    -T to test the archive.  zip.c (Ed)
+ 9. Add -DF (--difference-archive) which requires --out and turns off
+    copying unchanged entries to the new archive creating an archive with
+    just the changes and additions since the original archive was created.
+    zip.c, globals.c, zip.h (Ed)
+10. Update help.  zip.c (Ed)
+---------------------- September 7th 2006 version 3.0f18 ----------------------
+ 1. Split -t and -tt options and remove limitation that only one can be
+    used to allow setting a date range.  zip.c, WhatsNew (Ed)
+ 2. Minor changes in comments.  zipfile.c (Ed)
+ 3. Add entries for format of Unicode Path and Unicode Comment extra fields.
+    proginfo/extrafld.txt (Ed)
+ 4. Change note at top of infozip.who, but needs to be updated with all new
+    contributors.  proginfo/infozip.who (Ed)
+ 5. Note Zip 3 and UnZip 6 now support Zip64.  proginfo/ziplimit.txt (Ed)
+ 6. Add note on Unicode.  README (Ed)
+ 7. Update WHATSNEW.  WHATSNEW (Ed)
+ 8. Update help.  zip.c (Ed)
+ 9. Add {} support to -TT option, allowing insertion of temp archive path
+    into the command string to -TT similar to Unix find does.  zip.c (Ed)
+10. Start changes for -F fix option.  Add checks when reading input archive
+    and skip bad central directory entries and bad local entries.  Currently
+    -F requires the central directory to be intact (except for bad CD entries
+    that will be skipped) and local entries and data to be where the
+    central directory say they are.  This allows all recovered entries to
+    be complete with all central directory information.  Calculate CRC of
+    input entry and compare to CRC from central directory.  Allow skipping
+    split disks the user may not have.  Store state of output archive
+    before each local entry and data are read, allowing seeking back and
+    restoring state to skip bad entries.  fileio.c, global.c, zipfile.c,
+    zip.h (Ed)
+11. Started changes for fixfix.  fileio.c (Ed)
+12. Update help on -t and -tt.  zip.c (Ed)
+13. Add note on Unicode support, but may change if add handling of names
+    with characters not supported in current character set.  README (Ed)
+14. Combined ToDo30.txt and ToDo but more to be done.  TODO (Ed)
+15. Update ToDo list.  ToDo30.txt (Ed)
+16. Add -F and -FF to help.  zip.c (Ed)
+17. Run fix mode in copy mode, as it is copying from one archive to
+    another, and use those checks.  zip.c (Ed)
+18. Add Try -F and Try -FF warnings in places.  zipfile.c (Ed)
+19. Allow reading version 4.6 (bzip2) archives.  zipfile.c (Ed)
+20. Add Unicode Path and Unicode Comment extra field descriptions.
+    proginfo/extrafld.txt (Ed)
+21. First attempt at updating the Who file.  proginfo/infozip.who (Ed)
+22. Add note to top of ziplimit.txt.  proginfo/ziplimit.txt (Ed)
+23. Add possible fix for paths returned by the Win32 directory scan with
+    '?' in the name.  These are characters in the Unicode name stored on
+    disk but not represented in the multi-byte character set used by zip
+    for the scan.  In this case, return the short name in 8.3 format so
+    directory scan can continue.  Could put the Unicode name in the Unicode
+    extra field, but not done.  Add warning when long name is replaced
+    by short name.  Not fully tested.  win32/win32zip.c, zip.h, zip.c,
+    fileio.c (Ed)
+24. If archive name and -sf are the only parameters, list archive contents.
+    zip.c (Ed)
+---------------------- September 8th 2006 version 3.0f19 ----------------------
+ 1. Fix error message.  zipfile.c (SMS, Ed)
+ 2. Put crc32() in ifndef UTIL as only needed for fix.  fileio.c (SMS, Ed)
+---------------------- November 3rd 2006 version 3.0f20 -----------------------
+ 1. Fix comment.  vms/vmszip.c (SMS)
+ 2. Include oem_to_local_string() if UNICODE_SUPPORT.  win32/win32.c,
+    zip.h (Ed)
+ 3. Modify procname_win32() to flag a path not supported by the local
+    character set so can get Unicode for it.  Check Unicode names.
+    win32/win32zip.c (Ed)
+ 4. Add matching of escaped Unicode names to proc_archive_name() that
+    reads entries from an archive.  Add sorted zlist zusort.
+    globals.c, fileio.c, zip.h, zipfile.c (Ed)
+ 5. Add support for non-local character set names and paths for WIN32,
+    getting and storing the UTF-8 path when needed.  Use 8.3 name
+    when normal name has characters not supported in current local
+    character set.  Note when short name used.  zip.c, fileio.c (Ed)
+ 6. Add support for fix = 2 which reads local headers first to
+    bfcopy().  fileio.c, zip.h (Ed)
+ 7. Allow selection of .zip split in ask_for_split_read_path() when
+    reading a split archive that has no end records giving the total
+    split count.  fileio.c (Ed)
+ 8. Add zoff_t casts to dot counts.  fileio.c (Ed)
+ 9. Comment changes for Unicode.  fileio.c (Ed)
+10. Call wide_to_local_string() separately in utf8_to_local_string()
+    to free up temp value.  fileio.c (Ed)
+11. Support new AppNote bit 11 for forcing UTF-8, but needs finishing.
+    globals.c (Ed)
+12. Add to zlist struct zuname for the escaped version of the UTF-8
+    name in uname and add ouname for the display version of zuname.
+    zip.c, zip.h, zipfile.c (Ed)
+13. Add zipmessage_nl() that can output to the screen and to the log
+    file like zipmessage(), but can write lines without a newline.
+    zip.c, zip.h, zipcloak.c, zipnote.c, zipsplit.c (Ed)
+14. Update help for -FF and Unicode.  zip.c (Ed)
+15. Change > to >= for byte message check to avoid -0 (negative zero).
+    zip.c (Ed)
+16. Add -su show unicode option which adds escaped unicode paths to
+    -sf.  Also uses show_files = 3.  zip.c (Ed)
+17. Update comments for -UN and -X.  zip.c (Ed)
+18. Add support for new AppNote bit 11 that says standard path and
+    comment have UTF-8 when -UN=f is used.  zip.c (Ed)
+19. Fix zipfile name message by replacing value with zipfile.
+    zip.c (Ed)
+20. Add new code for -FF, which processes archives by trying to read
+    the EOCDR to get split count, then starting with the local
+    entries.  This option does not use the standard code but does
+    everything itself.  Add scanzipf_fixnew(), which tries to read
+    the EOCDR, then the local entries, then the central directory.
+    zip.c, zipfile.c (Ed)
+21. Update note for ZIP64_CENTRAL_DIR_TAIL_SIZE.  zipfile.c (Ed)
+22. Put read_Unicode_Path_entry() and read_Unicode_Path_local_entry()
+    into UNICODE_SUPPORT ifdef.  zipfile.c (Ed)
+23. Add zuqcmp() and zubcmp() to support Unicode sorted list of
+    paths.  zipfile.c (Ed)
+24. Update zsearch() to also search unicode paths.  zipfile.c (Ed)
+25. Split out iname in read_Unicode_Path_entry() for debugging.
+    Should put it back.  Update Unicode mismatch warning.
+    zipfile.c (Ed)
+26. Update Unicode in readlocal().  zipfile.c (Ed)
+27. Add more Unicode support to scanzipf_regnew().  zipfile.c (Ed)
+28. Add support for fix = 2 to zipcopy().  Add checks and warnings,
+    but allow scan to continue when can.  Use local data to fill
+    in central directory fields in case no central directory entry
+    for local entry.  zipfile.c (Ed)
+29. Add get_win32_utf8path() to get UTF-8 from Windows if can.
+    zipfile.c (Ed)
+---------------------- November 7th 2006 version 3.0f21 -----------------------
+ 1. Add crude data descriptor support to -FF in bfcopy() that should be
+    updated by release.  fileio.c (Ed)
+ 2. Change %d to %s and use zip_fzofft() to format zoff_t byte count.
+    zipfile.c (SMS, Ed)
+ 3. Call local_to_oem_string() for only WIN32 in zipcopy().  zipfile.c
+    (SMS, Ed)
+---------------------- November 29th 2006 version 3.0f22 -----------------------
+ 1. Change ' to " in extended help.  zip.c (Ed)
+ 2. Change -dv disk number display to indisk>outdisk.  zip.c (Ed)
+ 3. Finish -FF fix option.  Move detailed output to require -v.  zip.c (Ed)
+ 4. Add note to help to use -v with -FF to see details.  zip.c (Ed)
+ 5. Add -sU option to view only Unicode names when exist.  zip.c (Ed)
+ 6. Change default dot size in verbose from every buffer to 10 MB.  zip.c (Ed)
+ 7. Exit if --out and in path same as out path.  zip.c (Ed)
+ 8. Remove verbose information when fixing archive.  zip.c (Ed)
+ 9. Initialize in disk to 0, but still problem with disk number of first entry
+    for each disk lagging by 1.  zip.c (Ed)
+10. Consistently use ZE error codes for exit from ask_for_split_read_path.
+    zipfile.c, zip.c (Ed)
+11. Seek back when fix finds bad entries.  Also skip last entry of split
+    if next split is missing.  Should check if entry completed.  zip.c (Ed)
+12. Add messages to -sd for writing the central directory, replacing the old
+    zip file, and setting file type.  zip.c (Ed)
+13. Don't set file type on stdout.  zip.c (Ed)
+14. Increase errbuf from FNMAX + 81 to FNMAX + 4081.  zip.h (Ed)
+15. Add skip_this_disk, des_good, des_crc, des_csize, and des_usize globals
+    for -FF and reading data descriptors.  Change note on display_volume.
+    Add global skip_current_disk.  zip.h, globals.c (Ed)
+16. BFWRITE_HEADER define now also does data descriptor.  zip.h (Ed)
+17. Skip zipoddities() if fix.  Maybe can later add back.  zipfile.c (Ed)
+18. Update fix messages.  zipfile.c (Ed)
+19. Allow user to end archive early using ZE_EOF.  zipfile.c, fileio.c (Ed)
+20. Only show split numbers and offsets for -FF if verbose.  zipfile.c (Ed)
+21. Handle spanning signature at top of split archive.  zipfile.c (Ed)
+22. Only close in_file if open.  zipfile.c (Ed)
+23. Add note if no .zip and only splits suggest use -FF.  zipfile.c (Ed)
+24. In putlocal() and putcentral() only convert to OEM if z->vem == 20.
+    zipfile.c (Ed)
+25. Do not OEM convert archive comment as PKWare says this should
+    be ASCII.  zipfile.c (Ed)
+26. Fix swap of siz and len and LOCSIZ and LOCLEN.  zipfile.c (Ed)
+27. Call read_Unicode_Path_local_entry() before OEM conversion so Unicode
+    checksum checks iname before conversion.  zipfile.c (Ed)
+28. Only check if local and central crc match if not stream entry.
+    zipfile.c (Ed)
+29. Keep data descriptors if fix == 2, but need to look at this.
+    zipfile.c (Ed)
+30. Fix bug adding up header bytes in n by adding 4 for signature.
+    zipfile.c (Ed)
+31. If fix == 2 use local crc for central, otherwise use central crc
+    for local.  zipfile.c (Ed)
+32. In zipcopy(), check data descriptor and skip if not correct one.
+    zipfile.c (Ed)
+33. Add SH, LG, and LLG macros from zipfile.c to allow reading the data in
+    the data descriptor.  fileio.c (Ed)
+34. In bfcopy(), read and check the data descriptor if n == -2.  If
+    run out of bytes before find descriptor, return error.  fileio.c (Ed)
+35. In ask_for_split_read_path(), increase buf to SPLIT_MAX_PATH + 100,
+    fix bug by adding "- 1", set split_dir = "" if current directory,
+    and update prompts to add skip and end choices.  Add skip and end
+    choices.  fileio.c (Ed)
+36. Increase buffer for fgets to SPLIT_MAXPATH.  fileio.c (Ed)
+37. Update WhatsNew.  WhatsNew (Ed)
+---------------------- December 10th 2006 version 3.0f23 -----------------------
+ 1. Handle additional ODS5 issues by upper casing many symbols and file names.
+    vms/build_zip.com, vms/collect_deps.com, vms/descrip.mms,
+    vms/descrip_mkdeps.mms, vms/descrip_src.mms, vms/find_bzip2_lib.com (SMS)
+ 2. Update VMS Find Help Library code.  vms/hlp_lib_next.com (SMS)
+ 3. Instead of tempname use temp_name as parameter to avoid function
+    tempname().  zipsplit.c, zipnote.c, zipcloak.c, zip.c (Ed)
+ 4. If fixing archive with -FF and no EOCDR to get disk count, see if top of
+    archive has spanning signature or local header and guess if it is
+    single-disk archive, then ask user to confirm.  zipfile.c (Ed)
+ 5. For Unix where NO_MKSTEMP is not defined, replace mktemp() with mkstemp()
+    that avoids a race condition.  zip.c, zipcloak.c, zipnote.c, fileio.c (Ed)
+ 6. Eliminate mkstemp() warning by using mkstemp() instead of mktemp() for
+    Unix.  Only for UNIX and if NO_MKSTEMP is not defined.  Many OS do not
+    have mkstemp().  zipcloak.c, zipnote.c, zip.c, fileio.c (Ed)
+ 7. If UNICODE_SUPPORT and UNIX then try to switch to UTF-8 locale to allow
+    displaying of Unicode, otherwise just get escapes.  This results in some
+    characters displaying as whitespace if needed fonts, such as East Asian,
+    are not installed.  zip.c (Ed)
+ 8. If new global unicode_escape_all is set, then escape all non-ASCII
+    characters when converting Unicode file path.  This allows viewing paths
+    as escapes on Unix that would otherwise be white space.  If not set, any
+    characters that map to the current locale are returned as is.  Can only
+    display if either supported as base by the OS or fonts installed.  Set
+    using -UN=escape option.  zip.c, fileio.c, zip.h, globals.c (Ed)
+ 9. Update extended help for Unicode.  zip.c (Ed)
+10. All variables used by Win32 in global.c should now be initialized at
+    start so dll is initialized each call.  zip.c (Ed)
+---------------------- January 1st 2007 version 3.0f24 -----------------------
+ 1. Fix a problem when building with (old, obsolete) IM attribute encoding
+    combined with bzip2 support.  vms/descrip_src.mms (SMS)
+ 2. Update WHATSNEW.  WhatsNew (Ed)
+ 3. Update README.  ReadMe (Ed)
+ 4. Remove in_crc code.  Too involved to implement but may look at later.
+    fileio.c, globals.c, zip.c (Ed)
+ 5. Use 0x50 and 0x4b for 'P' and 'K' in signatures to handle EBCDIC case.
+    zipfile.c, fileio.c (Ed)
+ 6. Implement new -FS file sync option that deletes entries missing on the
+    file system from an archive being updated.  globals.c, zip.c (?, Ed)
+ 7. Update help.  zip.h, zip.c (Ed)
+ 8. Include scanning files dots when update small but new file scan long.
+    zip.c (Ed)
+ 9. Ask if single-file archive when using -FF and can't tell.  zipfile.c (Ed)
+10. Display message when entry would be truncated.  zipfile.c (Ed)
+11. Check for VMS_IM_EXTRA.  Update bzip2 support for VMS.  Change
+    destination directory if large-file enabled.  vms/build_zip.com,
+    vms/descrip_src.mms (SMS)
+12. Change parameters for VMS bzip2 search.  vms/find_bzip2_lib.com (SMS)
+---------------------- January 12th 2007 version 3.0f25 -----------------------
+ 1. Incorporate faster crc32.c including the Rodney Brown changes (originally
+    implemented in the zlib project) from UnZip, which includes the
+    IZ_CRC_BE_OPTIMIZ and IZ_CRC_LE_OPTIMIZ optimizations when those symbols
+    are defined.  These modifications include:
+     - enlarge unrolling of loops to do 16 bytes per turn
+     - use offsets to access each item
+     - add support for "unfolded tables" optimization variant
+    crc32.c  (Christian)
+ 2. As the crc32.c module now includes crc table generation, remove crctab.c.
+    crctab.c (remove) (Christian)
+ 3. Update crc i386 assembler code from UnZip (details see above).
+    win32/crc_lcc.asm, win32/crc_i386.asm, win32/crc_i386.c, crc_i386.S
+    (Christian)
+ 4. Guard against redefinition of symbols @CodeSize and @DataSize in memory
+    model setup section to work around Open Watcom (version 1.6) wasm
+    assembler problem.  msdos/crc_i86.asm (Christian)
+ 5. Change type of keys[] array for new crc, add IZ_CRC_BE_OPTIMIZ, and
+    use new crypt crc table.  Use header buffer instead of buf for header.
+    crypt.c, crypt.h (Christian)
+ 6. Update version and remove crc table.  crypt.h (Christian)
+ 7. Add crc32.h, change sprintf() format for disk number from d to lu as
+    can go over 16-bit, remove crc32u().  fileio.c (Christian)
+ 8. Update to use new crc.  msdos/makefile.bor, msdos/makefile.dj1,
+    msdos/makefile.dj2, msdos/makefile.emx, msdos/makefile.msc,
+    msdos/makefile.tc, msdos/makefile.wat, unix/Makefile,
+    vms/build_zip.com, vms/descrip_deps.mms, vms/descrip_src.mms,
+    vms/osdep.h, win32/makefile.bor, win32/makefile.dj, win32/makefile.emx,
+    win32/makefile.gcc, win32/makefile.ibm, win32/makefile.lcc,
+    win32/makefile.w10, win32/makefile.w32, win32/makefile.wat,
+    win32/makenoas.w32, win32/vc6/zip.dsp,
+    win32/vc6/zipcloak.dsp, win32/vc6/zipnote.dsp, win32/vc6/zipsplit.dsp,
+    win32/vc6bz2/zip.dsp, win32/vc6bz2/zipcloak.dsp, win32/vc6bz2/zipnote.dsp,
+    win32/vc6bz2/zipsplit.dsp, windll/visualc/dll/zip32.dsp,
+    windll/visualc/dll/zip32.mak, windll/visualc/lib/zip32.dsp,
+    win32/visualc/lib/zip32.mak (Christian)
+ 9. Include crc32.h.  Make variable uname local in proc_archive_name().
+    Remove unused num and new_base_path.  Change %02d to %02l2 for
+    disk number in print format.  Remove crc32u() as now use crc32().
+    Add parentheses around conditions in loops.  Use 0 instead of NULL
+    for zwchar.  fileio.c (Christian)
+10. Add z_uint4 defines from crypt.c to tailor.h.  Move uch, ush, and ulg
+    typedefs before tailor.h include which needs them.  tailor.h, zip.h (SMS)
+11. Include crc32.h.  change add_name() to return not int but long
+    since number of command line arguments can exceed 16 bits.  Cast
+    variable option to (int) for subtraction.  Change 0x400 to 0x400L.
+    Add braces to show_files print block.  zip.c (Christian)
+12. Add warning if use -F or -FF without --out.  Change defined(NO_MKSTEMP)
+    to !defined(NO_MKSTEMP).  zip.c (Ed)
+13. Define EC64LOC and EC64REC for size of Zip64 EOCD Locator and Zip64
+    EOCD Record.  Add extern for crc_32_tab.  Move crc32() to crc32.h.
+    zip.h (Christian)
+14. Add crc.h.  zipcloak.c (Christian)
+15. Include crc32.h.  Comment out scanzipf_reg() and scanzipf_fix() as
+    no longer used, which are left in for now for comparison.  Cast
+    blocksize to extent for malloc().  Instead of 0x10000 malloc 0xFFFF for
+    extra field block so fits in 16 bits.  Instead of crc32u() use crc32().
+    Only do lflg != flg check for fix == 2.  Add comments to various #endif.
+    Indent comment.  Comment out copy_sig() which is not used.  Reduce size
+    of SCAN_BUFSIZE to EC64REC for MEMORY16.  Use ENDHEAD for EOCDR size.
+    Change %u to %lu in print formats for disk count.  Use EC64LOC for size
+    of Zip64 EOCD Locator.  Use EC64REC for size of Zip64 EOCD Record.
+    Add streaming and was_zip64 to ZIP64_SUPPORT.  Remove lflg != flg check
+    in zipcopy().  zipfile.c (Christian)
+16. Add note that z-flg & ~0xf check will fail if new bit 12 for UTF-8 paths
+    and comments is set.  Update -FF warning.  zipfile.c (Ed)
+17. Include crc32.h.  Modify tempzn update.  Fix comment.  Set
+    z->lflg = z->flg after deflate as deflate may have set bits in z->flg
+    [Ed, Christian].  Include BZIP2_SUPPORT block in !UTIL block.  zipup.c
+    (Christian)
+18. Changes to use crc32.c.  acorn/gmakefile, acorn/makefile, amiga/lmkfile,
+    amiga/makefile.azt, amiga/smakefile, aosvs/make.cli, atari/makefile,
+    atheos/makefile, beos/makefile, cmsmvs/cczip.exec, cmsmvs/mvs.mki,
+    cmsmvs/zip.makefile, cmsmvs/zipmvsc.job, cmsmvs/zipvmc.exec,
+    human68k/makefile, human68k/makefile.gcc, novell/makefile, novell/zip.lnk,
+    os2/makefile.os2, qdos/makefile.qdos, qdos/makefile.qlzip, tandem/history,
+    tandem/macros, tandem/tandem.h, theos/makefile, tops20/make.mic,
+    unix/configure, unix/makefile, win32/makefile.a64 (Christian)
+19. Add note to use BZ_NO_STDIO.  bzip2/install.txt (Ed)
+20. Remove crctab.  cmsmvs/zipvmc.exec (Ed)
+21. Update comment.  macos/source/pathname.c (Christian)
+22. Start of manual update.  Zip.1 (Ed)
+23. Changes to use crc32.c.  vms/descrip.mms, vms/descrip_deps.mms,
+    vms/descrip_mkdeps.mms, vms/descrip_src.mms, vms/vms.c (SMS)
+---------------------- January 17th 2007 version 3.0f26 -----------------------
+ 1. Add note for UnZip.  crypt.c (Christian)
+ 2. Change current_disk and disk_number from int to ulg.  Change num from int
+    to unsigned int.  [Even though a 16-bit system likely won't see more than
+    64k disks, it probably should be ulg - Ed]  Remove unused mbsize.  Change
+    match from long to int as the number of possible options should always fit
+    in that.  fileio.c, globals.c (Christian)
+ 3. Use -Gt to force some data into separate data segments so all data fits.
+    msdos/makefile.msc (Christian)
+ 4. Move some copyright constants to far to save near space.
+    revision.h (Christian)
+ 5. Change u for character from int to unsigned int.  util.c (Christian)
+ 6. Move include of crc32.h from vms/vms.c to vms/vms_pk.c.  vms/vms.c,
+    vms/vms_pk.c (Christian)
+ 7. Update crci386_.o.  win32/makefile.gcc (Christian)
+ 8. Use NOASM=1 to disable assembler and clear variables when do not.
+    win32/makefile.w32 (Christian)
+ 9. Remove unused totalslashes and returnslashes from get_win32_utf8path().
+    win32/win32zip.c (Christian)
+10. Remove local versions of tempzip and tempzf.
+    zip.c (Christian)
+11. Make options[] far.  Change cd_start_disk from int to ulg.  Cast -1 to
+    (ulg) for cd_start_disk.  Put here = zftello() in DEBUG defines.
+    zip.h, zip.c (Christian)
+12. Change length of zipfile comment parameter from ush to extent.  Change
+    disk numbers from int to ulg in close_split(), ask_for_split_read_path(),
+    ask_for_split_write_path(), get_in_split_path(), find_in_split_path(),
+    get_out_split_path().  Add Far to longopt and name strings in
+    option_struct.  zip.h (Christian)
+13. Add far to options[].  zipcloak.c (Christian, Ed)
+14. Define write_string_to_mem() only for UNICODE_SUPPORT.  Change ulg to
+    extent for append to mem memory offset and blocksize parameters.  Make
+    at_signature() local.  Cast usValue to char.  Remove unused oname in
+    read_Unicode_Path_local_entry().  Remove local definitions of zip64_entry
+    as Zip is always processing one entry at a time and this is a global
+    flag for the current entry.  Make find_next_signature() and
+    find_signature() local.  Add ZCONST to signature parameter.  Make
+    is_signature() and at_signature() local.  Change m, result of fread(),
+    from int to extent.  Reduce SCAN_BUFSIZE from 0x40000 to the size of the
+    largest header being read.  As find_next_signature() is used to scan for
+    the next signature and that reads a byte at a time, the scan buf is only
+    used to read in the found headers.  Since we skip the extra parts of the
+    Zip64 EOCDR, all headers are a fixed size.  Remove unused variables from
+    scanzipf_fixnew().  Use ENDCOM for end comment offset.  Instead of 64 KB
+    seek back 128 KB to find EOCDR.  Use ENDOFF and ENDTOT for offsets in
+    EOCDR.  Remove tabs.  Merge versions of putend().  Update Amiga SFX.
+    Remove unused offset in zipcopy().  Make size local in zipcopy().
+    zipfile.c (Christian)
+15. Update putend() comment.  zipfile.c (Ed)
+16. Add far to options[].  zipnote.c, zipsplit.c (Christian)
+17. Add NO_ASM versions of Win32 zipnote, zipsplit, and zipcloak projects.
+    Add crc32.h and crc32.c to zipsplit and zipnote projects.
+    win32/vc6/zipsplit.dsp, win32/vc6/zipnote.dsp, win32/vc6/zipcloak.dsp (Ed)
+18. Add NO_ASM versions of Win32 bzip2 zipnote, zipsplit, and Zipcloak
+    projects.  Add crc32.h and crc32.c.  win32/vc6bz2/zipsplit.dsp,
+    win32/vc6bz2/zipnote.dsp, win32/vc6bz2/zipcloak.dsp (Ed)
+19. Update Win32 dll and lib projects and make files.
+    windll/visualc/lib/zip32.dsp, windll/visualc/lib/zip32.mak,
+    windll/visualc/dll/zip32.dsp, windll/visualc/dll/zip32.mak (Ed)
+20. Remove space in front of #ifdef and other conditionals that slipped in.
+    zipfile.c, zipup.c (SMS)
+21. Updates for bzip2.  vms/bzlib.h, vms/install_vms.txt (SMS)
+22. Updates.  vms/notes.txt (SMS)
+23. Update copyrights.  crc32.c, deflate.c, globals.c, revision.h, ziperr.h,
+    trees.c, win32/nt.c, win32/win32.c, win32/win32i64.c, win32/win32zip.h,
+    win32/zipup.h (Ed)
+24. Update WhatsNew.  WHATSNEW (Ed)
+---------------------- February 4th 2007 version 3.0f27 -----------------------
+ 1. Fix array sizes and loop lengths in wide_to_escape_string().  fileio.c
+    (Johnny, Ed)
+ 2. Fix escape_string_to_wide() to handle hex strings, then comment out as
+    not used.  zip.h, fileio.c (Ed)
+ 3. Use ZIPERRORS() macro instead of ziperrors[] array.  zip.c, zipcloak.c,
+    zipnote.c, zipsplit.c (SMS)
+ 4. Add VMS-compatible "severity" values, add new ZE_SEV_PERR define to
+    set when perror() needs to be called, add ZIPERRORS() macro, change
+    PERR() to use ZE_SEV_PERR, change ziperrors[] to new structure array
+    to hold error strings, add new VMS facility names and severity codes
+    assigned by HP to ziperrors[] array, and add new official
+    VMS_MSG_IDENT.  ziperr.h (SMS)
+ 5. Change ZE_SEV defines to ZE_S to save space and reformat ziperrors[].
+    ziperr.h (Ed)
+ 6. Update install.txt to include generic Unix case.  bzip2/install.txt (Ed)
+ 7. Add creation of message file and add NOMSG message.  vms/build_zip.com,
+    vms/descrip.mms, vms/install_vms.txt (SMS)
+ 8. Update notes.txt to add changes to program exit status values and changes
+    to messages.  vms/notes.txt (SMS)
+ 9. Include crc32.h, include ssdef.h, instead of FAB_OR_NAM use FAB_OR_NAML,
+    add status code summary note detailing old versus new error codes, and if
+    CTL_FAC_IZ_ZIP is 0x7FFF and OLD_STATUS is defined use old VMS error codes.
+    vms/vms.c (SMS)
+10. Change FAB_OR_NAM to FAB_OR_NAML and remove NAME_DNA, NAME_DNS, NAME_FNA,
+    and NAME_FNS.  vms/vms.h (SMS)
+11. Change FAB_OR_NAM to FAB_OR_NAML.  vms/vms_im.c, vms/vms_pk.c,
+    vms/vmszip.c (SMS)
+12. Fix compile warning on VC 2005.  win32/makefile.w32 (Johnny)
+13. Update readmevb.txt and readvb64.txt.  windll/vb/readmevb.txt,
+    windll/vbz64/readvb64.txt (Ed)
+14. Change tch from int to ulg in utf8_from_ucs4_char().  Move comments to keep
+    line lengths to 80 characters.  fileio.c (Christian)
+15. Update comment for total_cd_entries.  global.c, zip.c, zip.h (Christian)
+16. Comment out unused Adler-16 code.  util.c, zip.h (Christian)
+17. Add InterlockedExchangePointer() macro if not defined.  Update Initialize()
+    to use macro.  nt.c (Christian)
+18. Move zip64 eocd disk and offset variables next to input archive variables.
+    zip.c (Ed)
+19. Remove zipbegset from scanzipf_fixnew() as offsets are ignored when this
+    is fixing archives.  Add comment to cd_total_entries.  Remove local
+    cd_start_disk and cd_start_offset as these are already global.  Use
+    ZIP_UWORD16_MAX when disk number exceeds this to flag use of Zip64.
+    zipfile.c (Christian)
+20. Some comment changes.  zipfile.c (Ed)
+21. Fix indentation in places.  zipsplit.c (Christian)
+22. Remove unused variable zfile.  zipup.c (Christian)
+23. Update manual.  zip.1, zip.txt, zipsplit.txt (Ed)
+---------------------- February 22nd 2007 version 3.0f28 ----------------------
+ 1. Update notes.  vms/notes.txt (SMS)
+ 2. Add stream_lf.fdl to specify carriage control.  vms/stream_lf.fdl (SMS)
+ 3. Update License to also refer to www.info-zip.org and to hopefully provide
+    an example of misrepresentative use.  LICENSE (Ed)
+ 4. Update Readme.  README (Ed)
+ 5. Update WhatsNew.  WHATSNEW (Ed)
+ 6. Change output archive cd_start_disk and cd_start_offset to input archive
+    local in_cd_start_disk and in_cd_start_offset in scanzipf_fixnew() and
+    scanzipf_regnew() to avoid mixing in and out.  zipfile.c (Ed)
+ 7. Update copyright.  Remove crc32.h include.  vms/vms.c (Christian)
+ 8. Changes for new crc32.  Remove CRC32.  Add CRCA_0 and CRCAUO.  Add
+    compiling of crc_i386.S.  win32/makefile.emx. (Christian)
+ 9. Add handlers for better RSXNT and Windows OEM conversions.  Add detailed
+    comments on conversions.  win32/osdef.h (Christian)
+10. Define CP_UTF8.  win32/rsxntwin.h (Christian)
+11. Define WIN32_LEAN_AND_MEAN to reduce size of Windows includes.
+    win32/win32.c, win32/win32zip.c, zip.c (Christian)
+12. Use only standard FAT attributes if OEM.  win32/win32zip.c (Christian)
+13. Add use of INTERN_TO_OEM() and related OEM changes.  Add console comment.
+    zip.c (Christian)
+14. Change severity from char to int.  Update macros.  ziperror.h. (Christian)
+15. Update Visual Basic project to clarify some of the code.
+    windll/vbz64/vbzip.vbp, windll/vbz64/vbzipbas.bas,
+    windll/vbz64/vbzipfrm.frm (Ed)
+16. Update copyright.  api.c (Ed)
+17. Update format for duplicate entry warning.  fileio.c (Ed)
+18. Instead of ifdef __RSXNT__ use ifdef WIN32.  Define WIN32_LEAN_AND_MEAN.
+    Use WIN32_CRT_OEM.  Change OEM check from vem == 20 to vem & 0xff00 == 0
+    and instead of local_to_oem_string() use _INTERN_OEM().  Remove unused
+    first_CD in scanzipf_fixnew().  Instead of oem_to_local_string() use
+    Ext_ASCII_TO_Native().  Instead of local_to_oem_string() use
+    INTERN_TO_OEM().  zipfile.c (Christian)
+19. Replace escape from zipsplit man page with '.  zipsplit.txt (Christian)
+20. Instead of using 20 every time, account for dosify when setting vem.
+    Update FAT comment.  zipup.c (Christian)
+------------------------ March 3rd 2007 version 3.0f29 -------------------------
+ 1. Remove crctab.c.  vms/build_zip.com (SMS)
+ 2. Add LFLAGS_ARCH.  vms/descrip.mms (SMS)
+ 3. Remove redundant includes descrip.h, rms.h, and atrdef.h.
+    vms/vmsmunch.c (SMS)
+ 4. Remove includes descrip.h and rms.h.  vms/vmszip.c (SMS)
+ 5. Only define NO_UNISTD_H if __VAX defined or __CRTL_VER is
+    less than 70301000, allowing support of the new symbolic
+    links in VMS.  Also use unlink instead of delete if version
+    above 70000000.  vms/osdep.h (SMS)
+ 6. Formatting changes.  vms/notes.txt, vms/install_vms.txt (Christian)
+ 7. Remove spaces before tabs.  win32/makefile.emx (Christian)
+ 8. Formatting change.  win32/osdep.h (Christian)
+ 9. If -y on VMS open the link not the target file.  vms/vms_im.c (SMS)
+10. If -y on VMS search for the link, not the target file.  vms/vms_pk.c (SMS)
+11. Change default for Unicode path mismatch from error to warning, so
+    processing will continue.  zip.c, globals.c (Ed)
+------------------------ March 12th 2007 version 3.0f30 ------------------------
+ 1. Add bzip2 support for the reduced no stdio bzip2 library for VMS and Unix.
+    Use libbz2_ns_.olb for VMS bzip2 library which is compiled from the VMS
+    version of bzip2 with the BZ_NO_STDIO flag set.  This flag removes most
+    standard bzip2 stdio support and enables using a callback routine for
+    errors.  zbz2err.c, unix/Makefile, vms/build_zip.com, vms/descrip.mms,
+    vms/descrip_deps.mms, vms/descrip_src.mms (SMS)
+ 2. Add zbz2err.c to Win32 vc6bz2 project for support of BZ_NO_STDIO for bzip2.
+    Modify zbz2err.c to handle different ports.  zbz2err.c (Ed)
+ 3. Update license.  zip.h (Ed)
+ 4. Update copyright.  zip.c, zipfile.c, zipup.c, zbz2err.c, revision.h (Ed)
+ 5. Fix bug where directories got set to ver 4.6 in local headers instead of
+    ver 1.0 when using bzip2.  zipfile.c, zipup.c (Ed)
+ 6. Minor updates to INSTALL.  INSTALL (Ed)
+ 7. Minor updates to README.  README (Ed)
+ 8. Add BZ_NO_STDIO to vc6bz2 projects.  Error routine seems to work.
+    win32/vc6bz2 (Ed)
+ 9. Set bit FAB$M_BIO (.fab$v_bio) in the FAB when using sys$open() on a
+    symlink.  vms/vms_im.c (SMS)
+10. Change sys$disk to SYS$DISK.  vms/build_zip.com (SMS)
+11. Update extended help.  zip.c (Ed)
+12. Update bzip2 install.  bzip2/install.txt (Ed)
+------------------------ March 19th 2007 version 3.0f31 ------------------------
+ 1. Define bz2_olb as LIBBZ2_NS.OLB.  Change LIBBZ2.OLB to bz2_olb.  Use
+    ZZBZ2ERR.C error callback for bzip2.  vms/build_zip.com (SMS)
+ 2. Change NO_SYMLINK to NO_SYMLINKS to be consistent with UnZip.  tailor.h,
+    acorn/osdep.h, macos/osdep.h, tops20/osdep.h, vms/osdep.h (SMS)
+ 3. Minor note changes.  Add section on Symbolic Links.  vms/notes.txt (SMS)
+ 4. Update copyright.  globals.c (Ed)
+ 5. Update License with official copy.  LICENSE (Greg, Ed)
+ 6. Update Readme.  README (Ed)
+ 7. Add support for NO_BZIP2_SUPPORT.  tailor.h (Ed)
+ 8. Add common compiler flags to Install.  INSTALL (Ed)
+ 9. Remove SPLIT_FILE define.  zip.c (Ed)
+10. Minor updates to extended help.  zip.c (Ed)
+11. Modify Makefile to also build bzip2 library if found.  Split $MAKE
+    ("make -f unix/Makefile") into $MAKE and $MAKEF, leaving $MAKE as defined by
+    Make and defining $MAKEF to "-f unix/Makefile".  Add clean_bzip2 target.
+    unix/Makefile (SMS)
+12. Modify configure to handle compiling bzip2.  unix/configure (SMS)
+13. Remove linking bzip2 with utilities.  Other changes.  unix/Makefile (Ed)
+14. Change bzip2 wrong library errors to warnings.  Put back OS bzip2 library
+    check.  Only compile bzip2 if in bzip2 directory.  unix/configure (Ed)
+15. More modifications to Makefile and configure to only allow compiling in
+    the bzip2 directory.  unix/Makefile, unix/configure (Ed)
+------------------------ March 27th 2007 version 3.0f32 ------------------------
+ 1. Modify configure and Makefile to only allow compiling bzip2 in the Zip bzip2
+    source directory.  unix/Makefile, unix/configure (SMS, Ed)
+ 2. Update bzip2 installation instructions.  bzip2/install.txt (SMS, Ed)
+ 3. Remove need for BZIP2_USEBZIP2DIR define by using an appropiate include dir
+    specification (-I ../../bzip2) when needed.  zip.c, win32/vc6bz2/zip.dsp,
+    unix/configure (SMS, Ed, Christian)
+ 4. Update VC6 readme.  win32/readmeVC.txt (Christian, Ed)
+ 5. Add crc32.h to VC projects.  Add assembler group to zipcloak, zipnote, and
+    zipsplit projects.  Add BZ_NO_STDIO to all configurations with bzip2 so
+    reduced bzip2 code is used.  win32/vc6/zip.dsp, win32/vc6/zipcloak.dsp,
+    win32/vc6/zipnote.dsp, win32/vc6/zipsplit.dsp (Christian)
+ 6. Update VC6bz2 readme.  win32/readVCBZ.txt (Christian, Ed)
+ 7. Modify bzip2 VC6 workspace to use standard zipcloak, zipnote, and zipsplit
+    projects as they don't need bzip2.  win32/vc6bz2/zip.dsw (Christian)
+ 8. Fix zlib flag problem by properly setting and clearing deflInit flag to
+    initialize and release resources.  zipup.c (Bill Brinzer, Christian)
+ 9. Update copyright.  crypt.h, api.c, tailor.h, fileio.c, ziperr.h,
+    zipsplit.c, zipnote.c, zipcloak.c, util.c (Ed)
+------------------------ April 25th 2007 version 3.0f33 ------------------------
+ 1. Fix -dd display_dots option for VMS.  Fix adding value for -ds to command
+    line.  Fix /NAMES = AS_IS for older header files.  cmdline.c (SMS)
+ 2. Add Win32 wide scan support.  In fileio.c add Win32 wide functions lastw(),
+    msnamew(), newnamew(), wchar_to_wide_string(), is_ascii_stringw(),
+    wchar_to_local_string(), and wchar_to_utf8_string().  In globals.c
+    add no_win32_wide that is true if the wide versions of calls like
+    GetFileAttributesW() do not work as on Win9x without the Unicode kit.
+    In tailor.h define zwstat for stats that use wchar_t strings and
+    defines SSTATW and LSSTATW.  In util.c add isshexpw() and recmatchw()
+    and dosmatchw() for matching using wchar_t strings.  In win32.c add
+    FSusesLocalTimeW(), IsFileSystemOldFATW(), GetFileModeW(), GetLongPathEAW(),
+    and zstat_zipwin32w().  In win32zip.c add zdirscanw structure,
+    GetDirAttribsW(), zDIRSCANW, readdw(), wild_recursew(), procname_win32w(),
+    OpenDirScanW(), GetNextDirEntryW(), CloseDirScanW(), procnamew(),
+    local_to_wchar_string(), wchar_to_utf8_string(), in wild() code to
+    check if W versions are supported and send zip down byte or wide path,
+    ex2inw(), in2exw(), and filetimew().  In zipup.h define zwopen to use
+    wide paths.  In zipup.c if supported use filetimew() and zwopen().
+    In zip.h add namew, inamew, and znamew to zlist and flist.  In zip.c
+    remove duplicate initialization of use_wide_to_mb_default, force_zip64,
+    zip64_entry, and zip64_archive.  Use filetimew() if UNICODE_SUPPORT and
+    using wide paths for directory scan.  Remove old 8.3 path Unicode fix as
+    now use wide paths and get all where the 8.3 kluge missed paths where
+    characters in path needed multiple code pages.  Changes to bit 11 Unicode
+    but still not ready.  fileio.c, globals.c, tailor.h, util.c, zipup.h,
+    win32/win32.c, win32/win32zip.c, win32/win32.h, zipup.c, zip.c (Ed)
+ 3. Update copyright.  Don't define UNICODE_SUPPORT if already defined.
+    Define MATCHW and zstat_zipwin32w().  win32/osdep.h (Ed)
+------------------------ April 29th 2007 version 3.0f34 ------------------------
+ 1. Add temporary option -sC to test Unicode file creation enabled with
+    UNICODE_TEST define.  zip.c, fileio.c (Ed)
+ 2. On Unix display control characters as ^X as UnZip.  (SMS) fileio.c
+ 3. Update extended help.  zip.c (Ed)
+ 4. Fix bugs in Unicode changes.  zip.c, fileio.c (SMS, Ed)
+ 5. Add NAMES AS_IS support.  Handle root dir [000000].  zip.h,
+    vms/install_vms.txt, vms/vmszip.c, vms/vmsmunch.c (SMS)
+ 6. Add global zipfile_exists to handle missing zipfile errors better.  zip.h,
+    globals.c, zip.c (Ed)
+ 7. Add functions utf8_to_escape_string(), wide_to_escape_string(),
+    local_to_escape_string(), utf8_to_wchar_string(), and
+    rename wide_to_escape_string() to wide_char_to_escape_string().  fileio.c,
+    win32/win32zip.c, zip.h (Ed)
+ 9. Free f->inamew in fexpel().  Use zuname for matching.  fileio.c (Ed)
+10. Fix memory bug by setting z->namew, z->inamew, and z->znamew to NULL.
+    Set f->namew, f->inamew, and f->znamew to NULL for new file in newname().
+    Free wide_string in local_to_utf8().  Other Unicode fixes.  Add namew,
+    inamew, and znamew to freeup().  fileio.c, win32/win32zip.c, zip.h (Ed)
+11. Move wchar functions only used by Windows to win32zip.c.  fileio.c,
+    zip.h (Ed)
+12. Fix spelling in manual.  zip.1 (SMS, Ed)
+13. Add zuebcmp() for Unicode.  zipfile.c
+14. Open files to read using wide name as input path.  zipup.c (Ed)
+15. Update help.  zip.c (Ed)
+16. Change -TT long option from --unzip-path to --unzip-command.  zip.c (Ed)
+17. Update Manual to include section on Unicode, add -TT option, make some
+    changes to Unicode in other sections, update copyright at bottom, and
+    some small changes to wording and examples.  man/zip.1, zip.txt (Ed)
+18. Put #ifdef WIN32 around WIN32 blocks.  zipfile.c (Ed)
+------------------------- May 14th 2007 version 3.0f35 -------------------------
+ 1. Update VMS to include new options.  vms/cmdline.c, vms/zip_cli.cld (SMS)
+ 2. Update VMS help.  vms/vms_zip.rnh (SMS)
+ 3. Minor updates to VMS help.  vms/vms_zip.rnh (Ed)
+ 4. Create global filter_match_case that defaults to 1 (case-sensitive).  zip.c
+    zip.h, globals.c (Ed)
+ 5. Add option -fc to fold case for case-insensitive matching in filter().
+    Currently enabled only for WIN32.  zip.c, win32/osdep.h (Ed)
+ 6. Change (action == DELETE || action == FRESHEN) to filter_match_case in
+    PROCNAME() define.  I just couldn't figure out what was going on here and
+    why the case flag was controlled by this.  zip.c (Ed)
+ 7. Update WhatsNew.  WHATSNEW (Ed)
+------------------------- May 17th 2007 version 3.0f36 -------------------------
+ 1. Touch date on generated file.  vms/ZIP_MSG.MSG (SMS, Ed)
+ 2. Update Betas readme to include Release Candidates.  Betas_Readme.txt (Ed)
+ 3. Update Zip 3.0f announcement.  zip30f.ann (Ed)
+ 4. Minor updates to VMS help.  vms/cvthelp.tpu, vms/vms_zip.rnh (SMS)
+ 5. Major changes to VMS CLI help.  vms/zip_cli.help (SMS, Ed)
+ 6. Update license.  revision.h (Ed)
+------------------------- May 21st 2007 version 3.0f37 -------------------------
+ 1. Rename -fc (fold case) to -ic (ignore case) which may be more intuitive.
+    zip.c (Ed)
+ 2. VMS CLI updates for new options.  vms/cmdline.c, vms/vms_zip.rnh,
+    vms/zip_cli.cld, vms/zip_cli.help (SMS)
+ 3. Updates to support Watcom C, mingw, djgppv2 and msc-16-bit, including
+    supporting wide stat and compare calls and work-around for problem with
+    "no symlink support" detection.  tailor.h, util.c, zip.c, win32/osdep.h,
+    win32/win32.c, win32/win32/zipup.h (Christian)
+------------------------- May 29th 2007 version 3.0f38 -------------------------
+ 1. Update description.  file_id.diz (Ed)
+ 2. Handle better when not splitting and run out of disk space.  Also, for split
+    method 1 (automatically write all splits to same place) exit if run out of
+    space instead of filling available space with near empty splits.  For split
+    method 2 require splits to be at least 64K bytes (the minimum split size).
+    fileio.c (Ed)
+ 3. Add line break in ziperr() if message line has been started.  zip.c (Ed)
+ 4. In ziperr() don't close output handle y if same as current_local_file handle
+    and just closed that.  zip.c (Ed)
+ 5. Change default definition of PROCNAME() to handle new filter_match_case flag
+    and restore backward compatibility.  zip.c (Christian, Ed)
+ 6. Add note detailing definition of PROCNAME().  zip.c (Ed)
+ 7. Remove nonlocalpath parameter from procname_win32() and procname_win32w()
+    and variables nonlocal_path and nonlocal_name as this is not used now that
+    unicode is implemented in WIN32 using the wide calls.
+ 8. Enable ignore case option for VMS.  zip.c (SMS)
+ 9. Update -v and other updates in manual.  man/zip.1 (Christian, Ed)
+10. Updates for Watcom C and Win32 symlinks.  win32/osdep.h (Christian)
+11.  Fix historic problem with VAX seeking.  zipfile.c (SMS)
+12. Add NAM_M_EXP_DEV.  Add determination if device is in file specification.
+    If device name in file specification do ODS2 and ODS5 down-casing.
+    Define explicite_dev().  vms/vms.h, vms/vmszip.c (SMS)
+------------------------- June 4th 2007 version 3.0f39 -------------------------
+ 1. Update osdep.h to use new filter_match_case flag.  vms/osdep.h (SMS)
+ 2. Fix unterminated string bug and trim extra allocated space in
+    local_to_display_string().  fileio.c (Ed)
+ 3. Updated extended help for -u and -ic options.  zip.c (Ed)
+ 4. Update Manual.  man/zip.1, zip.txt (Ed)
+------------------------- June 15th 2007 version 3.0f40 -------------------------
+ 1. Update Unicode Path and Unicode Comment descriptions based on suggestions
+    from WinZip.  proginfo/extrafld.txt (Steve Gross, Ed)
+ 2. Update descriptions for Add, Update, and Freshen in the manual.  man/zip.1
+    (Christian)
+ 3. Update default definition of PROCNAME() to use filter_case_match flag to
+    turn off case matching in filter().  zip.c (Christian)
+ 4. Update WhatsNew.  WHATSNEW (Ed)
+ 5. Update announcement.  zip30f.ann (Ed)
+ 6. Update manual.  man/zip.1, zip.txt (Ed)
+------------------------- July 7th 2007 version 3.0f41 -------------------------
+ 1. Use File Name as Unicode path if UTF-8 flag is set in header.  zip.c,
+    globals.c, zipfile.c, zip.h (Ed)
+ 2. Update ToDo.  TODO (Ed)
+ 3. Update WhatsNew.  WHATSNEW (Ed)
+ 4. Update ReadMe.  README (Ed)
+ 5. Fix problems with incompatible stat types on Win32.  fileio.c, tailor.h,
+    zip.h, win32/win32.c, win32/win32zip.c, win32/osdep.h (Ed)
+ 6. Define NO_STREAMING_STORE to turn off storing while streaming.
+    INSTALL, zipup.c (Ed)
+ 7. Define UNICODE_ALLOW_FORCE to enable -UN=force option which is now
+    disabled and would need work.  globals.c, zip.h (Ed)
+ 8. Add global using_utf8 to flag when OS current character set is UTF-8.
+    If an existing entry has the UTF-8 flag set the flag is kept.  If a new
+    entry needs Unicode and on a UTF-8 system assume the strings are UTF-8
+    and set the UTF-8 flag.  globals.c, zip.h (Ed)
+ 9. Update Unicode extra field descriptions.  proginfo/extrafld.txt (Ed)
+10. Add include directory so can find bzip2 header file when using bzip2
+    directory.  unix/configure (Ed)
+11. Fix wide character wild(), wild_recursew() and OpenDirScanW() for Win32 so
+    work like the regular versions.  win32/win32zip.c (Ed)
+12. Update Unicode in manual.  Update -W description in manual  zip.1
+13. Flush logfile writing.  zip.c (Ed)
+14. Update extended help for -UN option.  Update help for Update to note it
+    updates files where the OS has a later date.  Chance -UN=Exit to -UN=Quit
+    so can abbreviate to first letter.  zip.c (Ed)
+15. Fix a bug in readzipfile() when zip used in pipe.  Other pipe fixes.  zip.c,
+    zipfile.c (Ed)
+------------------------ August 10th 2007 version 3.0f42 -----------------------
+ 1. Update error message for -DF.  zip.c (Ed)
+ 2. Add bzipped message to write to log file.  zipup.c (Ed)
+ 3. Update bzip2 install instructions.  bzip2/install.txt (Ed)
+ 4. Move local.h include to tailor.h to fix compiler multiple define.  tailor.h,
+    zip.c (SMS)
+ 5. Add additional C compiler checks for GNU and HP.  unix/configure (SMS)
+ 6. Fix to build libbz2.a.  unix/Makefile (SMS)
+ 7. Update copyright.  acorn/osdep.h, macos/osdep.h, tops20/osdep.h,
+    vms/vmszip.c, vms/vmsmunch.c, vms/vms_pk.c, vms/vms_im.c, vms/vms.h,
+    vms/vms.c, vms/osdep.h, win32/rsxntwin.h, win32/osdep.h, win32/nt.c (Ed)
+ 8. Change zfeeko(file, 0, SEEK_SET) to rewind(file) in ffile_size() so
+    EOF is always reset.  This was creating problems in WIN32 when
+    NO_ZIP64_SUPPORT was set but LARGE_FILE_SUPPORT was set.  zipfile.c (Ed)
+ 9. Update compile -v descriptions for LARGE_FILE_SUPPORT and ZIP64_SUPPORT to
+    be more specific as to what each does.  zip.c (Ed)
+10. Fix bug that added the local header size to the next entry compressed size
+    giving a wrong compressed size error if splitting and the split occurs when
+    writing a local header.  fileio.c (Ed)
+11. Remove UNICODE_TEST define from VC 6 projects.  win32/vc6/zip.dsp,
+    win32/vc6/zipcloak.dsp, win32/vc6/zipnote.dsp, win32/vc6/zipsplit.dsp (Ed)
+12. Update extended help.  zip.c (Ed)
+13. Only output -FF central directory messages in verbose mode.  zipfile.c (Ed)
+14. Add note about possible bug when copying entries from a split archive.
+    WHATSNEW (Ed)
+------------------------ August 11th 2007 version 3.0f43 -----------------------
+ 1. Display locale inside check to avoid NULL locale.  zip.c (SMS, Ed)
+ 2. Add include wchar.h to tailor.h.  tailor.h (SMS)
+------------------------ August 21st 2007 version 3.0f44 -----------------------
+ 1. Remove verbose messages when setting locale as verbose flag is not set yet.
+    zip.c (SMS, Ed)
+ 2. Change reading splits message "abort archive" to "abort archive - quit" and
+    change selection letter from a to q so q quits consistently.  For quit,
+    don't confirm as more annoying than helpful.  fileio.c (Ed)
+ 3. In bfwrite() handle case where a split ends at the end of one entry and
+    trying to write the next local header forces opening next split.  This
+    caused copying entries from one archive to another to fail if this came up.
+    Also handle case where a new split is needed while writing central directory
+    entries.  Now close last split and update pointers to point to the new
+    split.  fileio.c (Ed)
+ 4. Update use of mesg_line_started and add new logfile_line_started to account
+    for line ends in logfile.  fflush() output.  zip.c, zip.h, globals.c (Ed)
+ 5. Move setting split size if input archive is split and split_size not set
+    to after archive is read.  zipfile.c, zip.c (Ed)
+ 6. Update Manual to describe Unicode as implemented and note that old splits
+    are not automatically excluded.  man/zip.1, zip.txt (Ed)
+ 7. Update WhatsNew to remove note that creating and copying split archives
+    is broke as it seems fully working now.  WHATSNEW (Ed)
+ 8. Update announcement.  zip30f.ann (Ed)
+------------------------ August 31st 2007 version 3.0f45 -----------------------
+ 1. Unicode fix for VMS.  tailor.h (SMS)
+ 2. Add member current to zlist structure to flag when an archive entry is
+    current with the matching OS file using file time and size.  This is used by
+    File Sync to copy current entries from archive.  zip.h, zip.c (Ed)
+ 3. Comment out zip info verbose extra data message as this message does not
+    seem to add much.  zipfile.c (Ed)
+ 4. Add local and central directory Version Needed To Extract to mismatch
+    warning.  Update warning text.  zipfile.c (Ed)
+ 5. Add function BlankRunningStats() to output blanks for the running stats
+    part of the line to use when displaying stats for entries not on the mark
+    list so all output lines up.  zip.c
+ 6. Add -FS to extended help as new mode.  zip.c (Ed)
+ 7. Update description of -FF to remove Assume Worst.  zip.c (Ed)
+ 8. Add all_current flag that is set if all entries in archive are current and
+    skip updating archive if -FS and all entries are current.  zip.c (Ed)
+ 9. Change argv[] to args[] for "try: zip" error message as message depends on
+    new argument order in args where options are now at beginning.  zip.c (Ed)
+10. For File Sync, copy entries to new archive if file time and size are the
+    same.  If verbose, output ok when copying current entries, otherwise no
+    message when current_entry.  Set all_current to 0 if an entry not marked or
+    a file not on OS as need to avoid the All Current message in these cases to
+    catch only deletions.  zip.c (Ed)
+11. Initialize variables excluding zipstate and setjmp() if USE_ZIPMAIN defined
+    to fix bug when recall zipmain().  zip.c (Ed)
+12. Update Manual.  zip.1, zip.txt (Ed)
+13. Update WhatsNew.  WHATSNEW (Ed)
+14. Update announcement.  zip30f.ann (Ed)
+----------------------- September 5th 2007 version 3.0f46 ----------------------
+ 1. Move write of local header after when GPB11 UTF-8 bit set in putlocal().
+    zipfile.c (Ed)
+ 2. Change to uppercase for compatibility.  vms/install_vms.txt (SMS)
+ 3. Set cenbeg and bytes_this_split to fix grow.  Check if grow split archive.
+    zipfile.c, zip.c (Ed)
+----------------------- September 14th 2007 version 3.0f47 --------------------
+ 1. Include address for new Info-ZIP forum.  Add note on 16-bit OS support.
+    Add note about text file line ends.  README (Ed)
+ 2. Update WhatsNew to include latest on Unicode.  Add section on plans for
+    Zip 3.1.  WHATSNEW (Ed)
+ 3. Minor change in note for Unicode in extended help.  zip.c (Ed)
+ 4. Modify definitions of Unicode extra fields based on discussions with PKWare
+    and WinZip.  proginfo/extrafld.txt (Ed)
+ 5. Add note on UTF-8 flag.  INSTALL (Ed)
+ 6. Minor updates to ToDo list.  Needs more work.  TODO (Ed)
+ 7. Update announcement.  zip30f.ann (Ed)
+ 8. Change definition of IZ_OUR_BZIP2_DIR to be compatible with Configure and
+    to work with HP-UX.  unix/Makefile (SMS)
+------------------------ September 24th 2007 version 3.0f ---------------------
+ 1. Update extended help Unicode description.  zip.c (Ed)
+ 2. Update Readme.  README (Ed)
+ 3. Fix case of define identifying IA64.  vms/vms.c (SMS)
+ 4. Update announcement date.  zip30f.ann (Ed)
+ 5. Update Unicode extra field definitions based on changes proposed for
+    AppNote.  extrafld.txt (Ed)
+------------------------ October 17th 2007 version 3.0g01 ---------------------
+ 1. Can get stuck on open Unix FIFO so default to skip and add option -FI to
+    enable reading FIFO.  Add global allow_fifo.  zip.c, zip.h, globals.c
+    (Willus 0, Ed)
+ 2. As problems with MinGW with wide-character paths, disable wide-character
+    Unicode support.  zip.c, unix/unix.c (Willus 0, Ed)
+ 3. Update manual installs to include zipcloak.1, zipnote.1, and zipsplit.1
+    pages.  unix/Makefile (Ed)
+ 4. Update Solaris packages.  unix/Packaging/pkginfo.in,
+    unix/Packaging/postinstall, unix/Packaging/preinstall.in,
+    unix/Packaging/prototype (SMS)
+------------------------ October 30th 2007 version 3.0g02 ---------------------
+ 1. Fix bug in get_in_split_path() where look for .zip split when attempting
+    to open archives without a .zip extension, even when a single file archive
+    like jar file.  fileio.c (Gabriele (balducci@units.it), Ed)
+ 2. Fix bug where temp file got created in current working directory on Unix
+    by giving entire archive path to mkstemp() as template.  fileio.c, zip.c
+    (Willus, Ed)
+ 3. Use 64-bit output functions for bits_sent.  trees.c (SMS)
+ 4. Add -FF to fixfix -sd messages to make different from identical main
+    messages. zip.c (SMS, Ed)
+ 5. If quiet do not ask for splits and all splits must be in same location.
+    zipfile.c (Ed)
+ 6. Clean up making zip manuals.  unix/Makefile (Ed, SMS)
+ 7. Add clean_exe to make.  unix/Makefile (SMS)
+ 8. Update to VMS Notes, including adding details on symlinks, -V, and UTC
+    dates times.  vms/notes.txt (SMS)
+ 9. Fix bug in wild() when calling wile_recursew() where qw should be
+    pointing inside pw.  win32/win32zip.c (Willus, Ed)
+10. Fix bug where is_ascii_string() fails when passed a NULL string.  This
+    may fix problem where the CentOS mbstowcs() function is returning -1 when
+    trying to convert a file name with a bad character (0xe6), causing
+    local_to_wide_string() and then local_to_utf8_string() to return NULL, so
+    f->uname gets NULL and so is_ascii_string() fails with SIGSEGV.  fileio.c
+    (Willus, Ed)
+------------------------ October 31st 2007 version 3.0g03 ---------------------
+ 1. Add handling of -b temp directory when opening splits in bfwrite() using
+    mkstemp().  fileio.c (SMS, Ed)
+------------------------ November 3rd 2007 version 3.0g04 ---------------------
+ 1. Move show_files to global so can avoid split warning for -sf.  zip.c,
+    globals.c, zip.h, zipfile.c (Ed)
+ 2. Account for -b tempath when opening temp file.  zip.c, zipnote.c,
+    zipcloak.c (SMS, Ed)
+------------------------ November 4th 2007 version 3.0g05 ---------------------
+ 1. Minor fixes to fdopen calls.  zipcloak.c, zipnote.c (SMS, Ed)
+------------------------ November 4th 2007 version 3.0g06 ---------------------
+ 1. Add negation to -db, -dc, -dd, -dg, -du, -dv display options.  zip.c (Ed)
+ 2. Put back UNICODE_SUPPORT no_win32_wide code left out in previous fix.
+    win32/win32zip.c (Willus, Ed)
+------------------------ November 21st 2007 version 3.0g07 ---------------------
+ 1. Fix bug preventing newline in some cases in zipmessage().  zip.c (Ed)
+ 2. Update Unicode help.  zip.c (Ed)
+ 3. Update -sd messages.  zip.c (Ed)
+ 4. Add filetimew() for Unicode case.  zip.c (Ed)
+ 5. Add ClearArchiveBitW() for Win32 wide.  zip.c, zip.h, win32/win32.c (Ed)
+ 6. Only ask for .zip split if path ends in .znn or .znnn where n 0 to 9.  This
+    allows -FF to work on .exe sfx files without adding .zip.  zipfile.c (Ed)
+ 7. Fix bug where only backed up 20 bytes to find Z64 EOCD Locator.  Now back
+    up 24 bytes to include size of Z64 EOCD Locator signature.  This prevented
+    reading and updating archives greater than 4 GB.  zipfile.c (Ed)
+ 8. If -FF on Win32 initialize wide strings namew, inamew, and znamew to NULL.
+    zipfile.c (Ed)
+ 9. Add #include <wctype.h> to support towupper().  tailor.h (SMS)
+------------------------ December 4th 2007 version 3.0g08 ---------------------
+ 1. Update dot_size comment.  globals.c (Ed)
+ 2. Update Compression in extended help.  zip.c (Ed)
+ 3. Add extended help on self extractor -A and -J.  zip.c (Ed)
+ 4. Update VMS SYMLINK version information.  zip.c (SMS)
+ 5. Remove not final from Unicode version information as final now.  zip.c (Ed)
+ 6. Remove apparently not needed WINDLL variable retcode.  zip.c (Ed)
+ 7. Fix -A to calculate sfx offset and adjust offsets as it should.  zip.c (Ed)
+ 8. Split -F and -FF used with -A warning to separate warnings.  zip.c (Ed)
+ 9. Add adjusting to can't to that to split archive error.  zip.c (Ed)
+10. Fix bug for -A that tries to open split by asking for disk 0 instead of
+    disk 1.  Add adjust_offset and cd_total_size variables.  Calculate
+    sfx offset by determining offset of start of central directory.  Archives
+    larger than 4 GB are not supported as sfx archives but these don't seem
+    to work anyway.  Add adjust_offset to Zip64 EOCDR offset and central
+    directory offsets.  zip.c, zipfile.c (Ed)
+11. Comment out here debug variable in find_next_signature().  zipfile.c (Ed)
+12. Change %2x to %02x as format for parts of a signature in error messages.
+    zipfile.c (SMS)
+13. Add warning adjusting split archives not yet supported.  zipfile.c (Ed)
+14. Add period to central directory comment.  zipfile.c (Ed)
+15. Update readme for vb Zip64 project.  windll/vbz64/readvb64.txt (Ed)
+16. Update comments of VB for Zip64 example.  Add SplitSize to VB Zip64
+    example.  windll/vbz64/vbzipbas.bas, windll/vbz64/vbzipfrm.frm  (Ed)
+17. Add SourceForge to comment noting where can get the source code.
+    windll/vbz64/vbzipfrm.frm (Ed)
+18. Update WhatsNew.  WHATSNEW (Ed)
+------------------------ December 12th 2007 version 3.0g09 --------------------
+ 1. A few minor changes to extended help.  zip.c (Ed)
+ 2. Uppercase beginning of most -sd messages.  zip.c (Ed)
+ 3. Add spaces between options in some error messages.  zip.c (Ed)
+ 4. Update comments in scanzipf_regnew().  zipfile.c (Ed)
+ 5. Update scanzipf_regnew() to figure out sfx offset. (Ed)
+ 6. Uppercase VMS RUNOFF file as apparently needed.  VMS_ZIP.RNH (SMS)
+ 7. Add comments to zipmessage().  zip.c (Ed)
+ 8. Update extended help and option descriptions.  zip.c (Ed)
+------------------------ December 20th 2007 version 3.0g10 --------------------
+ 1. Fix -F to include -A adjustment check.  zipfile.c (Ed)
+ 2. Change -FF message when find EOCDR.  zipfile.c (Ed)
+ 3. For -FF, reset first CD entry flag in_central_directory when a local entry
+    is found after CD entries so that another CD entry forces sorting of all
+    local entries to that point.  This allows files with multiple archives in
+    them to be processed.  zipfile.c (Ed)
+ 4. Add message when a local entry is found after a central directory.
+    zipfile.c (Ed)
+ 5. Remove word offset from disk offset location messages.  zipfile.c (Ed)
+ 6. Make Adjust offset message more descriptive.  zipfile.c (SMS, Ed)
+ 7. In scanzipf_regnew(), if adjustment to offsets, add it to
+    in_cd_start_offset.  zipfile.c (Ed)
+ 8. Allocate cextra only if localz->ext not 0 in zipcopy().  zipfile.c (Ed)
+------------------------ December 28th 2007 version 3.0g11 --------------------
+ 1. Include definitions of zip64_eocdr_start and z64eocdl_offset in
+    ZIP64_SUPPORT ifdef block.  Add comments for End Of CD Record (EOCDR).
+    Update comments for adjust offset detection.  zipfile.c (Ed)
+ 2. Change ((uzoff_t)1 << 32) to 0xFFFFFFFF.  zipfile.c (SMS, Ed)
+ 3. Leave off local header detection as not useful when searching for start
+    of central directory to get adjust offset.  Looks like all expected cases
+    are now covered as long as archive is intact.  zipfile.c (Ed)
+ 4. Update some warning messages.  Simplify adjust offset information message.
+    zipfile.c (Ed)
+ 5. Add braces to unicode_mismatch if block.  zipfile.c (Christian)
+ 6. Add (void *) cast in InterlockedExchangePointer() mutex calls to fix
+    compile warnings in MinGW (GCC 3.4.4).  win32/nt.c (Christian)
+ 7. Remove unused nonlocalpath variable.  win32/win32zip.c (Christian)
+ 8. Update betas readme file.  betas_readme.txt (Ed)
+ 9. Partial update to Who list of contributors.  proginfo/infozip.who (Ed)
+10. Update ReadMe.  Create Announcement.  README, zip30g.ann (Ed)
+11. Update WhatsNew.  WHATSNEW (Ed)
+------------------------ January 7th 2008 version 3.0g12 --------------------
+ 1. Convert Scanning files message to use standard zipmessage_nl() so line
+    ends are generated when needed.  fileio.c (Ed)
+ 2. Add line ends in DisplayRunningStats() if a display line has been
+    started.  zip.c (Ed)
+ 3. For the command line listed at the top of the log file, add double
+    quotes around any arguments that have spaces in them.
+    zip.c (Ed)
+ 4. Instead of stdout use standard mesg output stream for show files.
+    Output new line for show files for display and log file if there was
+    output on the current line.  zip.c (Ed)
+ 5. Comment out new line output code after zipup() and replace with
+    call to zipmessage_nl("", 1) to output new line if needed.
+    zip.c (Ed)
+ 6. In GetFileMode() and GetFileModeW() when get attributes fails
+    instead of fprintf(mesg, ...) use zipwarn() so error goes in
+    log file and new lines are displayed when needed.  win32/win32.c (Ed)
+ 7. In GetSD(), change cbytes from long to ulg.  Check cbytes (the
+    compressed size of the security descriptor) and issue warning if
+    the compressed security descriptor is greater than 0x7FFF (32k)
+    as the entire header this extra field is in needs to fit in the
+    64k header.  Should be a check on the running size of the header
+    so the actual space remaining is tracked.  Maybe in Zip 3.1.  If
+    cbytes OK cast to ush and store.  win32/win32zip.c (Ed)
+ 8. Use zipmessage_nl() for bytes security message so new lines are
+    handled and message goes in log file.  win32/win32zip.c (Ed)
+ 9. Add new option -RE to enable [list] (regex) matching in DOS and
+    WIN32 but disable [list] matching otherwise.  Default behavior
+    is restored if ALLOW_REGEX is defined.  globals.c, util.c,
+    zip.h, zip.c (Ed)
+------------------------ January 20th 2008 version 3.0g13 --------------------
+ 1. Update copyrights to 2008.  zip.c, zipcloak.c, zipfile.c, zipnote.c,
+    zipsplit.c, zipup.c, README (Ed)
+ 2. Update Who.  proginfo/infozip.who (Ed)
+------------------------ January 30th 2008 version 3.0g14 --------------------
+ 1. Update copyrights.  fileio.c, globals.c, revision.h, util.c, zip.h,
+    win32/win32.c, win32/win32zip.c (Ed)
+ 2. Updates.  README, proginfo/infozip.who (Ed)
+ 3. Update announcement and WhatsNew.  zip30g.ann, WHATSNEW (Ed)
+ 4. Add ALLOW_REGEX to INSTALL define list.  INSTALL (Ed)
+ 5. Change -sd message.  zip.c (Ed)
+ 6. For bzip2 check for binary and set binary/text flag.  Handle -l and -ll
+    line end conversions for bzip2.  zipup.c (Ed)
+------------------------ February 3rd 2008 version 3.0g --------------------
+ 1. Change && to || to fix logic bug in show files.  zip.c (Johnny)
+ 2. Add CLEAN and CLEAN_ALL VMS targets.  vms/descrip_mkdeps.mms (SMS)
+----------------------- February 22nd 2008 version 3.0h01 --------------------
+ 1. Update some echo statements to use CFLAGS_OPT.  Add GNUC check.
+    unix/configure (SMS)
+ 2. Only store UID and GID if 16 bit.  unix/unix.c (Ed)
+----------------------- March 21st 2008 version 3.0h02 --------------------
+ 1. Change long Unicode escapes from 8 characters to 6 characters based on
+    change in UnZip 6.0.  fileio.c (Ed)
+ 2. Put zuebcmp() declaration in #if 0 block as definition already is.  This
+    function would be used to allow Unicode escapes on the command line
+    without using the -UN=escape option, but the utility of this is still
+    being determined.  zipfile.c (SMS, Ed)
+ 3. Remove declaration for unused bz_deflate_init().  zipup.c (SMS, Ed)
+ 4. Add release announcement file, anticipating the long-awaited release.
+    zip30.ann (Ed)
+ 5. Update WhatsNew.  WHATSNEW (Ed)
+----------------------- March 24th 2008 version 3.0h03 --------------------
+ 1. Update Unix configure script to better test for modern HP-UX compiler.
+    unix/configure (SMS)
+ 2. Updated Beta Readme.  betas_readme.txt (Ed)
+ 3. Update Install.  INSTALL (Ed)
+ 4. Update ReadMe.  README (Ed)
+ 5. Small change to main help screen.  zip.c (Ed)
+ 6. Small update to top of ToDo list.  Actual updating of items still
+    needs to be done.  TODO (Ed)
+----------------------- April 2nd 2008 version 3.0h04 --------------------
+ 1. Update copyright.  crc32.h (Christian)
+ 2. Remove zip.h include.  crc32.h (Christian)
+ 3. Add local prototypes for Unicode functions.  Add cast for split size
+    check.  Make many Unicode functions local.  #if 0 out currently unused
+    utf8_chars().  Fix memory leak in wide_to_local_string() by adding
+    free() for buffer on error return.  Fix memory leak in copy_args() on
+    error return by adding free-args().  Add ZCONST to arg in
+    insert_arg().  Shorten some lines to less than 80 characters.  Add
+    free() to get_longopt() to fix memory leak.  fileio.c (Christian)
+ 4. Create Win32 versions of wide_to_local_string() and
+    local_to_wide_string() so can use Win32 conversion functions.
+    fileio.c, win32/win32.c (Christian)
+ 5. Update comments for get_option().  fileio.c (Ed)
+ 6. Update encryption code readme.  README.cr (Ed)
+ 7. Add prototype for recmatchw().  util.c (Christian)
+ 8. Change count_args() from static to local.  util.c (Christian)
+ 9. Change ifdefs for includes for prototypes for version_info(),
+    zipstdout(), and check_zipfile() for WINDLL and MACOS and add
+    check_unzip_version().  zip.c (Christian)
+10. Change ifndef NO_SYMLINKS to ifdef S_IFLNK for determining compiler
+    information.  zip.c (Christian)
+11. Change UTF-8 locale from en_GB.UTF-8 to .UTF-8.  zip.c (Christian)
+12. Change cast of -1 for dot_size from uzoff_t to zoff_t.
+    zip.c (Christian)
+13. Change prototype for set_filetype to include parameter char *.
+    Change prototype of has_win32_wide to include parameter void.
+    zip.h (Christian)
+14. Add prototypes for find_next_signature(), find_signature(),
+    and is_signature().  Change duplicate prototype scanzipf_regnew()
+    to missing prototype scanzipf_fixnew().  Change comment for Adler-16
+    checksum to CRC-32 checksum as that is being used at that point in
+    the code.  Move multiple uname assignments to common assignment.
+    Add inameLocal for WIN32_OEM and use define for inameLocal if not
+    to save memory allocation when not not using WIN32_OEM.  Also
+    change _INTERN_OEM(str1) to INTERN_TO_OEM(src, dst) for OEM
+    conversion.  Format comment for vem to fit in 80 character lines.
+    zipfile.c (Christian)
+15. Change variable a from buffer to a pointer and add abf as the
+    buffer for zgetline() to handle NULL case.  zipnote.c (Christian)
+16. Change comments to zipentry comments and zipfile comment in
+    messages.  zipnote.c (Ed)
+17. Use uidgid_16bit as flag variable instead of uid_size.  Modify
+    size check that prevents saving Unix UIDs and GIDs in the old
+    Unix extra field if they are not 16 bits.  Change memory
+    allocation based on uidgid_16bit.  Delete unused code for memory
+    copy for extra field.  unix/unix.c (Christian, Ed)
+18. Change compiler flag from -zp8 to -Zp8 for LCC Win32.
+    win32/makefile.lcc (Christian)
+19. Add ifndef debug.  Add bzip2 support.  Add additional compiler
+    flags.  win32/makenoas.w32 (Christian)
+----------------------- April 10th 2008 version 3.0h05 --------------------
+ 1. Fix bug found by forum poster where Zip stops recursing down a tree
+    when option -AS is set and a directory without the Windows archive
+    bit is reached.  Now Zip continues down the tree to include files with
+    the bit set.  win32/win32zip.c (forum poster, Ed)
+ 2. Update comments.  win32/osdep.h (Ed)
+ 3. Update VMS notes to better organize and add information about file
+    name case.  Additional small updates.  vms/notes.txt (SMS)
+ 4. Fix bugs from previous changes to unix.  unix/unix.c (SMS, Christian,
+    Ed)
+ 5. Add unix IBM support.  unix/unix.c (SMS)
+ 6. Update INSTALL to account for new distribution structure and other
+    changes. INSTALL (SMS, Ed)
+ 7. Update bzip2 install readme.  bzip2/install.txt (SMS, Ed)
+ 8. Fix bug noted in forum where -@ and -x generated a "nothing to
+    select from error" by also checking filelist variable populated by
+    -@ for entries.  zip.c (forum poster, Ed)
+----------------------- April 20th 2008 version 3.0h06 --------------------
+ 1. Start announcement for Zip 3.0h public beta.  zip30h.ann (Ed)
+ 2. Update beta readme.  betas_readme.txt (Ed)
+ 3. Update case of README.CR.  INSTALL (Ed)
+ 4. Change -W to -ws for option to stop wildcards from scanning directory
+    boundaries in path.  This frees up -W for later use, maybe as extendted
+    option introducer.  zip.c, man/zip.1 (Ed)
+ 5. Updated date in announcement to May 4th.  zip30.ann (Ed)
+ 6. Added announcement for public beta Zip 3.0h.  zip30h.ann (Ed)
+ 7. Fix large file support for MinGW by checking for compiler environments
+    before the check for (generic) gcc.  zipup.c, win32/osdep.h
+    (Will, Christian)
+ 8. Fix large file support for bzip2.  Additionally, the "dot printout"
+    code has also been adapted for LARGE_FILE support.  zipup.c
+    (Will, Christian)
+ 9. Add comments to top of configure.  unix/configure (Ed)
+10. Move comment and comment out value size check for UID/GID extra field.
+    unix/unix.c (Ed)
+11. Change case of file ToDo to TODO for consistency and to work with Unix
+    package.  TODO (SMS, Ed)
+----------------------- April 26th 2008 version 3.0h07 --------------------
+ 1. For -AS, which for Windows only includes files with the archive bit
+    set, exclude directory entries (by setting -D) as some directories may
+    not have any files with the archive bit set and so the directory would
+    be empty.  zip.c (Ed)
+ 2. Fix UID/GID size detection to use byte sizes and remove data fit test.
+    unix/unix.c (Ed)
+ 3. Update announcement.  zip30h.ann (Ed)
+ 4. Add new unix extra field with tag 'ux' that stores UIDs/GIDs of 1 to 4
+    bytes (8 to 32 bits).  unix/unix.c (Ed)
+ 5. Update VB readme.  windll/vbz64/readVB64.txt (Ed)
+ 6. For Unicode escaped output also show escape for ASCII 7-bit if
+    isprintable() is false.  fileio.c (Ed)
+ 7. Use locale "en_US.UTF-8" for Unix.  zip.c (Ed)
+ 8. Also show escaped Unicode for new files in found list.  zip.c (Ed)
+ 9. Update manual.  man/zip.1, zip.txt (Ed)
+------------------------ May 4th 2008 version 3.0h08 -----------------------
+ 1. Handle when a bad Unicode string in archive forces
+    utf8_to_wide_string() to return a NULL string.  Give warning if UTF-8
+    in existing archive is bad.  Put WIN32 wide local header initializations
+    in UNICODE_SUPPORT block.  fileio.c, zipfile.c (Ed)
+ 2. Leave out Unicode escape code if not Unicode enabled.  zip.c (Ed)
+ 3. Enable oem_to_local_string() and local_to_oem_string() for WIN32
+    even if no Unicode.  zip.h, win32/win32.c (Christian, Ed)
+ 4. Update comment about encryption code.  zipcloak.c (Ed)
+ 4. Update zipmessage_nl() and zipmessage() from zip.c.  zipcloak.c,
+    zipnote.c, zipsplit.c (Ed)
+ 5. Add Mac OS X library check.  unix/configure (SMS)
+ 6. Add 16-bit UID/GID check.  unix/configure (Christian, Ed)
+ 7. Format echo and comment statements a bit.  unix/configure (Ed)
+ 8. Only compile in old 16-bit UID/GID code if new define UIDGID_NOT_16BIT
+    from unix configure script is not defined.  unix/unix.c (Christian)
+ 9. A couple changes to updated 16-bit UID/GID code.  Add 64-bit
+    UID/GID support to new Unix extra field.  unix/unix.c (Ed)
+10. Remove redundant "license" from options table.  zipcloak.c (Ed)
+11. Remove old unix build files.  unix/configure-orig, unix/Makefile-orig
+    (Christian)
+12. Add -O (--output-file) option to ZipCloak.  Fix bug by setting
+    out_path.  zipcloak.c (Ed)
+------------------------ May 8th 2008 version 3.0h09 -----------------------
+ 1. Update copyright.  Add check for NO_UNICODE_SUPPORT.  tailor.h (Ed)
+ 2. Fix bug where Unicode General Purpose Bit Flag 11 should force keeping
+    the old name field but it was being overwritten by the escaped name
+    in the central directory header.  Fixed some ZIPERR() calls in
+    putcentral() that referred to putlocal().  zipfile.c (Ed)
+ 3. Add comment about OCRCU8 and OCRCTB.  unix/configure (Ed)
+ 4. Change line in instructions to note that manuals should be made after
+    Zip is made.  Change OCRTB to OCRCTB.  Add $(OCRCTB) to rule for
+    zipcloak$E so crc32_.o is linked in.  Add comment for NO_UNICODE_SUPPORT
+    flag.  unix/makefile (Ed)
+ 5. Update WhatsNew.  Add additional items to the Zip 3.1 list.  Add note
+    about Zip 2.4.  WHATSNEW (Ed)
+ 6. Update Zip 3.0h announcement.  zip30h.ann (Ed)
+ 7. Update manual pages.  man/zip.1, man/zipsplit.1, man/zipnote.1,
+    man/zipcloak.1 (Ed)
+ 8. Add noted for UTF-8 locale.  zip.c (Ed)
+ 9. Set UTF-8 locale for Unix in utilities if UNICODE_SUPPORT enabled
+    so can display and process paths in archives correctly.  zipsplit.c,
+    zipcloak.c, zipnote.c (Ed)
+------------------------ May 12th 2008 version 3.0h10 ----------------------
+ 1. Add use of new Unix UID/GID extra field and of old Unix 16-bit UID/GID
+    extra field when system uses 16-bit UIDs/GIDs to version information.
+    zip.c (SMS, Ed)
+ 2. Add Unicode Path and Unicode Comment extra fields to extra fields list.
+    Update new Unix extra field revision date.  proginfo/extrafld.txt (Ed)
+ 3. Add Mac hardware platform to version information.  unix/unix.c (SMS)
+------------------------ May 19th 2008 version 3.0h11 ----------------------
+ 1. Initialize f->namew when streaming stdin to fix bug.  fileio.c (Ed)
+ 2. Change force_zip64 to start as -1 as unset, then use 1 for forcing use
+    of Zip64 and 0 for disabling use of Zip64.  Add negation of -fz to
+    prevent use of Zip64 during streaming from stdin to a non-seekable
+    output where data descriptors will be used, which allows creating
+    archives with the old stream format but will fail if a large file is
+    streamed.  Default is still to force Zip64 data descriptors when
+    streaming, which covers all cases but requires a Zip64 compatible
+    unzip.  zip.c, globals.c, zipfile.c (Ed)
+ 3. Handle case of bad Unicode in archive.  zipfile.c (Ed)
+------------------------ May 22nd 2008 version 3.0h12 ----------------------
+ 1. Fix bug introduced last beta that prevented streaming large files.  Use
+    separate error message depending on if -fz- was used.  zipfile.c (Ed)
+ 2. Change non existent to nonexistent.  unix/configure (SMS)
+ 3. Don't output blank line when zipmessage_nl() gets passed an empty
+    string.  This removes blank lines for skipped entries when -FS used.
+    zip.c (Ed)
+------------------------ May 27th 2008 version 3.0h13 ----------------------
+ 1. Change UNICODE_ALLOW_FORCE to UNICODE_SUPPORT, -UN=force to -UN=UTF8,
+    and unicode_force to utf8_force.  This option now standard with Unicode
+    support and forces Zip to save UTF-8 paths and comments, when not ASCII,
+    as if UTF-8 were the native character set.  globals.c, zip.c, zip.h (Ed)
+ 2. Add note to Todo that it's out of date.  TODO (Ed)
+ 3. Update WhatsNew.  WHATSNEW (Ed)
+ 4. Update Unicode help in extended help.  zip.c (Ed)
+ 5. Update announcements.  zip30h.ann, zip30.ann (Ed)
+ 6. Fix bug with -UN=UTF8.  zip.c, zipfile.c (Ed)
+ 7. Update Zip manual.  man/zip.1, zip.txt (Ed)
+ 8. Attempt an update to zip limits document.  proginfo/ziplimit.txt (Ed)
+ 9. Update README regarding forum postings.  README (Ed)
+10. Remove duplicate initialization lines for found and fnxt.  zip.c (SMS)
+------------------------ May 28th 2008 version 3.0h14 ----------------------
+ 1. Remove >= 0 check from wide character check as value is unsigned.
+    fileio.c (SMS)
+ 2. In putlocal(), move nam and use_uname to UNICODE_SUPPORT block.  If
+    no UNICODE_SUPPORT use z->nam instead of nam.  zipfile.c (SMS, Ed)
+ 3. Update announcement date for beta.  zip30h.ann (Ed)
+------------------------ May 31st 2008 version 3.0h ------------------------
+ 1. In putlocal() if using UTF-8 bit then also set UTF-8 bit in z->lflg so
+    is set in local header for streaming.  zipfile.c (Ed)
+ 2. Update announcement date for beta.  zip30h.ann (Ed)
+ 3. Rename lib and dll projects to zip32z64 and update project files so
+    project name is same as lib and dll libraries.  Export make files.
+    windll/visualc/dll/zip32z64.dsp, windll/visualc/dll/zip32z64.dsw,
+    windll/visualc/dll/zip32z64.mak, windll/visualc/libzip32z64.dsp,
+    windll/visualc/libzip32z64.dsw, windll/visualc/libzip32z64.mak (Ed)
+------------------------ June 7th 2008 version 3.0i01 ----------------------
+ 1. Update Mac ReadMe to note Mac OS X uses Unix port.  macos/readme.1st (Ed)
+ 2. Change UNIX to Unix in manual.  Update dates in manual and add note
+    about Mac OS X. Change switch to switches.  zip.1 (SMS, Ed)
+ 3. Add version information under Windows by adding a version resource.
+    win32/vc6/zip.dsp, win32/vc6bz2/zip.dsp, win32/zip.rc (Ed)
+------------------------ June 15th 2008 version 3.0i02 ----------------------
+ 1. Update Install instructions.  INSTALL (Ed)
+ 2. Update ReadMe.  README (Ed)
+ 3. Update ToDo list.  TODO (Ed)
+ 4. Update WhatsNew.  WHATSNEW (Ed)
+ 5. Add note to WHERE.  WHERE (Ed)
+ 6. Update announcement.  zip30.ann (Ed)
+ 7. Review man pages and update Zip man page.  Compile text files from man
+    pages.  man/zip.1, zip.txt, zipnote.txt, zipsplit.txt, zipcloak.txt (Ed)
+ 8. Update extended help.  zip.c (Ed)
+------------------------ June 17th 2008 version 3.0i03 ----------------------
+ 1. Fix bug where UTF-8 flag was not being set when using_utf8 was set as
+    result of UTF-8 being current character set.  zipfile.c (Ed)
+ 2. Update man page globbing description.  man/zip.1, zip.txt (SMS, Ed)
+ 3. Update web address to bzip2 package for VMS.  vms/install_vms.txt (SMS)
+------------------------ June 21st 2008 version 3.0i04 ----------------------
+ 1. Update comments.  zbz2err.c (Christian)
+ 2. Put use_uname in UNICODE_SUPPORT block.  zipfile.c (Christian)
+ 3. Increase st to 0x1400.  msdos/makefile.msc (Christian)
+ 4. Update copyright and put @CodeSize and @DataSize into ifndef blocks for
+    Huge, Large, Compact, Medium, and Small.  msdos/match.asm (Christian)
+ 5. Add check to disable symbolic links.  msdos/osdep.h (Christian)
+ 6. Put Mac OS X compiler check into if Mac OS X block to avoid problems on
+    some other Unix ports with the check.  unix/configure (SMS)
+ 7. Move set_extra_field() to fix compile problem.  unix/unix.c (SMS)
+ 8. Update USEBZIP2 to USEBZ2 and -DUSE_BZIP2 to -DBZIP2_SUPPORT.  Drop
+    -DMSDOS compile flag.  win32/makefile.w32 (Christian)
+ 9. Change BZIP2_SUPPORT to USEBZ2.  win32/makenoas.w32 (Christian)
+------------------------ June 23rd 2008 version 3.0i05 ----------------------
+ 1. Update and unify resources.  Remove any MFC dependencies from the resource
+    files zip.rc and windll.rc.  win32/zip.rc and windll/windll.rc now read
+    the version info from revision.h.  windll.rc internal flags modified to
+    "32-bit dll".  zip.rc internal flags liberated from "winnt 32-bit"
+    to "generic 32-bit windows".  Win32 zip.exe also supported on Win9x
+    (32-bit).  Update makefiles for Borland, MSC, GCC(mingw32), Watcom
+    to support inclusion of zip.rc version resources into zip.exe binary.
+    revision.h, msdos/osdep.h, win32/makefile.bor, win32/makefile.gcc,
+    win32/makefile.w10, win32/makefile.w32, win32/makefile.wat,
+    win32/makenoas.w32, win32/zip.rc, windll/windll.rc (Christian)
+ 2. Remove unused files.  win32/resource.h, windll/resource.h,
+    windll/windll.aps, windll/zipver.h, windll/visualc/dll/zip32z64.mak,
+    windll/visualc/lib/zip32z64.mak (Christian)
+ 3. Update VMS.  vms/descrip_deps.mms (SMS)
+------------------------ June 26th 2008 version 3.0i06 ----------------------
+ 1. Update Install and Readme in preparation for release.  Update WhatsNew.
+    INSTALL, README, WHATSNEW (Ed)
+ 2. Update announcement.  zip30.ann (Ed)
+ 3. Update original Visual Basic project comments and documentation.
+    windll/vb/readmevb.txt, windll/vb/vbzip.vbp, windll/vb/vbzip.vbw,
+    windll/vb/vbzipbas.bas, windll/vb/vbzipfrm.frm (Ed)
+ 4. Add bzip2 version of djgpp 2.x makefile thanks to Robert.  Assumes a
+    standard djgpp installation.  msdos/makebz2.dj2 (Robert Riebisch, Ed)
+------------------------ June 27th 2008 version 3.0i07 ----------------------
+ 1. Add DJGPP to bzip2 install instructions.  bzip2/install.txt,
+    msdos/makebz2.dj2 (Robert, Ed)
+------------------------- July 5th 2008 version 3.0 -------------------------
+ 1. Add -sd to extended help.  zip.c (Will, Ed)
+ 2. Fix memory bug when rebuilding Zip64 central directory extra field which
+    can crash MinGW and other ports when processing large files.  zipfile.c
+    (Will)
+ 3. Fix -v bug preventing display of version information when options in
+    environment variables.  zip.c (Ed)
+ 4. Update WhatsNew.  WHATSNEW (Ed)
+ 5. Update announcement.  zip30.ann (Ed)
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..be3e0c5
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,368 @@
+HOW TO INSTALL ZIP
+
+     Zip is distributed as C source code that can be compiled on a
+     wide range of systems:  Unix, VMS, MSDOS, OS/2, NT, Amiga, Atari,
+     BeOS, VM/CMS, ...  You will need Unzip 5.0p1 or later (under any
+     system) or PKUNZIP 2.04g or later (under MSDOS) to unpack the
+     distribution file, in this case zip30.zip.  But since you read this,
+     you have unpacked it already, or you cheated and got a tar.Z file...
+
+     Note:  Zip 3.0 distribution kits (unlike previously distributed
+     Zip 2.x kits) are created with a top-level directory ("zip30") in
+     the archive, making the creating of the zipsrc directory optional.
+
+Installation on Unix (see below for installation on other systems)
+
+     Let's assume that you start from scratch and have not yet unpacked
+     the sources.  First step, then, is to unpack Zip.  The following
+     assumes that you have zip30.zip in the current directory.
+
+     For example, to extract to a new zipsrc directory (assuming
+     zip30.zip is in the current directory):
+
+          mkdir zipsrc
+          cd zipsrc
+          cp ../zip30.zip .
+          unzip zip30.zip
+          cd zip30
+
+     To extract in an existing directory, such as /usr/local/src/zip:
+
+          cd /usr/local/src/zip
+          (copy zip30.zip here)
+          unzip zip30.zip
+          cd zip30
+
+     The first extracts all source files and documentation to the
+     directory "zipsrc/zip30".  The second places the zip30 directory
+     in the "/usr/local/src/zip" directory.  Both then cd in to the
+     zip30 directory where Zip will be built.
+
+     Note:  This release now includes the standard encryption code
+     previously in the separate package zcrypt29.zip, but you still
+     can decide whether to activate the crypt code or not.  Crypt is
+     enabled by default, but you may disable it by specifying the
+     option -DNO_CRYPT in the LOCAL_ZIP environment variable (or by
+     adding this option to the compilation options in the appropiate
+     makefile).  See README.CR for more on crypt.
+
+     You then do:
+
+          make -f unix/Makefile system
+
+     where "system" is one of:  generic, generic_gcc,
+     att6300, coherent, cray_v3, minix, sco_x286, xenix, zilog.
+
+     For Unix systems where "cc" is the preferred C compiler command,
+     try
+
+          make -f unix/Makefile generic
+
+     first.  If "gcc" is preferred, specify "generic_gcc" instead of
+     "generic".  This should work on most systems and automatically
+     selects compilation options based on a set of tests (in
+     unix/configure), including detection of large file support
+     sufficient to enable Zip64 large archive features.  If "generic"
+     (or "generic_gcc" if that is used) fail, then one of the special
+     targets given above may work.
+
+     Among other special systems are Cray Unicos, Zilog Zeus and MINIX.
+
+     The optimization settings for many systems should be close, but
+     if you see optimization for your system is not ideal, send in
+     the changes so we can improve it.
+
+     By default, Zip uses the "deflate" compression method.  To add
+     the additional optional "bzip2" compression method, see the file
+     bzip2/install.txt.  Note that bzip2 support is provided by
+     compiling or linking in the bzip2 library.  See the bzip2 site
+     (http://www.bzip.org/) for more on bzip2.
+
+     If you get error messages such as "constant expected" in
+     deflate.c, add -DDYN_ALLOC to CFLAGS in your makefile entry.
+
+     If you have lots of memory, try compiling with -DBIG_MEM. If your
+     system supports mmap(), try compiling with -DMMAP. This generally
+     gives faster compression but uses more memory. See the unix/Makefile
+     entry mmap_gcc for an example.
+
+     If none of these compiles, links, and functions properly on
+     your Unix system, then your system apparently has specific
+     requirements we did not account for.  See the file README for how
+     to get help.
+
+     If the appropriate system was selected, then the executables zip,
+     zipnote, zipcloak, and zipsplit will be created.  You can copy
+     them to an appropriate directory in the search path using:
+
+          make -f unix/Makefile install
+
+     The defaults are /usr/local/bin for the executables and
+     /usr/local/man/man1 for the manual pages. Change the macros
+     BINDIR and MANDIR in makefile to change these if needed.
+
+     If necessary, add the directory with the Zip executables to your
+     shell's PATH (or "path") variable.  (C-shell users may need to
+     use the "rehash" command so csh can find the new command in the
+     path.)  You should now be ready to use Zip.
+
+     You can get rid of the now unnecessary source and object files
+     with:
+
+          cd ..
+          rm -r zip30
+
+     This will remove the directory zip30 and its contents created
+     by unzip.  You should keep the zip30.zip file around though,
+     in case you need to build it again or want to give it to a
+     colleague.
+
+     You can add the following lines to the file /etc/magic for
+     usage by the 'file' command:
+
+0       string          PK              Zip archive
+>4      byte            011             (at least v0.9 to extract)
+>4      byte            012             (at least v1.0 to extract)
+>4      byte            013             (at least v1.1 to extract)
+>4      byte            024             (at least v2.0 to extract)
+>4      byte            025             (at least v2.1 to extract)
+
+
+Installation on other systems
+
+     The steps for installation under VMS, MSDOS, OS/2, NT, Amiga and
+     Atari are similar to the above:  first unzip the distribution
+     files into their own directory.  The system-dependent files are
+     stored in special subdirectories.
+
+     For all the non-Unix ports which support the creation of "UT" extra
+     fields (these ports contain USE_EF_UT_TIME in the list of optional
+     features displayed with "zip -v"), the timezone environment variable TZ
+     should be set according to the local timezone in order for the -f, -u,
+     -o, and similar options to work correctly.  This is not needed for the
+     WIN32 and WinDLL ports, since they get the timezone information from
+     the OS by other means.
+
+
+  MSDOS:
+
+     Do one of:
+
+          make msdos\makefile.msc               (Microsoft C 5.1)
+          nmake -f msdos\makefile.msc           (Microsoft C 6.0 and newer)
+          make -fmsdos\makefile.bor -DCC_REV=1  (Borland Turbo C++ 1.0)
+          make -fmsdos\makefile.bor             (Borland C++ 2.0 and newer)
+          make -fmsdos\makefile.tc              (Borland Turbo C 2.0x)
+          make -f msdos/makefile.dj1            (DJGPP v1.12m4)
+          make -f msdos/makefile.dj2            (DJGPP v2.01 and newer)
+          make -f msdos/makefile.emx            (gcc/emx 0.9b and newer)
+          make -f os2/makefile.os2 gccdos       (gcc/emx 0.9b and newer)
+          wmake -f msdos\makefile.wat           (Watcom C 11.x 16-bit)
+          wmake -f msdos\makefile.wat PM=1      (Watcom C 11.x 32-bit, PMODE/W)
+
+     for Microsoft, Borland C++ and Turbo C, Watcom C/C++ and the various
+     free GNU C implementations, respectively.  More detailed instructions
+     can be found in the respective makefiles.
+
+
+  WIN32 (Windows NT/2K/XP/2K3 and Windows 95/98/ME):
+
+     Supported compilers are Microsoft Visual C++, Borland C++, Watcom C/C++,
+     and miscellaneous free GNU C implementations (gcc/mingw, CygWin, ...).
+     The makefiles supplied in the win32/ subdirectory contain further
+     information.
+
+
+  Windows DLL (WIN32):
+
+     Supported environments are Visual C++ (32-bit only, 5.x and newer).
+     For instructions how to build the DLLs and where find the makefiles,
+     look into windll/contents.
+
+
+  OS/2:
+
+     Type
+
+          {make} -f os2/makefile.os2
+
+     to get a list of supported targets/compiling environments.
+     (replace "{make}" with the name of your OS/2 make utility.)
+
+     To initiate the actual compiling process, you have to specify
+     a system target:
+
+          {make} -f os2/makefile.os2 {system}
+
+     An example: type
+
+          nmake -f os2/makefile.os2 msc
+
+     for Microsoft C 6.00.
+
+
+  VMS (OpenVMS):
+
+     The most complete information on building and installing Zip on VMS
+     is in [.vms]install_vms.txt.  Optimists in a hurry may wish to try
+     commands like these:
+
+           @ [.VMS]BUILD_ZIP.COM
+     or:
+           MMS /DESCRIP = [.VMS]DESCRIP.MMS CLEAN        ! Or MMK ...
+           MMS /DESCRIP = [.VMS]DESCRIP.MMS              ! Or MMK ...
+
+     When the executables have been created (or located if already installed),
+     most users define foreign command symbols for the Zip executables, like
+     this:
+
+          ZIP :== $ dev:[dir]ZIP.EXE            ! UNIX-like command line.
+     or:
+          ZIP :== $ dev:[dir]ZIP_CLI.EXE        ! VMS-like command line.
+
+     Such symbol definitions are often added to a user's
+     SYS$LOGIN:LOGIN.COM procedure, or to a common, site-specific
+     procedure, like SYS$MANAGER:SYLOGIN.COM.
+
+     Additional installation options are described in install_vms.txt.
+
+     The builders create help text files, ZIP.HLP and ZIP_CLI.HLP.  Also
+     see install_vms.txt for how to create the help libraries.
+
+
+Mac OS:
+
+     Mac OS X is part of the Unix port, so use the Unix installation above.
+
+     Mac OS before Mac OS X use the Mac OS port, though little testing has
+     been done for that port recently.  See macos/README.TXT for more on
+     this port.
+
+
+Compiler Flags
+
+  Zip should compile fine out of the box for your port.  In particular,
+  for Unix the command
+    make -f unix/Makefile generic
+  should automatically detect the features available on your system and
+  set the flags appropriately.  In some cases, however, you may need to
+  set one or more compiler flags yourself to get Zip to compile or to
+  add features you want or remove features that cause trouble for your
+  port.  Below are the more common compiler macros you can set.
+
+  LARGE_FILE_SUPPORT
+    Tell Zip that the OS supports large files (generally files larger
+    than 4 GB).  Zip will try to compile in the large file calls
+    (typically 64-bit) for the OS instead of using the standard
+    (typically 32-bit) file calls.  On Unix Zip tries to switch over to
+    the 64-bit file environment.  If setting this flag causes errors
+    or Zip still can't handle large files on that port, then probably
+    either Zip doesn't have the code to support large files on your OS
+    (write a patch and send it in to us) or your OS doesn't support large
+    files.
+
+    Note that the flag ZIP64_SUPPORT must also be set to create archives
+    with large files.
+
+    This flag should be set automatically on Unix, Win32, and some
+    other ports.  Setting NO_LARGE_FILE_SUPPORT turns this flag off.
+
+  ZIP64_SUPPORT
+    Enable the Zip64 code in Zip that supports the Zip64 extensions noted
+    in the PKWare AppNote.  These extensions allow storing files larger
+    than 4 GB in archives and the creating of archives larger than 4 GB.
+    They also allow storing more than 64K files in an archive.  Currently
+    Zip does not handle archives of PKZip version 4.5 or later unless
+    this flag is set.
+
+    To enable large file support in Zip, you generally need to set both
+    LARGE_FILE_SUPPORT (to read and write large files) and ZIP64_SUPPORT
+    (to store them in and read them from archives).  Files larger than
+    4 GB may be invisible to Zip (directory scans don't see them) if
+    LARGE_FILE_SUPPORT is not enabled.
+
+    Keeping LARGE_FILE_SUPPORT and ZIP64_SUPPORT separate allows easier
+    debugging of these features.  When testing large file support on an
+    OS, first set just LARGE_FILE_SUPPORT to test the file calls (all
+    should compile and work as before with small files), then turn on
+    ZIP64_SUPPORT to let Zip recognize and handle large files.
+
+    This flag should be set automatically on most ports if
+    LARGE_FILE_SUPPORT is set.  Setting NO_ZIP64_SUPPORT turns this flag
+    off.
+
+  UNICODE_SUPPORT
+    Enable storing and using UTF-8 paths.  These paths are stored in
+    a backward-compatible way so that archives with UTF-8 paths still
+    work on zips and unzips that don't support Unicode.  This support
+    follows the recent additions to the PKWare AppNote for Unicode
+    support, except that Unicode comments on systems where UTF-8 is
+    not the current character set is not implemented in this release.
+
+    On some ports UNICODE_SUPPORT is set automatically if wide characters
+    are supported.  Setting NO_UNICODE_SUPPORT turns off this flag.
+
+  USE_EF_UT_TIME
+    Enables storing UT time in an extra field.  This becomes useful
+    for ports that normally store file times as local time, resulting
+    in problems when files are moved across time zones and when
+    there are daylight savings time changes.  Zip and UnZip will
+    automatically correct for time zone changes when UT time is stored.
+
+    This is usually set by default.  Use NO_EF_UT_TIME to turn this off.
+
+  NTSD_EAS (Win32 only)
+    Enable storing Windows NT file security descriptors.  This allows
+    restoring the descriptors (file ACL's, etc.).
+
+    This is on by default for Win32.  Use NO_NTSD_EAS to turn this off.
+
+  BZIP2_SUPPORT
+    Enable compressing zip entries using the bzip2 library.  You must get
+    the bzip2 library from somewhere else as we only provide a way to
+    compile or link the library in and compress files using bzip2.  Enables
+    a new compression method, bzip2, that can be used instead of the default
+    Zip compression method deflate.
+
+    This flag is set on Unix, including Mac OS X, when compiling using
+    generic if the bzip2 library is found.  Set on Win32 if the bzip2
+    projects are used.  See the VMS documentation for when VMS sets this
+    flag.  Setting NO_BZIP2_SUPPORT turns this off.
+
+    See bzip2/install.txt for more on installing bzip2 support.
+
+  WIN32_OEM (Win32 only)
+    Enable saving paths on Win32 in the OEM character set.  Zip has stored
+    paths using the standard ANSI local character set, but other zips have
+    used the OEM character set on MSDOS and Win32.  This flag should make
+    Zip more compatible with other DOS and Win32 zips and unzips.  It also
+    enables the translation of OEM paths in DOS archives to ANSI and should
+    eliminate some problems with funny characters showing up in path names.
+
+    If Unicode is enabled and used, Unicode paths generally override
+    local paths using OEM character sets.
+
+    This flag is on by default on most Win32 ports.  Some ports apparently
+    have problems with OEM conversions.  If your port or compiler does
+    funny things with file names, you may want to turn this off.  Defining
+    NO_WIN32_OEM turns this flag off.
+
+  NO_STREAMING_STORE
+    Because storing zip archives inside a zip entry adds "false" signatures
+    and this causes problems when using data descriptors if the archive
+    needs fixing, this option is provided to force deflating when streaming.
+    This version of Zip includes an advanced algorithm for correctly finding
+    these signatures, but if an archive is "broke", there is no telling
+    what's where.  This is only a problem if an archive becomes broke for
+    some reason, but to be safe define this.
+
+  ALLOW_REGEX
+    For MSDOS and Windows, now "[list]" wildcard matching (where any
+    character between [ and ] can be used to match the character at that
+    position) is turned off unless the new -RE option is used.  Defining
+    this flag forces "[list]" matching to be always on as in previous
+    releases.
+
+
+For command help on any of the zip* utilities, simply enter
+the name with no arguments.
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..bcfe47e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,60 @@
+This is version 2007-Mar-4 of the Info-ZIP license.
+The definitive version of this document should be available at
+ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely and
+a copy at http://www.info-zip.org/pub/infozip/license.html.
+
+
+Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+For the purposes of this copyright and license, "Info-ZIP" is defined as
+the following set of individuals:
+
+   Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
+   Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth,
+   Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,
+   David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,
+   Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,
+   Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda,
+   Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren,
+   Rich Wales, Mike White.
+
+This software is provided "as is," without warranty of any kind, express
+or implied.  In no event shall Info-ZIP or its contributors be held liable
+for any direct, indirect, incidental, special or consequential damages
+arising out of the use of or inability to use this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the above disclaimer and the following restrictions:
+
+    1. Redistributions of source code (in whole or in part) must retain
+       the above copyright notice, definition, disclaimer, and this list
+       of conditions.
+
+    2. Redistributions in binary form (compiled executables and libraries)
+       must reproduce the above copyright notice, definition, disclaimer,
+       and this list of conditions in documentation and/or other materials
+       provided with the distribution.  The sole exception to this condition
+       is redistribution of a standard UnZipSFX binary (including SFXWiz) as
+       part of a self-extracting archive; that is permitted without inclusion
+       of this license, as long as the normal SFX banner has not been removed
+       from the binary or disabled.
+
+    3. Altered versions--including, but not limited to, ports to new operating
+       systems, existing ports with new graphical interfaces, versions with
+       modified or added functionality, and dynamic, shared, or static library
+       versions not from Info-ZIP--must be plainly marked as such and must not
+       be misrepresented as being the original source or, if binaries,
+       compiled from the original source.  Such altered versions also must not
+       be misrepresented as being Info-ZIP releases--including, but not
+       limited to, labeling of the altered versions with the names "Info-ZIP"
+       (or any variation thereof, including, but not limited to, different
+       capitalizations), "Pocket UnZip," "WiZ" or "MacZip" without the
+       explicit permission of Info-ZIP.  Such altered versions are further
+       prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP
+       e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP
+       will provide support for the altered versions.
+
+    4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip,"
+       "UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its
+       own source and binary releases.
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..a559425
--- /dev/null
+++ b/README
@@ -0,0 +1,234 @@
+Zip 3.0 is the first Zip update adding large file support.  For now Zip 2.3x
+remains available and supported, but users should switch to this new release.
+
+Testing for Zip 3.0 has focused mainly on Unix, VMS, Max OS X, and Win32,
+and some other ports may not be fully supported yet.  If you find your
+favorite port is broke, send us the details or, better, send bug fixes.  It's
+possible that support for some older ports may be dropped in the future.
+
+
+
+Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+See the accompanying file LICENSE (the contents of which are also included
+in unzip.h, zip.h and wiz.h) for terms of use.  If, for some reason, all
+of these files are missing, the Info-ZIP license also may be found at:
+ftp://ftp.info-zip.org/pub/infozip/license.html and
+http://www.info-zip.org/pub/infozip/license.html.
+
+
+Zip 3.0 is a compression and file packaging utility.  It is compatible with
+PKZIP 2.04g (Phil Katz ZIP) for MSDOS systems.  There is a companion to zip
+called unzip (of course) which you should be able to find in the same place
+you got zip.  See the file 'WHERE' for details on ftp sites and mail
+servers.
+
+So far zip has been ported to a wide array of Unix and other mainframes,
+minis, and micros including VMS, OS/2, Minix, MSDOS, Windows, Atari, Amiga,
+BeOS and VM/CMS.  Although highly compatible with PKware's PKZIP and PKUNZIP
+utilities of MSDOS fame, our primary objective has been one of portability
+and other-than-MSDOS functionality.  Features not found in the PKWare version
+include creation of zip files in a pipe or on a device; VMS, BeOS and OS/2
+extended file attributes; conversion from Unix to MSDOS text file format; and,
+of course, the ability to run on most of your favorite operating systems.  And
+it's free.
+
+See the file zip30.ann for a summary of new features in Zip 3.0 and WhatsNew
+for the detailed list of new features and changes since Zip 2.32.  The file
+CHANGES details all day-to-day changes during development.
+
+Notes:
+
+Multi-volume support.  This version does not support multi-volume spanned
+archives as in pkzip 2.04g, and there is no intention at this point to support
+spanned archives, but Zip 3.0 supports split archives.  A split archive is an
+archive split into a set of files, each file a piece of the archive and each
+file using an extension, such as .z02 as in the file name archive.z02, that
+provides the order of the splits.  In contrast, a spanned archive is the
+original multi-floppy archive supported by pkzip 2.0g where the split order
+is contained in the volume labels.  The contents of split and spanned archives
+are mostly identical and there is a simple procedure to convert between the
+formats.  Many current unzips now support split archives.
+
+Zip64 support.  This version supports Zip64 archives as described in the
+PKWare AppNote.  These archives use additional fields to support archives
+greater than 2 GB and files in archives over the 2 GB previous limit (4 GB
+on some ports).  The Zip64 format also allows more than 64k entries in an
+archive.  Support by the OS for files larger than 4 GB is needed for Zip to
+create and read large files and archives.  On Unix, Win32, and some other
+ports, large file and Zip64 support is automatically checked for and
+compiled in if available.  Use of Zip64 by Zip is automatic and to maximize
+backward compatibility the Zip64 fields will only be used if needed.  A
+Zip64 archive requires a pkzip 4.5 compatible unzip, such as UnZip 6.0.
+
+Unicode support.  This version has initial Unicode support.  This allows
+paths and names of files in other character sets to be accurately recreated
+on OS that have sufficient character set support.  On Win32, if wide
+character calls are supported (not Win 9x unless Unicode support has been
+added) all files (including paths with illegal characters in the current
+character set) should now be readable by zip.  Unicode support is provided
+using a new set of UTF-8 path and comment extra fields and a new UTF-8 bit
+for flagging when the current character set is already UTF-8.  Zip 3.0
+maintains backward compatibility with older archives and is mostly compliant
+with the new Unicode additions in the latest PKWare AppNote.  The exception
+is UTF-8 comments, which are not supported if UTF-8 is not the native
+character set, but should be fully implemented in Zip 3.1.
+
+16-bit OS support.  Though Zip 3.0 is designed to support the latest zip
+standards and modern OS, some effort has been made to maintain support
+for older and smaller systems.  If you find Zip 3.0 does not fit on or
+otherwise does not work well on a particular OS, send in the details and
+we might be able to help.
+
+Compression methods.  In addition to the standard store and deflate methods,
+Zip now can use the bzip2 compression format using the bzip2 library.  Though
+bzip2 compression generally takes longer, in many cases using bzip2 results
+in much better compression.  However, many unzips may not yet support
+bzip2 compressed entries in archives, so test your unzip first before using
+bzip2 compression.
+
+Installation.  Please read the file INSTALL for information on how to compile
+and install zip, zipsplit, zipcloak, and zipnote and please read the manual
+pages ZIP.txt, ZIPSPLIT.txt, ZIPCLOAK.txt, and ZIPNOTE.txt for information on
+how to use them.  Also, if you are using MSDOS or Windows, note that text
+files in the distribution are generally in Unix line end format (LF only)
+and Windows and DOS users will need to either convert the files as needed to
+DOS line ends (CR LF) or extract the distribution contents using unzip -a.
+
+Utilities.  At this point zipsplit, zipcloak, and zipnote should work with
+large files, but they currently do not handle split archives.  A work around
+is to use zip to convert a split archive to a single file archive and then use
+the utilities on that archive.
+
+Encryption.  This version supports standard zip encryption.  Until recently
+the encryption code was distributed separately because of the US export
+regulations but now is part of the main distribution.  See crypt.c for
+details.  Decryption can be made with unzip 5.0p1 or later, or with zipcloak.
+
+Bug reports.  All bug reports or patches should go to zip-bugs via the web
+site contact form at http://www.info-zip.org/zip-bug.html (we have discontinued
+the old email address zip-bugs@lists.wku.edu because of too much spam lately)
+and suggestions for new features can be submitted there also (although we don't
+promise to use all of them).  We also are on SourceForge at
+http://sourceforge.net/projects/infozip/ and now automatically get Bug Reports
+and Feature Requests submitted there.  In addition, a new Info-ZIP discussion
+forum is available as well.  See below.  Though bug reports can be posted there,
+we don't have automatic monitoring of all postings set up yet so you may want
+to use the web form or SoureForge for a quicker response.  A good approach may
+be to post the details on the forum so others can benefit from the posting,
+then use the web reply form to let us know you did that if you don't get a
+reply in a reasonable time.
+
+Ports.  If you're considering a port, please check in with zip-bugs FIRST,
+since the code is constantly being updated behind the scenes.  We'll
+arrange to give you access to the latest source.
+
+Discussion group.  If you'd like to keep up to date with our Zip (and companion
+UnZip utility) development, join the ranks of BETA testers, add your own
+thoughts and contributions, etc., check out the new discussion forum.  This is
+the latest offering, after the various Info-ZIP mailing-lists on
+mxserver@lists.wku.edu (courtesy of Hunter Goatley) were no longer available
+and the temporary QuickTopic discussion group for Info-ZIP issues at
+http://www.quicktopic.com/27/H/V6ZQZ54uKNL died a horrible death due to large
+amounts of spam.  The new discussion forum is now available at
+http://www.info-zip.org/board/board.pl (thanks again to Hunter Goatley) and
+can be used to discuss issues, request features, and is one place new betas
+and releases are announced.  It also is a place to post bug reports, and
+patches can be submitted as attachments.  However, we don't yet get
+automatic notification of all postings there so try one of the other methods
+if you don't get a response.  You can also post Bug Reports and Feature
+Requests at Source Forge.  However, the web site contact form remains
+available if you would rather not post on the public forums.
+
+Frequently asked questions on zip and unzip:
+
+Q. When unzipping I get an error message about "compression method 8".
+
+A. This is standard deflate, which has been around for awhile.  Please
+   get a current version of unzip.  See the file 'WHERE' for details.
+
+
+Q. How about "compression method 12"?
+
+A. Compression method 12 is bzip2 and requires a relatively modern unzip.
+   Please get the latest version of unzip.
+
+
+Q. I can't extract this zip file that I just downloaded.  I get
+   "zipfile is part of multi-disk archive" or some other message.
+
+A. Please make sure that you made the transfer in binary mode.  Check
+   in particular that your copy has exactly the same size as the original.
+   Note that the above message also may actually mean you have only part
+   of a multi-part archive.  Also note that UnZip 5.x does not and UnZip 6.0
+   probably won't have multi-disk (split) archive support.  A work around
+   is to use Zip 3.0 to convert the split archive to a single-file archive
+   then use UnZip on that archive.  As a last result, if there's something
+   readable in what you have, zip -FF should be able to recover it.
+
+
+Q. When running unzip, I get a message about "End-of-central-directory
+   signature not found".
+
+A. This usually means that your zip archive is damaged, or that you
+   have an uncompressed file with the same name in the same directory.
+   In the first case, it makes more sense to contact the person you
+   obtained the zip file from rather than the Info-ZIP software
+   developers, and to make sure that your copy is strictly identical to
+   the original.  In the second case, use "unzip zipfile.zip" instead
+   of "unzip zipfile", to let unzip know which file is the zip archive
+   you want to extract.
+
+
+Q. Why doesn't zip do <something> just like PKZIP does?
+
+A. Zip is not a PKZIP clone and is not intended to be one.  In some
+   cases we feel PKZIP does not do the right thing (e.g., not
+   including pathnames by default); in some cases the operating system
+   itself is responsible (e.g., under Unix it is the shell which
+   expands wildcards, not zip).  Info-ZIP's and PKWARE's zipfiles
+   are interchangeable, not the programs.
+
+   For example, if you are used to the following PKZIP command:
+               pkzip -rP foo *.c
+   you must use instead on Unix:
+               zip -R foo "*.c"
+   (the quotes are needed to let the shell know that it should
+    not expand the *.c argument but instead pass it on to the program,
+    but are not needed on ports that do not expand file paths like
+    MSDOS)
+
+
+Q. Can I distribute zip and unzip sources and/or executables?
+
+A. You may redistribute the latest official distributions without any
+   modification, without even asking us for permission. You can charge
+   for the cost of the media (CDROM, diskettes, etc...) and a small copying
+   fee.  If you want to distribute modified versions please contact us at
+   www.Info-ZIP.org first. You must not distribute beta versions.
+   The latest official distributions are always on ftp.Info-ZIP.org in
+   directory /pub/infozip and subdirectories and at SourceForge.
+
+
+Q. Can I use the executables of zip and unzip to distribute my software?
+
+A. Yes, so long as it is made clear in the product documentation that
+   zip or unzip are not being sold, that the source code is freely
+   available, and that there are no extra or hidden charges resulting
+   from its use by or inclusion with the commercial product.  See the
+   Info-ZIP license for more.  Here is an example of a suitable notice:
+
+     NOTE:  <Product> is packaged on this CD using Info-ZIP's compression
+     utility.  The installation program uses UnZip to read zip files from
+     the CD.  Info-ZIP's software (Zip, UnZip and related utilities) is
+     freely distributed under the Info-ZIP license and can be obtained as
+     source code or executables from various anonymous-ftp sites,
+     including ftp://ftp.info-zip.org/pub/infozip.
+
+
+Q. Can I use the source code of zip and unzip in my commercial application?
+
+A. Yes, as long as the conditions in the Info-ZIP license are met.  We
+   recommend you include in your product documentation an acknowledgment
+   and note that the original compression sources are available at
+   www.Info-ZIP.org. If you have special requirements contact us.
diff --git a/README.CR b/README.CR
new file mode 100644 (file)
index 0000000..c777d19
--- /dev/null
+++ b/README.CR
@@ -0,0 +1,119 @@
+_____________________________________________________________________________
+
+  This is Info-ZIP's README.CR for zcrypt29.zip, last updated 27 March 2008.
+_____________________________________________________________________________
+
+
+The files described below contain the encryption/decryption code for Zip 2.31,
+UnZip 5.52, and WiZ 5.02 (and later).  These files are included in the main
+source distributions for all of these now, but the encryption patch is still
+available for earlier versions of these.  This file both describes the history
+of the encryption package and notes the current conditions for use.  Check
+the comments at the top of crypt.c and crypt.h for additional information.
+
+As of version 2.9, this encryption source code is copyrighted by Info-ZIP;
+see the enclosed LICENSE file for details.  Older versions remain in the pub-
+lic domain.  Zcrypt was originally written in Europe and, as of April 2000,
+can be freely distributed from the US as well as other countries.
+
+(The ability to export from the US is new and is due to a change in the Bureau
+of Export Administration's regulations, as published in Volume 65, Number
+10, of the Federal Register [14 January 2000].  Info-ZIP filed the required
+notification via e-mail on 9 April 2000; see the USexport.msg file in this
+archive.  However, as of June 2002, it can now be freely distributed in both
+source and object forms from any country, including the USA under License
+Exception TSU of the U.S. Export Administration Regulations (section 740.13(e))
+of 6 June 2002.)
+
+    LIKE ANYTHING ELSE THAT IS FREE, ZIP, UNZIP AND THEIR ASSOCIATED
+    UTILITIES ARE PROVIDED AS IS AND COME WITH NO WARRANTY OF ANY KIND,
+    EITHER EXPRESSED OR IMPLIED. IN NO EVENT WILL THE AUTHORS BE LIABLE
+    FOR ANY DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE.
+
+The encryption code is a direct transcription of the algorithm from
+Roger Schlafly, described by Phil Katz in the file appnote.txt.  This
+file is distributed with the PKZIP program (even in the version without
+encryption capabilities).  Note that the encryption will probably resist
+attacks by amateurs if the password is well chosen and long enough (at 
+least 8 characters) but it will probably not resist attacks by experts.
+Paul Kocher has made available information concerning a known-plaintext
+attack for the PKWARE encryption scheme; see http://www.cryptography.com/
+for details.)  Short passwords consisting of lowercase letters only can be
+recovered in a few hours on any workstation.  But for casual cryptography
+designed to keep your mother from reading your mail, it's OK.
+
+For more serious encryption, check into PGP (Pretty Good Privacy), a
+public-key-based encryption system available from various Internet sites.
+PGP has Zip and UnZip built into it.  The most recent version at the time
+this was originally written was 6.5, although older versions were still
+widespread.  At the time of this writing there are now GPG, PGP Universal
+2.0, and various others based on OpenPGP.
+
+We are looking at adding AES strong encryption to future versions of Zip and
+UnZip.
+
+Zip 2.3x and UnZip 5.5x and later are compatible with PKZIP 2.04g.  (Thanks
+to Phil Katz for accepting our suggested minor changes to the zipfile format.)
+
+IMPORTANT NOTE:
+
+  Zip archives produced by Zip 2.0 or later must not be *updated* by
+  Zip 1.1 or PKZIP 1.10 or PKZIP 1.93a, if they contain encrypted members
+  or if they have been produced in a pipe or on a non-seekable device.
+  The old versions of Zip or PKZIP would destroy the zip structure.  The
+  old versions can list the contents of the zipfile but cannot extract
+  it anyway (because of the new compression algorithm).  If you do not
+  use encryption and compress regular disk files, you need not worry about
+  this problem.
+
+
+Contents that were distributed and now are part of the main source files:
+
+  file           what it is
+  ----           ----------
+  README.CR      this file
+  LICENSE        Info-ZIP license (terms of reuse and redistribution)
+  USexport.msg   export notice sent to US Bureau of Export Administration
+  WHERE          where Zip/UnZip/WiZ and related utilities can be found
+  crypt.c        code for encryption and decryption
+  crypt.h        code for encryption and decryption
+  file_id.diz    description file for some BBSes
+
+Most all of the files are in Unix (LF only) format.  On MSDOS systems, you
+can use the -a option of UnZip to convert the source files to CRLF
+format.  This is only necessary if you wish to edit the files -- they
+will compile as is with Microsoft C and Turbo/Borland C++ 1.0 or
+later.  However, you will have to convert the files (using "unzip -a")
+to the CRLF format to compile with the older Turbo C 1.0 or 2.0.  You
+should be able to find Zip and UnZip in the same place you found this 
+(see ftp://ftp.info-zip.org/pub/infozip/Info-ZIP.html or the file
+"WHERE" for details).
+
+Current releases all have encryption built in.  To update previous versions
+using the zcrypt sources:
+
+  (1) Get the main sources (e.g., Zip 2.3) and unpack into a working
+      directory, as usual.
+
+  (2) Overwrite the dummy crypt.c and crypt.h from the main sources with 
+      the versions from this package.  If you want to overwrite directly
+      out of the zcrypt29 archive, do not use UnZip's freshen/updating
+      option; the dummy files may be newer than the real sources in
+      zcrypt29.  ("unzip -o zcrypt29 -d /your/working/dir" will do the
+      Right Thing in most cases, although it may overwrite a newer WHERE
+      file under some circumstances.)
+
+  (3) Read the main INSTALL document and compile normally!  No makefile
+      changes are necessary on account of the zcrypt sources.  You can
+      check that the version you just compiled has encryption or decryption
+      support enabled by typing "zip -v" or "unzip -v" and verifying that
+      the last "special compilation option" says encryption or decryption
+      is included.
+
+Encryption enables new "-e" and "-P password" options in Zip, and a new
+"-P password" option in UnZip--see the normal Zip and UnZip documentation
+for details.  (Note that passing a plaintext password on the command line
+is potentially much more insecure than being prompted for it interactively,
+which is the default for UnZip and for Zip with "-e".  Also note that the
+interactive method allows UnZip to deal with archives that use different
+passwords for different files.)
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..8d51732
--- /dev/null
+++ b/TODO
@@ -0,0 +1,142 @@
+Todo list (last updated 12 June 2008).
+
+Features for next official version:
+
+- Extended attributes for Windows, Linux, and Mac OS X.
+- Win32 ACL rewrite to use backup api to create new and more useful extra
+  field (need unzip support) (Kai).
+- Allow -d@ to read in a list of names to delete (11/17/2005).
+- AES encryption (3/19/05).
+
+Features that may make the next release:
+
+- Allow reading in list of files using @filename.
+- When -R, -x, or -i pattern ends in a directory add / to the end
+      (11/5/2004 Nehal).
+- Decide if -R, -i and -x should use external rather than internal patterns.
+      Also, change pattern matching to not do ex2in() and then in2ex() if
+      appropriate.  (12/26/2005 SMS)
+- Though Unicode paths have been implemented and tested, Unicode comments
+      are not yet supported (except for comments on UTF-8 native systems which
+      are supported).
+- Verbose mode -v may still need work.
+
+- Add C# example for Zip 3.0 (need to be converted to new DLLs) - original
+      C# example added with note.
+- Path Prefix maybe, so entries added to an archive can have a directory
+      path string prepended to each path so can zip multiple drives and avoid
+      name conflicts (4/17/2006).
+- UNC paths like \\server\path (4/26/2005).
+- Support for other languages maybe.
+
+- Add About page option similar to -h2 and -v but lists Info-ZIP
+      information (could be -sa) (4/29/2006).
+- Update utilities ZipSplit, ZipNote, and ZipCloak to handle split archives.
+- Update ziperr and finish if needed.
+- Review memory allocation and fill in memory leaks if any.
+- Enhance -FF to fix common problems such as archives ftp in text mode
+      and fixing checksums so entries can be extracted if that makes
+      sense (6/17/2007).
+- Add \ to / conversion in zipsplit to fix problem in
+      1/29/2004 email.
+- Encryption bug with small stored file (12/27/2005) (fixed?).
+
+- When updating large archives with few entries being
+      updated maybe display something in large periods of
+      quiet (1/23/2006).
+- Windows OEM comments (5/17/2006).
+- Example of using MVS zip and unzip (3/30/2004) (Need one).
+- UTF-8 comments need to be implemented (6/17/2007)
+- Maybe convert ../ in archive (5/20/2006).
+- Per so many buffers dll callback (12/23/2005 Ale).
+- Allow rename stdin "-" to something else (12/27/2005 gregor).
+- Check for possible buffer overrun weaknesses while reading zip files.
+- Do Active Template Library (ATL) (4/27/2005).
+- Flush Win16 support - to be determined (Mike).
+- Way to convert file names on input, converting foo.c to dir/foo_bar.c
+      for instance (4/8/2004, 3/12/2004).
+- French WiZ (not a Zip thing actually but dependent on zip and unzip).
+- Then there is that wierd ^D being converted to \000 error reported
+      in 6/21/2003 email when Zip is outputted into a pipe on Windows ports.
+
+Old list:
+
+Main features still missing for next official version (last updated 2/11/2001):
+
+- what about the binary/text detection ? (seems done)
+- -b and -t options in help screen (covered in -h2)
+- findfirst/findnext and after that LSSTAT (performance!!)
+- use IS_EXEC from djgpp stat.h
+- use install in unix/Makefile instead of mkdir -p, look at install sh script.
+- #elif for those ports that can handle it.
+- what about zopen vs. fopen ?
+- Add zcreate or zfcreate for win32.
+- Assembler stuff in match.S (subexpressions)
+- zipping huge files (> 2G, unsigned 32bit) (done)
+- Testsuite for zip and unzip (John D. Mitchell)
+- make a version.c or version.h that includes all the compiler names
+- run utils with dmalloc().
+- what to do with zip -F and zip -FF (readzipfile2()) ? (done?)
+- profiling of the code
+- multi disk zip files (could be done)
+- zipfile modification tool (Greg)
+- Implement -- option (Thomas Klauser, wiz@danbala.tuwien.ac.at) (could be done)
+- don't add files with "Archive bit" or add files with "Archive bit"
+       (uwe.becher@metronet.de) (could be done with -AS and -AC)
+- 32 bit file attributes
+- generate output without having to seek at all (this seems to be stream output)
+- remove contractions from zip error messages, make them clearer (Steve)
+- display "[text]" for ascii files when not quiet (no -q) (Timo Salmi)
+- does zipnote accept names with version number?
+- for a WORM, zip should create temp file only when updating; new archives
+       should be created directly.
+- APPNOTE.TXT specifies "4) The entries in the central directory may
+      not necessarily be in the same order that files appear in the zipfile"
+      but readzipfile() relies on same order. (new read does not, and now
+      the read for -FF searches for central directory matches rather than
+      rely on the order)
+- on Mac, MPW C 3.3.1 requires #if (a || b)  ["#if a || b" taken as "#if a"]
+- on Unix, let -S be "include non-regular files without reading from them"
+       (as pkzip on Unix). This requires unzip support.
+- zip -l should do ebcdic->ascii translation on CMS and MVS
+- zip as subroutine (zdig/241) (some work done on this)
+- accept k and M in zipsplit
+- store / (part of file name) as ! in OS/2 (problem only with -E ?)
+- in addition to -l (LF to CR LF) and -ll (CR LF to LF) add -lc
+       (LF to CR LF but CR LF remains unchanged)
+
+Known bugs:
+
+- On VMS, zip fails reading some files with "byte record too large for
+       user's buffer". You must use the "-V" option for such files.
+       (many changes to VMS so may be fixed)
+
+- on MSDOS, zip386.exe does not like "zip -bc: foo ..."
+
+- on MSDOS, zip386.exe is sometimes much slower than zip.exe. This is
+       probably a problem with DJGPP (to be investigated).
+
+- on NT with C shell, zip should not do file name expansion again.
+
+- zip zipfile ... ignores existing zipfile if name does not have an extension
+      (except for the -A option, generally used on self-extracting files).
+      (archives should probably have extensions.  Things like archive.jar work)
+
+- For an sfx file without extension, "zip -A sfx" works but "zip sfx -A"
+       doesn't.  (because options were required first, but now both OK)
+
+- When storing files in a zipfile (-0), zip marks all of them as binary.
+
+- On VMS, some indexed files are not restored correctly after zip -V and unzip.
+       (This is now known to be a problem of UnZip. The workaround for Zip 2.2
+       and newer is to use PK-style VMS extra fields; this is now the default.
+       NOTE that UnZip 5.32 has been fixed [971019]!) (many VMS changes so
+       this may be fixed)
+
+- zip and unzip should use the same pattern matching rules, particularly
+       on MSDOS and OS/2. On OS/2, "zip foo *.*" should also match files
+       without extension.
+       Partially DONE (OS/2 "*.*" matches "*".)
+
+- there should be a way to avoid updating archive members (only addition
+       of new files allowed)
diff --git a/USexport.msg b/USexport.msg
new file mode 100644 (file)
index 0000000..068aa9f
--- /dev/null
@@ -0,0 +1,75 @@
+From roelofs (at) sonic.net  Tue Jun 17 08:26:55 2003
+Date: Tue, 17 Jun 2003 08:26:50 -0700
+Message-Id: <200306171526.h5HFQoaw014091 (at) bolt.sonic.net>
+From: Greg Roelofs <newt (at) pobox.com>
+Reply-To: Greg Roelofs <newt (at) pobox.com>
+To: crypt (at) bis.doc.gov, enc (at) ncsc.mil, web_site (at) bis.doc.gov
+Subject: TSU NOTIFICATION - Encryption (Info-ZIP zcrypt.zip)
+Cc: newt (at) pobox.com, zip-bugs (at) lists.wku.edu
+
+
+   SUBMISSION TYPE:       TSU
+   SUBMITTED BY:          Greg Roelofs
+   SUBMITTED FOR:         the Info-ZIP group (an informal, Internet-based
+                          collection of software developers with the contact
+                          address given in next item)
+   POINT OF CONTACT:      Zip-Bugs (at) lists.wku.edu
+   PHONE and/or FAX:      n/a
+   MANUFACTURER:          n/a
+   PRODUCT NAME/MODEL #:  zcrypt
+   ECCN:                  5D002
+
+   NOTIFICATION:
+
+       ftp://ftp.info-zip.org/pub/infozip/src/zcrypt.zip
+
+
+FURTHER COMMENTS:
+
+(1) This notice is being sent in order to ensure that we may legally
+    take advantage of the 6 June 2002 amendment to 740.13 regarding
+    "corresponding object code."  The encryption code in question is
+    unchanged since our original notification of 9 April 2000, appended
+    below and also reproduced within the above zcrypt.zip archive.
+    (Indeed, there has been no change to the core encryption/decryption
+    code in well over five years.)
+
+(2) The (larger) source archives for Zip, UnZip, MacZip, WiZ, and
+    potentially other packages, currently available in the same ftp
+    directory given above, also contain (or may contain) copies of
+    the same zcrypt source code.
+
+(3) ftp.info-zip.org currently points to a site in Germany, so techni-
+    cally it is not involved in "US export" in any direct way.  However,
+    we encourage other sites to "mirror" our software, and some of these
+    mirror sites may be US-based (and therefore involved in reexport of
+    the code in question).  In addition, some Info-ZIP members reside in
+    the US, and www.info-zip.org currently points to a site in Kentucky.
+
+
+ORIGINAL NOTIFICATION:
+
+From roelofs (at) sonic.net  Sun Apr  9 15:11:45 2000
+Date: Sun, 9 Apr 2000 15:11:27 -0700
+Message-Id: <200004092211.PAA20023 (at) sonic.net>
+From: Greg Roelofs <newt (at) pobox.com>
+To: crypt (at) bxa.doc.gov
+Subject: notice of export of unrestricted encryption source code
+Cc: newt (at) pobox.com, zip-bugs (at) lists.wku.edu
+
+The Info-ZIP group, an informal, Internet-based collection of software
+developers with contact address Zip-Bugs (at) lists.wku.edu, hereby notifies
+the US Bureau of Export Administration (BXA) of the posting of freely
+available encryption source code on the Internet under License Exception
+TSU, to commence later today at this location:
+
+       ftp://ftp.info-zip.org/pub/infozip/src/zcrypt.zip
+
+This notification is in accordance with section 740.13(e) of the amended
+Export Administration Regulations, as published in the 14 January 2000
+issue of the Federal Register.
+
+-- 
+Greg Roelofs            newt (at) pobox.com            http://pobox.com/~newt/
+Newtware, PNG Group, Info-ZIP, Philips Research, ...
+
diff --git a/WHATSNEW b/WHATSNEW
new file mode 100644 (file)
index 0000000..9e8d52b
--- /dev/null
+++ b/WHATSNEW
@@ -0,0 +1,333 @@
+What's New
+
+Last updated 1 July 2008
+
+This file is the full list of new features and major changes for Zip 3.0
+by beta release.  See the announcement file zip30.ann for a quick summary
+of all features and changes in Zip 3.0.  Also see the file README for
+release information, INSTALL for installation procedures, and the manual
+pages zip.txt, zipsplit.txt, zipcloak.txt, and zipnote.txt for how to use
+the new features.  The file CHANGES has all the day-to-day changes made
+during development.
+
+
+Below are some of the more significant items on the list for Zip 3.1
+(see ToDo for a more complete list):
+
+- AES encryption.
+- Extended attributes for Windows, Linux, and Mac OS X.
+- Support -d@ for deleting list of files.
+- Decide if -R, -i and -x should use external rather than internal patterns.
+- Though Unicode paths have been implemented and tested, Unicode comments
+  are not yet supported (except for comments on UTF-8 native systems which
+  are supported).
+- Verbose mode -v may still need work.
+- When pattern is directory add end / automatically.
+- Add C# example for Zip 3.0 (need to be converted to new DLLs) - original
+  C# example added with note.
+- Path Prefix maybe, so entries added to an archive can have a directory
+  path string prepended to each path.
+- UNC path support maybe.
+- Support for other languages maybe.
+- Send in your suggestions.
+- ...
+
+
+MAJOR CHANGES BY BETA VERSION
+-----------------------------
+
+New things in Zip 3.0 since Zip 3.0h:
+
+- Unicode fixes.
+- Test and fix various ports as needed.
+- Update Win32 resource to support more Windows ports.
+- Add djgpp 2.x makefile that includes bzip2.
+- Add Win32 version resource to Win32 executable.
+- Bug fixes.
+- Documentation updates.
+- Package for release.
+
+
+New things in Zip 3.0h
+
+- Allow -@ and -x to work together.
+- Unicode code cleanup.
+- Allow forcing use of UTF-8 storage in standard path and comment.
+- Update symbolic link checks.
+- Add support for storing 32-bit UIDs/GIDs using new extra field.
+  Backward compatible support for the old 16-bit UID/GID extra field
+  remains if Zip is compiled on an OS that has 16-bit UID/GID
+  storage.
+- Update VMS notes.
+- Directory scan using -AS (include only files with Windows archive
+  bit set) now ignores archive bit on directories to include all files
+  with archive bit set in all directories.  Also, to avoid empty
+  directories being created, -AS now does not store directory
+  entries.
+- Add Unix IBM support.
+- Change -W to -ws to free -W for later use.
+- Fix large file support for MinGW.
+- Fix large file support for bzip2.
+- Fix compile error in ZipCloak when UNICODE_SUPPORT is not enabled.
+- Fix Unicode bug in ZipCloak involving Unicode paths.
+- Long Unicode escapes changed from #Lxxxxxxxx to #Lxxxxxx to shorten
+  paths with escaped Unicode.
+- Bug fixes.
+
+
+New things in Zip 3.0g
+
+- Add split support to VB project for Zip64.
+- Disable reading of Unix FIFOs unless new -FI option used to avoid an
+  archiving operation stopping when it hits an active unfed FIFO.
+- The "[list]" wildcard expression (regular expression matching of any
+  character or range of characters in list) is now disabled on DOS and
+  Windows as it has caused confusion when filenames have [ and ] in
+  them.  The new -RE option reenables it.
+- Add negation to many display options such as -dc and -db.
+- Allow -FF to read and fix archives having local entries that appear
+  after central directory entries.
+- Bug fixes.
+
+
+New things in Zip 3.0f
+
+- bzip2 - The bzip2 compression method looks supported for at least
+  Windows, Unix, and VMS using the bzip2 library.  A new option, -Z cm,
+  selects the compression method.
+
+- Split archives - Can now use -s to create a split archive.  The
+  default is to update split files as the archive is being written,
+  which requires all splits to remain open until the archive is done.
+  This should be no problem when writing the archive to a hard drive,
+  for example, and this approach creates archives that should be
+  supported by all unzips that support splits.  Adding the -sp option
+  enables split pause mode that instead writes splits that do not
+  need updating and pauses Zip after each split.  This allows splits
+  to be written directly to removable media, however -sp archives
+  may not be as universally compatible.
+
+- Unicode support - Zip now stores Unicode paths that should be more
+  portable across character sets and languages.  The unzip must have
+  Unicode support enabled or the Unicode paths are ignored.  If
+  reading an archive with Unicode paths, unsupported characters are
+  replaced by #Uxxxx and #Lxxxxxxxx escapes in the file name.  Option
+  -UN controls how Unicode is handled.  Also, on systems where the
+  current character set is UTF-8, preliminary support for the new
+  General Purpose Bit Flag, bit 11, UTF-8 flag, that indicates UTF-8
+  is stored in the path and comment fields is implemented for paths.
+- Unicode on Win32 - On WIN32 systems that support the wide character
+  calls (mainly NT and later systems using NTFS), when UNICODE SUPPORT
+  is enabled Zip will now do directory scans using Unicode and convert
+  the Unicode paths to the local character set for storage in the standard
+  path field and store UTF-8 in the Unicode extra field.  This allows
+  directory scans to complete successfully regardless of the character
+  set the path is in.  On Win9x systems wide character scans are not
+  generally supported and Zip automatically uses a local character scan
+  instead.
+
+- Keep extra fields option - The default operation has been, and continues
+  to be, to read then strip old extra fields when reading entries from an
+  existing archive and then recreate the extra fields that Zip knows about.
+  Extra fields specific to each operating system get added by default also.
+  The new option -X- (negated -X) keeps any old extra fields, copying
+  them to the updated archive unchanged (unless Zip has updated them).
+  The unnegated -X still strips most all extra fields except Zip64,
+  Unicode, and UT time.
+
+- License - minor updates to the license.
+
+- Windows OEM - When compiled with WIN32_OEM (the default for WIN32),
+  Zip on WIN32 now stores OEM paths, which should be more compatible
+  with other zips and should fix some character set problems.
+- Windows Archive Bit support - On Windows can now use new -AS
+  (include if archive bit set) option to select files with the DOS
+  archive bit set and use new -AC (clear archive bits) option to clear
+  the archive bits on files after the archive has been created.
+  But -DF is probably better.
+
+- Difference mode - A new option -DF (--dif) creates an output archive
+  that includes only files changed or new since the input archive was
+  created.  Can use to create incremental backups.
+- File Sync - The new option -FS enables File Sync, a new mode that
+  synchronizes the entries in an archive with the files on the file
+  system, adding updating, and deleting entries as needed.  This
+  should create the same results as creating a new archive, but
+  since existing entries are copied, may be much faster.
+
+- Copy Mode - A new --out option allows creating a new archive with a
+  different name than the input archive, leaving the input archive
+  unchanged.  This allows updating split archives.  It also allows
+  for a new copy mode to select entries in one archive and copy them
+  directly to a new archive.
+- Empty archives - Now an empty archive is created when -i or -i@ is used
+  and the file patterns given do not match anything.  This has been
+  requested to support scripts.
+
+- Global dots - A new -dg option now displays progress dots as -dd does,
+  but instead of displaying them for each file, the dots track the total
+  bytes read for the archive.  The -dg option also works when -q is used
+  to disable most output, which allows for something like zip -qdgds 100m
+  to be used to not display specific files but display a dot every 100 MB
+  as a global status.
+- Date range - Can now use -t and -tt to set a date range
+- Fix options - Option -F redone and can recover files from an archive
+  with a mostly complete central directory more reliably, but no longer
+  can handle truncated archives.  Option -FF redone and now can salvage
+  files from slightly more damaged archives, including truncated archives.
+  In some ways -F is less powerful but more stable than it was and -FF will
+  be needed where -F in Zip 2.32 was enough.  One big change is -F and -FF
+  both now support split archives.
+- Console writing - Updates to how messages are written to the console have
+  been made including more consistent handling of line breaks.
+- Show Files options - Option -sf lists the files that would be operated
+  on.  This option can be used alone to list the files in an archive.
+  Also see options -su and -sU for showing Unicode paths.
+- UnZip Check - Now check that UnZip 6.00 or later is being used for
+  unzip if testing a Zip64 archive.  A new option -TT can be used to set
+  the unzip to use with the -T check.  Currently UnZip does not support
+  split archives so split archives can't be tested by UnZip.
+- Streaming - Directories are now handled better when streaming.
+- Case matching - Normally all matching against archive entries is case
+  sensitive, so *.BAR will not match or find foo.bar in an archive
+  when deleting, copying, or freshening entries (deleting and copying
+  only on VMS).  New option -ic (--ignore-case) enables case insensitive
+  matching.  Currently -ic is only implemented on WIN32 and VMS.
+
+- Delete date bug fixed - Bug when using -d to delete files while
+  using -t or -tt to select the files based on date is fixed
+- Large file encryption bug fixed - Fix for bug that very rarely
+  results in bad data being stored when deflating and encrypting
+  uncompressable data and resulting in CRC errors when extracting,
+  but the chance of error increases with file size (thanks to
+  WinZip for finding this bug).  See CHANGES for details.
+
+
+New things in Zip 3.0e
+
+- Bugs described in Debian patches 004 (unix configure script update) and
+  005 (large path bug) fixed
+- Various fixes
+- Add optional running stats and also end stats if not all files could
+  be read
+- Options -l and -ll now do quick binary check on first buffer and skip
+  formatting if first buffer has binary - still check at end to note
+  if formatting was done on file that was later determined to be binary,
+  but now potential file corruption is generally avoided
+- Main binary check now uses new algorithm that should also treat UTF-8 and
+  other similar encodings as text, allowing proper line end translation
+  for UTF-8 files
+- When output is not updatable by seeking back and Zip64 is enabled, output
+  is forced to Zip64 to avoid possible later need for Zip64 when not enabled
+- More work on splits, but still not usable
+- Fixes for djgpp
+- Add log file capability to save all errors and optionally messages
+- Add code to test for a Zip64 archive when compiled without Zip64 support
+- New VC6 projects for Win32 and WinDLL
+- Updates to extended help
+- Changes to force-zip64 option
+- ZE_BIG error now given also for files too big to read or write
+- Fix file delete bug
+- Update license
+- Update export documentation
+- Add VMS extended filename support
+- Add directory traversal improvements, some for Win32 ports and some for
+  all ports, that can result in a 10 times increase in speed in some cases
+
+
+New things in Zip 3.0d
+
+- Some large file crypt fixes
+- Some updates to support WiZ
+- On VMS, changed -V (/VMS) processing to truncate file at EOF, allowing
+  greater compatability with non-VMS systems.  New -VV (/VMS=ALL) option
+  saves all allocated blocks in a file.  (Previously, -V did neither.)
+- On VMS, pushed 2GB file size limit with -V out to 4GB
+- On VMS (recent, non-VAX), with SET PROCESS /PARSE = EXTEND,
+  command-line case is preserved.  This obviates quoting upper-case
+  options, like -V, when enabled
+- On VMS, fixed problems with mixed-case directory names.  Also changed
+  to keep ODS5 extended file name escape characters ("^") out of the
+  archived names in simple cases
+- Changes to the display dots
+- Option -W should now force wildcard matching to not cross directory
+  separators.  For example, a/b*r/d will match a/bar/d but not a/ba/r/d
+- Option -nw should turn off all wildcard matching so foo[bar] is matched
+  literally and [bar] is not considered a regular expression
+- Atheos port
+- Debugging of Unix and VMS large file ports.  Most features may work now
+  on these ports for large files.  Still need to fix 2 GB to 4 GB when not
+  compiled with large file support
+- On VMS, added an open callback function which (where supported) senses
+  the process RMS_DEFAULT values for file extend quantity (deq)
+  multi-block count (mbc), and multi-buffer count (mbf), and sets the
+  FAB/RAB parameters accordingly.  The default deq is now much larger
+  than before (16384 blocks, was none), and the default mbc is now 127
+  (up from 64), speeding creation of a large archive file.  The "-v"
+  option shows some of the activity.  On old VMS versions, RMS_DEFAULT
+  sensing (GETJPI) fails (silently, without "-v"), and no changes will
+  be made.  Even there, (DCL) SET RMS /EXTEND = <big> can help
+  performance.  RMS_DEFAULT values override built-in default values.
+
+
+New things in Zip 3.0c
+
+- Converted to using 64-bit file environment instead of transitional functions
+  like fseeko64 for ports that support it
+- Added "--" argument to read all following arguments as paths
+- Second help page added
+- Binary detection adjusted from 20% binary is binary to 2%
+- When -R and -i used together now -i has precedence over -R
+- Archive names with spaces can now be tested on MSDOS and Win32
+
+
+New things in Zip 3.0b
+
+- Fixed ifdefs so can test base code by compiling with NO_LARGE_FILE_SUPPORT, then
+  compiling with NO_ZIP64_SUPPORT to test 64-bit file calls (if port enables) but
+  otherwise use base code, and compiling normally to enable Zip64 code
+- Unix Zip64 fixes - should now be able to create and read large files
+- WinDLL changes to support Zip64.  Zip 3.0 dll named Zip32z64.dll
+- New VB example to show use of Zip32z64.dll
+- New options -sc (show final command line and exit) and -sd (show each
+  step zip is doing, a little different than verbose which is still there) added
+  to help debug but both or at least -sd might go away in the release
+- Some minor posted bugs fixed (see Changes)
+
+
+New things in Zip 3.0a
+
+- Initial Zip64 support allowing large files and large numbers of files
+- New command line processor
+- Other changes, see file Changes
+
+
+Note:  Zip 2.4 was never released.  That code was the start of the Zip 3.0
+effort above.
+
+
+New things in Zip 2.3
+
+- IBM OS/390 port (Unix like, but EBCDIC) by Paul von Behren
+- Apple Macintosh (MACOS) port by Dirk Haase
+- Theos port by Jean-Michel Dubois
+- Multibyte characterset support by Yoshioka Tsuneo
+- Support for ISO 8601 date format with -t and -tt options
+- Info-ZIP license
+
+
+New things in Zip 2.2
+
+- BEOS port by Chris Herborth
+- QDOS port by Jonathan Hudson
+- TANDEM port by Dave Smith
+- WINDLL port (16-bit Win 3.x and 32-bit WinNT/Win95) by Mike White
+- SYSV packages support by John Bush
+- zip -P SeCrEt encrypts entries in the zip file with password SeCrEt
+  (WARNING: THIS IS INSECURE, use at your own risk)
+- zip -R recurses into subdirectories of current dir like "PKZIP -rP"
+- zip -x@exclude.lst excludes files specified in the file exclude.lst
+- zip -i@include.lst includes files specified in the file include.lst
+- zip -@ only handles one filename per line, but supports whitespace in names
+- zip -t mmddyyyy, 4 digit year number for uniqueness of years beyond 2000
+- zip -tt mmddyyyy only includes files before a specified date
diff --git a/WHERE b/WHERE
new file mode 100644 (file)
index 0000000..94a0d55
--- /dev/null
+++ b/WHERE
@@ -0,0 +1,261 @@
+__________________________________________________________________________
+
+   This is the Info-ZIP file ``WHERE,'' last updated on 1 March 2005.
+__________________________________________________________________________
+
+   This file is out of date.  We plan to update the structure of the ftp
+   site shortly and should be updating this file as soon as that's done.
+
+   The latest version of this file can be found online at:
+
+           ftp://ftp.info-zip.org/pub/infozip/doc/WHERE
+
+   Note that some ftp sites may not yet have the latest versions of Zip
+   and UnZip when you read this.  The latest versions always appear in
+   ftp://ftp.info-zip.org/pub/infozip/ (and subdirectories thereof) first,
+   except for encryption binaries, which always appear in
+   ftp://ftp.icce.rug.nl/infozip/ (and subdirectories) first.
+
+   IF YOU FIND AN ERROR:  please let us know!  We don't have time to
+   check each and every site personally (or even collectively), so any
+   number of the sites listed below may have moved or disappeared en-
+   tirely.  E-mail to Zip-Bugs@lists.wku.edu and we'll update this file.
+__________________________________________________________________________
+
+
+Info-ZIP's home WWW site is listed on Yahoo and is at:
+
+   ftp://ftp.info-zip.org/pub/infozip/Info-ZIP.html  (master version)
+   http://ftp.info-zip.org/pub/infozip/              (master version)
+   http://www.info-zip.org/
+
+Note that the old sites at http://www.cdrom.com/pub/infozip/ and
+http://www.freesoftware.com/pub/infozip are PERMANENTLY BROKEN.  They
+cannot be updated or removed, apparently.
+
+The Zip and UnZip pages have links to most known mirror sites carrying our
+source and/or binary distributions, and they generally are more up-to-date
+and have better information than what you are reading:
+
+   ftp://ftp.info-zip.org/pub/infozip/Zip.html
+   ftp://ftp.info-zip.org/pub/infozip/UnZip.html
+
+The related zlib package by Info-ZIP's Jean-loup Gailly and Mark Adler is at:
+
+   http://www.zlib.net/
+
+Source-code archives for Info-ZIP's portable Zip, UnZip, and related
+utilities:
+
+   zip231.zip        Zip 2.31 (deflation; includes zipnote/zipsplit/zipcloak)
+   zip231.tar.Z      ditto, compress'd tar format
+
+   zip11.zip         Zip 1.1 (shrinking, implosion; compatible w. PKUNZIP 1.1)
+   zip11.tar.Z       ditto, compress'd tar format
+
+   unzip552.zip      UnZip 5.52 (all methods[*]; unzip/funzip/unzipsfx/zipgrep)
+   unzip552.tar.gz   ditto, gzip'd tar format
+   unzip552.tar.Z    ditto, compress'd tar format
+
+   unred552.zip      UnZip 5.52 add-on, contains copyrighted unreduce support
+
+   zcrypt29.zip      encryption support for Zip 2.3[**]
+   zcrypt10.zip      encryption support for Zip 1.1
+
+   MacZip106src.zip  contains all the GUI stuff and the project files to build
+                     the MacZip main-app.  To build MacZip successfully, both
+                     the Zip 2.31 and UnZip 5.52 sources are required, too.
+
+   wiz502.zip        WiZ 5.02, Windows 9x/NT GUI front-end for Info-ZIP DLLs
+   wiz502+dlls.zip   WiZ 5.02, Windows 9x/NT GUI front-end plus DLL sources
+
+[*] Unreducing is disabled by default, but is available as add-on.
+    As of July 2004, Unisys's LZW patent was expired worldwide, and
+    unshrinking is turned on by default since the release of UnZip 5.52.
+    See UnZip's INSTALL file for details.
+
+[**] As of January 2000, US export regulations were amended to allow export
+     of free encryption source code from the US.  As of June 2002, these
+     regulations were further relaxed to allow export of encryption binaries
+     associated with free encryption source code.  The Zip 2.31, UnZip 5.52
+     and Wiz 5.02 archives now include full crypto source code.  As of the
+     Zip 2.31 release, all official binaries include encryption support; the
+     former "zcr" archives ceased to exist.
+     (Note that restrictions may still exist in other countries, of course.)
+
+Executables archives (and related files) for Info-ZIP's software; not all
+of these will be immediately available due to lack of access to appropriate
+systems on the part of Info-ZIP members.
+
+   zip231x.zip       MSDOS executables and docs
+   zip231x1.zip      OS/2 1.x (16-bit) executables and docs
+   zip231x2.zip      OS/2 2/3/4.x (32-bit) executables and docs
+   zip231xA.zip      Amiga executables and docs
+   zip231xB.zip      BeOS executables and docs
+   zip231xC.zip      VM/CMS executable and docs
+   zip231xK.zip      Tandem NSK executables and docs
+   zip231xM.xmit     MVS classic executable
+   zip231xM-docs.zip MVS classic port, docs only
+   zip231dN.zip      WinNT/Win9x (Intel) DLL, header files, docs
+   zip231xN.zip      WinNT/Win9x (Intel) executables and docs
+   zip231xN-axp.zip  WinNT (Alpha AXP) executables and docs
+   zip231xN-mip.zip  WinNT (MIPS R4000) executables and docs
+   zip231xN-ppc.zip  WinNT (PowerPC) executables and docs
+   zip231xO.zip      IBM OS/390 Open Edition binaries and docs
+   zip231xQ.zip      SMS/QDOS executables and docs
+   zip231xR.zip      Acorn RISC OS executables and docs
+   zip231xT.zip      Atari TOS executables and docs
+   zip231-vms-axp-obj.zip
+                     VMS (Alpha AXP) object libs, link procedure and docs
+   zip231-vms-axp-exe.zip
+                     VMS (Alpha AXP) executables for VMS 6.1 or later and docs
+   zip231-vms-vax-decc-obj.zip
+                     VMS (VAX) object libs (new DEC C), link procedure and docs
+   zip231-vms-vax-decc-exe.zip
+                     VMS (VAX) executables (DEC C) for VMS 6.1 or later; docs
+   zip231-vms-vax-vaxc-obj.zip
+                     VMS (VAX) object libs (old VAX C), link procedure and docs
+   zip231x.hqx       Macintosh BinHex'd executables and docs
+
+   unz552x.exe       MSDOS self-extracting executable (16-bit unzip, ..., docs)
+   unz552x3.exe      MSDOS self-extracting executable (16-, 32-bit unzip, docs)
+   unz552x1.exe      OS/2 1.x (16-bit) self-extracting executables and docs
+   unz552x2.exe      OS/2 2/3/4.x (32-bit) self-extracting executables and docs
+   unz552d2.zip      OS/2 2/3/4.x (32-bit) DLL, header file, demo exe and docs
+   unz552xA.ami      Amiga self-extracting executables and docs
+   unz552xA.lha      Amiga executables and docs, LHa archive
+   unz552xB.sfx      BeOS self-extracting executables and docs
+   unz552xB.tar.gz   BeOS executables and docs, gzip'd tar archive
+   unz552xC.mod      VM/CMS executable module in "packed" format
+   unz552xC-docs.zip VM/CMS docs, only
+   unz552xF.zip      FlexOS executable and docs
+   unz552xK.zip      Tandem NSK executable and docs
+   unz552xM.xmit     MVS classic executable
+   unz552xM-docs.zip MVS classic port, docs only
+   unz552dN.zip      NT4/W2K/XP/2K3/W9x (32-bit Intel) DLL, header files, docs
+   unz552xN.exe      NT/2K/XP/2K3/W9x self-extracting i386 executables and docs
+   unz552xN-axp.exe  WinNT (Alpha AXP) self-extracting executables and docs
+   unz552xN-mip.exe  WinNT (MIPS R4000) self-extracting executables and docs
+   unz552xN-ppc.exe  WinNT (PowerPC) self-extracting executables and docs
+   unz552xQ.sfx      SMS/QDOS self-extracting executables and docs
+   unz552xO.tar.Z    IBM OS/390 Open edition (Unix-like), exes and docs
+   unz552xR.exe      Acorn RISC OS self-extracting executables and docs
+   unz552xR.spk      Acorn RISC OS Spark'd executables and docs
+   unz552xT.tos      Atari TOS self-extracting executables and docs
+   unz552x-vms-axp-obj.bck    VMS backup saveset,
+                     contains UnZip (Alpha) obj libs, link procedure, docs
+   unz552x-vms-axp-obj.exe    VMS (Alpha AXP) SFX archive (statically linked),
+                     contains UnZip (Alpha) obj libs, link procedure, docs
+   unz552x-vms-axp-exe.exe    VMS (Alpha AXP) SFX archive (dynamically linked),
+                     contains UnZip (Alpha AXP, DEC C) executables and docs,
+                     smaller than object archive, but requires VMS 6.1
+   unz552x-vms-vax-decc-obj.bck   VMS backup saveset,
+                     contains UnZip (new DEC C) obj libs, link procedure, docs
+   unz552x-vms-vax-decc-obj.exe   VMS (VAX) SFX archive (statically linked),
+                     contains UnZip (new DEC C) obj libs, link procedure, docs
+   unz552x-vms-vax-decc-exe.exe   VMS (VAX) SFX archive (dynamically linked),
+                     contains UnZip (new DEC C) executables and docs,
+                     smaller than object archive, but requires VMS 6.1
+   unz552x-vms-vax-vaxc-obj.bck   VMS backup saveset,
+                     contains UnZip (old VAX C) obj libs, link procedure, docs
+   unz552x-vms-vax-vaxc-obj.exe   VMS (VAX) SFX archive (statically linked),
+                     contains UnZip (old VAX C) obj libs, link procedure, docs
+   unz552x.hqx       Macintosh BinHex'd executables and docs for unzip
+  (unz552x.tar.{Z,gz}  Unix exes/docs for Solaris 2.x, SCO Unix, Linux, etc.,
+                     depending on directory/location; generally only provided
+                     in cases where the OS does *not* ship with a bundled C
+                     compiler)
+
+   MacZip106nc.hqx   Macintosh combined Zip&UnZip application with GUI,
+                     executables and docs (no encryption)
+   MacZip106c.hqx    Macintosh combined Zip&UnZip application with GUI,
+                     executables and docs (with encryption)
+
+   wiz502xN.exe      WiZ 5.02 32-bit (Win9x/NT/2K/XP/2K3) app+docs (self-extr.)
+
+   UnzpHist.zip      complete changes-history of UnZip and its precursors
+   ZipHist.zip       complete changes-history of Zip
+
+ftp/web sites for the US-exportable sources and executables:
+
+   NOTE:  Look for the Info-ZIP file names given above (not PKWARE or third-
+   party stuff) in the following locations.  Some sites like to use slightly
+   different names, such as zip-2.31.tar.gz instead of zip231.tar.Z.
+
+   ftp://ftp.info-zip.org/pub/infozip/                 [THE INFO-ZIP HOME SITE]
+   ftp://sunsite.doc.ic.ac.uk/packages/zip/    [MIRRORS THE INFO-ZIP HOME SITE]
+   ftp://unix.hensa.ac.uk/mirrors/uunet/pub/archiving/zip/
+
+   ftp://ftp.cmdl.noaa.gov/aerosol/doc/archiver/{all,dos,os2,mac,vax_alpha}/
+   ftp://garbo.uwasa.fi/pc/arcers/                    [AND OTHER GARBO MIRRORS]
+   ftp://garbo.uwasa.fi/unix/arcers/                  [AND OTHER GARBO MIRRORS]
+   ftp://ftp.elf.stuba.sk/pub/pc/pack/                [AND OTHER STUBA MIRRORS]
+   ftp://ftp-os2.cdrom.com/pub/os2/archiver/
+   ftp://ftp-os2.nmsu.edu/os2/archiver/
+   ftp://ftp.informatik.tu-muenchen.de/pub/comp/os/os2/archiver/
+   ftp://sumex-aim.stanford.edu/info-mac/cmp/
+   ftp://ftp.wustl.edu/pub/aminet/util/arc/          [AND OTHER AMINET MIRRORS]
+   ftp://atari.archive.umich.edu/pub/Archivers/       [AND OTHER UMICH MIRRORS]
+   http://www.umich.edu/~archive/atari/Archivers/
+   ftp://jake.educom.com.au/pub/infozip/acorn/                  [Acorn RISC OS]
+   http://www.sitec.net/maczip/                                   [MacZip port]
+
+ftp/web sites for the encryption and decryption sources and/or executables:
+
+   Outside the US:
+      ftp://ftp.info-zip.org/pub/infozip/   [THE INFO-ZIP HOME SITE]
+      ftp://ftp.icce.rug.nl/infozip/        [THE INFO-ZIP ENCRYPTION HOME SITE]
+      ftp://ftp.elf.stuba.sk/pub/pc/pack/
+      ftp://garbo.uwasa.fi/pc/arcers/
+      ftp://ftp.inria.fr/system/arch-compr/
+      ftp://ftp.leo.org/pub/comp/os/os2/leo/archiver/
+        (mail server at ftp-mailer@ftp.leo.org)
+
+      ftp://ftp.win.tue.nl/pub/compression/zip/
+      ftp://ftp.uni-erlangen.de/pub/pc/msdos/arc-utils/zip/
+
+
+The primary distribution site for the MacZip port can be found at:
+
+   http://www.sitec.net/maczip/
+
+ftp sites for VMS-format Zip and UnZip packages (sources, object files and
+executables, no encryption/decryption--see also "Mail servers" section below):
+
+   ftp.spc.edu [192.107.46.27] and ftp.wku.edu:
+
+   [.MACRO32]AAAREADME.TXT
+   [.MACRO32.SAVESETS]UNZIP.BCK  or  UNZIP.ZIP  (if already have older version)
+   [.MACRO32.SAVESETS]ZIP.ZIP
+
+To find other ftp/web sites:
+
+   The "archie" ftp database utility can be used to find an ftp site near
+   you (although the command-line versions always seem to find old ver-
+   sions...the `FTPsearch' server at http://ftpsearch.ntnu.no/ftpsearch
+   --formerly `Archie 95'--is quite up-to-date, however).  Or check a stan-
+   dard WWW search engine like AltaVista (http://www.altavista.digital.com/)
+   or Yahoo (http://www.yahoo.com/).  If you don't know how to use these,
+   DON'T ASK US--read the web sites' help pages or check the Usenet groups
+   news.announce.newusers or news.answers or some such, or ask your system
+   administrator.
+
+Mail servers:
+
+   To get the encryption sources by e-mail, send the following commands
+   to ftp-mailer@informatik.tu-muenchen.de:
+
+      get /pub/comp/os/os2/archiver/zcrypt29.zip
+      quit
+
+   To get the VMS Zip/UnZip package by e-mail, send the following
+   commands in the body of a mail message to fileserv@wku.edu (the
+   "HELP" command is also accepted):
+
+      SEND FILESERV_TOOLS
+      SEND UNZIP
+      SEND ZIP
+
+   To get Atari executables by e-mail, send a message to
+   atari@atari.archive.umich.edu for information about the mail server.
+__________________________________________________________________________
diff --git a/acorn/GMakefile b/acorn/GMakefile
new file mode 100644 (file)
index 0000000..01842c4
--- /dev/null
@@ -0,0 +1,130 @@
+# Makefile for Zip, ZipNote, ZipCloak and ZipSplit
+
+# add -g to CC to debug
+# add -d to BIND to debug
+CC   = gcc -mlibscl
+BIND = $(CC)
+AS   = $(CC) -c
+ASM  = AS
+SQUEEZE = squeeze -v
+E    =
+
+# flags
+#   CFLAGS    flags for C compile
+#   LFLAGS1   flags after output file spec, before obj file list
+#   LFLAGS2   flags after obj file list (libraries, etc)
+#
+LIB      =
+CFLAGS   = -O2 -mthrowback -DASMV
+ASMFLAGS = -throwback -objasm -upper
+LFLAGS1  = 
+LFLAGS2  = $(LIB)
+
+# Uncomment the following line to enable support for Unix
+# Extra Field (Timezone)
+#CFLAGS  = $(CFLAGS) -DUSE_EF_UT_TIME
+
+# object file lists
+OBJZ = o.zip o.zipfile o.zipup o.fileio o.util o.globals o.crc32 \
+       o.crypt o.ttyio o.riscos o.acornzip o.swiven
+
+OBJI = o.deflate o.trees
+OBJA = o.match o.sendbits
+OBJU = o.zipfile_ o.fileio_ o.util_ o.globals o.riscos o.acornzip_ o.swiven
+OBJN = o.zipnote  $(OBJU)
+OBJC = o.zipcloak $(OBJU) o.crc32_ o.crypt_ o.ttyio
+OBJS = o.zipsplit $(OBJU)
+
+ZIP_H = h.zip h.ziperr h.tailor acorn.h.osdep acorn.h.riscos acorn.h.swiven
+
+all:      zip zipnote zipsplit zipcloak
+
+install:  %.zip %.zipnote %.zipsplit %.zipcloak %.acorn.zipsfx \
+          zip zipnote zipsplit zipcloak acorn.zipsfx
+       $(SQUEEZE) zip %.zip
+       $(SQUEEZE) zipnote %.zipnote
+       $(SQUEEZE) zipsplit %.zipsplit
+       $(SQUEEZE) zipcloak %.zipcloak
+       copy acorn.zipsfx %.zipsfx ~CVF
+
+# rules for zip, zipnote, zipcloak and zipsplit
+
+o.api:         c.api
+       $(CC) $(CFLAGS) -c c.api -o o.api
+o.crc32:       c.crc32 $(ZIP_H) h.crc32
+       $(CC) $(CFLAGS) -c c.crc32 -o o.crc32
+o.crypt:       c.crypt $(ZIP_H) h.crypt h.crc32 h.ttyio
+       $(CC) $(CFLAGS) -c c.crypt -o o.crypt
+o.deflate:     c.deflate $(ZIP_H)
+       $(CC) $(CFLAGS) -c c.deflate -o o.deflate
+o.fileio:      c.fileio $(ZIP_H) h.crc32
+       $(CC) $(CFLAGS) -c c.fileio -o o.fileio
+o.globals:     c.globals $(ZIP_H)
+       $(CC) $(CFLAGS) -c c.globals -o o.globals
+o.mktime:      c.mktime
+       $(CC) $(CFLAGS) -c c.mktime -o o.mktime
+o.trees:       c.trees $(ZIP_H)
+       $(CC) $(CFLAGS) -c c.trees -o o.trees
+o.ttyio:       c.ttyio $(ZIP_H) h.crypt
+       $(CC) $(CFLAGS) -c c.ttyio -o o.ttyio
+o.util:                c.util $(ZIP_H)
+       $(CC) $(CFLAGS) -c c.util -o o.util
+o.zip:         c.zip $(ZIP_H) h.crc32 h.crypt h.revision h.ttyio
+       $(CC) $(CFLAGS) -c c.zip -o o.zip
+o.zipcloak:    c.zipcloak $(ZIP_H) h.crc32 h.crypt h.revision h.ttyio
+       $(CC) $(CFLAGS) -c c.zipcloak -o o.zipcloak
+o.zipfile:     c.zipfile $(ZIP_H) h.crc32
+       $(CC) $(CFLAGS) -c c.zipfile -o o.zipfile
+o.zipnote:     c.zipnote $(ZIP_H) h.revision
+       $(CC) $(CFLAGS) -c c.zipnote -o o.zipnote
+o.zipsplit:    c.zipsplit $(ZIP_H) h.revision
+       $(CC) $(CFLAGS) -c c.zipsplit -o o.zipsplit
+o.zipup:       c.zipup $(ZIP_H) h.crc32 h.crypt h.revision
+       $(CC) $(CFLAGS) -c c.zipup -o o.zipup
+
+o.crc32_: c.crc32 $(ZIP_H) h.crc32
+       $(CC) $(CFLAGS) -DUTIL -c c.crc32 -o o.crc32_
+o.crypt_: c.crypt $(ZIP_H) h.crypt h.crc32 h.ttyio
+       $(CC) $(CFLAGS) -DUTIL -c c.crypt -o o.crypt_
+o.util_: c.util $(ZIP_H)
+       $(CC) $(CFLAGS) -DUTIL -c c.util -o o.util_
+o.fileio_: c.fileio $(ZIP_H) h.crc32
+       $(CC) $(CFLAGS) -DUTIL -c c.fileio -o o.fileio_
+o.zipfile_: c.zipfile $(ZIP_H) h.crc32
+       $(CC) $(CFLAGS) -DUTIL -c c.zipfile -o o.zipfile_
+o.acornzip_: acorn.c.acornzip $(ZIP_H)
+       $(CC) $(CFLAGS) -I@ -DUTIL -c acorn.c.acornzip -o o.acornzip_
+
+o.riscos: acorn.c.riscos acorn.h.riscos $(ZIP_H)
+       $(CC) $(CFLAGS) -I@ -c acorn.c.riscos -o o.riscos
+
+o.acornzip: acorn.c.acornzip $(ZIP_H)
+       $(CC) $(CFLAGS) -I@ -c acorn.c.acornzip -o o.acornzip
+
+o.match: acorn.s.match
+       $(ASM) $(ASMFLAGS) -I@ acorn.s.match -o o.match
+
+o.sendbits: acorn.s.sendbits
+       $(ASM) $(ASMFLAGS) -I@ acorn.s.sendbits -o o.sendbits
+
+o.swiven: acorn.s.swiven
+       $(ASM) $(ASMFLAGS) -I@ acorn.s.swiven -o o.swiven
+
+zip:   $(OBJZ) $(OBJI) $(OBJA)
+       $(BIND) -o zip$(E) $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote:  $(OBJN)
+       $(BIND) -o zipnote$(E) $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak: $(OBJC)
+       $(BIND) -o zipcloak$(E) $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit: $(OBJS)
+       $(BIND) -o zipsplit$(E) $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+clean: 
+       remove zip
+       remove zipcloak 
+       remove zipsplit
+       remove zipnote
+       create o.!fake! 0
+       wipe o.* ~cf
+
+# end of Makefile
diff --git a/acorn/ReadMe b/acorn/ReadMe
new file mode 100644 (file)
index 0000000..41c37a5
--- /dev/null
@@ -0,0 +1,85 @@
+Acorn-specific compile instructions
+-----------------------------------
+
+Use the "RunMe1st" file (it is an Obey file) to convert all the files from
+"filename/[chs]" to "[chs].filename" (so that zip could be easily compiled
+under RISC OS). It will also set the correct makefile.
+
+To compile just set the CSD to the main zip directory and run 'amu'.
+
+Currently only the Acorn C V5 compiler has been tested but probably also
+Acorn C V4 and the Acorn Assembler V2 will be able to compile zip.
+
+The default makefile is configured without the support for the
+Extended Timestamp Extra Field. If you wan to enable it you have to
+add "-DUSE_EF_UT_TIME" to CFLAGS (see makefile). Without the Extended
+Timestamp Field support, zipfiles created by zip are identical to the
+zipfiles created by SparkFS. However, the Extended Timestamp Field can
+be useful if you are going to unzip your zipfiles on a non-RISC OS machine
+since the correct time stamp will be preserved across different timezones.
+Note that in this case, both the SparkFS Extra Field and the Extended
+Timestamp Extra Field will be used, so the zipfiles will still be fully
+compatible with SparkFS and with the RISC OS version of unzip.
+
+The executables-only distributions will be compiled without the support for
+the Extended Timestamp Extra Field. If you need it but you can't compile zip
+yourself, you can contact the authors at the Info-ZIP address who will do it
+for you.
+
+
+Acorn-specific usage instructions
+---------------------------------
+
+An extra option ('I') has been added to the Acorn port: if it is specified
+zip will not consider Image files (eg. DOS partitions or Spark archives when
+SparkFS is loaded) as directories but will store them as single files. This
+means that if you have, say, SparkFS loaded, zipping a Spark archive will
+result in a zipfile containing a directory (and its content) while using the
+'I' option will result in a zipfile containing a Spark archive. Obviously
+this second case will also be obtained (without the 'I' option) if SparkFS
+isn't loaded.
+
+When adding files to a zipfile; to maintain FileCore compliance, all
+files named "file/ext" will be added to the archive as "file.ext".
+This presents no problem if you wish to use unzip to extract them on any
+other machine, as the files are correctly named. This also presents no
+problem if you use unzip for RISC OS, as the files are converted back to
+"file/ext" format. The only problem appears when you use SparkFS to
+decompress the files, as a file called "file.ext" will be extracted as
+"file_ext", not what it was added as. You must be careful about this.
+
+Case Specific. Depending on how you type the command, files will be added
+exactly as named; in this example:
+*zip new/zip newfile
+*zip new/zip NewFile
+*zip new/zip NEWFILE
+will create an archive containing 3 copies of the same Risc OS file 'newfile'
+called 'newfile', 'NewFile' and 'NEWFILE'. Please be careful.
+
+The Acorn port conserves file attributes, including filetype, so if you
+zip on an Acorn, and unzip on another Acorn, filetypes will be maintained
+precisely as if you used uncompressed files. If you de-archive on another
+machine (PC, Mac, Unix etc..), filetypes will be ignored, but the files
+will be identical despite this. This feature is fully compatible with
+SparkFS, so zipfiles created by zip will be correctly uncompressed (including
+filetype, etc.) by SparkFS.
+
+An additional feature went into this port to cope better with C-code
+and extensions. This allows the acorn files "c.foo" to be added to the
+archive as "foo/c", eventually appearing in the archive as "foo.c", allowing
+for better handling of C or C++ code. Example:
+*Set Zip$Exts "dir1:dir2:dir3"
+*zip new/zip dir1.file
+*zip new/zip dir2.help
+*zip new/zip dir3.textfile
+Creates a zipfile new/zip, with entries file.dir1, help.dir2, textfile.dir3.
+The usual settings for Zip$Exts are "h:o:s:c", allowing C code to be added
+to the archive in standard form.
+
+A final note about the Acorn port regards the use of the 'n' option: this is
+used to specify a list of suffixes that will not be compressed (eg. .ZIP,
+since it is already a compressed file). Since RISC OS uses filetypes instead
+of suffixes, this list of suffixes is actually considered as a list of
+filetypes (3 hex digit format). By default, zip doesn't compress filetypes
+DDC (Archive, Spark or Zip), D96 (CFS files) and 68E (PackDir).
+
diff --git a/acorn/ReadMe.GMakefile b/acorn/ReadMe.GMakefile
new file mode 100644 (file)
index 0000000..8762cdb
--- /dev/null
@@ -0,0 +1,16 @@
+GMakefile is for use with Acorn RISC OS and the forthcoming
+post-Acorn RISC OS for the compilation of both the current release and
+development versions of zip.
+
+It is recommended that you use gcc 2.95.4 or higher and you will need a 
+suitable 'make' utility. Both are available from 
+<URL:http://hard-mofo.dsvr.net/gcc/>.
+
+You will need the files gcc.zip and cc1.zip for the C compiler with the
+documentation available in the gccdoc.zip archive. GNU make can be 
+found in the utils.zip archive, although most versions of 'make' should be
+fine.
+
+When using gcc, check RunMe1st for two lines which need uncommenting.
+
+
diff --git a/acorn/RunMe1st b/acorn/RunMe1st
new file mode 100644 (file)
index 0000000..a330adb
--- /dev/null
@@ -0,0 +1,23 @@
+| This Obey file prepares the zip port for a Desktop C re-compile.
+| Run it and it will copy all the needed files into the correct
+| place.
+
+| Set the correct type of 'srcrename' so that the only requirement
+| for the user is to set 'RunMe1st' to Obey
+SetType <Obey$Dir>.srcrename FF8
+
+| Run 'srcrename' on the main zip directory with recursion enabled
+/<Obey$Dir>.srcrename -r -e c:h:s:o <Obey$Dir>.^
+
+| Create the 'o' directory
+CDir <Obey$Dir>.^.o
+
+| Put the Makefile in its correct place and set the correct filetype
+Copy <Obey$Dir>.makefile <Obey$Dir>.^.makefile ~C ~V F
+
+| Uncomment the following lines if you're using gcc
+|| Put the Makefile in its correct place and set the correct filetype
+|Copy <Obey$Dir>.GMakefile <Obey$Dir>.^.makefile ~C~VF
+
+SetType <Obey$Dir>.^.makefile FE1
+SetType <Obey$Dir>.zipsfx Obey
diff --git a/acorn/acornzip.c b/acorn/acornzip.c
new file mode 100644 (file)
index 0000000..40debc0
--- /dev/null
@@ -0,0 +1,592 @@
+/*
+  Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#include <stdlib.h>
+#include <string.h>
+#include "zip.h"
+
+#ifndef UTIL
+
+#define PAD 0
+#define PATH_END '/'
+
+
+local int wild_recurse(char *whole, char *wildtail);
+local int uxtime2acornftime(unsigned *pexadr, unsigned *pldadr, time_t ut);
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+char *readd(DIR *d)
+/* Return a pointer to the next name in the directory stream d, or NULL if
+   no more entries or an error occurs. */
+{
+   struct dirent *e;
+
+   e = readdir(d);
+   return (e == NULL ? (char *) NULL : e->d_name);
+}
+
+/* What we have here is a mostly-generic routine using opend()/readd() and */
+/* isshexp()/MATCH() to find all the files matching a multi-part filespec  */
+/* using the portable pattern syntax.  It shouldn't take too much fiddling */
+/* to make it usable for any other platform that has directory hierarchies */
+/* but no shell-level pattern matching.  It works for patterns throughout  */
+/* the pathname, such as "foo:*.?/source/x*.[ch]".                         */
+
+/* whole is a pathname with wildcards, wildtail points somewhere in the  */
+/* middle of it.  All wildcards to be expanded must come AFTER wildtail. */
+
+local int wild_recurse(whole, wildtail) char *whole; char *wildtail;
+{
+    DIR *dir;
+    char *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
+    ush newlen, amatch = 0;
+    struct stat statb;
+    int disk_not_mounted=0;
+    int e = ZE_MISS;
+
+    if (!isshexp(wildtail)) {
+        if (stat(whole,&statb)==0 && (statb.st_mode & S_IREAD)!=0) {
+            return procname(whole, 0);
+        } else
+            return ZE_MISS;                     /* woops, no wildcards! */
+    }
+
+    /* back up thru path components till existing dir found */
+    do {
+        name = wildtail + strlen(wildtail) - 1;
+        for (;;)
+            if (name-- <= wildtail || *name == '.') {
+                subwild = name + 1;
+                plug2 = *subwild;
+                *subwild = 0;
+                break;
+            }
+        if (glue)
+            *glue = plug;
+        glue = subwild;
+        plug = plug2;
+        dir = opendir(whole);
+    } while (!dir && !disk_not_mounted && subwild > wildtail);
+    wildtail = subwild;                 /* skip past non-wild components */
+
+    if ((subwild = strchr(wildtail + 1, '.')) != NULL) {
+        /* this "+ 1" dodges the   ^^^ hole left by *glue == 0 */
+        *(subwild++) = 0;               /* wildtail = one component pattern */
+        newlen = strlen(whole) + strlen(subwild) + 32;
+    } else
+        newlen = strlen(whole) + 31;
+    if (!dir || !(newwhole = malloc(newlen))) {
+        if (glue)
+            *glue = plug;
+        e = dir ? ZE_MEM : ZE_MISS;
+        goto ohforgetit;
+    }
+    strcpy(newwhole, whole);
+    newlen = strlen(newwhole);
+    if (glue)
+        *glue = plug;                           /* repair damage to whole */
+    if (!isshexp(wildtail)) {
+        e = ZE_MISS;                            /* non-wild name not found */
+        goto ohforgetit;
+    }
+
+    while (name = readd(dir)) {
+        if (MATCH(wildtail, name, 0)) {
+            strcpy(newwhole + newlen, name);
+            if (subwild) {
+                name = newwhole + strlen(newwhole);
+                *(name++) = '.';
+                strcpy(name, subwild);
+                e = wild_recurse(newwhole, name);
+            } else
+                e = procname(newwhole, 0);
+            newwhole[newlen] = 0;
+            if (e == ZE_OK)
+                amatch = 1;
+            else if (e != ZE_MISS)
+                break;
+        }
+    }
+
+  ohforgetit:
+    if (dir) closedir(dir);
+    if (subwild) *--subwild = '.';
+    if (newwhole) free(newwhole);
+    if (e == ZE_MISS && amatch)
+        e = ZE_OK;
+    return e;
+}
+
+int wild(p)
+char *p;
+{
+  char *path;
+  int toret;
+
+  /* special handling of stdin request */
+  if (strcmp(p, "-") == 0)   /* if compressing stdin */
+    return newname(p, 0, 0);
+
+  path=p;
+  if (strchr(p, ':')==NULL && *p!='@') {
+    if (!(path=malloc(strlen(p)+3))) {
+      return ZE_MEM;
+    }
+    strcpy(path,"@.");
+    strcat(path,p);
+  }
+
+  toret=wild_recurse(path, path);
+
+  if (path!=p) {
+    free(path);
+  }
+  return toret;
+}
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  DIR *d;               /* directory stream from opendir() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (LSSTAT(n, &s))
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  if ((s.st_mode & S_IFDIR) == 0)
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0, caseflag)) != ZE_OK)
+      return m;
+  } else {
+    /* Add trailing / to the directory name */
+    if ((p = malloc(strlen(n)+2)) == NULL)
+      return ZE_MEM;
+    if (strcmp(n, ".") == 0) {
+      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      strcpy(p, n);
+      a = p + strlen(p);
+      if (a[-1] != '.')
+        strcpy(a, ".");
+      if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+        free((zvoid *)p);
+        return m;
+      }
+    }
+    /* recurse into directory */
+    if (recurse && (d = opendir(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if (strcmp(e, ".") && strcmp(e, ".."))
+        {
+          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+          {
+            closedir(d);
+            free((zvoid *)p);
+            return ZE_MEM;
+          }
+          strcat(strcpy(a, p), e);
+          if ((m = procname(a, caseflag)) != ZE_OK)   /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", a);
+            else
+              ziperr(m, a);
+          }
+          free((zvoid *)a);
+        }
+      }
+      closedir(d);
+    }
+    free((zvoid *)p);
+  } /* (s.st_mode & S_IFDIR) == 0) */
+  return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t;              /* shortened name */
+  char *tmp;
+  int dosflag;
+  char *lastlastdir=NULL;   /* pointer to 2 dirs before... */
+  char *lastdir=NULL;       /* pointer to last dir... */
+
+  /* Malloc space for internal name and copy it */
+  if ((tmp = malloc(strlen(x) + 1)) == NULL)
+    return NULL;
+  strcpy(tmp, x);
+
+  dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+  /* Find starting point in name before doing malloc */
+  for(t=tmp;*t;t++) {
+    if (*t=='/') {
+      *t='.';
+    }
+    else if (*t=='.') {
+      *t='/';
+      lastlastdir=lastdir;
+      lastdir=t+1;
+    }
+  }
+
+  t=strchr(tmp,'$');      /* skip FS name */
+  if (t!=NULL)
+    t+=2;                 /* skip '.' after '$' */
+  else
+    t=tmp;
+  if (*t=='@')            /* skip @. at the beginning of filenames */
+    t+=2;
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+
+  /* return a pointer to '\0' if the file is a directory with the same
+     same name as an extension to swap (eg. 'c', 'h', etc.) */
+  if (isdir && exts2swap!=NULL) {
+    if (lastlastdir==NULL)
+      lastlastdir=t;
+    if (checkext(lastlastdir)) {
+      free((void *)tmp);
+      n=malloc(1);
+      if (n!=NULL)
+        *n='\0';
+      return n;
+    }
+  }
+
+  if (exts2swap!=NULL && lastdir!=NULL) {
+    if (lastlastdir==NULL)
+      lastlastdir=t;
+    if (checkext(lastlastdir)) {
+      if (swapext(lastlastdir,lastdir-1)) {
+        free((void *)tmp);
+        return NULL;
+      }
+    }
+  }
+
+  if (!pathput)
+    t = last(t, PATH_END);
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL) {
+    free((void *)tmp);
+    return NULL;
+  }
+  strcpy(n, t);
+
+  free((void *)tmp);
+
+  if (dosify)
+    msname(n);
+
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+  return n;
+}
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+  char *t;              /* scans name */
+  char *lastext=NULL;   /* pointer to last extension */
+  char *lastdir=NULL;   /* pointer to last dir */
+
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+    return NULL;
+  strcpy(x, n);
+
+  for(t=x;*t;t++) {
+    if (*t=='.') {
+      *t='/';
+      lastext=t+1;
+    }
+    else if (*t=='/') {
+      *t='.';
+      lastdir=t+1;
+    }
+  }
+
+  if (exts2swap!=NULL && (int)lastext>(int)lastdir) {
+    if (lastdir==NULL)
+      lastdir=x;
+    if (checkext(lastext)) {
+      if (swapext(lastdir,lastext-1)) {
+        free((void *)x);
+        return NULL;
+      }
+    }
+  }
+
+  return x;
+}
+
+local int uxtime2acornftime(unsigned *pexadr, unsigned *pldadr, time_t ut)
+{
+  unsigned timlo;       /* 3 lower bytes of acorn file-time plus carry byte */
+  unsigned timhi;       /* 2 high bytes of acorn file-time */
+
+  timlo = ((unsigned)ut & 0x00ffffffU) * 100 + 0x00996a00U;
+  timhi = ((unsigned)ut >> 24);
+  timhi = timhi * 100 + 0x0000336eU + (timlo >> 24);
+  if (timhi & 0xffff0000U)
+      return 1;         /* calculation overflow, do not change time */
+
+  /* insert the five time bytes into loadaddr and execaddr variables */
+  *pexadr = (timlo & 0x00ffffffU) | ((timhi & 0x000000ffU) << 24);
+  *pldadr = (*pldadr & 0xffffff00U) | ((timhi >> 8) & 0x000000ffU);
+
+  return 0;             /* subject to future extension to signal overflow */
+}
+
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+  time_t m_time;
+  unsigned int loadaddr, execaddr;
+  int attr;
+
+  /* Convert DOS time to time_t format in m_time */
+  m_time = dos2unixtime(d);
+
+  /* set the file's modification time */
+  SWI_OS_File_5(f,NULL,&loadaddr,NULL,NULL,&attr);
+
+  if (uxtime2acornftime(&execaddr, &loadaddr, m_time) != 0)
+      return;
+
+  SWI_OS_File_1(f,loadaddr,execaddr,attr);
+}
+
+ulg filetime(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  /* convert FNMAX to malloc - 11/8/04 EG */
+  char *name;
+  unsigned int len = strlen(f);
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '.')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+
+  if (strcmp(f, "-") == 0) {
+  /* forge stat values for stdin since Amiga and RISCOS have no fstat() */
+    s.st_mode = (S_IREAD|S_IWRITE|S_IFREG);
+    s.st_size = -1;
+    s.st_mtime = time(&s.st_mtime);
+  } else if (LSSTAT(name, &s) != 0) {
+             /* Accept about any file kind including directories
+              * (stored with trailing / with -r option)
+              */
+    free(name);
+    return 0;
+  }
+  free(name);
+
+  if (a != NULL) {
+    *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+    if ((s.st_mode & S_IFDIR) != 0) {
+      *a |= MSDOS_DIR_ATTR;
+    }
+  }
+  if (n != NULL)
+    *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = s.st_ctime;
+  }
+
+  return unix2dostime((time_t *) &s.st_mtime);
+}
+
+int set_extra_field(z, z_utim)
+        struct zlist far *z;
+        iztimes *z_utim;
+{
+#ifdef USE_EF_UT_TIME
+  char *eb_ptr;
+#endif /* USE_EF_UT_TIME */
+  char *name;
+  extra_block *block;
+
+#define EB_SPARK_LEN    20
+#define EB_SPARK_SIZE (EB_HEADSIZE+EB_SPARK_LEN)
+#ifdef USE_EF_UT_TIME
+# ifdef IZ_CHECK_TZ
+#  define EB_UTTIME_SIZE (zp_tz_is_valid ? EB_HEADSIZE+EB_UT_LEN(1) : 0)
+# else
+#  define EB_UTTIME_SIZE (EB_HEADSIZE+EB_UT_LEN(1))
+# endif
+#else
+#  define EB_UTTIME_SIZE 0
+#endif
+#define EF_SPARK_TOTALSIZE (EB_SPARK_SIZE + EB_UTTIME_SIZE)
+
+  if ((name=(char *)malloc(strlen(z->name)+1))==NULL) {
+    fprintf(stderr," set_extra_field: not enough memory for directory name\n");
+    return ZE_MEM;
+  }
+
+  strcpy(name,z->name);
+
+  if (name[strlen(name)-1]=='.') {  /* remove the last '.' in directory names */
+    name[strlen(name)-1]=0;
+  }
+
+  z->extra=(char *)malloc(EF_SPARK_TOTALSIZE);
+  if (z->extra==NULL) {
+    fprintf(stderr," set_extra_field: not enough memory\n");
+    free(name);
+    return ZE_MEM;
+  }
+  z->cextra = z->extra;
+  z->cext = z->ext = EF_SPARK_TOTALSIZE;
+
+  block=(extra_block *)z->extra;
+  block->ID=SPARKID;
+  block->size=EB_SPARK_LEN;
+  block->ID_2=SPARKID_2;
+  block->zero=0;
+
+  if (SWI_OS_File_5(name,NULL,&block->loadaddr,&block->execaddr,
+                    NULL,&block->attr) != NULL) {
+    fprintf(stderr," OS error while set_extra_field of %s\n",name);
+  }
+
+  free(name);
+
+#ifdef USE_EF_UT_TIME
+# ifdef IZ_CHECK_TZ
+  if (zp_tz_is_valid) {
+# endif
+    eb_ptr = z->extra + EB_SPARK_SIZE;
+
+    eb_ptr[0]  = 'U';
+    eb_ptr[1]  = 'T';
+    eb_ptr[2]  = EB_UT_LEN(1);          /* length of data part of e.f. */
+    eb_ptr[3]  = 0;
+    eb_ptr[4]  = EB_UT_FL_MTIME;
+    eb_ptr[5]  = (char)(z_utim->mtime);
+    eb_ptr[6]  = (char)(z_utim->mtime >> 8);
+    eb_ptr[7]  = (char)(z_utim->mtime >> 16);
+    eb_ptr[8]  = (char)(z_utim->mtime >> 24);
+# ifdef IZ_CHECK_TZ
+  }
+# endif
+#endif /* USE_EF_UT_TIME */
+
+  return ZE_OK;
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+void version_local()
+{
+    static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+
+    printf(CompiledWith,
+#ifdef __GNUC__
+      "gcc ", __VERSION__,
+#else
+#  ifdef __CC_NORCROFT
+      "Norcroft ", "cc",
+#  else
+      "cc", "",
+#  endif
+#endif
+
+      "RISC OS",
+
+      " (Acorn Computers Ltd)",
+
+#ifdef __DATE__
+      " on ", __DATE__
+#else
+      "", ""
+#endif
+      );
+
+} /* end function version_local() */
diff --git a/acorn/makefile b/acorn/makefile
new file mode 100644 (file)
index 0000000..323ffca
--- /dev/null
@@ -0,0 +1,115 @@
+# Makefile for Zip, ZipNote, ZipCloak and ZipSplit
+
+# add -g to CC to debug
+# add -d to BIND to debug
+CC   = cc
+BIND = link
+AS   = $(CC) -c
+ASM  = objasm
+SQUEEZE = squeeze -v
+E    =
+
+# flags
+#   CFLAGS    flags for C compile
+#   LFLAGS1   flags after output file spec, before obj file list
+#   LFLAGS2   flags after obj file list (libraries, etc)
+#
+LIB      =
+CBASE    = -throwback -wn -DASMV -apcs 3/26
+CFLAGS   = $(CBASE) -IC:,@.
+ASMFLAGS = -Throwback -Stamp -NoCache -CloseExec -quit -apcs 3/26
+LFLAGS1  =
+LFLAGS2  = $(LIB) C:o.Stubs
+
+# Uncomment the following line to enable support for Unix
+# Extra Field (Timezone)
+#CFLAGS  = $(CFLAGS) -DUSE_EF_UT_TIME
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crc32.o \
+       crypt.o ttyio.o riscos.o acornzip.o swiven.o
+
+OBJI = deflate.o trees.o
+OBJA = match.o sendbits.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o riscos.o acornzip_.o swiven.o
+OBJN = zipnote.o  $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h acorn/osdep.h acorn/riscos.h acorn/swiven.h
+
+all:      zip zipnote zipsplit zipcloak
+
+
+install:  %.zip %.zipnote %.zipsplit %.zipcloak %.zipsfx \
+          zip zipnote zipsplit zipcloak zipsfx
+        $(SQUEEZE) zip %.zip
+        $(SQUEEZE) zipnote %.zipnote
+        $(SQUEEZE) zipsplit %.zipsplit
+        $(SQUEEZE) zipcloak %.zipcloak
+        copy acorn.zipsfx %.zipsfx ~CVF
+
+# suffix rules
+.SUFFIXES:      _.o .o .c
+.c_.o:
+        $(CC) $(CFLAGS) -DUTIL -c $*.c -o $*_.o
+.c.o:
+        $(CC) $(CFLAGS) -c $<
+.s.o:
+        $(ASM) $(ASMFLAGS) -from @*.s -to @*.o
+
+# rules for zip, zipnote, zipcloak and zipsplit
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o crc32.o crypt.o fileio.o zipfile.o zipup.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+
+crc32_.o: crc32.c
+        $(CC) $(CFLAGS) -DUTIL -c c.crc32 -o o.crc32_
+crypt_.o: crypt.c
+        $(CC) $(CFLAGS) -DUTIL -c c.crypt -o o.crypt_
+util_.o: util.c
+        $(CC) $(CFLAGS) -DUTIL -c c.util -o o.util_
+fileio_.o: fileio.c
+        $(CC) $(CFLAGS) -DUTIL -c c.fileio -o o.fileio_
+zipfile_.o: zipfile.c
+        $(CC) $(CFLAGS) -DUTIL -c c.zipfile -o o.zipfile_
+acornzip_.o: acorn/acornzip.c $(ZIP_H)
+        $(CC) $(CFLAGS) -DUTIL -c acorn/acornzip.c -o o.acornzip_
+
+riscos.o: acorn/riscos.c acorn/riscos.h
+        $(CC) $(CFLAGS) -c acorn/riscos.c
+
+acornzip.o: acorn/acornzip.c $(ZIP_H)
+        $(CC) $(CFLAGS) -c acorn/acornzip.c
+
+match.o: acorn/match.s
+        $(ASM) $(ASMFLAGS) -from acorn.s.match -to o.match
+
+sendbits.o: acorn/sendbits.s
+        $(ASM) $(ASMFLAGS) -from acorn.s.sendbits -to o.sendbits
+
+swiven.o: acorn/swiven.s
+        $(ASM) $(ASMFLAGS) -from acorn.s.swiven -to o.swiven
+
+zip:      $(OBJZ) $(OBJI) $(OBJA)
+          $(BIND) -o zip$(E) $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote:  $(OBJN)
+          $(BIND) -o zipnote$(E) $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak: $(OBJC)
+          $(BIND) -o zipcloak$(E) $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit: $(OBJS)
+          $(BIND) -o zipsplit$(E) $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+clean:  ;remove zip; remove zipcloak;
+        remove zipsplit; remove zipnote;
+        create o.!fake! 0
+        wipe o.* ~cf
+
+# end of Makefile
diff --git a/acorn/match.s b/acorn/match.s
new file mode 100644 (file)
index 0000000..ee68ce6
--- /dev/null
@@ -0,0 +1,217 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; match.s for ARM by Sergio Monesi.
+
+r0 RN 0
+r1 RN 1
+r2 RN 2
+r3 RN 3
+r4 RN 4
+r5 RN 5
+r6 RN 6
+r7 RN 7
+r8 RN 8
+r9 RN 9
+sl RN 10
+fp RN 11
+ip RN 12
+sp RN 13
+lr RN 14
+pc RN 15
+
+MAX_DIST   EQU  32506
+WMASK      EQU  32767
+MAX_MATCH  EQU  258
+
+                AREA    |C$$code|, CODE, READONLY
+
+
+; r1 = chain_lenght
+; r2 = scan
+; r3 = match
+; r4 = len (tmp)
+; r5 = best_len
+; r6 = limit
+; r7 = strend
+; r8 = scan_end1
+; r9 = scan_end
+; lr = window
+; fp = prev
+
+|__max_chain_length|
+        IMPORT  max_chain_length
+        DCD     max_chain_length
+|__window|
+        IMPORT  window
+        DCD     window
+|__prev|
+        IMPORT  prev
+        DCD     prev
+|__prev_length|
+        IMPORT  prev_length
+        DCD     prev_length
+|__strstart|
+        IMPORT  strstart
+        DCD     strstart
+|__good_match|
+        IMPORT  good_match
+        DCD     good_match
+|__nice_match|
+        IMPORT  nice_match
+        DCD     nice_match
+|__match_start|
+        IMPORT  match_start
+        DCD     match_start
+
+        DCB     "longest_match"
+        DCB     &00,&00,&00
+        DCD     &ff000010
+
+        EXPORT  longest_match
+longest_match
+        STMFD   sp!, {r4-r9,fp,lr}
+
+        LDR     fp, [pc, #|__prev|-.-8]
+
+        LDR     r1, [pc, #|__max_chain_length|-.-8]
+        LDR     r1, [r1]
+        LDR     lr, [pc, #|__window|-.-8]
+
+        LDR     ip, [pc, #|__strstart|-.-8]
+        LDR     ip, [ip]
+        ADD     r2, lr, ip
+        LDR     r5, [pc, #|__prev_length|-.-8]
+        LDR     r5, [r5]
+        SUBS    ip, ip, #MAX_DIST-250       ; if r6 > MAX_DIST
+        SUBCSS  r6, ip, #250                ; r6 = r6 - MAXDIST
+        MOVLS   r6, #0                      ; else r6 = 0
+
+        ADD     r7, r2, #MAX_MATCH-256
+        ADD     r7, r7, #256                ; r7 = r2 + MAX_MATCH (=258);
+
+        SUB     ip, r5, #1
+        LDRB    r8, [r2, ip]
+        LDRB    r9, [r2, r5]
+
+        LDR     ip, [pc, #|__good_match|-.-8]
+        LDR     ip, [ip]
+        CMP     r5, ip
+        MOVCS   r1, r1, LSR #2
+
+cycle
+        ADD     r3, lr, r0
+
+        LDRB    ip, [r3, r5]
+        CMP     ip, r9
+        BNE     cycle_end
+
+        SUB     ip, r5, #1
+        LDRB    ip, [r3, ip]
+        CMP     ip, r8
+        BNE     cycle_end
+
+        LDRB    ip, [r2]
+        LDRB    r4, [r3]
+        CMP     ip, r4
+        BNE     cycle_end
+
+        LDRB    ip, [r3, #1]
+        LDRB    r4, [r2, #1]
+        CMP     ip, r4
+        BNE     cycle_end
+
+        ADD     r2, r2, #2
+        ADD     r3, r3, #2
+
+inn_cycle
+        LDRB    ip, [r2, #1]!
+        LDRB    r4, [r3, #1]!
+        CMP     ip, r4
+        BNE     exit_inn_cycle
+
+        LDRB    ip, [r2, #1]!
+        LDRB    r4, [r3, #1]!
+        CMP     ip, r4
+        BNE     exit_inn_cycle
+
+        LDRB    ip, [r2, #1]!
+        LDRB    r4, [r3, #1]!
+        CMP     ip, r4
+        BNE     exit_inn_cycle
+
+        LDRB    ip, [r2, #1]!
+        LDRB    r4, [r3, #1]!
+        CMP     ip, r4
+        BNE     exit_inn_cycle
+
+        LDRB    ip, [r2, #1]!
+        LDRB    r4, [r3, #1]!
+        CMP     ip, r4
+        BNE     exit_inn_cycle
+
+        LDRB    ip, [r2, #1]!
+        LDRB    r4, [r3, #1]!
+        CMP     ip, r4
+        BNE     exit_inn_cycle
+
+        LDRB    ip, [r2, #1]!
+        LDRB    r4, [r3, #1]!
+        CMP     ip, r4
+        BNE     exit_inn_cycle
+
+        LDRB    ip, [r2, #1]!
+        LDRB    r4, [r3, #1]!
+        CMP     ip, r4
+        BNE     exit_inn_cycle
+
+        CMP     r2, r7
+        BCC     inn_cycle
+
+exit_inn_cycle
+        SUB     r4, r2, r7               ; len = MAX_MATCH - (int)(strend - scan);
+        ADD     r4, r4, #MAX_MATCH-256
+        ADD     r4, r4, #256
+
+        SUB     r2, r2, r4               ; scan = strend - MAX_MATCH
+
+        CMP     r4, r5                   ; if (len > best_len) {
+        BLE     cycle_end
+
+        LDR     ip, [pc, #|__match_start|-.-8]  ; match_start = cur_match;
+        STR     r0, [ip]
+        MOV     r5, r4                          ; best_len = len;
+
+        LDR     ip, [pc, #|__nice_match|-.-8]   ; if (len >= nice_match)
+        LDR     ip, [ip]
+        CMP     r4, ip
+        BGE     exit_match                      ;   break;
+
+        SUB     ip, r5, #1                      ; scan_end1  = scan[best_len-1];
+        LDRB    r8, [r2, ip]
+        LDRB    r9, [r2, r5]                    ; scan_end   = scan[best_len];
+
+cycle_end
+        MOV     ip, r0, LSL #17          ; cur_match & WMASK
+        MOV     ip, ip, LSR #17
+
+        LDR     r0, [fp, ip, ASL #1]     ; cur_match = prev[cur_match & WMASK]
+        MOV     r0, r0, ASL #16
+        MOV     r0, r0, LSR #16
+
+        CMP     r0, r6                  ; cur_match > limit
+        BLS     exit_match
+        SUBS    r1, r1, #1              ; --chain_length
+        BNE     cycle                   ; chain_length != 0
+
+exit_match
+        MOV     r0, r5
+
+        LDMFD   sp!, {r4-r9,fp,pc}^
+
+        END
diff --git a/acorn/osdep.h b/acorn/osdep.h
new file mode 100644 (file)
index 0000000..9f7783e
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#include "riscos.h"
+
+#define RISCOS
+#define NO_SYMLINKS
+#define NO_FCNTL_H
+#define NO_UNISTD_H
+#define NO_MKTEMP
+
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+                     procname(n, 1))
+
+#define isatty(a) 1
+#define fseek(f,o,t) riscos_fseek((f),(o),(t))
+
+#define localtime riscos_localtime
+#define gmtime riscos_gmtime
+
+#ifdef ZCRYPT_INTERNAL
+#  define ZCR_SEED2     (unsigned)3141592654L   /* use PI as seed pattern */
+#endif
diff --git a/acorn/riscos.c b/acorn/riscos.c
new file mode 100644 (file)
index 0000000..84dd2d3
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+  Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* riscos.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zip.h"
+#include "riscos.h"
+
+#define MAXEXT 256
+
+/* External globals */
+extern int scanimage;
+
+/* Local globals (!?!?) */
+char *exts2swap = NULL; /* Extensions to swap (actually, directory names) */
+
+int stat(char *filename,struct stat *res)
+{
+ int attr;              /* object attributes */
+ unsigned int load;     /* load address */
+ unsigned int exec;     /* exec address */
+ int type;              /* type: 0 not found, 1 file, 2 dir, 3 image */
+
+ if (!res)
+   return -1;
+
+ if (SWI_OS_File_5(filename,&type,&load,&exec,(int *)&res->st_size,&attr)!=NULL)
+   return -1;
+
+ if (type==0)
+   return -1;
+
+ res->st_dev=0;
+ res->st_ino=0;
+ res->st_nlink=0;
+ res->st_uid=1;
+ res->st_gid=1;
+ res->st_rdev=0;
+ res->st_blksize=1024;
+
+ res->st_mode = ((attr & 0001) << 8) | ((attr & 0002) << 6) |
+                ((attr & 0020) >> 2) | ((attr & 0040) >> 4);
+
+ switch (type) {
+   case 1:                        /* File */
+    res->st_mode |= S_IFREG;
+    break;
+   case 2:                        /* Directory */
+    res->st_mode |= S_IFDIR | 0700;
+    break;
+   case 3:                        /* Image file */
+    if (scanimage)
+      res->st_mode |= S_IFDIR | 0700;
+    else
+      res->st_mode |= S_IFREG;
+    break;
+ }
+
+ if ((((unsigned int) load) >> 20) == 0xfff) {     /* date stamped file */
+   unsigned int t1, t2, tc;
+
+   t1 = (unsigned int) (exec);
+   t2 = (unsigned int) (load & 0xff);
+
+   tc = 0x6e996a00U;
+   if (t1 < tc)
+     t2--;
+   t1 -= tc;
+   t2 -= 0x33;          /* 00:00:00 Jan. 1 1970 = 0x336e996a00 */
+
+   t1 = (t1 / 100) + (t2 * 42949673U);  /* 0x100000000 / 100 = 42949672.96 */
+   t1 -= (t2 / 25);             /* compensate for .04 error */
+
+   res->st_atime = res->st_mtime = res->st_ctime = t1;
+ }
+ else
+   res->st_atime = res->st_mtime = res->st_ctime = 0;
+
+ return 0;
+}
+
+#ifndef SFX
+
+DIR *opendir(char *dirname)
+{
+ DIR *thisdir;
+ int type;
+ int attr;
+ os_error *er;
+
+ thisdir=(DIR *)malloc(sizeof(DIR));
+ if (thisdir==NULL)
+   return NULL;
+
+ thisdir->dirname=(char *)malloc(strlen(dirname)+1);
+ if (thisdir->dirname==NULL) {
+   free(thisdir);
+   return NULL;
+ }
+
+ strcpy(thisdir->dirname,dirname);
+ if (thisdir->dirname[strlen(thisdir->dirname)-1]=='.')
+   thisdir->dirname[strlen(thisdir->dirname)-1]=0;
+
+ if (er=SWI_OS_File_5(thisdir->dirname,&type,NULL,NULL,NULL,&attr),er!=NULL ||
+     type<=1 || (type==3 && !scanimage))
+ {
+   free(thisdir->dirname);
+   free(thisdir);
+   return NULL;
+ }
+
+ thisdir->buf=malloc(DIR_BUFSIZE);
+ if (thisdir->buf==NULL) {
+   free(thisdir->dirname);
+   free(thisdir);
+   return NULL;
+ }
+
+ thisdir->size=DIR_BUFSIZE;
+ thisdir->offset=0;
+ thisdir->read=0;
+
+ return thisdir;
+}
+
+struct dirent *readdir(DIR *d)
+{
+ static struct dirent dent;
+
+ if (d->read==0) {    /* no more objects read in the buffer */
+   if (d->offset==-1) {    /* no more objects to read */
+     return NULL;
+   }
+
+   d->read=255;
+   if (SWI_OS_GBPB_9(d->dirname,d->buf,&d->read,&d->offset,DIR_BUFSIZE,NULL)!=NULL)
+     return NULL;
+
+   if (d->read==0) {
+     d->offset=-1;
+     return NULL;
+   }
+   d->read--;
+   d->act=(char *)d->buf;
+ }
+ else {     /* some object is ready in buffer */
+   d->read--;
+   d->act=(char *)(d->act+strlen(d->act)+1);
+ }
+
+ strcpy(dent.d_name,d->act);
+ dent.d_namlen=strlen(dent.d_name);
+
+ return &dent;
+}
+
+void closedir(DIR *d)
+{
+ if (d->buf!=NULL)
+   free(d->buf);
+ if (d->dirname!=NULL)
+   free(d->dirname);
+ free(d);
+}
+
+int unlink(f)
+char *f;                /* file to delete */
+/* Delete the file *f, returning non-zero on failure. */
+{
+ os_error *er;
+ char canon[256];
+ int size=255;
+
+ er=SWI_OS_FSControl_37(f,canon,&size);
+ if (er==NULL) {
+   er=SWI_OS_FSControl_27(canon,0x100);
+ }
+ else {
+   er=SWI_OS_FSControl_27(f,0x100);
+ }
+ return (int)er;
+}
+
+int deletedir(char *d)
+{
+ int objtype;
+ char *s;
+ int len;
+ os_error *er;
+
+ len = strlen(d);
+ if ((s = malloc(len + 1)) == NULL)
+   return -1;
+
+ strcpy(s,d);
+ if (s[len-1]=='.')
+   s[len-1]=0;
+
+ if (er=SWI_OS_File_5(s,&objtype,NULL,NULL,NULL,NULL),er!=NULL) {
+   free(s);
+   return -1;
+ }
+ if (objtype<2 || (!scanimage && objtype==3)) {
+   /* this is a file or it doesn't exist */
+   free(s);
+   return -1;
+ }
+
+ if (er=SWI_OS_File_6(s),er!=NULL) {
+   /* maybe this is a problem with the DDEUtils module, try to canonicalise the path */
+   char canon[256];
+   int size=255;
+
+   if (er=SWI_OS_FSControl_37(s,canon,&size),er!=NULL) {
+     free(s);
+     return -1;
+   }
+   if (er=SWI_OS_File_6(canon),er!=NULL) {
+     free(s);
+     return -1;
+   }
+ }
+ free(s);
+ return 0;
+}
+
+#endif /* !SFX */
+
+int chmod(char *file, int mode)
+{
+/*************** NOT YET IMPLEMENTED!!!!!! ******************/
+/* I don't know if this will be needed or not... */
+ file=file;
+ mode=mode;
+ return 0;
+}
+
+void setfiletype(char *fname,int ftype)
+{
+ char str[256];
+ sprintf(str,"SetType %s &%3.3X",fname,ftype);
+ SWI_OS_CLI(str);
+}
+
+void getRISCOSexts(char *envstr)
+{
+ char *envptr;                               /* value returned by getenv */
+
+ envptr = getenv(envstr);
+ if (envptr == NULL || *envptr == 0) return;
+
+ exts2swap=malloc(1+strlen(envptr));
+ if (exts2swap == NULL)
+   return;
+
+ strcpy(exts2swap, envptr);
+}
+
+int checkext(char *suff)
+{
+ register char *extptr=exts2swap;
+ register char *suffptr;
+ register int e,s;
+
+ if (extptr != NULL) while(*extptr) {
+   suffptr=suff;
+   e=*extptr; s=*suffptr;
+   while (e && e!=':' && s && s!='.' && s!='/' && e==s) {
+     e=*++extptr; s=*++suffptr;
+   }
+   if (e==':') e=0;
+   if (s=='.' || s=='/') s=0;
+   if (!e && !s) {
+     return 1;
+   }
+   while(*extptr!=':' && *extptr!='\0')    /* skip to next extension */
+     extptr++;
+   if (*extptr!='\0')
+     extptr++;
+ }
+ return 0;
+}
+
+int swapext(char *name, char *exptr)
+{
+ char *ext;
+ char *p1=exptr;
+ char *p2;
+ int extchar=*exptr;
+ unsigned int i=0;
+
+ while(*++p1 && *p1!='.' && *p1!='/')
+   ;
+ ext=malloc(i=p1-exptr);
+ if (!ext)
+   return 1;
+ memcpy(ext, exptr+1, i);
+ p2=exptr-1;
+ p1=exptr+i-1;
+ while(p2 >= name)
+   *p1--=*p2--;
+ strcpy(name,ext);
+ *p1=(extchar=='/'?'.':'/');
+ free(ext);
+ return 0;
+}
+
+void remove_prefix(void)
+{
+ SWI_DDEUtils_Prefix(NULL);
+}
+
+void set_prefix(void)
+{
+ char *pref;
+ int size=0;
+
+ if (SWI_OS_FSControl_37("@",pref,&size)!=NULL)
+   return;
+
+ size=1-size;
+
+ if (pref=malloc(size),pref!=NULL) {
+   if (SWI_OS_FSControl_37("@",pref,&size)!=NULL) {
+     free(pref);
+     return;
+   }
+
+   if (SWI_DDEUtils_Prefix(pref)==NULL) {
+     atexit(remove_prefix);
+   }
+
+   free(pref);
+ }
+}
+
+#ifdef localtime
+#  undef localtime
+#endif
+
+#ifdef gmtime
+#  undef gmtime
+#endif
+
+/* Acorn's implementation of localtime() and gmtime()
+ * doesn't consider the timezone offset, so we have to
+ * add it before calling the library functions
+ */
+
+struct tm *riscos_localtime(const time_t *timer)
+{
+ time_t localt=*timer;
+
+ localt+=SWI_Read_Timezone()/100;
+
+ return localtime(&localt);
+}
+
+struct tm *riscos_gmtime(const time_t *timer)
+{
+ time_t localt=*timer;
+
+ localt+=SWI_Read_Timezone()/100;
+
+ return gmtime(&localt);
+}
+
+
+int riscos_fseek(FILE *fd, long offset, int whence)
+{
+  int ret;
+  switch (whence)
+  {
+    case SEEK_END:
+      ret = (fseek) (fd, 0, SEEK_END);
+      if (ret)
+        return ret;
+      /* fall through */
+    case SEEK_CUR:
+      offset += ftell (fd);
+      /* fall through */
+    default: /* SEEK_SET */
+      return (fseek) (fd, offset < 0 ? 0 : offset, SEEK_SET);
+  }
+}
diff --git a/acorn/riscos.h b/acorn/riscos.h
new file mode 100644 (file)
index 0000000..c45a148
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+  Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* riscos.h */
+
+#ifndef __riscos_h
+#define __riscos_h
+
+#include <time.h>
+#include <stdio.h>
+
+typedef struct {
+  int errnum;
+  char errmess[252];
+} os_error;
+
+#ifndef __swiven_h
+#  include "swiven.h"
+#endif
+
+#define MAXPATHLEN 256
+#define MAXFILENAMELEN 64  /* should be 11 for ADFS, 13 for DOS, 64 seems a sensible value... */
+#define DIR_BUFSIZE 1024   /* this should be enough to read a whole E-Format directory */
+
+struct stat {
+  unsigned int st_dev;
+  int st_ino;
+  unsigned int st_mode;
+  int st_nlink;
+  unsigned short st_uid;
+  unsigned short st_gid;
+  unsigned int st_rdev;
+  unsigned int st_size;
+  unsigned int st_blksize;
+  time_t st_atime;
+  time_t st_mtime;
+  time_t st_ctime;
+};
+
+typedef struct {
+  char *dirname;
+  void *buf;
+  int size;
+  char *act;
+  int offset;
+  int read;
+} DIR;
+
+#define dstrm DIR
+
+struct dirent {
+  unsigned int d_off;          /* offset of next disk directory entry */
+  int d_fileno;                /* file number of entry */
+  size_t d_reclen;             /* length of this record */
+  size_t d_namlen;             /* length of d_name */
+  char d_name[MAXFILENAMELEN]; /* name */
+};
+
+typedef struct {
+  unsigned int load_addr;
+  unsigned int exec_addr;
+  int lenght;
+  int attrib;
+  int objtype;
+  char name[13];
+} riscos_direntry;
+
+#define SPARKID   0x4341        /* = "AC" */
+#define SPARKID_2 0x30435241    /* = "ARC0" */
+
+typedef struct {
+  short         ID;
+  short         size;
+  int           ID_2;
+  unsigned int  loadaddr;
+  unsigned int  execaddr;
+  int           attr;
+  int           zero;
+} extra_block;
+
+
+#define S_IFMT  0770000
+
+#define S_IFDIR 0040000
+#define S_IFREG 0100000  /* 0200000 in UnixLib !?!?!?!? */
+
+#ifndef S_IEXEC
+#  define S_IEXEC  0000100
+#  define S_IWRITE 0000200
+#  define S_IREAD  0000400
+#endif
+
+extern char *exts2swap; /* Extensions to swap */
+
+int stat(char *filename,struct stat *res);
+DIR *opendir(char *dirname);
+struct dirent *readdir(DIR *d);
+char *readd(DIR *d);
+void closedir(DIR *d);
+int unlink(char *f);
+int chmod(char *file, int mode);
+void setfiletype(char *fname,int ftype);
+void getRISCOSexts(char *envstr);
+int checkext(char *suff);
+int swapext(char *name, char *exptr);
+void remove_prefix(void);
+void set_prefix(void);
+struct tm *riscos_localtime(const time_t *timer);
+struct tm *riscos_gmtime(const time_t *timer);
+
+int riscos_fseek(FILE *fd, long offset, int whence);
+/* work around broken assumption that fseek() is OK with -ve file offsets */
+
+#endif /* !__riscos_h */
diff --git a/acorn/sendbits.s b/acorn/sendbits.s
new file mode 100644 (file)
index 0000000..f12921a
--- /dev/null
@@ -0,0 +1,105 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; sendbits.s for ARM by Sergio Monesi and Darren Salt.
+
+r0      RN      0
+r1      RN      1
+r2      RN      2
+r3      RN      3
+r4      RN      4
+r5      RN      5
+r6      RN      6
+r7      RN      7
+r8      RN      8
+r9      RN      9
+sl      RN      10
+fp      RN      11
+ip      RN      12
+sp      RN      13
+lr      RN      14
+pc      RN      15
+
+        AREA    |Asm$$Code|, CODE, READONLY
+
+        =       "send_bits",0
+        ALIGN
+        &       &FF00000C
+
+        IMPORT  __rt_stkovf_split_small
+        IMPORT  flush_outbuf
+
+        IMPORT  bi_valid
+        IMPORT  bi_buf
+        IMPORT  out_size
+        IMPORT  out_offset
+        IMPORT  out_buf
+
+        EXPORT  send_bits
+send_bits
+        MOV     ip,sp
+        STMDB   sp!,{r4,r5,fp,ip,lr,pc}
+        SUB     fp,ip,#4
+        LDR     r5,=bi_buf
+        LDR     r3,=bi_valid
+        LDR     r4,[r5]
+        LDR     r2,[r3]
+        ORR     r4,r4,r0,LSL r2 ; |= value<<bi_valid
+        ADD     r2,r2,r1        ; += length
+        CMP     r2,#&10
+        STRLE   r2,[r3]         ; short? store & return
+        STRLE   r4,[r5]
+        LDMLEDB fp,{r4,r5,fp,sp,pc}^
+
+        SUB     r2,r2,#&10      ; adjust bi_valid, bi_buf
+        MOV     ip,r4,LSR #16   ;  (done early, keeping the old bi_buf
+        STR     r2,[r3]         ;  in R4 for later storage)
+        STR     ip,[r5]
+
+        LDR     r0,=out_size
+        LDR     r1,=out_offset
+        LDR     r0,[r0]
+        LDR     r2,[r1]
+        SUB     r0,r0,#1
+        CMP     r2,r0           ; if out_offset >= out_size-1
+        LDRHS   r0,=out_buf
+        LDRHS   r0,[r0]
+        BLHS    flush_outbuf    ; then flush the buffer
+        LDR     r0,=out_buf
+        LDR     r1,=out_offset
+        LDR     r0,[r0]
+        LDR     r2,[r1]
+        MOV     r5,r4,LSR #8
+        STRB    r4,[r0,r2]!     ; store 'old' bi_buf
+        STRB    r5,[r0,#1]
+        ADD     r2,r2,#2
+        STR     r2,[r1]
+
+        LDMDB   fp,{r4,r5,fp,sp,pc}^
+
+
+ptr_bi          &       bi_valid
+                &       bi_buf
+
+
+        =       "bi_reverse",0
+        ALIGN
+        &       &FF00000C
+
+        EXPORT  bi_reverse
+bi_reverse
+        MOV     r2,#0
+loop    MOVS    r0,r0,LSR #1
+        ADCS    r2,r2,r2
+        SUBS    r1,r1,#1
+        BNE     loop
+        MOV     r0,r2
+        MOVS    pc,lr
+
+
+        END
diff --git a/acorn/srcrename b/acorn/srcrename
new file mode 100644 (file)
index 0000000..7bd6119
Binary files /dev/null and b/acorn/srcrename differ
diff --git a/acorn/swiven.h b/acorn/swiven.h
new file mode 100644 (file)
index 0000000..c860d7d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/* swiven.h */
+
+#ifndef __swiven_h
+#define __swiven_h
+
+os_error *SWI_OS_FSControl_26(char *source, char *dest, int actionmask);
+/* copy */
+
+os_error *SWI_OS_FSControl_27(char *filename, int actionmask);
+/* wipe */
+
+os_error *SWI_OS_GBPB_9(char *dirname, void *buf, int *number,
+                        int *offset, int size, char *match);
+/* read dir */
+
+os_error *SWI_OS_File_1(char *filename, unsigned int loadaddr,
+                        unsigned int execaddr, int attrib);
+/* write file attributes */
+
+os_error *SWI_OS_File_5(char *filename, int *objtype, unsigned int *loadaddr,
+                        unsigned int *execaddr, int *length, int *attrib);
+/* read file info */
+
+os_error *SWI_OS_File_6(char *filename);
+/* delete */
+
+os_error *SWI_OS_File_7(char *filename, int loadaddr, int execaddr, int size);
+/* create an empty file */
+
+os_error *SWI_OS_CLI(char *cmd);
+/* execute a command */
+
+int SWI_OS_ReadC(void);
+/* get a key from the keyboard buffer */
+
+os_error *SWI_OS_ReadVarVal(char *var, char *buf, int len, int *bytesused);
+/* reads an OS varibale */
+
+os_error *SWI_OS_FSControl_54(char *buffer, int dir, char *fsname, int *size);
+/* reads the path of a specified directory */
+
+os_error *SWI_OS_FSControl_37(char *pathname, char *buffer, int *size);
+/* canonicalise path */
+
+os_error *SWI_DDEUtils_Prefix(char *dir);
+/* sets the 'prefix' directory */
+
+int SWI_Read_Timezone(void);
+/* returns the timezone offset (centiseconds) */
+
+#endif /* !__swiven_h */
diff --git a/acorn/swiven.s b/acorn/swiven.s
new file mode 100644 (file)
index 0000000..1630124
--- /dev/null
@@ -0,0 +1,276 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; SWI veneers used by Zip/Unzip
+;
+
+r0              RN      0
+r1              RN      1
+r2              RN      2
+r3              RN      3
+r4              RN      4
+r5              RN      5
+r6              RN      6
+r7              RN      7
+r8              RN      8
+r9              RN      9
+r10             RN      10
+r11             RN      11
+r12             RN      12
+sp              RN      13
+lr              RN      14
+pc              RN      15
+
+sl              RN      10
+fp              RN      11
+ip              RN      12
+
+
+XOS_Bit                         EQU &020000
+
+OS_GBPB                         EQU &00000C
+OS_File                         EQU &000008
+OS_FSControl                    EQU &000029
+OS_CLI                          EQU &000005
+OS_ReadC                        EQU &000004
+OS_ReadVarVal                   EQU &000023
+DDEUtils_Prefix                 EQU &042580
+Territory_ReadCurrentTimeZone   EQU &043048
+
+        MACRO
+        STARTCODE $name
+        EXPORT $name
+$name
+        MEND
+
+
+                AREA    |C$$code|, CODE, READONLY
+
+; os_error *SWI_OS_FSControl_26(char *source, char *dest, int actionmask);
+
+        STARTCODE SWI_OS_FSControl_26
+
+        MOV     ip, lr
+
+        MOV     r3, r2
+        MOV     r2, r1
+        MOV     r1, r0
+        MOV     r0, #26
+
+        SWI     OS_FSControl + XOS_Bit
+
+        MOVVC   r0, #0
+
+        MOVS    pc, ip
+
+
+; os_error *SWI_OS_FSControl_27(char *filename, int actionmask);
+
+        STARTCODE SWI_OS_FSControl_27
+
+        MOV     ip, lr
+
+        MOV     r3, r1
+        MOV     r1, r0
+        MOV     r0, #27
+
+        SWI     OS_FSControl + XOS_Bit
+
+        MOVVC   r0, #0
+
+        MOVS    pc, ip
+
+
+; os_error *SWI_OS_GBPB_9(char *dirname, void *buf, int *number,
+;                         int *offset, int size, char *match);
+
+        STARTCODE SWI_OS_GBPB_9
+
+        MOV     ip, sp
+        STMFD   sp!, {r2-r6,lr}
+        LDMIA   ip, {r5,r6}
+        LDR     r4, [r3]
+        LDR     r3, [r2]
+        MOV     r2, r1
+        MOV     r1, r0
+        MOV     r0, #9
+        SWI     OS_GBPB + XOS_Bit
+        LDMVSFD sp!, {r2-r6,pc}^
+        MOV     r0, #0
+        LDMFD   sp, {r5,r6}
+        STR     r3, [r5]
+        STR     r4, [r6]
+        LDMFD   sp!, {r2-r6,pc}^
+
+
+; os_error *SWI_OS_File_1(char *filename, int loadaddr, int execaddr, int attrib);
+
+        STARTCODE SWI_OS_File_1
+
+        STMFD   sp!, {r5,lr}
+        MOV     r5, r3
+        MOV     r3, r2
+        MOV     r2, r1
+        MOV     r1, r0
+        MOV     r0, #1
+        SWI     OS_File + XOS_Bit
+        MOVVC   r0, #0
+        LDMFD   sp!, {r5,pc}^
+
+
+
+; os_error *SWI_OS_File_5(char *filename, int *objtype, int *loadaddr,
+;                         int *execaddr, int *length, int *attrib);
+
+        STARTCODE SWI_OS_File_5
+
+        STMFD   sp!, {r1-r5,lr}
+        MOV     r1, r0
+        MOV     r0, #5
+        SWI     OS_File + XOS_Bit
+        LDMVSFD sp!, {r1-r5,pc}^
+        LDR     lr, [sp]
+        TEQ     lr, #0
+        STRNE   r0, [lr]
+        LDR     lr, [sp, #4]
+        TEQ     lr ,#0
+        STRNE   r2, [lr]
+        LDR     lr, [sp, #8]
+        TEQ     lr, #0
+        STRNE   r3, [lr]
+        LDR     lr, [sp ,#24]
+        TEQ     lr, #0
+        STRNE   r4, [lr]
+        LDR     lr, [sp ,#28]
+        TEQ     lr, #0
+        STRNE   r5, [lr]
+        MOV     r0, #0
+        LDMFD   sp!, {r1-r5,pc}^
+
+
+; os_error *SWI_OS_File_6(char *filename);
+
+        STARTCODE SWI_OS_File_6
+
+        STMFD   sp!, {r4-r5,lr}
+        MOV     r1, r0
+        MOV     r0, #6
+        SWI     OS_File + XOS_Bit
+        MOVVC   r0, #0
+        LDMFD   sp!, {r4-r5,pc}^
+
+
+; os_error *SWI_OS_File_7(char *filename, int loadaddr, int execaddr, int size);
+
+        STARTCODE SWI_OS_File_7
+
+        STMFD   sp!, {r4-r5,lr}
+        MOV     r5, r3
+        MOV     r4, #0
+        MOV     r3, r2
+        MOV     r2, r1
+        MOV     r1, r0
+        MOV     r0, #7
+        SWI     OS_File + XOS_Bit
+        MOVVC   r0, #0
+        LDMFD   sp!, {r4-r5,pc}^
+
+
+; os_error *SWI_OS_CLI(char *cmd);
+
+        STARTCODE SWI_OS_CLI
+
+        MOV     ip, lr
+        SWI     OS_CLI + XOS_Bit
+        MOVVC   r0, #0
+        MOVS    pc, ip
+
+
+; int SWI_OS_ReadC(void);
+
+        STARTCODE SWI_OS_ReadC
+
+        MOV     ip, lr
+        SWI     OS_ReadC + XOS_Bit
+        MOVS    pc, ip
+
+
+; os_error *SWI_OS_ReadVarVal(char *var, char *buf, int len, int *bytesused);
+
+        STARTCODE SWI_OS_ReadVarVal
+
+        STMFD   sp!, {r4,lr}
+        MOV     ip, r3
+        MOV     r3, #0
+        MOV     r4, #0
+        SWI     OS_ReadVarVal + XOS_Bit
+        LDMVSFD sp!, {r4,pc}^
+        TEQ     ip, #0
+        STRNE   r2, [ip]
+        MOV     r0, #0
+        LDMFD   sp!, {r4,pc}^
+
+
+; os_error *SWI_OS_FSControl_54(char *buffer, int dir, char *fsname, int *size);
+
+        STARTCODE SWI_OS_FSControl_54
+
+        STMFD   sp!, {r3-r6,lr}
+        LDR     r5, [r3]
+        MOV     r3, r2
+        MOV     r2, r1
+        MOV     r1, r0
+        MOV     r0, #54
+        SWI     OS_FSControl + XOS_Bit
+        LDMVSFD sp!, {r3-r6,pc}^
+        MOV     r0, #0
+        LDMFD   sp!, {r3}
+        STR     r5, [r3]
+        LDMFD   sp!, {r4-r6,pc}^
+
+
+; os_error *SWI_OS_FSControl_37(char *pathname, char *buffer, int *size);
+
+        STARTCODE SWI_OS_FSControl_37
+
+        STMFD   sp!, {r2,r3-r5,lr}
+        LDR     r5, [r2]
+        MOV     r3, #0
+        MOV     r4, #0
+        MOV     r2, r1
+        MOV     r1, r0
+        MOV     r0, #37
+        SWI     OS_FSControl + XOS_Bit
+        LDMVSFD sp!, {r2,r3-r5,pc}^
+        MOV     r0, #0
+        LDMFD   sp!, {r2}
+        STR     r5, [r2]
+        LDMFD   sp!, {r3-r5,pc}^
+
+
+; os_error *SWI_DDEUtils_Prefix(char *dir);
+
+        STARTCODE SWI_DDEUtils_Prefix
+
+        MOV     ip, lr
+        SWI     DDEUtils_Prefix + XOS_Bit
+        MOVVC   r0, #0
+        MOVS    pc, ip
+
+; int SWI_Read_Timezone(void);
+
+        STARTCODE SWI_Read_Timezone
+
+        MOV     ip, lr
+        SWI     Territory_ReadCurrentTimeZone + XOS_Bit
+        MOVVC   r0, r1
+        MOVVS   r0, #0
+        MOVS    pc, ip
+
+
+        END
diff --git a/acorn/zipsfx b/acorn/zipsfx
new file mode 100644 (file)
index 0000000..7d63492
--- /dev/null
@@ -0,0 +1,9 @@
+| zipsfx 0.1
+| Written by Darren Salt
+| Assumes that unzipsfx is on Run$Path (eg. in !Boot.Library)
+| Assumes that IfThere is available as either *command or utility
+
+If "%1" = "" Then Error 220 Syntax: zipsfx |<archive> |<SEA>
+If "%0" = "" Then Error 220 Syntax: zipsfx |<archive> |<SEA>
+Copy Run:unzipsfx %1 A~C~D~F~L~N~R~S~T~V
+Print %0 { >> %1 }
\ No newline at end of file
diff --git a/acorn/zipup.h b/acorn/zipup.h
new file mode 100644 (file)
index 0000000..47c3536
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define fhow "r"
+#define fbad (NULL)
+typedef FILE *ftype;
+#define zopen(n,p) fopen(n,p)
+#define zread(f,b,n) fread((b),1,(n),(FILE*)(f))
+#define zclose(f) fclose(f)
+#define zerr(f) (k==(extent)(-1L))
+#define zstdin 0
diff --git a/amiga/LMKfile b/amiga/LMKfile
new file mode 100644 (file)
index 0000000..8c838ea
--- /dev/null
@@ -0,0 +1,117 @@
+# Makefile for Zip, ZipNote, ZipCloak and ZipSplit, Amiga SAS/C 5.10b
+# See the master Makefile under the top level Zip/Unzip source directory
+# for more information on compiler macros and flags for this version.
+# Last update: Jan 07, 2007
+# -John Bush, <J.Bush@MD-B.Prime.COM>, <JBush@BIX.COM>
+
+
+#######################
+# MACROBE DEFINITIONS #
+#######################
+
+# Compiler and loader debug flags.  Omit comments as req'd.
+# Do not set when building production version.
+# CDBG = -d3
+# LDBG = ADDSYM
+
+DEFINES = -DNO_MKTEMP
+CC = lc
+OPT = -O
+CFLAGS = $(OPT) $(DEFINES) $(CDBG) -v -mat -cuisf -b0 -j85i86i87i100i
+
+LD = blink
+LDSTART = LIB:c.o
+LDFLAGS = LIB LIB:lc.lib+LIB:amiga.lib
+
+TMPFILE = ram:MakeZip.tmp
+
+###############################################
+# BASIC COMPILE INSTRUCTIONS AND DEPENDENCIES #
+###############################################
+
+# default C rules
+.c.o:
+        $(CC) $(CFLAGS) -o$@ $*.c
+
+# Alternate rules for routines containing entries needed by utilities
+.c.oo:
+        $(CC) $(CFLAGS) -DUTIL -o$*.oo $*.c
+
+# object file macrough lists
+
+HFILES = zip.h ziperr.h tailor.h revision.h crc32.h crypt.h ttyio.h \
+         amiga/amiga.h amiga/zipup.h amiga/osdep.h
+
+OBJA = zipfile.o zipup.o fileio.o util.o globals.o crc32.o crypt.o \
+       timezone.o ttyio.o amiga.o amigazip.o filedate.o
+OBJI = deflate.o trees.o
+OBJU = zipfile.oo fileio.oo util.oo globals.o timezone.o \
+       amiga.o amigazip.oo filedate.o
+
+OBJZ = zip.o $(OBJA) $(OBJI)
+
+OBJN = zipnote.o  $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32.oo crypt.oo ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIPS = zip zipnote zipcloak zipsplit
+
+all:      Message $(ZIPS)
+
+Message:
+       -echo " "
+       -echo "WARNING: Lattice 5.x HAS NOT BEEN TESTED WITH THIS ZIP VERSION"
+       -echo "Report problems to <zip-bugs@lists.wku.edu>"
+       -echo " "
+
+zip: $(OBJZ) $(HFILES)
+        -echo "$(OBJZ)" > $(TMPFILE)
+       $(LD) TO Zip      FROM $(LDSTART) WITH $(TMPFILE) $(LDFLAGS) $(LDBG)
+        -delete $(TMPFILE) Zip.info
+
+zipnote: $(OBJN) $(HFILES)
+        -echo "$(OBJN)" > $(TMPFILE)
+       $(LD) TO ZipNote  FROM $(LDSTART) WITH $(TMPFILE) $(LDFLAGS) $(LDBG)
+        -delete $(TMPFILE) ZipNote.info
+
+zipcloak: $(OBJC) $(HFILES)
+        -echo "$(OBJC)" > $(TMPFILE)
+       $(LD) TO ZipCloak FROM $(LDSTART) WITH $(TMPFILE) $(LDFLAGS) $(LDBG)
+        -delete $(TMPFILE) ZipCloak.info
+
+zipsplit: $(OBJS) $(HFILES)
+        -echo "$(OBJS)" > $(TMPFILE)
+       $(LD) TO ZipSplit FROM $(LDSTART) WITH $(TMPFILE) $(LDFLAGS) $(LDBG)
+        -delete $(TMPFILE) ZipSplit.info
+
+clean:
+       -delete $(OBJZ) all quiet force >nil:
+       -delete $(OBJU) all quiet force >nil:
+       -delete $(OBJA) all quiet force >nil:
+       -delete $(OBJI) all quiet force >nil:
+       -delete $(OBJN) all quiet force >nil:
+       -delete $(OBJC) all quiet force >nil:
+       -delete $(OBJS) all quiet force >nil:
+
+zip.o:      zip.c      $(HFILES)
+zipnote.o:  zipnote.c  $(HFILES)
+zipcloak.o: zipcloak.c $(HFILES)
+crypt.o:    crypt.c    $(HFILES)
+ttyio.o:    ttyio.c    $(HFILES)
+zipsplit.o: zipsplit.c $(HFILES)
+deflate.o:  deflate.c  $(HFILES)
+trees.o:    trees.c    $(HFILES)
+zipfile.o:  zipfile.c  $(HFILES)
+zipup.o:    zipup.c    $(HFILES)
+fileio.o:   fileio.c   $(HFILES)
+util.o:     util.c     $(HFILES)
+timezone.o: timezone.c $(HFILES) timezone.h
+crc32.o:    crc32.c    $(HFILES)
+crctab.o:   crctab.c   $(HFILES)
+globals.o:  globals.c  $(HFILES)
+
+# Amiga specific objects
+amiga.o: amiga/amiga.c $(HFILES)
+amigazip.o: amiga/amigazip.c $(HFILES)
+
+# end of Makefile
diff --git a/amiga/README b/amiga/README
new file mode 100644 (file)
index 0000000..861ff85
--- /dev/null
@@ -0,0 +1 @@
+the -A option currently does not work for the amiga.
diff --git a/amiga/amiga.c b/amiga/amiga.c
new file mode 100644 (file)
index 0000000..797d6d8
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+  Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2005-Feb-10 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* OS specific routines for AMIGA platform.
+ *
+ * John Bush    <John.Bush@east.sun.com>  BIX: jbush
+ * Paul Kienitz <kie@pacbell.net>
+ *
+ * History:
+ *
+ * Date     DoBee    Comments
+ * -------  -------- -----------------------------------------------
+ * 21Jan93  JBush    Original coding.
+ *                   Incorporated filedate.c (existing routine).
+ *
+ * 31Jan93  JBush    Made filedate.c include unconditional.
+ *
+ * 18Jul93  PaulK    Moved Aztec _abort() here from stat.c because we
+ *                   can't share the same one between Zip and UnZip.
+ *                   Added close_leftover_open_dirs() call to it.
+ *
+ * 17Apr95  PaulK    Added Amiga internal version string so that
+ *                   installer programs can compare the version being
+ *                   installed to see if the copy the user already has
+ *                   is older or newer.  Added Prestart_Hook to support
+ *                   debug tracing in deflate.a.
+ *
+ *  6May95  PaulK    Added GetComment() for filenote support.
+ *
+ * 12Nov95  PaulK    Added #define ZIP in front of filedate.c, for
+ *                   new options in there; removed declare of set_con()
+ *                   since echon() no longer expands to it (or anything).
+ *
+ * 12Feb96  PaulK    Removed call of echon() entirely.
+ *
+ * 12Jul97  PaulK    Made both Aztec and SAS define USE_TIME_LIB for filedate.c
+ *
+ * 26Aug97  PaulK    Added ClearIOErr_exit()
+ *
+ *  2Jan98  HWalt    Adapted for SAS/C using stat.c replacement functions
+ *
+ *  6Jun00  PaulK    Removed references to time_lib, since new filedate.c
+ *                   supercedes it
+ */
+
+#include <exec/memory.h>
+#ifdef AZTEC_C
+#  include <libraries/dos.h>
+#  include <libraries/dosextens.h>
+#  include <clib/exec_protos.h>
+#  include <clib/dos_protos.h>
+#  include <pragmas/exec_lib.h>
+#  include <pragmas/dos_lib.h>
+#else
+#  include <proto/exec.h>
+#  include <proto/dos.h>
+#endif
+#include <stdlib.h>
+#include "ziperr.h"
+void ziperr(int c, const char *h);
+
+#define ZIP
+#if !defined(UTIL)
+#  define NO_MKTIME
+#endif
+
+#ifdef AZTEC_C
+
+/* ============================================================= */
+/* filedate.c is an external file, since it's shared with UnZip. */
+/* Aztec includes it here, but SAS/C now compiles it separately. */
+#  include "amiga/filedate.c"
+
+/* the same applies to stat.c                                    */
+#  include "amiga/stat.c"
+
+#  define setenv BOGUS_INCOMPATIBLE_setenv
+#  include <fcntl.h>
+#  undef setenv
+#  ifdef DEBUG
+#    define PRESTART_HOOK
+#  endif
+#endif
+
+extern void close_leftover_open_dirs(void);
+
+
+/* the following handles cleanup when a ^C interrupt happens: */
+
+void _abort(void)               /* called when ^C is pressed */
+{
+    close_leftover_open_dirs();
+    ziperr(ZE_ABORT, "^C");
+}
+
+void ClearIOErr_exit(int e)     /* EXIT is defined as this */
+{
+    if (!e)
+        ((struct Process *) FindTask(NULL))->pr_Result2 = 0;
+    /* we clear IoErr() since we are successful, in a 1.x-compatible way */
+    exit(e);
+}
+
+
+/* Make sure the version number here matches the number in revision.h */
+/* as closely as possible in strict decimal "#.#" form:               */
+const char version_id[] = "\0$VER: Zip 2.3 ("
+#  include "env:VersionDate"
+")\r\n";
+
+/* call this with an arg of NULL to free storage: */
+
+char *GetComment(char *filename)
+{
+    BPTR lk;
+    static struct FileInfoBlock *fib = NULL;
+
+    if (!filename) {
+        if (fib) FreeMem(fib, sizeof(*fib));
+        fib = NULL;
+        return NULL;
+    }
+    if (!fib) {
+        if (!(fib = AllocMem(sizeof(*fib), MEMF_PUBLIC)))
+            ziperr(ZE_MEM, "was checking filenotes");
+    }
+    if (!(lk = Lock(filename, ACCESS_READ)))
+        return NULL;
+    if (!Examine(lk, fib))
+        fib->fib_Comment[0] = '\0';
+    UnLock(lk);
+    return fib->fib_Comment[0] ? &fib->fib_Comment[0] : NULL;
+}
diff --git a/amiga/amiga.h b/amiga/amiga.h
new file mode 100644 (file)
index 0000000..a1461d8
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef __amiga_amiga_h
+#define __amiga_amiga_h
+
+/* amiga.h
+ *
+ * Globular definitions that affect all of AmigaDom.
+ *
+ * Originally included in unzip.h, extracted for simplicity and eeze of
+ * maintenance by John Bush.
+ *
+ * This version is for use with Zip.  It is not globally included, but used
+ * only by functions in amiga/amigazip.c.  Much material that was needed for
+ * UnZip is absent here.
+ *
+ */
+
+#include <fcntl.h>          /* O_BINARY for open() w/o CR/LF translation */
+#include "amiga/z-stat.h"  /* substitute for <stat.h> and <dire(c|n)t.h> */
+#define direct dirent
+
+#ifndef MODERN
+#  define MODERN
+#endif
+
+#ifdef AZTEC_C                          /* Manx Aztec C, 5.0 or newer only */
+#  include <clib/dos_protos.h>
+#  include <pragmas/dos_lib.h>          /* do inline dos.library calls */
+#  define O_BINARY 0
+#endif /* AZTEC_C */
+
+
+#ifdef __SASC
+#  include <dirent.h>
+#  include <dos.h>
+#  define disk_not_mounted 0
+#  if ( (!defined(O_BINARY)) && defined(O_RAW))
+#    define O_BINARY O_RAW
+#  endif
+#endif /* SASC */
+
+
+/* Funkshine Prough Toe Taipes */
+
+LONG FileDate (char *, time_t[]);
+
+#endif /* __amiga_amiga_h */
diff --git a/amiga/amigazip.c b/amiga/amigazip.c
new file mode 100644 (file)
index 0000000..4e69d62
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include "zip.h"
+#include "amiga/amiga.h"
+
+#ifndef UTIL    /* the companion #endif is a bit of ways down ... */
+
+#define utime FileDate
+
+#define PAD 0
+#define PATH_END '/'
+
+/* Local globals (kinda like "military intelligence" or "broadcast quality") */
+
+extern char *label;             /* still declared in fileio.c */
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Local functions */
+local char *readd OF((DIR *));
+local int wild_recurse OF((char *, char *));
+
+
+local char *readd(d)
+DIR *d;                 /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+   no more entries or an error occurs. */
+{
+  struct dirent *e = readdir(d);
+  return e == NULL ? (char *) NULL : e->d_name;
+}
+
+
+/* What we have here is a mostly-generic routine using opendir()/readd() and */
+/* isshexp()/MATCH() to find all the files matching a multi-part filespec  */
+/* using the portable pattern syntax.  It shouldn't take too much fiddling */
+/* to make it usable for any other platform that has directory hierarchies */
+/* but no shell-level pattern matching.  It works for patterns throughout  */
+/* the pathname, such as "foo:*.?/source/x*.[ch]".                         */
+
+#define ONENAMELEN 30
+/* the length of one filename component on the Amiga */
+
+/* whole is a pathname with wildcards, wildtail points somewhere in the  */
+/* middle of it.  All wildcards to be expanded must come AFTER wildtail. */
+
+local int wild_recurse(whole, wildtail) char *whole; char *wildtail;
+{
+    DIR *dir;
+    char *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
+    ush newlen, amatch = 0;
+    BPTR lok;
+    int e = ZE_MISS;
+
+    if (!isshexp(wildtail))
+        if (lok = Lock(whole, ACCESS_READ)) {       /* p exists? */
+            UnLock(lok);
+            return procname(whole, 0);
+        } else
+            return ZE_MISS;                     /* woops, no wildcards! */
+
+    /* back up thru path components till existing dir found */
+    do {
+        name = wildtail + strlen(wildtail) - 1;
+        for (;;)
+            if (name-- <= wildtail || *name == PATH_END) {
+                subwild = name + 1;
+                plug2 = *subwild;
+                *subwild = 0;
+                break;
+            }
+        if (glue)
+            *glue = plug;
+        glue = subwild;
+        plug = plug2;
+        dir = opendir(whole);
+    } while (!dir && !disk_not_mounted && subwild > wildtail);
+    wildtail = subwild;                 /* skip past non-wild components */
+
+    if ((subwild = strchr(wildtail + 1, PATH_END)) != NULL) {
+        /* this "+ 1" dodges the   ^^^ hole left by *glue == 0 */
+        *(subwild++) = 0;               /* wildtail = one component pattern */
+        newlen = strlen(whole) + strlen(subwild) + (ONENAMELEN + 2);
+    } else
+        newlen = strlen(whole) + (ONENAMELEN + 1);
+    if (!dir || !(newwhole = malloc(newlen))) {
+        if (glue)
+            *glue = plug;
+
+        e = dir ? ZE_MEM : ZE_MISS;
+        goto ohforgetit;
+    }
+    strcpy(newwhole, whole);
+    newlen = strlen(newwhole);
+    if (glue)
+        *glue = plug;                           /* repair damage to whole */
+    if (!isshexp(wildtail)) {
+        e = ZE_MISS;                            /* non-wild name not found */
+        goto ohforgetit;
+    }
+
+    while (name = readd(dir)) {
+        if (MATCH(wildtail, name, 0)) {
+            strcpy(newwhole + newlen, name);
+            if (subwild) {
+                name = newwhole + strlen(newwhole);
+                *(name++) = PATH_END;
+                strcpy(name, subwild);
+                e = wild_recurse(newwhole, name);
+            } else
+                e = procname(newwhole, 0);
+            newwhole[newlen] = 0;
+            if (e == ZE_OK)
+                amatch = 1;
+            else if (e != ZE_MISS)
+                break;
+        }
+    }
+
+  ohforgetit:
+    if (dir) closedir(dir);
+    if (subwild) *--subwild = PATH_END;
+    if (newwhole) free(newwhole);
+    if (e == ZE_MISS && amatch)
+        e = ZE_OK;
+    return e;
+}
+
+int wild(p) char *p;
+{
+    char *use;
+
+    /* special handling of stdin request */
+    if (strcmp(p, "-") == 0)    /* if compressing stdin */
+        return newname(p, 0, 0);
+
+    /* wild_recurse() can't handle colons in wildcard part: */
+    if (use = strchr(p, ':')) {
+        if (strchr(++use, ':'))
+            return ZE_PARMS;
+    } else
+        use = p;
+
+    return wild_recurse(p, use);
+}
+
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  DIR *d;               /* directory stream from opendir() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (LSSTAT(n, &s))
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  if ((s.st_mode & S_IFDIR) == 0)
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0, caseflag)) != ZE_OK)
+      return m;
+  } else {
+    /* Add trailing / to the directory name */
+    if ((p = malloc(strlen(n)+2)) == NULL)
+      return ZE_MEM;
+    strcpy(p, n);
+    a = p + strlen(p);
+    if (*p && a[-1] != '/' && a[-1] != ':')
+      strcpy(a, "/");
+    if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+      free((zvoid *)p);
+      return m;
+    }
+    /* recurse into directory */
+    if (recurse && (d = opendir(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+        {
+          closedir(d);
+          free((zvoid *)p);
+          return ZE_MEM;
+        }
+        strcat(strcpy(a, p), e);
+        if ((m = procname(a, caseflag)) != ZE_OK)   /* recurse on name */
+        {
+          if (m == ZE_MISS)
+            zipwarn("name not matched: ", a);
+          else
+            ziperr(m, a);
+        }
+        free((zvoid *)a);
+      }
+      closedir(d);
+    }
+    free((zvoid *)p);
+  } /* (s.st_mode & S_IFDIR) == 0) */
+  return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t;              /* shortened name */
+  int dosflag;
+
+  dosflag = dosify;     /* default for non-DOS and non-OS/2 */
+
+  /* Find starting point in name before doing malloc */
+  if ((t = strrchr(x, ':')) != NULL)    /* reject ":" */
+    t++;
+  else
+    t = x;
+  {                                     /* reject "//" */
+    char *tt = t;
+    while (tt = strchr(tt, '/'))
+      while (*++tt == '/')
+        t = tt;
+  }
+  while (*t == '/')             /* reject leading "/" on what's left */
+    t++;
+
+  if (!pathput)
+    t = last(t, PATH_END);
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL)
+    return NULL;
+  strcpy(n, t);
+
+  if (dosify)
+    msname(n);
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+  return n;
+}
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+      return NULL;
+  strcpy(x, n);
+  return x;
+}
+
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+  time_t u[2];          /* argument for utime() */
+
+  /* Convert DOS time to time_t format in u */
+  u[0] = u[1] = dos2unixtime(d);
+
+  /* Set updated and accessed times of f */
+  utime(f, u);
+}
+
+ulg filetime(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  /* convert FNMAX to malloc - 11/8/04 EG */
+  char *name;
+  int len = strlen(f);
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+
+  if (strcmp(f, "-") == 0) {
+    if (fstat(fileno(stdin), &s) != 0)
+      error("fstat(stdin)");
+  } else if (SSTAT(name, &s) != 0) {
+             /* Accept about any file kind including directories
+              * (stored with trailing / with -r option)
+              */
+    free(name);
+    return 0;
+  }
+  free(name);
+
+  if (a != NULL) {
+    *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+    if ((s.st_mode & S_IFDIR) != 0) {
+      *a |= MSDOS_DIR_ATTR;
+    }
+  }
+  if (n != NULL)
+    *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = s.st_ctime;
+  }
+
+   return unix2dostime(&s.st_mtime);
+}
+
+int set_extra_field(z, z_utim)
+  struct zlist far *z;
+  iztimes *z_utim;
+  /* create extra field and change z->att if desired */
+{
+#ifdef USE_EF_UT_TIME
+#ifdef IZ_CHECK_TZ
+  if (!zp_tz_is_valid) return ZE_OK;    /* skip silently if no valid TZ info */
+#endif
+
+  if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
+    return ZE_MEM;
+
+  z->extra[0]  = 'U';
+  z->extra[1]  = 'T';
+  z->extra[2]  = EB_UT_LEN(1);          /* length of data part of e.f. */
+  z->extra[3]  = 0;
+  z->extra[4]  = EB_UT_FL_MTIME;
+  z->extra[5]  = (char)(z_utim->mtime);
+  z->extra[6]  = (char)(z_utim->mtime >> 8);
+  z->extra[7]  = (char)(z_utim->mtime >> 16);
+  z->extra[8]  = (char)(z_utim->mtime >> 24);
+
+  z->cextra = z->extra;
+  z->cext = z->ext  = (EB_HEADSIZE+EB_UT_LEN(1));
+
+  return ZE_OK;
+#else /* !USE_EF_UT_TIME */
+  return (int)(z-z);
+#endif /* ?USE_EF_UT_TIME */
+}
+
+int deletedir(d)
+char *d;                /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+   Return the result of rmdir(), delete(), or system().
+   For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
+ */
+{
+    return rmdir(d);
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+
+/* NOTE:  the following include depends upon the environment
+ *        variable $Workbench to be set correctly.  (Set by
+ *        default, by Version command in Startup-sequence.)
+ */
+int WBversion = (int)
+#include "ENV:Workbench"
+;
+
+void version_local()
+{
+   static ZCONST char CompiledWith[] = "Compiled with %s%s under %s%s%s%s.\n\n";
+
+/* Define buffers. */
+
+   char buf1[16];  /* compiler name */
+   char buf2[16];  /* revstamp */
+   char buf3[16];  /* OS */
+   char buf4[16];  /* Date */
+/*   char buf5[16];  /* Time */
+
+/* format "with" name strings */
+
+#ifdef AMIGA
+# ifdef __SASC
+   strcpy(buf1,"SAS/C ");
+# else
+#  ifdef LATTICE
+    strcpy(buf1,"Lattice C ");
+#  else
+#   ifdef AZTEC_C
+     strcpy(buf1,"Manx Aztec C ");
+#   else
+     strcpy(buf1,"UNKNOWN ");
+#   endif
+#  endif
+# endif
+/* "under" */
+  sprintf(buf3,"AmigaDOS v%d",WBversion);
+#else
+  strcpy(buf1,"Unknown compiler ");
+  strcpy(buf3,"Unknown OS");
+#endif
+
+/* Define revision, date, and time strings.
+ * NOTE:  Do not calculate run time, be sure to use time compiled.
+ * Pass these strings via your makefile if undefined.
+ */
+
+#if defined(__VERSION__) && defined(__REVISION__)
+  sprintf(buf2,"version %d.%d",__VERSION__,__REVISION__);
+#else
+# ifdef __VERSION__
+  sprintf(buf2,"version %d",__VERSION__);
+# else
+  sprintf(buf2,"unknown version");
+# endif
+#endif
+
+#ifdef __DATE__
+  sprintf(buf4," on %s",__DATE__);
+#else
+  strcpy(buf4," unknown date");
+#endif
+
+/******
+#ifdef __TIME__
+  sprintf(buf5," at %s",__TIME__);
+#else
+  strcpy(buf5," unknown time");
+#endif
+******/
+
+/* Print strings using "CompiledWith" mask defined above.
+ *  ("Compiled with %s%s under %s%s%s%s.")
+ */
+
+   printf(CompiledWith,
+     buf1,
+     buf2,
+     buf3,
+     buf4,
+     /* buf5, */ "",
+     "" );  /* buf6 not used */
+
+} /* end function version_local() */
diff --git a/amiga/crc_68.a b/amiga/crc_68.a
new file mode 100644 (file)
index 0000000..4cc2a25
--- /dev/null
@@ -0,0 +1,144 @@
+;===========================================================================
+; Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 2000-Apr-09 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+; crc_68 created by Paul Kienitz, last modified 04 Jan 96.
+;
+; Return an updated 32 bit CRC value, given the old value and a block of data.
+; The CRC table used to compute the value is gotten by calling get_crc_table().
+; This replaces the older updcrc() function used in Zip and fUnZip.  The
+; prototype of the function is:
+;
+;    ulg crc32(ulg crcval, uch *text, extent textlen);
+;
+; On the Amiga, type extent is always unsigned long, not unsigned int, because
+; int can be short or long at whim, but size_t is long.
+;
+; If using this source on a non-Amiga 680x0 system, note that we treat
+; a0/a1/d0/d1 as scratch registers not preserved across function calls.
+; We do not bother to support registerized arguments for crc32() -- the
+; textlen parm is usually large enough so that savings outside the loop
+; are pointless.
+;
+; Define NO_UNROLLED_LOOPS to use a simple short loop which might be more
+; efficient on certain machines with dinky instruction caches ('020?), or for
+; processing short strings.  If loops are unrolled, the textlen parm must be
+; less than 512K; if not unrolled, it must be less than 64K.
+
+        xdef    _crc32          ; (ulg val, uch *buf, extent bufsize)
+
+DO_CRC0 MACRO
+        moveq  #0,ltemp
+        move.b (textbuf)+,ltemp
+        eor.b  crcval,ltemp
+        lsl.w  #2,ltemp
+        move.l (crc_table,ltemp.w),ltemp
+        lsr.l  #8,crcval
+        eor.l  ltemp,crcval
+        ENDM
+
+        machine mc68020
+
+DO_CRC2 MACRO
+        move.b (textbuf)+,btemp
+        eor.b  crcval,btemp
+        lsr.l  #8,crcval
+        move.l (crc_table,btemp.w*4),ltemp
+        eor.l  ltemp,crcval
+        ENDM
+
+crc_table       equr    a0      array of unsigned long
+crcval          equr    d0      unsigned long initial value
+textbuf         equr    a1      array of unsigned char
+textbufsize     equr    d1      unsigned long (count of bytes in textbuf)
+btemp           equr    d2
+ltemp           equr    d3
+
+
+        xref    _get_crc_table  ; ulg *get_crc_table(void)
+
+        NOLIST
+        INCLUDE 'exec/execbase.i'
+        LIST
+        xref    _SysBase        ; struct ExecBase *
+
+
+_crc32:
+        move.l  8(sp),d0
+        bne.s   valid
+         moveq  #0,d0
+         rts
+valid:  movem.l btemp/ltemp,-(sp)
+        jsr     _get_crc_table
+        move.l  d0,ltemp
+        move.l  12(sp),crcval
+        move.l  16(sp),textbuf
+        move.l  20(sp),textbufsize
+        not.l   crcval
+        move.l  _SysBase,crc_table
+        move.w  AttnFlags(crc_table),btemp
+        move.l  ltemp,crc_table
+        btst    #AFB_68020,btemp
+        bne     twenty
+
+    IFD     NO_UNROLLED_LOOPS
+
+        bra.s   decr
+loop:    DO_CRC0
+decr:    dbra   textbufsize,loop
+        bra.s   done
+
+twenty: moveq   #0,btemp
+        bra.s   decr2
+loop2:   DO_CRC2
+decr2:   dbra   textbufsize,loop2
+
+    ELSE    ; !NO_UNROLLED_LOOPS
+
+        move.l  textbufsize,btemp
+        lsr.l   #3,textbufsize
+        bra     decr8
+loop8:   DO_CRC0
+         DO_CRC0
+         DO_CRC0
+         DO_CRC0
+         DO_CRC0
+         DO_CRC0
+         DO_CRC0
+         DO_CRC0
+decr8:   dbra   textbufsize,loop8
+        and.w   #7,btemp
+        bra.s   decr1
+loop1:   DO_CRC0
+decr1:   dbra   btemp,loop1
+        bra     done
+
+twenty: moveq   #0,btemp
+        move.l  textbufsize,-(sp)
+        lsr.l   #3,textbufsize
+        bra     decr82
+loop82:  DO_CRC2
+         DO_CRC2
+         DO_CRC2
+         DO_CRC2
+         DO_CRC2
+         DO_CRC2
+         DO_CRC2
+         DO_CRC2
+decr82:  dbra   textbufsize,loop82
+        move.l  (sp)+,textbufsize
+        and.w   #7,textbufsize
+        bra.s   decr12
+loop12:  DO_CRC2
+decr12:  dbra   textbufsize,loop12
+
+    ENDC    ; ?NO_UNROLLED_LOOPS
+
+done:   movem.l (sp)+,btemp/ltemp
+        not.l   crcval
+;;;;;   move.l  crcval,d0               ; crcval already is d0
+        rts
diff --git a/amiga/deflate.a b/amiga/deflate.a
new file mode 100644 (file)
index 0000000..b21adae
--- /dev/null
@@ -0,0 +1,1053 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; This is a 680x0 assembly language translation of the Info-ZIP source file
+; deflate.c, by Paul Kienitz. The function longest_match is based in part
+; on match.a by Carsten Steger, which in turn is partly based on match.s
+; for 386 by Jean-loup Gailly and Kai Uwe Rommel.  Mostly, however, this
+; material is based on deflate.c, by Gailly, Rommel, and Igor Mandrichenko.
+; This code is not commented very much; see deflate.c for comments that explain
+; what the functions are doing.
+;
+; The symbols that can be used to select different versions are as follows:
+;
+;   CPU020     if defined, use 68020 instructions always.
+;
+;   CPUTEST    if defined, check at runtime for CPU type.  Another symbol
+;               specifying the platform-specific test must be used with this.
+;               If neither of these is defined, use 68000 instructions only.
+;               Runtime test is nonportable; it is different for each OS.
+;
+;   AMIGA      use Amiga-specific test for 68020, if CPUTEST defined.  Also
+;               tells it that registers d0/a0/d1/a1 are not preserved by
+;               function calls.  At present, if AMIGA is not defined, it
+;               causes functions to preserve all registers.  ALL OF THIS CODE
+;               CURRENTLY ASSUMES THAT REGISTERS D2-D7/A2-A6 WILL BE PRESERVED
+;               BY ANY FUNCTIONS THAT IT CALLS.
+;
+;   DYN_ALLOC  should be defined here if it is defined for C source; tells us
+;               that big arrays are allocated instead of static.
+;
+;   WSIZE      must be defined as the same number used for WSIZE in the C
+;               source, and must be a power of two <= 32768.  As elsewhere,
+;               the default value is 32768.
+;
+;   INT16      define this if ints are 16 bits; otherwise 32 bit ints assumed.
+;
+;   SMALL_MEM  define this if it is defined in the C source; otherwise it uses
+;               the MEDIUM_MEM model.  BIG_MEM and MMAP are *not* supported.
+;               The FULL_SEARCH option in deflate.c is also not supported.
+;
+;   DEBUG      activates some tracing output, as in the C source.
+;
+;   QUADLONG   this selects a different version of the innermost longest_match
+;               loop code for 68020 operations, comparing bytes four at a time
+;               instead of two at a time.  It seems to be a tiny bit faster on
+;               average, but it's slower often enough that one can't generalize.
+;
+; This code currently assumes that function results are returned in D0 for
+; all platforms.  It assumes that args to functions are pushed onto the stack,
+; last arg first.  It also currently assumes that all C symbols have an
+; underscore prepended when referenced from assembly.
+
+    IFND    CPU020
+     IFND   CPUTEST
+CPU000  equ     1
+     ENDC
+    ENDC
+
+; Use these macros for accessing variables of type int:
+    IFD     INT16
+MOVINT  MACRO
+        move.w  \1,\2
+        ENDM
+CLRINT  MACRO
+        clr.w   \1
+        ENDM
+INTSIZE equ     2
+    ELSE    ; !INT16
+MOVINT  MACRO
+        move.l  \1,\2
+        ENDM
+CLRINT  MACRO
+        clr.l   \1
+        ENDM
+INTSIZE equ     4
+    ENDC
+
+    IFD     DYN_ALLOC
+BASEPTR MACRO
+        move.l  \1,\2
+        ENDM
+    ELSE
+BASEPTR MACRO
+        lea     \1,\2
+        ENDM
+    ENDC
+
+; constants we use, many of them adjustable:
+
+MAX_MATCH       equ     258
+MIN_MATCH       equ     3
+TOO_FAR         equ     4096
+    IFND    WSIZE
+WSIZE           equ     32768
+    ENDC
+WMASK           equ     WSIZE-1
+MAX_DIST        equ     WSIZE-MAX_MATCH-MIN_MATCH-1
+MIN_LOOKAHEAD   equ     MAX_MATCH+MIN_MATCH+1
+;    IFD     BIG_MEM      ; NOT supported -- type Pos needs to be 32 bits
+;HASH_BITS      equ     15
+;    ELSE
+    IFD    SMALL_MEM
+HASH_BITS       equ     13
+    ELSE
+HASH_BITS       equ     14      ; default -- MEDIUM_MEM
+    ENDC
+;    ENDC    ; BIG_MEM
+HASH_SIZE       equ     1<<HASH_BITS
+HASH_MASK       equ     HASH_SIZE-1
+H_SHIFT         equ     (HASH_BITS+MIN_MATCH-1)/MIN_MATCH
+B_SLOW          equ     1
+B_FAST          equ     2
+ZE_MEM          equ     4
+EOF             equ     -1
+
+; struct config is defined by these offsets:
+Good_length     equ     0
+Max_lazy        equ     2
+Nice_length     equ     4
+Max_chain       equ     6
+Sizeof_config   equ     8
+
+
+; external functions we call:
+        xref    _ct_tally       ; int ct_tally(int, int)
+        xref    _flush_block    ; unsigned long F(char *, unsigned long, int)
+        xref    _ziperr         ; void ziperr(int, char *)
+        xref    _error          ; void error(char *)
+        xref    _calloc         ; stdlib function: void *calloc(size_t, size_t)
+        xref    _free           ; stdlib function: void free(void *)
+    IFD     DEBUG
+        xref    _fputc          ; stdio function: int fputc(int, FILE *)
+        xref    _stderr         ; pointer to FILE, which we pass to fputc
+    ENDC
+
+; our entry points:
+        xdef    _lm_init        ; void lm_init(int level, unsigned short *flags)
+        xdef    _lm_free        ; void lm_free(void)
+        xdef    _deflate        ; void deflate(void)  ...the big one
+        xdef    _fill_window    ; this line is just for debugging
+
+
+; ============================================================================
+; Here is where we have our global variables.
+
+        section deflatevars,data
+
+; external global variables we reference:
+        xref    _verbose        ; signed int
+        xref    _level          ; signed int
+        xref    _read_buf       ; int (*read_buf)(char *, unsigned int)
+
+; global variables we make available:
+
+        xdef    _window
+        xdef    _prev
+        xdef    _head
+        xdef    _window_size
+        xdef    _block_start
+        xdef    _strstart
+
+    IFD     DYN_ALLOC
+_prev:          ds.l    1       ; pointer to calloc()'d unsigned short array
+_head:          ds.l    1       ; pointer to calloc()'d unsigned short array
+_window:        ds.l    1       ; pointer to calloc()'d unsigned char array
+    ELSE    ; !DYN_ALLOC
+_prev:          ds.w    WSIZE           ; array of unsigned short
+_head:          ds.w    HASH_SIZE       ; array of unsigned short
+_window:        ds.b    2*WSIZE         ; array of unsigned char
+    ENDC    ; ?DYN_ALLOC
+_window_size:   ds.l    1               ; unsigned long
+_block_start:   ds.l    1               ; unsigned long
+_strstart:      ds.w    INTSIZE/2       ; unsigned int
+
+; Now here are our private variables:
+
+    IFD     CPUTEST
+is020:          ds.w    1       ; bool: CPU type is '020 or higher
+    ENDC
+ins_h:          ds.w    1       ; unsigned short
+sliding:        ds.w    1       ; bool: the file is read a piece at a time
+eofile:         ds.w    1       ; bool: we have read in the end of the file
+max_lazy_match: ds.w    1       ; unsigned short
+lookahead:      ds.w    1       ; unsigned short
+
+; These are NOT DECLARED AS STATIC in deflate.c, but currently could be:
+max_chain_len:  ds.w    1       ; unsigned short (unsigned int in deflate.c)
+prev_length:    ds.w    1       ; unsigned short (unsigned int in deflate.c)
+good_match:     ds.w    1       ; unsigned short (unsigned int in deflate.c)
+nice_match:     ds.w    1       ; unsigned short (signed int in deflate.c)
+match_start:    ds.w    1       ; unsigned short (unsigned int in deflate.c)
+
+; This array of struct config is a constant and could be in the code section:
+config_table:   dc.w    0,0,0,0         ; level 0: store uncompressed
+                dc.w    4,4,8,4         ; level 1: fastest, loosest compression
+                dc.w    4,5,16,8        ; level 2
+                dc.w    4,6,32,32       ; level 3: highest to use deflate_fast
+                dc.w    4,4,16,16       ; level 4: lowest to use lazy matches
+                dc.w    8,16,32,32      ; level 5
+                dc.w    8,16,128,128    ; level 6: the default level
+                dc.w    8,32,128,256    ; level 7
+                dc.w    32,128,258,1024 ; level 8
+                dc.w    32,258,258,4096 ; level 9: maximum compression, slow
+
+
+;;CAL_SH  MACRO                   ; macro for calling zcalloc()
+;;     IFD    INT16
+;;        move.w  #2,-(sp)
+;;        move.w  #\1,-(sp)
+;;        jsr     _zcalloc
+;;        addq    #4,sp
+;;     ELSE
+;;        pea     2
+;;        pea     \1
+;;        jsr     _zcalloc
+;;        addq    #8,sp
+;;     ENDC
+;;        ENDM
+
+CAL_SH  MACRO                   ; Okay, we're back to using regular calloc()...
+        pea     2
+        pea     \1
+        jsr     _calloc
+        addq    #8,sp
+        ENDM
+
+; ============================================================================
+; And here we begin our functions.  match_init is for internal use only:
+
+        section deflate,code
+
+match_init:
+    IFD     CPUTEST             ; now check for platform type
+     IFD    AMIGA               ; Amiga specific test for '020 CPU:
+        xref    _SysBase
+        NOLIST
+        INCLUDE       'exec/execbase.i'
+        LIST
+
+        clr.w   is020                   ; default value is 68000
+        move.l  _SysBase,a0
+        btst    #AFB_68020,AttnFlags+1(a0)
+        beq.s   cheap
+        move.w  #1,is020
+cheap:
+     ELSE   ; !AMIGA
+
+        FAIL    Write an '020-detector for your system here!
+; On the Macintosh, I believe GetEnvironment() provides the information.
+
+     ENDC   ; AMIGA
+    ENDC    ; CPUTEST
+        rts     ; match_init consists only of rts if CPUTEST unset
+
+
+; ============================================================================
+; Here is longest_match(), the function that the rest of this was built up
+; from, the hottest hot spot in the program and therefore the most heavily
+; optimized.  It has two different versions, one for '020 and higher CPUs, and
+; one for 68000/68010.  It can test at runtime which version to use if you
+; create a test function in match_init for your platform.  Currently such a
+; test is implemented for the Amiga.  It can also be assembled to use '000 or
+; '020 code only.
+
+Cur_Match       equr    d0              ; unsigned int, kept valid as long
+Best_Len        equr    d1              ; unsigned int, kept valid as long
+Scan_Start      equr    d3              ; pair of bytes
+Scan_End        equr    d4              ; pair of bytes
+Limit           equr    d5              ; unsigned int
+Chain_Length    equr    d6              ; unsigned int
+Scan_Test       equr    d7              ; counter, pair of bytes sometimes
+Scan            equr    a0              ; pointer to unsigned char
+Match           equr    a1              ; pointer to unsigned char
+Prev_Address    equr    a2              ; pointer to unsigned short
+Scan_Ini        equr    a3              ; pointer to unsigned char
+Match_Ini       equr    a5              ; pointer to unsigned char
+; Note: "pair of bytes" means the two low order bytes of the register in
+; 68020 code, but means the lowest and third lowest bytes on the 68000.
+    IFD     AMIGA
+SAVEREGS        reg     d3-d7/a2/a3/a5      ; don't protect d0/d1/a0/a1
+    ELSE    ; !AMIGA
+SAVEREGS        reg     d1/d3-d7/a0-a3/a5   ; protect all except d0 return val
+    ENDC    ; ?AMIGA
+; d2, a4, a6 not used... on Amiga, a4 is used by small-data memory model
+
+
+longest_match:
+        movem.l SAVEREGS,-(sp)
+
+; setup steps common to byte and word versions:
+    IFD     INT16
+        and.l   #$0000FFFF,Cur_Match    ; upper half must be zero!
+; we use an and.l down here for the sake of ATSIGN/REGARGS.
+        moveq   #0,Limit                ; so adding to Scan_Ini works
+    ENDC
+        move.w  max_chain_len,Chain_Length
+        move.w  prev_length,Best_Len
+        MOVINT  _strstart,Limit
+        BASEPTR _prev,Prev_Address
+        BASEPTR _window,Match_Ini
+        move.l  Match_Ini,Scan_Ini
+        addq    #MIN_MATCH,Match_Ini    ; optimizes inner loop
+        add.l   Limit,Scan_Ini
+        sub.w   #MAX_DIST,Limit
+        bhi.s   limit_ok
+        moveq   #0,Limit
+limit_ok:
+        cmp.w   good_match,Best_Len
+        blo.s   length_ok
+        lsr.w   #2,Chain_Length
+length_ok:
+        subq.w  #1,Chain_Length
+
+    IFD     CPUTEST
+        tst.w   is020                   ; can we use '020 stuff today?
+        bne     WORD_match
+    ENDC
+
+    IFND    CPU020
+
+; for 68000 or 68010, use byte operations:
+        moveq   #0,Scan_Start           ; clear 2nd & 4th bytes, use 1st & 3rd
+        moveq   #0,Scan_End             ; likewise
+        moveq   #0,Scan_Test            ; likewise
+        move.b  (Scan_Ini),Scan_Start
+        swap    Scan_Start              ; swap is faster than 8 bit shift
+        move.b  1(Scan_Ini),Scan_Start
+        move.b  -1(Scan_Ini,Best_Len.w),Scan_End
+        swap    Scan_End
+        move.b  0(Scan_Ini,Best_Len.w),Scan_End
+        bra.s   bdo_scan
+
+blong_loop:
+        move.b  -1(Scan_Ini,Best_Len.w),Scan_End
+        swap    Scan_End
+        move.b  0(Scan_Ini,Best_Len.w),Scan_End
+
+bshort_loop:
+        add.w   Cur_Match,Cur_Match     ; assert value before doubling < 32K
+     IFNE   32768-WSIZE
+        and.w   #(WMASK*2),Cur_Match
+     ENDC
+        move.w  (Prev_Address,Cur_Match.l),Cur_Match
+        cmp.w   Limit,Cur_Match
+        dbls    Chain_Length,bdo_scan
+        bra     return
+
+bdo_scan:
+        move.l  Match_Ini,Match
+        add.l   Cur_Match,Match
+        move.b  -MIN_MATCH-1(Match,Best_Len.w),Scan_Test
+        swap    Scan_Test
+        move.b  -MIN_MATCH(Match,Best_Len.w),Scan_Test
+        cmp.l   Scan_Test,Scan_End
+        bne.s   bshort_loop
+        move.b  -MIN_MATCH(Match),Scan_Test
+        swap    Scan_Test
+        move.b  -MIN_MATCH+1(Match),Scan_Test
+        cmp.l   Scan_Test,Scan_Start
+        bne.s   bshort_loop
+        move.w  #(MAX_MATCH-3),Scan_Test
+        lea     MIN_MATCH(Scan_Ini),Scan        ; offset optimizes inner loop
+
+bscan_loop:
+        cmp.b   (Match)+,(Scan)+
+        dbne    Scan_Test,bscan_loop
+        subq    #1,Scan
+
+        sub.l   Scan_Ini,Scan           ; assert difference is 16 bits
+        cmp.w   Best_Len,Scan
+        bls.s   bshort_loop
+        MOVINT  Scan,Best_Len
+        move.w  Cur_Match,match_start
+        cmp.w   nice_match,Best_Len
+        blo.s   blong_loop
+     IFD    CPUTEST
+        bra     return
+     ENDC
+
+    ENDC    ; !CPU020
+
+    IFND    CPU000
+        MACHINE MC68020
+
+; for 68020 or higher, use word operations even on odd addresses:
+WORD_match:
+        move.w  (Scan_Ini),Scan_Start
+        move.w  -1(Scan_Ini,Best_Len.w),Scan_End
+        bra.s   wdo_scan
+
+wlong_loop:
+        move.w  -1(Scan_Ini,Best_Len.w),Scan_End
+
+wshort_loop:
+        and.w   #WMASK,Cur_Match
+        move.w  (Prev_Address,Cur_Match.w*2),Cur_Match  ; '020 addressing mode
+        cmp.w   Limit,Cur_Match
+        dbls    Chain_Length,wdo_scan
+        bra.s   return
+
+wdo_scan:
+        move.l  Match_Ini,Match
+        add.l   Cur_Match,Match
+        cmp.w   -MIN_MATCH-1(Match,Best_Len.w),Scan_End
+        bne.s   wshort_loop
+        cmp.w   -MIN_MATCH(Match),Scan_Start
+        bne.s   wshort_loop
+     IFD    QUADLONG
+; By some measurements, this version of the code is a little tiny bit faster.
+; But on some files it's slower.  It probably pays off only when there are
+; long match strings, and costs in the most common case of three-byte matches.
+        moveq   #((MAX_MATCH-MIN_MATCH)/16),Scan_Test     ; value = 15
+        lea     MIN_MATCH(Scan_Ini),Scan        ; offset optimizes inner loop
+
+wscan_loop:
+        cmp.l   (Match)+,(Scan)+                ; test four bytes at a time
+        bne.s   odd
+        cmp.l   (Match)+,(Scan)+
+        bne.s   odd
+        cmp.l   (Match)+,(Scan)+
+        bne.s   odd
+        cmp.l   (Match)+,(Scan)+
+        dbne    Scan_Test,wscan_loop            ; '020 can cache a bigger loop
+odd:
+        subq    #4,Scan
+        subq    #4,Match
+        cmp.b   (Match)+,(Scan)+        ; find good bytes in bad longword
+        bne.s   even
+        cmp.b   (Match)+,(Scan)+
+        bne.s   even
+        cmp.b   (Match)+,(Scan)+
+        beq.s   steven
+even:   subq    #1,Scan
+     ELSE   ; !QUADLONG
+        moveq   #((MAX_MATCH-MIN_MATCH)/2),Scan_Test    ; value = 127
+        lea     MIN_MATCH(Scan_Ini),Scan        ; offset optimizes inner loop
+
+wscan_loop:
+        cmp.w   (Match)+,(Scan)+
+        dbne    Scan_Test,wscan_loop
+        subq    #2,Scan
+        move.b  -2(Match),Scan_Test
+        cmp.b   (Scan),Scan_Test
+        bne.s   steven
+        addq    #1,Scan
+     ENDC   ; ?QUADLONG
+steven:
+        sub.l   Scan_Ini,Scan           ; assert: difference is 16 bits
+        cmp.w   Best_Len,Scan
+        bls.s   wshort_loop
+        MOVINT  Scan,Best_Len
+        move.w  Cur_Match,match_start
+        cmp.w   nice_match,Best_Len
+        blo.s   wlong_loop
+
+        MACHINE MC68000
+    ENDC    ; !CPU000
+
+return:
+        MOVINT  Best_Len,d0         ; return value (upper half should be clear)
+        movem.l (sp)+,SAVEREGS
+        rts
+
+
+; =============================================================================
+; This is the deflate() function itself, our main entry point.  It calls
+; longest_match, above, and some outside functions.  It is a hot spot, but not
+; as hot as longest_match.  It uses no special '020 code.
+
+; ================== Several macros used in deflate() and later functions:
+
+; Arg 1 is D-reg that new ins_h value is to be left in,
+; arg 2 is the byte value to be hashed into it, which must not be the same reg
+UP_HASH MACRO
+        move.w  ins_h,\1
+        asl.w   #H_SHIFT,\1
+        eor.b   \2,\1
+        and.w   #HASH_MASK,\1           ; ((ins_h << H_SHIFT) ^ c) & HASH_MASK
+        move.w  \1,ins_h                ; ins_h = that
+        ENDM
+
+; Arg 1 is scratch A, arg 2 is scratch D
+IN_STR  MACRO
+        move.l  Strst,\2
+        addq.w  #MIN_MATCH-1,\2
+        move.b  (Window,\2.l),\2        ; window[strstart + MIN_MATCH - 1]
+        UP_HASH Head,\2
+        add.l   Head,Head               ; assert upper word is zero before add
+        BASEPTR _head,\1
+        add.l   Head,\1
+        move.w  (\1),Head               ; hash_head = head[ins_h]
+        move.w  Strst,(\1)              ; head[ins_h] = strstart
+        move.l  Strst,\2
+    IFNE    WSIZE-32768
+        and.w   #WMASK,\2
+    ENDC
+        add.w   \2,\2                   ; masks implicitly when WSIZE == 32768
+        move.w  Head,(Prev,\2.l)        ; prev[str_start & WMASK] = hash_head
+        ENDM
+
+; Arg 1 is bool (int) EOF flag, flush_block result is in d0, trashes d1/a0/a1
+FLUSH_B MACRO
+    IFC     '\1','#0'
+        CLRINT  -(sp)
+    ELSE
+        MOVINT  \1,-(sp)
+    ENDC
+        move.l  _block_start,d0
+        blt.s   nenu\@
+        move.l  Window,a0
+        add.l   d0,a0
+        bra.s   nun\@
+nenu\@: sub.l   a0,a0           ; if block_start < 0, push NULL
+nun\@:  sub.l   Strst,d0
+        neg.l   d0
+        move.l  d0,-(sp)
+        move.l  a0,-(sp)
+        jsr     _flush_block
+        lea     8+INTSIZE(sp),sp
+        ENDM
+
+; This expands to nothing unless DEBUG is defined.
+; Arg 1 is a byte to be trace-outputted -- if it is d0 it must be a valid int
+TRACE_C MACRO
+    IFD    DEBUG
+        cmp.w  #1,_verbose+INTSIZE-2    ; test lower word only
+        ble.s   qui\@
+     IFNC    '\1','d0'
+        moveq   #0,d0
+        move.b  \1,d0
+     ENDC
+        move.l  _stderr,-(sp)
+        MOVINT  d0,-(sp)
+        jsr     _fputc
+        addq    #4+INTSIZE,sp
+qui\@:
+    ENDC    ; DEBUG
+        ENDM
+
+; ================== Here are the register vars we use, and deflate() itself:
+
+Window  equr    a2              ; cached address of window[]
+Prev    equr    a3              ; cached address of prev[]
+Strst   equr    d7              ; strstart cached as a longword
+Look    equr    d6              ; lookahead cached as short
+Head    equr    d5              ; local variable hash_head, short
+PrevL   equr    d4              ; prev_length cached as short
+MatchL  equr    d3              ; local variable match_length, unsigned short
+Avail   equr    d2              ; local variable available_match, bool
+PrevM   equr    a5              ; local variable prev_match, int in an A-reg
+
+    IFD     AMIGA
+DEFREGS reg     d2-d7/a2/a3/a5
+    ELSE
+DEFREGS reg     d0-d7/a0/a2/a3/a5       ; play it safe, preserve all regs
+    ENDC
+
+
+_deflate:           ; first, setup steps common to deflate and deflate_fast:
+        movem.l DEFREGS,-(sp)
+    IFD     INT16
+        moveq   #0,Strst                ; make sure strstart is valid as a long
+    ENDC
+        moveq   #0,Head                 ; ditto for hash_head
+        MOVINT  _strstart,Strst
+        move.w  lookahead,Look
+        move.w  prev_length,PrevL
+        BASEPTR _window,Window
+        BASEPTR _prev,Prev
+        MOVINT  _level,d0
+        cmp.w   #3,d0
+        ble     deflate_fast
+        moveq   #MIN_MATCH-1,MatchL
+        moveq   #0,Avail
+
+look_loop:
+        tst.w   Look
+        beq     last_tally
+        IN_STR  a0,d0
+        move.w  MatchL,PrevL
+        move.w  match_start,PrevM
+        move.w  #MIN_MATCH-1,MatchL
+
+        tst.w   Head
+        beq.s   no_new_match
+        cmp.w   max_lazy_match,PrevL
+        bhs.s   no_new_match
+        move.w  Strst,d0
+        sub.w   Head,d0
+        cmp.w   #MAX_DIST,d0
+        bhi.s   no_new_match
+        move.w  PrevL,prev_length       ; longest_match reads these variables
+        MOVINT  Strst,_strstart
+        MOVINT  Head,d0                 ; parm for longest_match
+        bsr     longest_match           ; sets match_start
+        cmp.w   Look,d0                 ; does length exceed valid data?
+        bls.s   stml
+        move.w  Look,d0
+stml:   move.w  d0,MatchL               ; valid length of match
+        cmp.w   #MIN_MATCH,MatchL       ; is the match only three bytes?
+        bne.s   no_new_match
+        move.w  match_start,d0
+        sub.w   Strst,d0
+        cmp.w   #-TOO_FAR,d0
+        bge.s   no_new_match
+        moveq   #MIN_MATCH-1,MatchL     ; mark the current match as no good
+
+no_new_match:
+        cmp.w   #MIN_MATCH,PrevL
+        blo     literal
+        cmp.w   MatchL,PrevL
+        blo     literal
+        ; CHECK_MATCH   Strst-1,PrevM,PrevL
+        MOVINT  Strst,_strstart         ; ct_tally reads this variable
+        move.l  PrevL,d0
+        subq.w  #MIN_MATCH,d0
+        MOVINT  d0,-(sp)
+        move.l  Strst,d0
+        sub.w   PrevM,d0
+        subq.w  #1,d0
+        MOVINT  d0,-(sp)
+        jsr     _ct_tally               ; sets d0 true if we have to flush
+        addq    #2*INTSIZE,sp
+        subq.w  #3,PrevL                ; convert for dbra (prev_length - 2)
+        sub.w   PrevL,Look
+        subq.w  #2,Look
+insertmatch:
+        addq.w  #1,Strst
+        IN_STR  a0,d1                   ; don't clobber d0
+        dbra    PrevL,insertmatch
+        moveq   #0,Avail
+        moveq   #0,PrevL                ; not needed?
+        moveq   #MIN_MATCH-1,MatchL
+        addq.w  #1,Strst
+        tst.w   d0
+        beq     refill
+        FLUSH_B #0
+        move.l  Strst,_block_start
+        bra.s   refill
+
+literal:
+        tst.w   Avail
+        bne.s   yeslit
+        moveq   #1,Avail
+        bra.s   skipliteral
+yeslit: TRACE_C <-1(Window,Strst.l)>
+        MOVINT  Strst,_strstart         ; ct_tally reads this variable
+        moveq   #0,d0
+        move.b  -1(Window,Strst.l),d0
+        MOVINT  d0,-(sp)
+        CLRINT  -(sp)
+        jsr     _ct_tally
+        addq    #2*INTSIZE,sp
+        tst.w   d0
+        beq.s   skipliteral
+        FLUSH_B #0
+        move.l  Strst,_block_start
+skipliteral:
+        addq.w  #1,Strst
+        subq.w  #1,Look
+
+refill:
+        cmp.w   #MIN_LOOKAHEAD,Look
+        bhs     look_loop
+        bsr     fill_window
+        bra     look_loop
+
+last_tally:
+        tst.w   Avail
+        beq     last_flush
+        MOVINT  Strst,_strstart         ; ct_tally reads this variable
+        moveq   #0,d0
+        move.b  -1(Window,Strst.l),d0
+        MOVINT  d0,-(sp)
+        CLRINT  -(sp)
+        jsr     _ct_tally
+        addq    #2*INTSIZE,sp
+last_flush:
+        FLUSH_B #1
+        bra     deflate_exit
+
+; ================== This is another version used for low compression levels:
+
+deflate_fast:
+        moveq   #0,MatchL
+        moveq   #MIN_MATCH-1,PrevL
+flook_loop:
+        tst.w   Look
+        beq     flast_flush
+
+        IN_STR  a0,d0
+        tst.w   Head
+        beq.s   fno_new_match
+        move.w  Strst,d0
+        sub.w   Head,d0
+        cmp.w   #MAX_DIST,d0
+        bhi.s   fno_new_match
+        move.w  PrevL,prev_length       ; longest_match reads these variables
+        MOVINT  Strst,_strstart
+        MOVINT  Head,d0                 ; parm for longest_match
+        bsr     longest_match           ; sets match_start
+        cmp.w   Look,d0                 ; does length exceed valid data?
+        bls.s   fstml
+        move.w  Look,d0
+fstml:  move.w  d0,MatchL               ; valid length of match
+
+fno_new_match:
+        cmp.w   #MIN_MATCH,MatchL
+        blo     fliteral
+        ; CHECK_MATCH   Strst,match_start,MatchL
+        MOVINT  Strst,_strstart         ; ct_tally reads this variable
+        move.l  MatchL,d0
+        subq.w  #MIN_MATCH,d0
+        MOVINT  d0,-(sp)
+        move.l  Strst,d0
+        sub.w   match_start,d0
+        MOVINT  d0,-(sp)
+        jsr     _ct_tally               ; sets d0 true if we have to flush
+        addq    #2*INTSIZE,sp
+        sub.w   MatchL,Look
+        cmp.w   max_lazy_match,MatchL
+        bhi     ftoolong
+        subq.w  #2,MatchL
+finsertmatch:
+        addq.w  #1,Strst
+        IN_STR  a0,d1                   ; preserve d0
+        dbra    MatchL,finsertmatch
+        moveq   #0,MatchL               ; not needed?
+        addq.w  #1,Strst
+        bra.s   flushfill
+
+ftoolong:
+        add.w   MatchL,Strst
+        moveq   #0,MatchL
+        moveq   #0,d1                   ; preserve d0
+        move.b  (Window,Strst.l),d1
+        move.w  d1,ins_h
+; My assembler objects to passing <1(Window,Strst.l)> directly to UP_HASH...
+        move.b  1(Window,Strst.l),Avail ; Avail is not used in deflate_fast
+        UP_HASH d1,Avail                ; preserve d0
+    IFNE    MIN_MATCH-3
+        FAIL  needs to UP_HASH another MIN_MATCH-3 times, but with what arg?
+    ENDC
+        bra.s   flushfill
+
+fliteral:
+        TRACE_C <(Window,Strst.l)>
+        MOVINT  Strst,_strstart         ; ct_tally reads this variable
+        moveq   #0,d0
+        move.b  (Window,Strst.l),d0
+        MOVINT  d0,-(sp)
+        CLRINT  -(sp)
+        jsr     _ct_tally               ; d0 set if we need to flush
+        addq    #2*INTSIZE,sp
+        addq.w  #1,Strst
+        subq.w  #1,Look
+
+flushfill:
+        tst.w   d0
+        beq.s   frefill
+        FLUSH_B #0
+        move.l  Strst,_block_start
+frefill:
+        cmp.w   #MIN_LOOKAHEAD,Look
+        bhs     flook_loop
+        bsr     fill_window
+        bra     flook_loop
+
+flast_flush:
+        FLUSH_B #1                      ; sets our return value
+
+deflate_exit:
+        MOVINT  Strst,_strstart         ; save back cached values
+        move.w  PrevL,prev_length
+        move.w  Look,lookahead
+        movem.l (sp)+,DEFREGS
+        rts
+
+
+; =========================================================================
+; void fill_window(void) calls the input function to refill the sliding
+; window that we use to find substring matches in.
+
+More    equr    Head                    ; local variable in fill_window
+WindTop equr    Prev                    ; local variable used for sliding
+SlidIx  equr    PrevL                   ; local variable used for sliding
+
+    IFD     AMIGA
+FWREGS  reg     d2-d5/a2-a6             ; does NOT include Look and Strst
+    ELSE
+FWREGS  reg     d1-d5/a0-a6             ; likewise
+    ENDC
+; all registers available to be clobbered by the sliding operation:
+; we exclude More, WindTop, SlidIx, Look, Strst, Window, a4 and a7.
+SPAREGS reg     d0-d3/a0-a1/a5-a6
+SPCOUNT equ     8                       ; number of registers in SPAREGS
+
+
+_fill_window:                           ; C-callable entry point
+        movem.l Strst/Look,-(sp)
+    IFD     INT16
+        moveq   #0,Strst                ; Strst must be valid as a long
+    ENDC
+        MOVINT  _strstart,Strst
+        move.w  lookahead,Look
+        BASEPTR _window,Window
+        bsr.s   fill_window
+        MOVINT  Strst,_strstart
+        move.w  Look,lookahead
+        movem.l (sp)+,Strst/Look
+        rts
+
+; strstart, lookahead, and window must be cached in Strst, Look, and Window:
+fill_window:                            ; asm-callable entry point
+        movem.l FWREGS,-(sp)
+        tst.w   eofile                  ; we put this up here for speed
+        bne     fwdone
+        and.l   #$FFFF,Look             ; make sure Look is valid as long
+fw_refill:
+        move.l  _window_size,More       ; <= 64K
+        sub.l   Look,More
+        sub.l   Strst,More              ; Strst is already valid as long
+        cmp.w   #EOF,More
+        bne.s   notboundary
+        subq.w  #1,More
+        bra     checkend
+
+notboundary:
+        tst.w   sliding
+        beq     checkend
+        cmp.w   #WSIZE+MAX_DIST,Strst
+        blo     checkend
+    IFGT    32768-WSIZE
+        lea     WSIZE(Window),WindTop   ; WindTop is aligned when Window is
+    ELSE
+        move.l  Window,WindTop
+        add.l   #WSIZE,WindTop
+    ENDC
+        move.l  Window,d0
+        and.w   #3,d0
+        beq.s   isaligned
+        subq.w  #1,d0
+align:  move.b  (WindTop)+,(Window)+    ; copy up to a longword boundary
+        dbra    d0,align
+isaligned:
+; This is faster than a simple move.l (WindTop)+,(Window)+ / dbra loop:
+        move.w  #(WSIZE-1)/(4*SPCOUNT),SlidIx
+slide:  movem.l (WindTop)+,SPAREGS      ; copy, 32 bytes at a time!
+        movem.l SPAREGS,(Window)        ; a slight overshoot doesn't matter.
+        lea     4*SPCOUNT(Window),Window        ; can't use (aN)+ as movem.l dest
+        dbra    SlidIx,slide
+        BASEPTR _window,Window                  ; restore cached value
+        sub.w   #WSIZE,match_start
+        sub.w   #WSIZE,Strst
+        sub.l   #WSIZE,_block_start
+        add.w   #WSIZE,More
+        BASEPTR _head,a0
+        move.w  #HASH_SIZE-1,d0
+fixhead:
+        move.w  (a0),d1
+        sub.w   #WSIZE,d1
+        bpl.s   headok
+        moveq   #0,d1
+headok: move.w  d1,(a0)+
+        dbra    d0,fixhead
+        BASEPTR _prev,a0
+        move.w  #WSIZE-1,d0
+fixprev:
+        move.w  (a0),d1
+        sub.w   #WSIZE,d1
+        bpl.s   prevok
+        moveq   #0,d1
+prevok: move.w  d1,(a0)+
+        dbra    d0,fixprev
+        TRACE_C #'.'
+
+checkend:                               ; assert eofile is false
+        MOVINT  More,-(sp)              ; assert More's upper word is zero
+        move.l  Strst,d0
+        add.w   Look,d0
+        add.l   Window,d0
+        move.l  d0,-(sp)
+        move.l  _read_buf,a0
+        jsr     (a0)                    ; refill the upper part of the window
+        addq    #4+INTSIZE,sp
+        tst.w   d0
+        beq.s   iseof
+        cmp.w   #EOF,d0
+        beq.s   iseof
+        add.w   d0,Look
+        cmp.w   #MIN_LOOKAHEAD,Look
+        blo     fw_refill               ; eofile is still false
+
+        bra.s   fwdone
+iseof:  move.w  #1,eofile
+fwdone: movem.l (sp)+,FWREGS
+        rts
+
+
+; =========================================================================
+; void lm_free(void) frees dynamic arrays in the DYN_ALLOC version.
+
+        xdef    _lm_free                ; the entry point
+
+_lm_free:
+    IFD     DYN_ALLOC
+        move.l  _window,d0
+        beq.s   lf_no_window
+        move.l  d0,-(sp)
+        jsr     _free
+        addq    #4,sp
+        clr.l   _window
+lf_no_window:
+        move.l  _prev,d0
+        beq.s   lf_no_prev
+        move.l  d0,-(sp)
+        jsr     _free
+        move.l  _head,(sp)              ; reuse the same stack arg slot
+        jsr     _free
+        addq    #4,sp
+        clr.l   _prev
+        clr.l   _head
+lf_no_prev:
+    ENDC
+        rts
+
+; ============================================================================
+; void lm_init(int pack_level, unsigned short *flags) allocates dynamic arrays
+; if any, and initializes all variables so that deflate() is ready to go.
+
+        xdef    _lm_init                ; the entry point
+
+Level   equr    d2
+;Window equr    a2      ; as in deflate()
+    IFD     AMIGA
+INIREGS reg     d2/a2
+    ELSE
+INIREGS reg     d0-d2/a0-a1
+    ENDC
+
+_lm_init:
+        MOVINT  4(sp),d0
+        move.l  4+INTSIZE(sp),a0
+        movem.l INIREGS,-(sp)
+        move.w  d0,Level
+        cmp.w   #1,Level
+        blt.s   levelerr
+        bgt.s   try9
+        bset.b  #B_FAST,1(a0)
+try9:   cmp.w   #9,Level
+        bgt.s   levelerr
+        blt.s   levelok
+        bset.b  #B_SLOW,1(a0)
+        bra.s   levelok
+levelerr:
+        pea     level_message
+        jsr     _error                  ; never returns
+levelok:
+        clr.w   sliding
+        tst.l   _window_size
+        bne.s   gotawindowsize
+        move.w  #1,sliding
+        move.l  #2*WSIZE,_window_size
+gotawindowsize:
+
+        BASEPTR _window,Window
+    IFD     DYN_ALLOC
+        move.l  Window,d0               ; fake tst.l
+        bne.s   gotsomewind
+        CAL_SH  WSIZE
+        move.l  d0,Window
+        move.l  d0,_window
+        bne.s   gotsomewind
+        pea     window_message
+        MOVINT  #ZE_MEM,-(sp)
+        jsr     _ziperr                 ; never returns
+gotsomewind:
+        tst.l   _prev
+        bne.s   gotsomehead
+        CAL_SH  WSIZE
+        move.l  d0,_prev
+        beq.s   nohead
+        CAL_SH  HASH_SIZE
+        move.l  d0,_head
+        bne.s   gotfreshhead            ; newly calloc'd memory is zeroed
+nohead: pea     hash_message
+        MOVINT  #ZE_MEM,-(sp)
+        jsr     _ziperr                 ; never returns
+gotsomehead:
+    ENDC    ; DYN_ALLOC
+
+        move.w  #(HASH_SIZE/2)-1,d0     ; two shortwords per loop
+        BASEPTR _head,a0
+wipeh:  clr.l   (a0)+
+        dbra    d0,wipeh
+gotfreshhead:
+        move.l  Level,d0
+    IFEQ    Sizeof_config-8
+        asl.l   #3,d0
+    ELSE
+        mulu    #Sizeof_config,d0
+    ENDC
+        lea     config_table,a0
+        add.l   d0,a0
+        move.w  Max_lazy(a0),max_lazy_match
+        move.w  Good_length(a0),good_match
+        move.w  Nice_length(a0),nice_match
+        move.w  Max_chain(a0),max_chain_len
+        CLRINT  _strstart
+        clr.l   _block_start
+        bsr     match_init
+
+        clr.w   eofile
+        MOVINT  #WSIZE,-(sp)    ; We read only 32K because lookahead is short
+        move.l  Window,-(sp)    ; even when int size is long, as if deflate.c
+        move.l  _read_buf,a0    ; were compiled with MAXSEG_64K defined.
+        jsr     (a0)
+        addq    #4+INTSIZE,sp
+        move.w  d0,lookahead
+        beq.s   noread
+        cmp.w   #EOF,d0
+        bne.s   irefill
+noread: move.w  #1,eofile
+        clr.w   lookahead
+        bra.s   init_done
+
+irefill:
+        move.w  lookahead,d0
+        cmp.w   #MIN_LOOKAHEAD,d0
+        bhs.s   hashify
+        bsr     _fill_window            ; use the C-callable version
+hashify:
+        clr.w   ins_h
+        moveq   #MIN_MATCH-2,d0
+hash1:  move.b  (Window)+,d1
+        UP_HASH Level,d1
+        dbra    d0,hash1
+
+init_done:
+        movem.l (sp)+,INIREGS
+        rts
+
+; strings for error messages:
+hash_message    dc.b    'hash table allocation',0
+window_message  dc.b    'window allocation',0
+level_message   dc.b    'bad pack level',0
+
+        end
diff --git a/amiga/filedate.c b/amiga/filedate.c
new file mode 100644 (file)
index 0000000..9ccbdda
--- /dev/null
@@ -0,0 +1,599 @@
+/*
+  Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* Low-level Amiga routines shared between Zip and UnZip.
+ *
+ * Contains:  FileDate()
+ *            getenv()          [replaces inadequate standard library version]
+ *            setenv()          [SAS/C only, replaces standard library version]
+ *            set_TZ()          [SAS/C only]
+ *            GetPlatformLocalTimezone() [callback from timezone.c tzset()]
+ *            time()
+ *            sendpkt()
+ *            Agetch()
+ *
+ * The first five are used by most Info-ZIP programs except fUnZip.
+ * The last two are used by all except the non-CRYPT version of fUnZip.
+ * Probably some of the stuff in here is unused by ZipNote and ZipSplit too...
+ * sendpkt() is used by Agetch() and FileDate(), and by screensize() in
+ * amiga/amiga.c (UnZip); time() is used only by Zip.
+ */
+
+
+/* HISTORY/CHANGES
+ *  2 Sep 92, Greg Roelofs, Original coding.
+ *  6 Sep 92, John Bush, Incorporated into UnZip 5.1
+ *  6 Sep 92, John Bush, Interlude "FileDate()" defined, which calls or
+ *            redefines SetFileDate() depending upon AMIGADOS2 definition.
+ * 11 Oct 92, John Bush, Eliminated AMIGADOS2 switch by determining
+ *            revision via OpenLibrary() call.  Now only one version of
+ *            the program runs on both platforms (1.3.x vs. 2.x)
+ * 11 Oct 92, John Bush, Merged with Zip version and changed arg passing
+ *            to take time_t input instead of struct DateStamp.
+ *            Arg passing made to conform with utime().
+ * 22 Nov 92, Paul Kienitz, fixed includes for Aztec and cleaned up some
+ *            lint-ish errors; simplified test for AmigaDOS version.
+ * 11 Nov 95, Paul Kienitz, added Agetch() for crypt password input and
+ *            UnZip's "More" prompt -- simplifies crypt.h and avoids
+ *            use of library code redundant with sendpkt().  Made it
+ *            available to fUnZip, which does not use FileDate().
+ * 22 Nov 95, Paul Kienitz, created a new tzset() that gets the current
+ *            timezone from the Locale preferences.  These exist only under
+ *            AmigaDOS 2.1 and up, but it is probably correctly set on more
+ *            Amigas than the TZ environment variable is.  We check that
+ *            only if TZ is not validly set.  We do not parse daylight
+ *            savings syntax except to check for presence vs. absence of a
+ *            DST part; United States rules are assumed.  This is better
+ *            than the tzset()s in the Amiga compilers' libraries do.
+ * 15 Jan 96, Chr. Spieler, corrected the logic when to select low level
+ *            sendpkt() (when FileDate(), Agetch() or windowheight() is used),
+ *            and AMIGA's Agetch() (CRYPT, and UnZip(SFX)'s UzpMorePause()).
+ * 10 Feb 96, Paul Kienitz, re-fiddled that selection logic again, moved
+ *            stuff around for clarity.
+ * 16 Mar 96, Paul Kienitz, created a replacement localtime() to go with the
+ *            new tzset(), because Aztec's is hopelessly broken.  Also
+ *            gmtime(), which localtime() calls.
+ * 12 Apr 96, Paul Kienitz, daylight savings was being handled incorrectly.
+ * 21 Apr 96, Paul Kienitz, had to replace time() as well, Aztec's returns
+ *            local time instead of GMT.  That's why their localtime() was bad,
+ *            because it assumed time_t was already local, and gmtime() was
+ *            the one that checked TZ.
+ * 23 Apr 96, Chr. Spieler, deactivated time() replacement for UnZip stuff.
+ *            Currently, the UnZip sources do not make use of time() (and do
+ *            not supply the working mktime() replacement, either!).
+ * 29 Apr 96, Paul Kienitz, created a replacement getenv() out of code that
+ *            was previously embedded in tzset(), for reliable global test
+ *            of whether TZ is set or not.
+ * 19 Jun 96, Haidinger Walter, re-adapted for current SAS/C compiler.
+ *  7 Jul 96, Paul Kienitz, smoothed together compiler-related changes.
+ *  4 Feb 97, Haidinger Walter, added set_TZ() for SAS/C.
+ * 23 Apr 97, Paul Kienitz, corrected Unix->Amiga DST error by adding
+ *            mkgmtime() so localtime() could be used.
+ * 28 Apr 97, Christian Spieler, deactivated mkgmtime() definition for ZIP;
+ *            the Zip sources supply this function as part of util.c.
+ * 24 May 97, Haidinger Walter, added time_lib support for SAS/C and moved
+ *            set_TZ() to time_lib.c.
+ * 12 Jul 97, Paul Kienitz, adapted time_lib stuff for Aztec.
+ * 26 Jul 97, Chr. Spieler, old mkgmtime() fixed (ydays[] def, sign vs unsign).
+ * 30 Dec 97, Haidinger Walter, adaptation for SAS/C using z-stat.h functions.
+ * 19 Feb 98, Haidinger Walter, removed alloc_remember, more SAS.C fixes.
+ * 23 Apr 98, Chr. Spieler, removed mkgmtime(), changed FileDate to convert to
+ *            Amiga file-time directly.
+ * 24 Apr 98, Paul Kienitz, clip Unix dates earlier than 1978 in FileDate().
+ * 02 Sep 98, Paul Kienitz, C. Spieler, always include zip.h to get a defined
+ *            header inclusion sequence that resolves all header dependencies.
+ * 06 Jun 00, Paul Kienitz, removed time_lib.c due to its incompatible license,
+ *            moved set_TZ() back here, replaced minimal tzset() and localtime()
+ *            with new versions derived from GNU glibc source.  Gave locale_TZ()
+ *            reasonable European defaults for daylight savings.
+ * 17 Jun 00, Paul Kienitz, threw out GNU code because of objections to the GPL
+ *            virus, replaced with similar functions based on the public domain
+ *            timezone code at ftp://elsie.nci.nih.gov/pub.  As with the GNU
+ *            stuff, support for timezone files and leap seconds was removed.
+ * 23 Aug 00, Paul Kienitz, moved timezone code out from here into separate
+ *            platform-independent module 'timezone.c'.
+ * 31 Dec 00, Christian Spieler, moved system-specific timezone help funcions
+ *            back in here, from 'timezone.c'.
+ * 07 Jan 01, Paul Kienitz, Chr. Spieler, added missing #include "timezone.h"
+ *            and "symbolic" preprocessor constants for time calculations.
+ * 15 Jan 02, Paul Kienitz, excluded all time handling code from compilation
+ *            for Zip utilities (when "defined(UTIL)")
+ */
+
+#ifndef __amiga_filedate_c
+#define __amiga_filedate_c
+
+
+#include "zip.h"
+#include <ctype.h>
+#include <errno.h>
+
+#include <exec/types.h>
+#include <exec/execbase.h>
+#include <exec/memory.h>
+#include <dos/dosextens.h>
+
+#ifdef AZTEC_C
+#  include <libraries/dos.h>
+#  include <libraries/dosextens.h>
+#  include <clib/exec_protos.h>
+#  include <clib/dos_protos.h>
+#  include <clib/locale_protos.h>
+#  include <pragmas/exec_lib.h>
+#  include <pragmas/dos_lib.h>
+#  include <pragmas/locale_lib.h>
+#  define ESRCH  ENOENT
+#  define EOSERR EIO
+#endif
+
+#ifdef __SASC
+#  include <stdlib.h>
+#  if (defined(_M68020) && (!defined(__USE_SYSBASE)))
+                            /* on 68020 or higher processors it is faster   */
+#    define __USE_SYSBASE   /* to use the pragma libcall instead of syscall */
+#  endif                    /* to access functions of the exec.library      */
+#  include <proto/exec.h>   /* see SAS/C manual:part 2,chapter 2,pages 6-7  */
+#  include <proto/dos.h>
+#  include <proto/locale.h>
+#  ifdef DEBUG
+#     include <sprof.h>
+#  endif
+#  ifdef MWDEBUG
+#    include <stdio.h>      /* include both before memwatch.h again just */
+#    include <stdlib.h>     /* to be safe */
+#    include "memwatch.h"
+#  endif /* MWDEBUG */
+#endif /* __SASC */
+
+#include "crypt.h"            /* just so we can tell if CRYPT is supported */
+
+
+#if (!defined(FUNZIP) && !defined(UTIL))
+
+#include "timezone.h"         /* for AMIGA-specific timezone callbacks */
+
+#ifndef SUCCESS
+#  define SUCCESS (-1L)
+#  define FAILURE 0L
+#endif
+
+#define ReqVers 36L        /* required library version for SetFileDate() */
+#define ENVSIZE 100        /* max space allowed for an environment var   */
+
+extern struct ExecBase *SysBase;
+
+#ifndef min
+#  define min(a, b)  ((a) < (b) ? (a) : (b))
+#  define max(a, b)  ((a) < (b) ? (b) : (a))
+#endif
+
+#if defined(ZIP) || defined(HAVE_MKTIME)
+static const unsigned short ydays[] =
+    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
+#else
+extern const unsigned short ydays[];  /* in unzip's fileio.c */
+#endif
+
+#define LEAP(y)     (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
+#define YDAYS(m, y) (ydays[m] + (m > 1 && LEAP(y)))
+/* Number of leap years from 1978 to `y' (not including `y' itself). */
+#define ANLEAP(y)   (((y) - 1977) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
+#define SECSPERMIN  60
+#define MINSPERHOUR 60
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY  86400L
+
+/* prototypes */
+char *getenv(const char *var);
+#ifdef __SASC
+/*  XXX !!  We have really got to find a way to operate without these. */
+int setenv(const char *var, const char *value, int overwrite);
+void set_TZ(long time_zone, int day_light);
+#endif
+
+LONG FileDate(char *filename, time_t u[]);
+LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs);
+int Agetch(void);
+
+/* =============================================================== */
+
+/***********************/
+/* Function filedate() */
+/***********************/
+
+/*  FileDate() (originally utime.c), by Paul Wells.  Modified by John Bush
+ *  and others (see also sendpkt() comments, below); NewtWare SetFileDate()
+ *  clone cheaply ripped off from utime().
+ */
+
+/* DESCRIPTION
+ * This routine chooses between 2 methods to set the file date on AMIGA.
+ * Since AmigaDOS 2.x came out, SetFileDate() was available in ROM (v.36
+ * and higher).  Under AmigaDOS 1.3.x (less than v.36 ROM), SetFileDate()
+ * must be accomplished by constructing a message packet and sending it
+ * to the file system handler of the file to be stamped.
+ *
+ * The system's ROM version is extracted from the external system Library
+ * base.
+ *
+ * NOTE:  although argument passing conforms with utime(), note the
+ *        following differences:
+ *          - Return value is boolean success/failure.
+ *          - If a structure or array is passed, only the first value
+ *            is used, which *may* correspond to date accessed and not
+ *            date modified.
+ */
+
+LONG FileDate(filename, u)
+    char *filename;
+    time_t u[];
+{
+    LONG SetFileDate(UBYTE *filename, struct DateStamp *pDate);
+    LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs);
+    struct MsgPort *taskport;
+    BPTR dirlock, lock;
+    struct FileInfoBlock *fib;
+    LONG pktargs[4];
+    UBYTE *ptr;
+    long ret;
+
+    struct DateStamp pDate;
+    struct tm *ltm;
+    int years;
+
+    tzset();
+    /* Amiga file date is based on 01-Jan-1978 00:00:00 (local time):
+     * 8 years and 2 leapdays difference from Unix time.
+     */
+    ltm = localtime(&u[0]);
+    years = ltm->tm_year + 1900;
+    if (years < 1978)
+        pDate.ds_Days = pDate.ds_Minute = pDate.ds_Tick = 0;
+    else {
+        pDate.ds_Days = (years - 1978) * 365L + (ANLEAP(years)) +
+                        YDAYS(ltm->tm_mon, years) + (ltm->tm_mday - 1);
+        pDate.ds_Minute = ltm->tm_hour * 60 + ltm->tm_min;
+        pDate.ds_Tick = ltm->tm_sec * TICKS_PER_SECOND;
+    }
+
+    if (SysBase->LibNode.lib_Version >= ReqVers)
+    {
+        return (SetFileDate(filename,&pDate));  /* native routine at 2.0+ */
+    }
+    else  /* !(SysBase->lib_Version >=ReqVers) */
+    {
+        if( !(taskport = (struct MsgPort *)DeviceProc(filename)) )
+        {
+            errno = ESRCH;          /* no such process */
+            return FAILURE;
+        }
+
+        if( !(lock = Lock(filename,SHARED_LOCK)) )
+        {
+            errno = ENOENT;         /* no such file */
+            return FAILURE;
+        }
+
+        if( !(fib = (struct FileInfoBlock *)AllocMem(
+            (long)sizeof(struct FileInfoBlock),MEMF_PUBLIC|MEMF_CLEAR)) )
+        {
+            errno = ENOMEM;         /* insufficient memory */
+            UnLock(lock);
+            return FAILURE;
+        }
+
+        if( Examine(lock,fib)==FAILURE )
+        {
+            errno = EOSERR;         /* operating system error */
+            UnLock(lock);
+            FreeMem(fib,(long)sizeof(*fib));
+            return FAILURE;
+        }
+
+        dirlock = ParentDir(lock);
+        ptr = (UBYTE *)AllocMem(64L,MEMF_PUBLIC);
+        strcpy((ptr+1),fib->fib_FileName);
+        *ptr = strlen(fib->fib_FileName);
+        FreeMem(fib,(long)sizeof(*fib));
+        UnLock(lock);
+
+        /* now fill in argument array */
+
+        pktargs[0] = 0;
+        pktargs[1] = (LONG)dirlock;
+        pktargs[2] = (LONG)&ptr[0] >> 2;
+        pktargs[3] = (LONG)&pDate;
+
+        errno = ret = sendpkt(taskport,ACTION_SET_DATE,pktargs,4L);
+
+        FreeMem(ptr,64L);
+        UnLock(dirlock);
+
+        return SUCCESS;
+    }  /* ?(SysBase->lib_Version >= ReqVers) */
+} /* FileDate() */
+
+
+char *getenv(const char *var)         /* not reentrant! */
+{
+    static char space[ENVSIZE];
+    struct Process *me = (void *) FindTask(NULL);
+    void *old_window = me->pr_WindowPtr;
+    char *ret = NULL;
+
+    me->pr_WindowPtr = (void *) -1;   /* suppress any "Please insert" popups */
+    if (SysBase->LibNode.lib_Version >= ReqVers) {
+        if (GetVar((char *) var, space, ENVSIZE - 1, /*GVF_GLOBAL_ONLY*/ 0) > 0)
+            ret = space;
+    } else {                    /* early AmigaDOS, get env var the crude way */
+        BPTR hand, foot, spine;
+        int z = 0;
+        if (foot = Lock("ENV:", ACCESS_READ)) {
+            spine = CurrentDir(foot);
+            if (hand = Open((char *) var, MODE_OLDFILE)) {
+                z = Read(hand, space, ENVSIZE - 1);
+                Close(hand);
+            }
+            UnLock(CurrentDir(spine));
+        }
+        if (z > 0) {
+            space[z] = '\0';
+            ret = space;
+        }
+    }
+    me->pr_WindowPtr = old_window;
+    return ret;
+}
+
+#ifdef __SASC
+int setenv(const char *var, const char *value, int overwrite)
+{
+    struct Process *me = (void *) FindTask(NULL);
+    void *old_window = me->pr_WindowPtr;
+    int ret = -1;
+
+    me->pr_WindowPtr = (void *) -1;   /* suppress any "Please insert" popups */
+    if (SysBase->LibNode.lib_Version >= ReqVers)
+        ret = !SetVar((char *)var, (char *)value, -1, GVF_GLOBAL_ONLY | LV_VAR);
+    else {
+        BPTR hand, foot, spine;
+        long len = value ? strlen(value) : 0;
+        if (foot = Lock("ENV:", ACCESS_READ)) {
+            spine = CurrentDir(foot);
+            if (len) {
+                if (hand = Open((char *) var, MODE_NEWFILE)) {
+                    ret = Write(hand, (char *) value, len + 1) >= len;
+                    Close(hand);
+                }
+            } else
+                ret = DeleteFile((char *) var);
+            UnLock(CurrentDir(spine));
+        }
+    }
+    me->pr_WindowPtr = old_window;
+    return ret;
+}
+
+/* Stores data from timezone and daylight to ENV:TZ.                  */
+/* ENV:TZ is required to exist by some other SAS/C library functions, */
+/* like stat() or fstat().                                            */
+void set_TZ(long time_zone, int day_light)
+{
+    char put_tz[MAXTIMEZONELEN];  /* string for putenv: "TZ=aaabbb:bb:bbccc" */
+    int offset;
+    void *exists;     /* dummy ptr to see if global envvar TZ already exists */
+    exists = (void *)getenv(TZ_ENVVAR);
+    /* see if there is already an envvar TZ_ENVVAR. If not, create it */
+    if (exists == NULL) {
+        /* create TZ string by pieces: */
+        sprintf(put_tz, "GMT%+ld", time_zone / 3600L);
+        if (time_zone % 3600L) {
+            offset = (int) labs(time_zone % 3600L);
+            sprintf(put_tz + strlen(put_tz), ":%02d", offset / 60);
+            if (offset % 60)
+                sprintf(put_tz + strlen(put_tz), ":%02d", offset % 60);
+        }
+        if (day_light)
+            strcat(put_tz,"DST");
+        setenv(TZ_ENVVAR, put_tz, 1);
+    }
+}
+#endif /* __SASC */
+
+/* set state as well as possible from settings found in locale.library */
+int GetPlatformLocalTimezone(sp, fill_tzstate_from_rules)
+     register struct state * ZCONST sp;
+     void (*fill_tzstate_from_rules)(struct state * ZCONST sp_res,
+                                     ZCONST struct rule * ZCONST start,
+                                     ZCONST struct rule * ZCONST end);
+{
+    struct Library *LocaleBase;
+    struct Locale *ll;
+    struct Process *me = (void *) FindTask(NULL);
+    void *old_window = me->pr_WindowPtr;
+    BPTR eh;
+    int z, valid = FALSE;
+
+    /* read timezone from locale.library if TZ envvar missing */
+    me->pr_WindowPtr = (void *) -1;   /* suppress any "Please insert" popups */
+    if (LocaleBase = OpenLibrary("locale.library", 0)) {
+        if (ll = OpenLocale(NULL)) {
+            z = ll->loc_GMTOffset;    /* in minutes */
+            if (z == -300) {
+                if (eh = Lock("ENV:sys/locale.prefs", ACCESS_READ)) {
+                    UnLock(eh);
+                    valid = TRUE;
+                } else
+                    z = 300; /* bug: locale not initialized, default bogus! */
+            } else
+                valid = TRUE;
+            if (valid) {
+                struct rule startrule, stoprule;
+
+                sp->timecnt = 0;
+                sp->typecnt = 1;
+                sp->charcnt = 2;
+                sp->chars[0] = sp->chars[1] = '\0';
+                sp->ttis[0].tt_abbrind = 0;
+                sp->ttis[1].tt_abbrind = 1;
+                sp->ttis[0].tt_gmtoff = -z * MINSPERHOUR;
+                sp->ttis[1].tt_gmtoff = -z * MINSPERHOUR + SECSPERHOUR;
+                sp->ttis[0].tt_isdst = 0;
+                sp->ttis[1].tt_isdst = 1;
+                stoprule.r_type = MONTH_NTH_DAY_OF_WEEK;
+                stoprule.r_day = 0;
+                stoprule.r_week = 5;
+                stoprule.r_mon = 10;
+                stoprule.r_time = 2 * SECSPERHOUR;
+                startrule = stoprule;
+                startrule.r_mon = 4;
+                startrule.r_week = 1;
+                if (z >= -180 && z < 150) {
+                    /* At this point we make a really gratuitous assumption: */
+                    /* if the time zone could be Europe, we use the European */
+                    /* Union rules without checking what country we're in.   */
+                    /* The AmigaDOS locale country codes do not, at least in */
+                    /* 2.x versions of the OS, recognize very many countries */
+                    /* outside of Europe and North America.                  */
+                    sp->typecnt = 2;
+                    startrule.r_mon = 3;   /* one week earlier than US DST */
+                    startrule.r_week = 5;
+                } else if (z >= 150 && z <= 480 &&
+                           /* no DST in alaska, hawaii */
+                           (ll->loc_CountryCode == 0x55534100 /*"USA"*/ ||
+                            ll->loc_CountryCode == 0x43414E00 /*"CAN"*/))
+                    sp->typecnt = 2;
+                    /* We check the country code for U.S. or Canada because */
+                    /* most of Latin America has no DST.  Even in these two */
+                    /* countries there are some exceptions...               */
+                /* else if...  Feel free to add more cases here! */
+
+                if (sp->typecnt > 1)
+                    (*fill_tzstate_from_rules)(sp, &startrule, &stoprule);
+            }
+            CloseLocale(ll);
+        }
+        CloseLibrary(LocaleBase);
+    }
+    me->pr_WindowPtr = old_window;
+    return valid;
+}
+
+#ifdef ZIP
+time_t time(time_t *tp)
+{
+    time_t t;
+    struct DateStamp ds;
+    DateStamp(&ds);
+    t = ds.ds_Tick / TICKS_PER_SECOND + ds.ds_Minute * 60
+                                      + (ds.ds_Days + 2922) * SECSPERDAY;
+    t = mktime(gmtime(&t));
+    /* gmtime leaves ds in the local timezone, mktime converts it to GMT */
+    if (tp) *tp = t;
+    return t;
+}
+#endif /* ZIP */
+
+#endif /* !FUNZIP && !UTIL */
+
+
+#if CRYPT || !defined(FUNZIP)
+
+/*  sendpkt.c
+ *  by A. Finkel, P. Lindsay, C. Sheppner
+ *  returns Res1 of the reply packet
+ */
+/*
+#include <exec/types.h>
+#include <exec/memory.h>
+#include <libraries/dos.h>
+#include <libraries/dosextens.h>
+#include <proto/exec.h>
+#include <proto/dos.h>
+*/
+
+LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs);
+
+LONG sendpkt(pid,action,args,nargs)
+struct MsgPort *pid;           /* process identifier (handler message port) */
+LONG action,                   /* packet type (desired action)              */
+     *args,                    /* a pointer to argument list                */
+     nargs;                    /* number of arguments in list               */
+{
+
+    struct MsgPort *replyport, *CreatePort(UBYTE *, long);
+    void DeletePort(struct MsgPort *);
+    struct StandardPacket *packet;
+    LONG count, *pargs, res1;
+
+    replyport = CreatePort(NULL,0L);
+    if( !replyport ) return(0);
+
+    packet = (struct StandardPacket *)AllocMem(
+            (long)sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR);
+    if( !packet )
+    {
+        DeletePort(replyport);
+        return(0);
+    }
+
+    packet->sp_Msg.mn_Node.ln_Name  = (char *)&(packet->sp_Pkt);
+    packet->sp_Pkt.dp_Link          = &(packet->sp_Msg);
+    packet->sp_Pkt.dp_Port          = replyport;
+    packet->sp_Pkt.dp_Type          = action;
+
+    /* copy the args into the packet */
+    pargs = &(packet->sp_Pkt.dp_Arg1);      /* address of 1st argument */
+    for( count=0; count<nargs; count++ )
+        pargs[count] = args[count];
+
+    PutMsg(pid,(struct Message *)packet);   /* send packet */
+
+    WaitPort(replyport);
+    GetMsg(replyport);
+
+    res1 = packet->sp_Pkt.dp_Res1;
+
+    FreeMem((char *)packet,(long)sizeof(*packet));
+    DeletePort(replyport);
+
+    return(res1);
+
+} /* sendpkt() */
+
+#endif /* CRYPT || !FUNZIP */
+
+
+#if CRYPT || (defined(UNZIP) && !defined(FUNZIP))
+
+/* Agetch() reads one raw keystroke -- uses sendpkt() */
+
+int Agetch(void)
+{
+    LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs);
+    struct Task *me = FindTask(NULL);
+    struct CommandLineInterface *cli = BADDR(((struct Process *) me)->pr_CLI);
+    BPTR fh = cli->cli_StandardInput;   /* this is immune to < redirection */
+    void *conp = ((struct FileHandle *) BADDR(fh))->fh_Type;
+    char longspace[8];
+    long *flag = (long *) ((ULONG) &longspace[4] & ~3); /* LONGWORD ALIGNED! */
+    UBYTE c;
+
+    *flag = 1;
+    sendpkt(conp, ACTION_SCREEN_MODE, flag, 1);         /* assume success */
+    Read(fh, &c, 1);
+    *flag = 0;
+    sendpkt(conp, ACTION_SCREEN_MODE, flag, 1);
+    if (c == 3)                                         /* ^C in input */
+        Signal(me, SIGBREAKF_CTRL_C);
+    return c;
+}
+
+#endif /* CRYPT || (UNZIP && !FUNZIP) */
+
+#endif /* __amiga_filedate_c*/
diff --git a/amiga/makefile.azt b/amiga/makefile.azt
new file mode 100644 (file)
index 0000000..d9390c8
--- /dev/null
@@ -0,0 +1,304 @@
+# Makefile for Zip, ZipNote, ZipCloak, ZipSplit for Aztec C 5.2
+# Also ZipLM, a version of Zip that needs much less free memory
+#   -- Paul Kienitz, last updated 07 Jan 2007
+
+# Make sure platform is defined correctly, and select memory usage options:
+DEFINES = -d AMIGA -d DYN_ALLOC -d ASM_CRC
+
+CC = cc
+AS = as
+LD = ln
+LDLIBS = -lc16
+
+
+# -------- RELEASE VERSION:
+CFLAGS = -psb0e -sabfmnpu -wcr0u $(DEFINES)
+# -pbs means unsigned chars and short ints, -sabfmnpu is various small
+# optimizations, -wcr0u adjusts type checking strictness
+ASOPTS = -n -eAMIGA -eDYN_ALLOC -eCPUTEST -eINT16
+LDFLAGS = -m +q
+
+# -------- DEBUG VERSION:
+CFLAGD = -bs -psb0e -s0f0n -wcr0u $(DEFINES)
+# -bs is include source debugging info, -s0f0n is avoid hard-to-debug
+# optimizations
+LDFLAGD = -m +q -g -w
+
+# -------- MINIMUM MEMORY USAGE RELEASE VERSION:
+WSIZ = WSIZE=4096
+LOWFLAGS = $(CFLAGS) -d $(WSIZ) -d SMALL_MEM
+LOWASOPTS = $(ASOPTS) -e$(WSIZ) -eSMALL_MEM
+# Options used for assembling amiga/deflate.a; must generally match the
+# settings in DEFINES.
+
+# -------- MINIMUM MEMORY USAGE DEBUG VERSION:
+LOWFLAGD = $(CFLAGD) -d $(WSIZ) -d SMALL_MEM
+
+# the directory where we stick all the object files:
+O = obA/
+
+
+# default C rules
+.c.o :
+       $(CC) $(CFLAGS) -o $@ $*.c
+
+# rules for routines containing entries needed by utilities
+.c.oo :
+       $(CC) $(CFLAGS) -d UTIL -o $@ $*.c
+
+# rules for the low-memory version:
+
+.c.ol :
+       $(CC) $(LOWFLAGS) -o $@ $*.c
+
+# default C rules for debugging
+.c.od :
+       $(CC) $(CFLAGD) -o $@ $*.c
+
+# debugging rules for routines containing entries needed by utilities
+.c.dd :
+       $(CC) $(CFLAGD) -d UTIL -o $@ $*.c
+
+# rules for the debugging low-memory version:
+
+.c.dl :
+       $(CC) $(LOWFLAGD) -o $@ $*.c
+
+
+# object file lists
+
+ZIP_H = zip.h ziperr.h tailor.h amiga/osdep.h amiga/z-stat.h
+
+
+OBJZ = $(O)zip.o $(O)deflate.o \
+        $(O)trees.o $(O)zipfile.o $(O)zipup.o $(O)util.o $(O)timezone.o \
+        $(O)fileio.o $(O)globals.o $(O)crc32.o $(O)crypt.o $(O)ttyio.o \
+        $(O)amiga.o $(O)amigazip.o $(O)crc_68.o
+
+OBJL = $(O)zip.ol $(O)deflate.ol \
+        $(O)trees.ol $(O)zipfile.ol $(O)zipup.ol $(O)util.ol $(O)timezone.ol \
+        $(O)fileio.ol $(O)globals.ol $(O)crc32.ol $(O)crypt.ol $(O)ttyio.ol \
+        $(O)amiga.ol $(O)amigazip.ol $(O)crc_68.o
+
+OBJU = $(O)zipfile.oo $(O)fileio.oo \
+        $(O)util.oo $(O)globals.o $(O)amiga.oo $(O)amigazip.oo
+OBJN = $(O)zipnote.o  $(OBJU)
+OBJC = $(O)zipcloak.o $(OBJU) $(O)crc32.oo \
+        $(O)crypt.oo $(O)ttyio.o
+OBJS = $(O)zipsplit.o $(OBJU)
+
+# These are the debuggable versions:
+
+DBJZ = $(O)zip.od $(O)deflate.od \
+        $(O)trees.od $(O)zipfile.od $(O)zipup.od $(O)util.od $(O)timezone.od \
+        $(O)fileio.od $(O)globals.od $(O)crc32.od $(O)crypt.od $(O)ttyio.od \
+        $(O)amiga.od $(O)amigazip.od $(O)crc_68.o
+
+DBJL = $(O)zip.dl $(O)deflate.dl \
+        $(O)trees.dl $(O)zipfile.dl $(O)zipup.dl $(O)util.dl $(O)timezone.dl \
+        $(O)fileio.dl $(O)globals.dl $(O)crc32.dl $(O)crypt.dl $(O)ttyio.dl \
+        $(O)amiga.dl $(O)amigazip.dl $(O)crc_68.o
+
+DBJU = $(O)zipfile.dd $(O)fileio.dd \
+        $(O)util.dd $(O)globals.od $(O)amiga.dd $(O)amigazip.dd
+DBJN = $(O)zipnote.od  $(DBJU)
+DBJC = $(O)zipcloak.od $(DBJU) $(O)crc32.dd \
+        $(O)crypt.dd $(O)ttyio.od
+DBJS = $(O)zipsplit.od $(DBJU)
+
+
+#  HERE WE GO:
+
+all : Zip ZipNote ZipSplit ZipCloak ZipLM
+
+z : Zip
+
+n : ZipNote
+
+s : ZipSplit
+
+c : ZipCloak
+
+l : ZipLM
+
+# Debug versions:
+
+dall : Zip.dbg ZipNote.dbg ZipSplit.dbg ZipCloak.dbg ZipLM.dbg
+
+dz : Zip.dbg
+
+dn : ZipNote.dbg
+
+ds : ZipSplit.dbg
+
+dc : ZipCloak.dbg
+
+dl : ZipLM.dbg
+
+
+Zip : $(OBJZ) $(ZIP_H)
+       $(LD) $(LDFLAGS) -o $@ $(OBJZ) $(LDLIBS)
+       -@delete Zip.dbg
+
+ZipNote : $(OBJN) $(ZIP_H)
+       $(LD) $(LDFLAGS) -o $@ $(OBJN) $(LDLIBS)
+       -@delete ZipNote.dbg
+
+ZipSplit : $(OBJS) $(ZIP_H)
+       $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)
+       -@delete ZipSplit.dbg
+
+ZipCloak : $(OBJC) $(ZIP_H)
+       $(LD) $(LDFLAGS) -o $@ $(OBJC) $(LDLIBS)
+       -@delete ZipCloak.dbg
+
+ZipLM : $(OBJL) $(ZIP_H)
+       $(LD) $(LDFLAGS) -o $@ $(OBJL) $(LDLIBS)
+       -@delete ZipLM.dbg
+
+
+Zip.dbg : $(DBJZ) $(ZIP_H)
+       $(LD) $(LDFLAGD) -o Zip $(DBJZ) $(LDLIBS)
+
+ZipNote.dbg : $(DBJN) $(ZIP_H)
+       $(LD) $(LDFLAGD) -o ZipNote $(DBJN) $(LDLIBS)
+
+ZipSplit.dbg : $(DBJS) $(ZIP_H)
+       $(LD) $(LDFLAGD) -o ZipSplit $(DBJS) $(LDLIBS)
+
+ZipCloak.dbg : $(DBJC) $(ZIP_H)
+       $(LD) $(LDFLAGD) -o ZipCloak $(DBJC) $(LDLIBS)
+
+ZipLM.dbg : $(DBJL) $(ZIP_H)
+       $(LD) $(LDFLAGD) -o ZipLM $(DBJL) $(LDLIBS)
+
+
+clean : bugclean
+       -delete quiet $(OBJZ)
+       -delete quiet $(OBJL)
+       -delete quiet $(O)zipnote.o $(O)zipcloak.o $(O)zipsplit.o \
+                       $(O)crypt.oo $(OBJU)
+
+bugclean :
+       -delete quiet $(DBJZ)
+       -delete quiet $(DBJL)
+       -delete quiet $(O)zipnote.od $(O)zipcloak.od $(O)zipsplit.od \
+                       $(O)crypt.dd $(DBJU)
+
+cleaner : clean
+       -delete quiet Zip ZipNote ZipSplit ZipCloak ZipLM
+       -delete quiet Zip.dbg ZipNote.dbg ZipSplit.dbg ZipCloak.dbg ZipLM.dbg
+
+
+# header dependencies:
+
+$(O)zip.o $(O)zipnote.o $(O)zipcloak.o $(O)zipsplit.o $(O)crypt.o $(O)ttyio.o \
+   $(O)deflate.o $(O)trees.o $(O)zipfile.o $(O)zipup.o $(O)fileio.o $(O)util.o \
+   $(O)timezone.o $(O)crc32.o $(O)globals.o $(O)amiga.o : $(ZIP_H)
+
+$(O)zip.ol $(O)zipnote.ol $(O)zipcloak.ol $(O)zipsplit.ol $(O)crypt.ol \
+   $(O)ttyio.ol $(O)deflate.ol $(O)trees.ol $(O)zipfile.ol $(O)zipup.ol \
+   $(O)fileio.ol $(O)util.ol $(O)timezone.ol $(O)crc32.ol $(O)globals.ol \
+   $(O)amiga.ol : $(ZIP_H)
+
+$(O)crc32.oo $(O)crypt.oo $(O)zipfile.oo $(O)fileio.oo $(O)util.oo : $(ZIP_H)
+
+$(O)amigazip.o $(O)amigazip.ol $(O)amigazip.oo : amiga/amiga.h $(ZIP_H)
+
+$(O)zip.o $(O)zipnote.o $(O)zipcloak.o $(O)zipsplit.o $(O)zipup.o \
+   $(O)zip.ol $(O)zipnote.ol $(O)zipcloak.ol $(O)zipsplit.ol \
+   $(O)zipup.ol : revision.h
+
+$(O)amiga.o $(O)amiga.ol : crypt.h
+
+$(O)crc32.o $(O)crc32.oo $(O)crc32.ol $(O)crypt.o $(O)crypt.oo $(O)crypt.ol \
+   $(O)zipcloak.o $(O)zipcloak.ol $(O)zip.o $(O)zip.ol \
+   $(O)zipup.o $(O)zipup.ol \
+   $(O)zipfile.o $(O)zipfile.oo $(O)zipfile.ol \
+   $(O)fileio.o $(O)fileio.oo $(O)fileio.ol : crc32.h
+
+$(O)crypt.o $(O)crypt.oo $(O)crypt.ol $(O)ttyio.o $(O)ttyio.ol \
+   $(O)zipcloak.o $(O)zipcloak.ol $(O)zip.o $(O)zip.ol \
+   $(O)zipup.o $(O)zipup.ol : crypt.h ttyio.h
+
+$(O)timezone.o $(O)timezone.ol $(O)timezone.od $(O)timezone.dl \
+   $(O)amiga.o $(O)amiga.ol $(O)amiga.oo : timezone.h
+
+$(O)zipup.o $(O)zipup.ol : amiga/zipup.h
+
+
+# SPECIAL CASES:
+
+# -mr changes expression parsing; avoids a bogus "expression too complex" error:
+$(O)trees.o : trees.c
+       $(CC) $(CFLAGS) -mr -o $@ trees.c
+
+$(O)trees.ol : trees.c
+       $(CC) $(LOWFLAGS) -mr -o $@ trees.c
+
+$(O)trees.od : trees.c
+       $(CC) $(CFLAGD) -mr -o $@ trees.c
+
+$(O)trees.ld : trees.c
+       $(CC) $(LOWFLAGD) -mr -o $@ trees.c
+
+# Substitute the assembly version of deflate.c: (but not in debug version)
+$(O)deflate.o : amiga/deflate.a
+       $(AS) $(ASOPTS) -o $@ amiga/deflate.a
+
+$(O)deflate.ol : amiga/deflate.a
+       $(AS) $(LOWASOPTS) -o $@ amiga/deflate.a
+
+# The assembly CRC function:
+$(O)crc_68.o : amiga/crc_68.a
+       $(AS) -n -o $@ amiga/crc_68.a
+
+# Put the Amiga internal version data with today's date into amiga.c:
+$(O)amiga.o : amiga/amiga.c amiga/filedate.c amiga/stat.c
+       rx > env:VersionDate "say '""'translate(date('E'), '.', '/')'""'"
+       $(CC) $(CFLAGS) -o $@ amiga/amiga.c
+       delete env:VersionDate
+
+$(O)amiga.ol : amiga/amiga.c amiga/filedate.c amiga/stat.c
+       rx > env:VersionDate "say '""'translate(date('E'), '.', '/')'""'"
+       $(CC) $(LOWFLAGS) -o $@ amiga/amiga.c
+       delete env:VersionDate
+
+$(O)amiga.od : amiga/amiga.c amiga/filedate.c amiga/stat.c
+       rx > env:VersionDate "say '""'translate(date('E'), '.', '/')'""'"
+       $(CC) $(CFLAGD) -o $@ amiga/amiga.c
+       delete env:VersionDate
+
+$(O)amiga.ld : amiga/amiga.c amiga/filedate.c amiga/stat.c
+       rx > env:VersionDate "say '""'translate(date('E'), '.', '/')'""'"
+       $(CC) $(LOWFLAGD) -o $@ amiga/amiga.c
+       delete env:VersionDate
+
+$(O)amiga.oo : amiga/amiga.c amiga/filedate.c amiga/stat.c
+       rx > env:VersionDate "say '""'translate(date('E'), '.', '/')'""'"
+       $(CC) $(CFLAGS) -d UTIL -o $@ amiga/amiga.c
+       delete env:VersionDate
+
+$(O)amiga.dd : amiga/amiga.c amiga/filedate.c amiga/stat.c
+       rx > env:VersionDate "say '""'translate(date('E'), '.', '/')'""'"
+       $(CC) $(CFLAGD) -d UTIL -o $@ amiga/amiga.c
+       delete env:VersionDate
+
+# Put the compiler version number into amigazip.c:
+$(O)amigazip.o : amiga/amigazip.c
+       $(CC) $(CFLAGS) -o $@ -d __VERSION__=5 -d __REVISION__=2 amiga/amigazip.c
+
+$(O)amigazip.ol : amiga/amigazip.c
+       $(CC) $(LOWFLAGS) -o $@ -d __VERSION__=5 -d __REVISION__=2 amiga/amigazip.c
+
+$(O)amigazip.od : amiga/amigazip.c
+       $(CC) $(CFLAGD) -o $@ -d __VERSION__=5 -d __REVISION__=2 amiga/amigazip.c
+
+$(O)amigazip.ld : amiga/amigazip.c
+       $(CC) $(LOWFLAGD) -o $@ -d __VERSION__=5 -d __REVISION__=2 amiga/amigazip.c
+
+$(O)amigazip.oo : amiga/amigazip.c
+       $(CC) $(CFLAGS) -d UTIL -o $@ -d __VERSION__=5 -d __REVISION__=2 amiga/amigazip.c
+
+$(O)amigazip.dd : amiga/amigazip.c
+       $(CC) $(CFLAGD) -d UTIL -o $@ -d __VERSION__=5 -d __REVISION__=2 amiga/amigazip.c
diff --git a/amiga/match.a b/amiga/match.a
new file mode 100644 (file)
index 0000000..ec5bcf0
--- /dev/null
@@ -0,0 +1,182 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; match.a -- optional optimized asm version of longest match in deflate.c
+; Written by Jean-loup Gailly
+; Adapted for the Amiga by Carsten Steger <stegerc@informatik.tu-muenchen.de>
+; using the code in match.S.
+; The major change in this code consists of removing all unaligned
+; word accesses, because they cause 68000-based Amigas to crash.
+; For maximum speed, UNALIGNED_OK can be defined in Makefile.sasc.
+; The program will then only run on 68020-based Amigas, though.
+; If you have reduced WSIZE in zip.h, then make sure this is
+; assembled with an equivalent -dWSIZE=<whatever>.
+;
+; This code will run with registerized parameters too, unless SAS
+; changes parameter passing conventions between new releases of SAS/C.
+
+
+Cur_Match       reg     d0      ; Must be in d0!
+Best_Len        reg     d1
+Loop_Counter    reg     d2
+Scan_Start      reg     d3
+Scan_End        reg     d4
+Limit           reg     d5
+Chain_Length    reg     d6
+Scan_Test       reg     d7
+Scan            reg     a0
+Match           reg     a1
+Prev_Address    reg     a2
+Scan_Ini        reg     a3
+Match_Ini       reg     a4
+
+MAX_MATCH       equ     258
+MIN_MATCH       equ     3
+        ifnd    WSIZE
+WSIZE           equ     32768
+        endc
+MAX_DIST        equ     WSIZE-MAX_MATCH-MIN_MATCH-1
+
+
+        xref    _max_chain_length
+        xref    _prev_length
+        xref    _prev
+        xref    _window
+        xref    _strstart
+        xref    _good_match
+        xref    _match_start
+        xref    _nice_match
+
+
+        section match,code
+
+        xdef    _match_init
+        xdef    @match_init
+        xdef    _longest_match
+        xdef    @longest_match
+
+
+_match_init:
+@match_init:
+        rts
+
+
+_longest_match:
+        move.l  4(sp),Cur_Match
+@longest_match:
+        ifd     UNALIGNED_OK
+        movem.l d2-d6/a2-a4,-(sp)
+        else
+        movem.l d2-d7/a2-a4,-(sp)
+        endc
+        move.l  _max_chain_length,Chain_Length
+        move.l  _prev_length,Best_Len
+        lea     _prev,Prev_Address
+        lea     _window+MIN_MATCH,Match_Ini
+        move.l  _strstart,Limit
+        move.l  Match_Ini,Scan_Ini
+        add.l   Limit,Scan_Ini
+        subi.w  #MAX_DIST,Limit
+        bhi.b   limit_ok
+        moveq   #0,Limit
+limit_ok:
+        cmp.l   _good_match,Best_Len
+        bcs.b   length_ok
+        lsr.l   #2,Chain_Length
+length_ok:
+        subq.l  #1,Chain_Length
+
+        ifd     UNALIGNED_OK
+
+        move.w  -MIN_MATCH(Scan_Ini),Scan_Start
+        move.w  -MIN_MATCH-1(Scan_Ini,Best_Len.L),Scan_End
+
+        else
+
+        move.b  -MIN_MATCH(Scan_Ini),Scan_Start
+        lsl.w   #8,Scan_Start
+        move.b  -MIN_MATCH+1(Scan_Ini),Scan_Start
+        move.b  -MIN_MATCH-1(Scan_Ini,Best_Len.L),Scan_End
+        lsl.w   #8,Scan_End
+        move.b  -MIN_MATCH(Scan_Ini,Best_Len.L),Scan_End
+
+        endc
+
+        bra.b   do_scan
+
+long_loop:
+
+        ifd     UNALIGNED_OK
+
+        move.w  -MIN_MATCH-1(Scan_Ini,Best_Len.L),Scan_End
+
+        else
+
+        move.b  -MIN_MATCH-1(Scan_Ini,Best_Len.L),Scan_End
+        lsl.w   #8,Scan_End
+        move.b  -MIN_MATCH(Scan_Ini,Best_Len.L),Scan_End
+
+        endc
+
+short_loop:
+        lsl.w   #1,Cur_Match
+        move.w  0(Prev_Address,Cur_Match.L),Cur_Match
+        cmp.w   Limit,Cur_Match
+        dbls    Chain_Length,do_scan
+        bra.b   return
+
+do_scan:
+        move.l  Match_Ini,Match
+        add.l   Cur_Match,Match
+
+        ifd     UNALIGNED_OK
+
+        cmp.w   -MIN_MATCH-1(Match,Best_Len.L),Scan_End
+        bne.b   short_loop
+        cmp.w   -MIN_MATCH(Match),Scan_Start
+        bne.b   short_loop
+
+        else
+
+        move.b  -MIN_MATCH-1(Match,Best_Len.L),Scan_Test
+        lsl.w   #8,Scan_Test
+        move.b  -MIN_MATCH(Match,Best_Len.L),Scan_Test
+        cmp.w   Scan_Test,Scan_End
+        bne.b   short_loop
+        move.b  -MIN_MATCH(Match),Scan_Test
+        lsl.w   #8,Scan_Test
+        move.b  -MIN_MATCH+1(Match),Scan_Test
+        cmp.w   Scan_Test,Scan_Start
+        bne.b   short_loop
+
+        endc
+
+        move.w  #(MAX_MATCH-MIN_MATCH),Loop_Counter
+        move.l  Scan_Ini,Scan
+scan_loop:
+        cmpm.b  (Match)+,(Scan)+
+        dbne    Loop_Counter,scan_loop
+
+        sub.l   Scan_Ini,Scan
+        addq.l  #(MIN_MATCH-1),Scan
+        cmp.l   Best_Len,Scan
+        bls.b   short_loop
+        move.l  Scan,Best_Len
+        move.l  Cur_Match,_match_start
+        cmp.l   _nice_match,Best_Len
+        bcs.b   long_loop
+return:
+        move.l  Best_Len,d0
+        ifd     UNALIGNED_OK
+        movem.l (sp)+,d2-d6/a2-a4
+        else
+        movem.l (sp)+,d2-d7/a2-a4
+        endc
+        rts
+
+        end
diff --git a/amiga/match_68.a b/amiga/match_68.a
new file mode 100644 (file)
index 0000000..d1a6c39
--- /dev/null
@@ -0,0 +1,273 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; This is a 68000 assembly language version of the Zip function
+; longest_match().  It is written for any 680x0 based computer, but at this
+; time the feature for runtime testing of CPU type is only supported for the
+; Amiga.  Hopefully a similar test for the Macintosh is possible, and for any
+; other system that supports both 68000 and 68020+ CPUs.  This is written by
+; Paul Kienitz, partially derived from a simpler version by Carsten Steger,
+; derived in turn from a 386 assembly function by Jean-loup Gailly and Kai Uwe
+; Rommel... but also based directly on the C original.
+;
+; The main difference of this from other longest_match() implementations is
+; that it includes both byte based and word based versions of the function,
+; and various symbols can be defined to select whether to use one routine or
+; the other, or to do a platform-specific test at runtime.  The symbols that
+; can be used to select behavior are as follows:
+;
+;   CPU020     if defined, use 68020 instructions always
+;   CPUTEST    if defined, check at runtime for CPU type.  Another symbol
+;               specifying the platform-specific test must be used with this.
+;               If neither of these is defined, use 68000 instructions only.
+;   AMIGA      use Amiga-specific test for 68020, if CPUTEST defined.  Also
+;               tells it to let a0/a1/d1 be clobbered by functions.
+;   ATSIGN     define entry symbols in @foo form as well as _foo, with
+;               @longest_match taking its parm in d0 instead of on the stack.
+;   WSIZE      if defined, determines the sliding window size for deflate;
+;               the default is 32K. If you have reduced WSIZE for the C code,
+;               make sure that this module is assembled with an equivalent
+;               "-dWSIZE=<whatever>" (or "-e...") switch.
+;
+; NOTE: no provision is made for 16 bit ints.  All external int variables are
+; treated as 32 bit values.  This also assumes that longest_match's result is
+; returned in D0.
+
+        IFND    CPU020
+        IFND    CPUTEST
+CPU000  equ     1
+        ENDC
+        ENDC
+
+; global variables:
+        xref    _max_chain_length   ; unsigned int
+        xref    _prev_length        ; unsigned int
+        xref    _match_start        ; unsigned int
+        xref    _strstart           ; unsigned int
+        xref    _good_match         ; signed int
+        xref    _nice_match         ; signed int
+        xref    _window             ; array of unsigned char
+        xref    _prev               ; array of unsigned short
+
+; our entry points:
+        xdef    _match_init         ; void match_init(void);
+        xdef    _longest_match      ; int longest_match(unsigned cur_match);
+        IFD     ATSIGN
+        xdef    @match_init         ; for SAS assembler
+        xdef    @longest_match      ; ditto
+        ENDC
+
+; flag variable for remembering CPU type:
+        IFD     CPUTEST
+        section cpuflag,data
+is020:  ds.w    1
+        ENDC
+
+
+        section match,code
+_match_init:
+        IFD    ATSIGN
+@match_init:
+        ENDC
+
+        IFD     CPUTEST         ; now check for platform type
+        IFD     AMIGA           ; Amiga specific test for '020 CPU:
+
+        xref    _SysBase
+
+        NOLIST
+        INCLUDE       'exec/execbase.i'
+        LIST
+
+        clr.w   is020           ; default value is 68000
+        move.l  _SysBase,a0
+        btst    #AFB_68020,AttnFlags+1(a0)
+        beq.s   cheap
+        move.w  #1,is020
+
+cheap:
+        ELSE ; !AMIGA
+
+ !!   Write an '020-detector for your system here!
+
+        ENDC ; AMIGA
+        ENDC ; CPUTEST
+        rts                ; match_init consists only of rts if CPUTEST unset
+
+
+        IFD     AMIGA
+SAVEREGS        reg     d3-d7/a2/a3/a5      ; don't protect d0/d1/a0/a1
+        ELSE
+SAVEREGS        reg     d1/d3-d7/a0-a3/a5   ; protect all but d0 return val
+        ENDC
+
+Cur_Match       equr    d0                  ; Must be in d0!
+Best_Len        equr    d1
+Scan_Start      equr    d3
+Scan_End        equr    d4
+Limit           equr    d5
+Chain_Length    equr    d6
+Scan_Test       equr    d7
+Scan            equr    a0
+Match           equr    a1
+Prev_Address    equr    a2
+Scan_Ini        equr    a3
+Match_Ini       equr    a5
+
+
+MAX_MATCH       equ     258
+MIN_MATCH       equ     3
+        IFND    WSIZE
+WSIZE           equ     32768
+        ENDC
+MAX_DIST        equ     WSIZE-MAX_MATCH-MIN_MATCH-1
+
+_longest_match:
+        move.l  4(sp),Cur_Match         ; stack arg to register
+        IFD     ATSIGN
+@longest_match:
+        ENDC
+        movem.l SAVEREGS,-(sp)
+
+; setup steps common to byte and word versions:
+        move.l  _max_chain_length,Chain_Length
+        move.l  _prev_length,Best_Len
+        lea     _prev,Prev_Address
+        lea     _window,Match_Ini
+        move.l  _strstart,Limit
+        move.l  Match_Ini,Scan_Ini
+        addq    #MIN_MATCH,Match_Ini
+        add.l   Limit,Scan_Ini
+        subi.w  #MAX_DIST,Limit
+        bhi.s   limit_ok
+        moveq   #0,Limit
+limit_ok:
+        cmp.l   _good_match,Best_Len
+        bcs.s   length_ok
+        lsr.l   #2,Chain_Length
+length_ok:
+        subq.l  #1,Chain_Length
+
+        IFD     CPUTEST
+        tst.w   is020               ; can we use '020 stuff today?
+        bne     WORD_match
+        ENDC
+
+        IFND    CPU020
+
+; for 68000 or 68010, use byte operations:
+        moveq   #0,Scan_Start       ; clear 2nd and 4th bytes, use 1st & 3rd
+        moveq   #0,Scan_End
+        moveq   #0,Scan_Test
+        move.b  (Scan_Ini),Scan_Start
+        swap    Scan_Start
+        move.b  1(Scan_Ini),Scan_Start
+        move.b  -1(Scan_Ini,Best_Len),Scan_End
+        swap    Scan_End
+        move.b  0(Scan_Ini,Best_Len),Scan_End
+        bra.s   bdo_scan
+
+blong_loop:
+        move.b  -1(Scan_Ini,Best_Len),Scan_End
+        swap    Scan_End
+        move.b  0(Scan_Ini,Best_Len),Scan_End
+
+bshort_loop:
+        add.w   Cur_Match,Cur_Match
+        move.w  0(Prev_Address,Cur_Match.l),Cur_Match
+        cmp.l   Limit,Cur_Match
+        dbls    Chain_Length,bdo_scan
+        bra     return
+
+bdo_scan:
+        move.l  Match_Ini,Match
+        add.l   Cur_Match,Match
+        move.b  -MIN_MATCH-1(Match,Best_Len),Scan_Test
+        swap    Scan_Test
+        move.b  -MIN_MATCH(Match,Best_Len),Scan_Test
+        cmp.l   Scan_Test,Scan_End
+        bne.s   bshort_loop
+        move.b  -MIN_MATCH(Match),Scan_Test
+        swap    Scan_Test
+        move.b  -MIN_MATCH+1(Match),Scan_Test
+        cmp.l   Scan_Test,Scan_Start
+        bne.s   bshort_loop
+        move.w  #(MAX_MATCH-MIN_MATCH),Scan_Test
+        lea     MIN_MATCH(Scan_Ini),Scan
+
+bscan_loop:
+        cmpm.b  (Match)+,(Scan)+
+        dbne    Scan_Test,bscan_loop
+        subq    #1,Scan
+
+        sub.l   Scan_Ini,Scan
+        cmp.l   Best_Len,Scan
+        bls.s   bshort_loop
+        move.l  Scan,Best_Len
+        move.l  Cur_Match,_match_start
+        cmp.l   _nice_match,Best_Len
+        bcs.s   blong_loop
+        IFD     CPUTEST
+        bra     return
+        ENDC
+
+        ENDC ; !CPU020
+
+        IFND    CPU000
+
+; for 68020 or higher, use word operations even on odd addresses:
+WORD_match:
+        move.w  (Scan_Ini),Scan_Start
+        move.w  -1(Scan_Ini,Best_Len),Scan_End
+        bra.s   wdo_scan
+
+wlong_loop:
+        move.w  -1(Scan_Ini,Best_Len),Scan_End
+
+wshort_loop:
+        add.w   Cur_Match,Cur_Match
+        move.w  (Prev_Address,Cur_Match.l),Cur_Match
+        cmp.l   Limit,Cur_Match
+        dbls    Chain_Length,wdo_scan
+        bra.s   return
+
+wdo_scan:
+        move.l  Match_Ini,Match
+        add.l   Cur_Match,Match
+        cmp.w   -MIN_MATCH-1(Match,Best_Len),Scan_End
+        bne.s   wshort_loop
+        cmp.w   -MIN_MATCH(Match),Scan_Start
+        bne.s   wshort_loop
+        moveq   #((MAX_MATCH-MIN_MATCH)/2),Scan_Test    ; value = 127
+        lea     MIN_MATCH(Scan_Ini),Scan
+
+wscan_loop:
+        cmpm.w  (Match)+,(Scan)+
+        dbne    Scan_Test,wscan_loop
+        subq    #2,Scan
+        move.b  -MIN_MATCH+1(Match),Scan_Test
+        cmp.b   (Scan),Scan_Test
+        bne     steven
+        addq    #1,Scan
+steven:
+        sub.l   Scan_Ini,Scan
+        cmp.l   Best_Len,Scan
+        bls.s   wshort_loop
+        move.l  Scan,Best_Len
+        move.l  Cur_Match,_match_start
+        cmp.l   _nice_match,Best_Len
+        bcs.s   wlong_loop
+
+        ENDC ; !CPU000
+
+return:
+        move.l  Best_Len,d0             ; function return value
+        movem.l (sp)+,SAVEREGS
+        rts
+
+        end
diff --git a/amiga/osdep.h b/amiga/osdep.h
new file mode 100644 (file)
index 0000000..c573cf8
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+  Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2005-Feb-10 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __amiga_osdep_h
+#define __amiga_osdep_h
+
+/* default to MEDIUM_MEM, but allow makefile override */
+#if ( (!defined(BIG_MEM)) && (!defined(SMALL_MEM)))
+#  define MEDIUM_MEM
+#endif
+
+/* check that TZ environment variable is defined before using UTC times */
+#if (!defined(NO_IZ_CHECK_TZ) && !defined(IZ_CHECK_TZ))
+#  define IZ_CHECK_TZ
+#endif
+
+#ifndef IZTZ_GETLOCALETZINFO
+#  define IZTZ_GETLOCALETZINFO GetPlatformLocalTimezone
+#endif
+
+/* AmigaDOS can't even support disk partitions over 4GB, let alone files */
+#define NO_LARGE_FILE_SUPPORT
+#ifdef LARGE_FILE_SUPPORT
+#  undef LARGE_FILE_SUPPORT
+#endif
+
+#define USE_CASE_MAP
+#define USE_EF_UT_TIME
+#define HANDLE_AMIGA_SFX
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+                     procname(n, 1))
+#define EXIT(e) ClearIOErr_exit(e)
+void ClearIOErr_exit(int e);
+
+#include "amiga/z-stat.h"
+
+#ifdef __SASC
+#  include <sys/types.h>
+#  include <exec/execbase.h>
+#  if (defined(_M68020) && (!defined(__USE_SYSBASE)))
+                            /* on 68020 or higher processors it is faster   */
+#    define __USE_SYSBASE   /* to use the pragma libcall instead of syscall */
+#  endif                    /* to access functions of the exec.library      */
+#  include <proto/exec.h>   /* see SAS/C manual:part 2,chapter 2,pages 6-7  */
+#  include <proto/dos.h>
+#  if (defined(_M68020) && !defined(UNALIGNED_OK))
+#     define UNALIGNED_OK
+#  endif
+#  ifndef REENTRANT
+#    define REENTRANT
+#  endif
+#  if (defined(_NEAR_DATA) && !defined(DYN_ALLOC))
+#    define DYN_ALLOC
+#  endif
+#  ifdef DEBUG
+#    include <sprof.h>      /* profiler header file */
+#  endif
+#  ifndef IZTZ_SETLOCALTZINFO
+     /*  XXX !!  We have really got to find a way to operate without these. */
+#    define IZTZ_SETLOCALTZINFO
+#  endif
+
+/*
+ A word on short-integers and SAS/C (a bug of [mc]alloc?)
+ Using short integers (i.e. compiling with option SHORT-INTEGERS) is
+ *not* recommended. To get maximum compression ratio the window size stored
+ in WSIZE should be 32k (0x8000). However, since the size of the window[]
+ array is 2*WSIZE, 65536 bytes must be allocated. The calloc function can
+ only allocate UINT_MAX (defined in limits.h) bytes which is one byte short
+ (65535) of the maximum window size if you are compiling with short-ints.
+ You'll get an error message "Out of memory (window allocation)" whenever
+ you try to deflate. Note that the compiler won't produce any warning.
+ The maximum window size with short-integers is therefore 32768 bytes.
+ The following is only implemented to allow the use of short-integers but
+ it is once again not recommended because of a loss in compression ratio.
+*/
+#  if (defined(_SHORTINT) && !defined(WSIZE))
+#    define WSIZE 0x4000        /* only half of maximum window size */
+#  endif                        /* possible with short-integers     */
+#endif /* __SASC */
+/*
+ With Aztec C, using short integers imposes no size limits and makes
+ the program run faster, even with 32 bit CPUs, so it's recommended.
+*/
+#ifdef AZTEC_C
+#  define NO_UNISTD_H
+#  define NO_RMDIR
+#  define BROKEN_FSEEK
+#  ifndef IZTZ_DEFINESTDGLOBALS
+#    define IZTZ_DEFINESTDGLOBALS
+#  endif
+#endif
+
+extern int real_timezone_is_set;
+void tzset(void);
+#define VALID_TIMEZONE(tempvar) (tzset(), real_timezone_is_set)
+
+#ifdef ZCRYPT_INTERNAL
+#  ifndef CLIB_EXEC_PROTOS_H
+     void *FindTask(void *);
+#  endif
+#  define ZCR_SEED2     (unsigned)(ulg)FindTask(NULL)
+#endif
+
+int Agetch(void);               /* getch() like function, in amiga/filedate.c */
+char *GetComment(char *);
+
+#define FOPR "rb"
+#define FOPM "rb+"
+#define FOPW "wb"
+/* prototype for ctrl-C trap function */
+void _abort(void);
+
+#endif /* !__amiga_osdep_h */
diff --git a/amiga/smakefile b/amiga/smakefile
new file mode 100644 (file)
index 0000000..ce1317d
--- /dev/null
@@ -0,0 +1,662 @@
+#===========================================================================
+# Makefile for Zip, ZipNote, ZipCloak, ZipSplit     AMIGA SAS/C Version 6.58
+# Version:  2.3                                   last revised:  07 Jan 2007
+#===========================================================================
+# -John Bush, <John.Bush@East.Sun.COM>
+#         or: <JBush@Bix.COM>
+
+# updated for SAS/C Version 6.56+ and AmigaDOS 3.1 (V40)
+# by Haidinger Walter, <walthaid@unix.ict.tuwien.ac.at>
+
+# additional supplements and maintenance by Paul Kienitz
+
+# This makefile should work with at least AmigaDOS 2.04 (V37)  (not tested)
+# and will probably not work with AmigaDOS 1.3 (V34)
+
+# If you have any improvements, critics or else please feel free to mail.
+# Any response is appreciated. Haidinger Walter <walthaid@unix.ict.tuwien.ac.at>
+
+# Available targets:
+# all           builds all executeables below
+# zip           builds zip executeable
+# zipsplit      builds zipsplit executeable
+# zipcloak      builds zipcloak executeable
+# zipnote       builds zipnote executeable
+# ziplm         builds low memory version of zip executable
+# clean         remove all files created by the compilation
+# spotless      like clean target but removes binaries too
+
+
+##########################
+# USER MACRO DEFINITIONS #
+##########################
+
+# *** NOTE ***
+# The assembly version is not implemented yet.
+# (Un)commenting the assembler macros has no effect unless the
+# file dependencies are changed too.
+# Most of the amiga/*.a files do not assmble with 68000 instructions.
+# Any help is appreciated, of course.
+
+# Set the processor to generate code for.
+# Compiler:    ANY 68000 68010 68020 68030 68040 68060
+# Assembler:     0     0     1     2     3     4   n/a
+# Defaults: ANY and 0
+#
+CUSECPU = ANY
+AUSECPU = 0
+
+# UNCOMMENT to use 68020 instructions in the assembly version of deflate.o
+# Only use if code is generated for 68020 or higher processors above.
+# Note: You could use CPUTEST too to enable runtime cpu detection.
+# However, it is not recommended since both 68000 and 68020 code will be
+# included which would be an unnecessary increase in size.
+# (see amiga/deflate.a for more information)
+#
+#AUSE020 = CPU020
+
+# To disable the assembler replacements and use the standard C source,
+# you have to change the Zip and ZipLM dependencies. See below for details.
+# (remember that assembler use is *not* implemented yet)
+
+# Uncomment both CUTIL and LUTIL to make use of utility.library of OS 2.04+
+# The utility.library is *not* used for UnZipSFX to ensure maximum portability
+# between the different Amiga systems (minimal config: 68000 and OS 1.2).
+# You can change this by adding the $(LUTIL) macro in the UnZipSFX linking
+# rules (See below: Final output targets, UnZipSFX:).
+# WARNINGS when using the utility library:
+# 1. All Executables will *only* work with AmigaDOS 2.04 (v37) or higher.
+# 2. You *need not* compile/link with short-integers using the
+#    utility.library. It will crash your machine. See Libraries below.
+#
+# Default: commented (not used)
+#
+#CUTIL = UTILLIB DEFINE=_UTILLIB
+#LUTIL = WITH SC:LIB/utillib.with    # include necessary linker defines
+# Choose one stack-handling method (default=faster)
+# StackExtend: Dynamic runtime stack extension. You won't notice stack overflows.
+# StackCheck: On a stack overflow a requester appears which allows you to exit.
+# Note that either stack watching will slow down your executable because of the
+# extra code run on each function entry. On the other hand, you won't crash
+# anymore due to stack overflows. However, you should not have *any* stack
+# problems with Info-ZIP programs if you raise your stack to 10000 (which I'd
+# recommend as a minimum default stack for all applications) or more using the
+# shell stack command. Type 'Stack 20000' or add it to your S:Shell-Startup.
+# BTW: Typing 'Stack' prints your current stack size.
+#
+CSTACK = NOSTACKCHECK STACKEXTEND     # slow, but always works
+#CSTACK = STACKCHECK NOSTACKEXTEND    # slow, requester & graceful exit
+#CSTACK = NOSTACKCHECK NOSTACKEXTEND  # faster but relies on larger stack (>=10K)
+
+
+#
+# LIBRARIES
+# ---------
+
+# Choose one DATAOPTS , SASLIB , ASMOPTS and LSTARTUP
+# Always comment/uncomment all macros of a set.
+
+# Library to use with near data and 2-byte integers
+# Notes: o  slower than 4-byte integers with 68000 cpu
+#        o  *not* recommended due to poor overall performance
+#        o  see comment in amiga/osdep.h
+#DATAOPTS = DATA=NEAR SHORTINTEGERS DEF=_NEAR_DATA
+#SASLIB   = scs
+#ASMOPTS  = -dINT16
+#LSTARTUP = cres.o
+
+# Library to use with near data and 4-byte integers (DEFAULT)
+# *** use this with the utility.library ***
+DATAOPTS = DATA=NEAR DEF=_NEAR_DATA
+SASLIB   = sc
+ASMOPTS  =
+LSTARTUP = cres.o
+
+# Library to use with far data and 2-byte integers
+# use if DYN_ALLOC is not defined
+# old default - far data always works but is slower
+#DATAOPTS = DATA=FAR SHORTINTEGERS DEF=_FAR_DATA
+#SASLIB   = scsnb
+#ASMOPTS  = -dINT16
+#LSTARTUP = c.o
+
+# Library to use with far data and 4-byte integers
+# if everything else fails: try this
+#DATAOPTS = DATA=FAR DEF=_FAR_DATA
+#SASLIB   = scnb
+#ASMOPTS  =
+#LSTARTUP = c.o
+
+
+#
+# DEBUGGING
+# ---------
+
+# Default: No debugging information added.
+# The three macros below will be overwritten if you choose to add
+# debug info, therefore no need to comment.
+
+CDBG = NODEBUG NOPROFILE NOCOVERAGE    # default: no debug info
+ADBG =
+LDBG = STRIPDEBUG                      # default: no debug info
+
+# Compiler and loader debug flags.  Uncomment as needed.  Recomment when done.
+# Optimization disabled for faster compilation (by using NOOPT)
+
+#CDBG1 = DEF=DEBUG DEF=DEBUG_TIME     # enables Info-Zip's debug output
+
+# Enable profiling and coverage when desired. Option COVERAGE commented
+# seperately because running coverage may corrupt your drive in case of a
+# system crash since a file 'cover.dat' is created in your working directory.
+# Note that the use of COVERAGE forces the use of the c.o startup module.
+
+#CDBG2 = PROFILE
+#CDBG3 = COVERAGE        # must use c.o startup code:
+#LSTARTUP = c.o          # Uncomment *only* when you use COVERAGE
+
+# *Uncomment* here macros CDBG, ADBG and LDBG to include debugging information
+
+#CDBG = $(CDBG1) $(CDBG2) $(CDBG3) ADDSYM DEBUG=FULLFLUSH STACKCHECK NOOPT
+#ADBG = DEBUG
+#LDBG = ADDSYM
+
+# Optional use of memwatch.library which can be found in your
+# sc:extras/memlib directory. Please read the short docs (memlib.doc).
+# Note that memwatch.library has a small bug: MWTerm() displays always
+# the first entry.
+# Get the latest version from aminet (dev/debug/memlib.lha) or
+# contact me to get the patch. Uncomment all macros to use.
+#CMEMLIB  = DEFINE=MWDEBUG=1       # define to enable library
+#LMEMLIB  = SC:LIB/memwatch.lib       # path to library
+#LSTARTUP = c.o                    # must use c.o with memlib!
+
+
+#
+# MAPPING
+# -------
+
+# Map filenames used when mapping (no need to comment)
+#
+MAPFZ = zip.map                # Zip      map filename
+MAPFN = zipnote.map            # ZipNote  map filename
+MAPFC = zipcloak.map           # ZipCloak map filename
+MAPFS = zipsplit.map           # ZipSplit map filename
+MAPFL = ziplm.map              # Zip low memory version map filename
+
+# Map file output: Uncomment to highlight and bold headings.
+#
+#MAPFSTYLE = FANCY
+
+# Map flags for each EXECUTABLE. Uncomment to enable mapping.
+# For map options please refer to:
+# SAS/C v6 manual, volume 1: user's guide, chapter 8, page 136: map
+# Default: all options enabled: f,h,l,o,s,x
+#                                 |-> options start here
+#LMAPZ = $(MAPFSTYLE) MAP $(MAPFZ) f,h,l,o,s,x   # Zip      maps
+#LMAPN = $(MAPFSTYLE) MAP $(MAPFN) f,h,l,o,s,x   # ZipNote  maps
+#LMAPC = $(MAPFSTYLE) MAP $(MAPFC) f,h,l,o,s,x   # ZipCloak maps
+#LMAPS = $(MAPFSTYLE) MAP $(MAPFS) f,h,l,o,s,x   # ZipSplit maps
+#LMAPL = $(MAPFSTYLE) MAP $(MAPFL) f,h,l,o,s,x   # Zip lowmem maps
+
+#
+# LISTINGS
+# --------
+
+# Listfile-extensions for each executable (enter *with* dot)
+#
+LISTEXTZ = .lst   # extension for Zip listfiles
+LISTEXTU = .ulst  # extension for utility listfiles (ZipNote,ZipCloak,ZipSplit)
+LISTEXTL = .llst  # extension for Zip low memory listfiles
+
+
+# List files and cross references for each OBJECT.
+# Add/remove flags as needed. Not all listed by default.
+# Use LISTINCLUDES to determine the dependencies for smake
+#
+CLISTOPT = LISTHEADERS LISTMACROS # LISTSYSTEM LISTINCLUDES
+CXREFOPT = XHEAD XSYS
+#
+# Uncomment to enable listing (default: commented)
+# *** WARNING: List files require *lots* of disk space!
+#
+#CLIST = LIST $(CLISTOPT)
+#CXREF = XREF $(CXREFOPT)
+
+
+#
+# SUPPRESSED COMPILER WARNINGS
+# ----------------------------
+
+# Compiler warnings to ignore
+#
+# Warning 105 : module does not define any externally-known symbols
+# Warning 304 : Dead assignment eliminated...
+# Note    306 : ...function inlined...
+# Warning 317 : possibly uninitialized variable...
+# Comment to enable.
+#
+CIGNORE = IGNORE=105,304,306,317
+
+
+#
+# OBJECT EXTENSIONS
+#
+
+# Extensions used for objects of each executeable.
+# Transformation rules require unique extensions.
+# Enter *with* dot.
+#
+O  = .o     # extension for Zip     objects
+OU = .uo    # extension for utility objects (ZipNote, ZipSplit and ZipCloak)
+OL = .lo    # extension for low memory Zip objects
+
+
+# Filename used to store converted options from environment variable
+# LOCAL_ZIP. Default: scoptions_local_zip
+#
+CWITHOPT = scoptions_local_zip
+
+
+# Filenames to store compiler options to prevent command line overflow
+#
+# Common options file for Zip and other executables
+CFILE = scoptions-zip
+
+
+# Temp filenames for object lists to load using linker "WITH" command.
+OBJLISTZ = zip_objlist.with            # Zip      object list
+OBJLISTN = zipnote_objlist.with        # ZipNote  object list
+OBJLISTC = zipcloak_objlist.with       # ZipCloak object list
+OBJLISTS = zipsplit_objlist.with       # ZipSplit object list
+OBJLISTL = ziplm_objlist.with          # Zip low-mem object list
+
+
+# Filenames to store linker options
+#
+LWITHZ = zip.lnk                       # zip      linker options
+LWITHN = zipnote.lnk                   # zipnote  linker options
+LWITHC = zipcloak.lnk                  # zipcloak linker options
+LWITHS = zipsplit.lnk                  # zipsplit linker options
+LWITHL = ziplm.lnk                     # zip low-mem linker options
+
+
+# Define AMIGA_BETA to print "Beta Notice" up front.  See tailor.h.
+# Undefine AMIGA_BETA when building a released version.
+#CDEFBETA = DEF=AMIGA_BETA
+
+#####################################
+# NOTHING TO CHANGE BEYOND HERE ... #
+#####################################
+# (except for C/asm dependencies)
+
+# Define MEDIUM_MEM for production release (per Paul Kienitz).
+# This reduces runtime memory requirement but not speed or compression.
+# Note: Do *not* use BIG_MEM or MMAP since it isn't yet supported by the
+        assembler version of deflate.c : amiga/deflate.a
+CUSEMEM = DEF=MEDIUM_MEM
+AUSEMEM = -DMEDIUM_MEM       # for asm deflate.o, must match above
+
+
+# Defines for building low-memory use version of Zip
+WSIZEL   = WSIZE=4096     # deflate.c window size for low-mem version
+CLOWMEM = DEF=SMALL_MEM DEF=$(WSIZEL)
+ALOWMEM = -DSMALL_MEM   -D$(WSIZEL)  # for asm deflate.o, must match above
+
+
+# Compiler definitions
+#
+CC = sc
+#
+# Optimizer flags
+#
+OPTPASSES = 6     # set number of global optimizer passes
+#
+OPT1 = OPT OPTINL OPTINLOCAL OPTTIME OPTLOOP OPTSCHED
+OPT2 = OPTCOMP=$(OPTPASSES) OPTDEP=$(OPTPASSES) OPTRDEP=$(OPTPASSES)
+OPT  = $(OPT1) $(OPT2)
+
+
+# Compiler flags
+#
+CDEFINES = $(CMEMLIB) $(CDEFBETA) DEF=AMIGA
+COPTIONS = $(DATAOPTS) CODE=NEAR CPU=$(CUSECPU) VERBOSE PARAMETERS=BOTH NOMINC
+COPTIONS = $(COPTIONS) ERRORREXX NOERRORCONSOLE MEMSIZE=HUGE $(CLIST) $(CXREF)
+COPTIONS = $(COPTIONS) $(CSTACK) $(CUTIL) STRICT UNSCHAR NOICONS STRINGMERGE
+CFLAGS = $(CDEFINES) $(COPTIONS) $(OPT) $(CDBG) $(CIGNORE)
+
+
+# Linker definitions
+#  See SASLIB definition above
+#
+LD = slink
+# special linker flags for pure (i.e. resident) binary.
+LDFLAGSS = FROM SC:LIB/$(LSTARTUP)
+# common linker flags for all other executeables
+LDFLAGSC = FROM SC:LIB/c.o
+LDFLAGS2 = NOICONS $(LDBG)
+LIBFLAGS = LIB $(LMEMLIB) SC:LIB/$(SASLIB).lib SC:LIB/amiga.lib
+
+
+# Assembler definitions
+#
+ASM = asm
+#
+# Options used for assembling amiga/deflate.a
+# Must match defines in C-Source.
+#
+AFLAGS0  = -d__SASC -dSASC -dAMIGA
+AFLAGS1  = $(AUSE020) $(ASMOPTS) $(ADBG)
+AFLAGS2  = -m$(AUSECPU) -jm -iINCLUDE:
+AFLAGS   = $(AFLAGS0) $(AFLAGS1) $(AFLAGS2)
+ASMOPTSZ = $(AFLAGS) $(AUSEMEM) -dDYN_ALLOC     # Zip asm flags
+ASMOPTSL = $(AFLAGS) $(ALOWMEM)                 # Zip low-mem version asm flags
+
+
+##################
+# TARGET OBJECTS #
+##################
+
+
+# Zip objects
+OBJZ1 = zip$(O) zipfile$(O) zipup$(O) fileio$(O) util$(O) globals$(O)
+OBJZ2 = crc32$(O) crypt$(O) timezone$(O) ttyio$(O)
+OBJZI = deflate$(O) trees$(O)
+OBJZA = amiga$(O) amigazip$(O) stat$(O) filedate$(O)
+OBJZ  = $(OBJZ1) $(OBJZ2) $(OBJZI) $(OBJZA)
+
+# Shared utility objects for ZipNote, ZipCloak and ZipSplit
+OBJU1 = globals$(O)
+OBJUU = zipfile$(OU) fileio$(OU) timezone$(O) util$(OU)
+OBJUA = amigazip$(OU) amiga$(O) stat$(O) filedate$(O)
+OBJU  = $(OBJU1) $(OBJUU) $(OBJUA)
+
+# ZipNote objects
+OBJN1 = zipnote$(O)
+OBJN  = $(OBJN1) $(OBJU)
+
+# ZipCloak objects
+OBJC1 = zipcloak$(O)
+OBJCU = $(OBJU) crypt$(OU)
+OBJCS = crc32$(OU) ttyio$(O)
+OBJC  = $(OBJC1) $(OBJCU) $(OBJCS)
+
+#ZipSplit objects
+OBJS1 = zipsplit$(O)
+OBJS  = $(OBJS1) $(OBJU)
+
+# ZipLM objects
+OBJL1 = zip$(OL) zipfile$(OL) zipup$(OL) fileio$(OL) util$(OL) globals$(OL)
+OBJL2 = crc32$(OL) crypt$(OL) timezone$(OL) ttyio$(OL)
+OBJLI = deflate$(OL) trees$(OL)
+OBJLA = amiga$(OL) amigazip$(OL) stat$(OL) filedate$(OL)
+OBJL  = $(OBJL1) $(OBJL2) $(OBJLI) $(OBJLA)
+
+# Common header files
+ZIP_H1 = zip.h ziperr.h tailor.h
+ZIP_HA = amiga/osdep.h amiga/z-stat.h
+ZIP_H  = $(ZIP_H1) $(ZIP_HA)
+
+# Output targets
+ZIPS  = Zip ZipNote ZipCloak ZipSplit ZipLM
+
+
+# Temp filenames for object lists to load using linker "WITH" command.
+OBJLISTZ = zip_objlist.with            # Zip      object list
+OBJLISTN = zipnote_objlist.with        # ZipNote  object list
+OBJLISTC = zipcloak_objlist.with       # ZipCloak object list
+OBJLISTS = zipsplit_objlist.with       # ZipSplit object list
+OBJLISTL = ziplm_objlist.with          # Zip low-mem object list
+
+#######################################
+# DEFAULT TARGET AND PROCESSING RULES #
+#######################################
+
+all: request flush $(ZIPS)
+
+# Zip transformation rules
+#
+.c$(O):
+      $(CC) WITH=$(CFILE) $(CUSEMEM) LISTFILE=$>$(LISTEXTZ) OBJNAME=$@ $*.c
+
+# Zip low-memory version transformation rules
+#
+.c$(OL):
+      $(CC) WITH=$(CFILE) $(CLOWMEM) LISTFILE=$>$(LISTEXTL) OBJNAME=$@ $*.c
+
+# Utilities (ZipNote, ZipCloak and ZipSplit) transformation rules
+#
+.c$(OU):
+      $(CC) WITH=$(CFILE) $(CUSEMEM) DEF=UTIL LISTFILE=$>$(LISTEXTU) OBJNAME=$@ $*.c
+
+
+#########################
+# Final output targets. #
+#########################
+
+
+zip:      local_zip CommonFlags $(OBJZ)
+          @Echo "$(OBJZ)" > $(OBJLISTZ)
+          Type $(OBJLISTZ)
+          @Echo "$(LDFLAGSS) $(LUTIL) WITH $(OBJLISTZ) $(LIBFLAGS)" \
+                "$(LDFLAGS2) $(LMAPZ)" >$(LWITHZ)
+          Type $(LWITHZ)
+          $(LD) TO Zip      WITH $(LWITHZ)
+
+zipnote:  local_zip CommonFlags $(OBJN)
+          @Echo "$(OBJN)" > $(OBJLISTN)
+          Type $(OBJLISTN)
+          @Echo "$(LDFLAGSS) $(LUTIL) WITH $(OBJLISTN) $(LIBFLAGS) " \
+                "$(LDFLAGS2) $(LMAPN)" >$(LWITHN)
+          Type $(LWITHN)
+          $(LD) TO ZipNote  WITH $(LWITHN)
+
+zipcloak: local_zip CommonFlags $(OBJC)
+          @Echo "$(OBJC)" > $(OBJLISTC)
+          Type $(OBJLISTC)
+          @Echo "$(LDFLAGSS) $(LUTIL) WITH $(OBJLISTC) $(LIBFLAGS) " \
+                "$(LDFLAGS2) $(LMAPC)" >$(LWITHC)
+          Type $(LWITHC)
+          $(LD) TO ZipCloak WITH $(LWITHC)
+
+zipsplit: local_zip CommonFlags $(OBJS)
+          @Echo "$(OBJS)" > $(OBJLISTS)
+          Type $(OBJLISTS)
+          @Echo "$(LDFLAGSS) $(LUTIL) WITH $(OBJLISTS) $(LIBFLAGS) " \
+                "$(LDFLAGS2) $(LMAPS)" >$(LWITHS)
+          Type $(LWITHS)
+          $(LD) TO ZipSplit WITH $(LWITHS)
+
+ziplm:    local_zip CommonFlags $(OBJL)
+          @Echo "$(OBJL)" > $(OBJLISTL)
+          Type $(OBJLISTL)
+          @Echo "$(LDFLAGSS) $(LUTIL) WITH $(OBJLISTL) $(LIBFLAGS) " \
+                "$(LDFLAGS2) $(LMAPL)" >$(LWITHL)
+          Type $(LWITHL)
+          $(LD) TO ZipLM    WITH $(LWITHL)
+
+
+clean:
+        -Delete >nil: $(OBJZ) quiet
+        -Delete >nil: $(OBJN) quiet
+        -Delete >nil: $(OBJC) quiet
+        -Delete >nil: $(OBJS) quiet
+        -Delete >nil: $(OBJL) quiet
+        -Delete >nil: $(OBJLISTZ) $(OBJLISTL) $(OBJLISTN) $(OBJLISTS) $(OBJLISTC) quiet
+        -Delete >nil: $(MAPFZ) $(MAPFN) $(MAPFC) $(MAPFS) $(MAPFL) quiet
+        -Delete >nil: \#?$(LISTEXTZ) \#?$(LISTEXTU) \#?$(LISTEXTL) quiet
+        -Delete >nil: $(CWITHOPT) $(CFILE) quiet
+        -Delete >nil: $(LWITHZ) $(LWITHN) $(LWITHC) $(LWITHS) $(LWITHL) quiet
+        -Delete >nil: env:VersionDate quiet
+        -Delete >nil: \#?.q.?? \#?.tmp \#?.cov quiet
+
+spotless: clean
+        -Delete >nil: $(ZIPS) quiet
+
+
+################
+# DEPENDENCIES #
+################
+
+# To change between the assembler and C sources, you have to comment/uncomment
+# the approprite lines. C sources are marked by #C-src and assembler sources
+# #asm-src at the end.
+# Zip dependencies:
+#
+
+zip$(O):        zip.c      $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipup$(O):      zipup.c    $(ZIP_H) revision.h crc32.h crypt.h amiga/zipup.h
+zipfile$(O):    zipfile.c  $(ZIP_H) revision.h crc32.h
+crypt$(O):      crypt.c    $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio$(O):      ttyio.c    $(ZIP_H) crypt.h ttyio.h
+deflate$(O):    deflate.c  $(ZIP_H)                          #C-src
+trees$(O):      trees.c    $(ZIP_H)
+fileio$(O):     fileio.c   $(ZIP_H) crc32.h
+util$(O):       util.c     $(ZIP_H)
+crc32$(O):      crc32.c    $(ZIP_H) crc32.h
+globals$(O):    globals.c  $(ZIP_H)
+timezone$(O):   timezone.c $(ZIP_H) timezone.h
+# Amiga specific objects
+stat$(O):       amiga/stat.c     amiga/z-stat.h
+filedate$(O):   amiga/filedate.c crypt.h timezone.h
+amiga$(O):      amiga/amiga.c    ziperr.h
+amigazip$(O):   amiga/amigazip.c $(ZIP_H) amiga/amiga.h env:Workbench
+# Substitute assembly version of deflate.c:
+#deflate$(O):  amiga/deflate.a                               #asm-src
+#        $(ASM) $(ASMOPTSZ) -o$@ $*.a                        #asm-src
+
+
+# Utility (ZipNote, ZipCloak, ZipSplit) dependencies:
+#
+zipnote$(O):    zipnote.c  $(ZIP_H) revision.h
+zipcloak$(O):   zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipsplit$(O):   zipsplit.c $(ZIP_H) revision.h
+zipfile$(OU):   zipfile.c  $(ZIP_H) revision.h crc32.h
+fileio$(OU):    fileio.c   $(ZIP_H) crc32.h
+util$(OU):      util.c     $(ZIP_H)
+crc32$(OU):     crc32.c    $(ZIP_H) crc32.h
+crypt$(OU):     crypt.c    $(ZIP_H) crypt.h crc32.h ttyio.h
+# Amiga specific objects
+amigazip$(OU):   amiga/amigazip.c $(ZIP_H) amiga/amiga.h env:Workbench
+
+# ZipLM dependencies:
+#
+zip$(OL):       zip.c      $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipup$(OL):     zipup.c    $(ZIP_H) revision.h crc32.h crypt.h amiga/zipup.h
+zipfile$(OL):   zipfile.c  $(ZIP_H) revision.h crc32.h
+crypt$(OL):     crypt.c    $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio$(OL):     ttyio.c    $(ZIP_H) crypt.h ttyio.h
+deflate$(OL):   deflate.c  $(ZIP_H)
+trees$(OL):     trees.c    $(ZIP_H)
+fileio$(OL):    fileio.c   $(ZIP_H) crc32.h
+util$(OL):      util.c     $(ZIP_H)
+crc32$(OL):     crc32.c    $(ZIP_H)
+globals$(OL):   globals.c  $(ZIP_H)
+timezone$(OL):  timezone.c $(ZIP_H) timezone.h
+# Amiga specific objects
+stat$(OL):      amiga/stat.c     amiga/z-stat.h
+filedate$(OL):  amiga/filedate.c crypt.h timezone.h
+amiga$(OL):     amiga/amiga.c    ziperr.h
+# Substitute assembly version of deflate.c:
+#deflate$(OL): amiga/deflate.a
+#        $(ASM) $(ASMOPTSL) -o$@ $*.a
+
+
+########################
+# DEPENDECIES END HERE #
+########################
+
+# flush all libraries to provide more mem for compilation
+flush:
+        @Avail flush >nil:
+
+# write common compiler flags to file and echo to user
+CommonFlags:
+        @Echo "$(CFLAGS)"    >$(CFILE)
+        @Type "$(CWITHOPT)" >>$(CFILE)
+        -Type $(CFILE)
+
+
+# special rules for adding Amiga internal version number to amiga/amiga.c
+amiga$(O):
+         rx > env:VersionDate "say '""'translate(date('E'),'.','/')'""'"
+         $(CC) WITH=$(CFILE) $(CUSEMEM) LISTFILE=$>$(LISTEXTZ) OBJNAME=$@ $*.c
+         -Delete env:VersionDate
+
+amiga$(OL):
+         rx > env:VersionDate "say '""'translate(date('E'),'.','/')'""'"
+         $(CC) WITH=$(CFILE) $(CLOWMEM) LISTFILE=$>$(LISTEXTL) OBJNAME=$@ $*.c
+         -Delete env:VersionDate
+
+
+# needed in amiga/amigazip.c
+# should be set in startup-sequence, but just in case:
+# (only works with OS 2.0 and above)
+
+env\:WorkBench:
+        @Execute < < (Workbench_smk.tmp)
+           FailAt 21
+           If not exists ENV:Workbench
+              Version >nil:
+              SetEnv Workbench $$Workbench
+           Endif
+        <
+
+
+# Read environment variable LOCAL_ZIP and convert options to SAS format
+#
+# e.g.: to define FOO_ONE and FOO_TWO enter:
+#
+# SetEnv LOCAL_ZIP "-DFOO_ONE -DFOO_TWO"
+#
+# Put the statement into your startup-sequence or (for AmigaDOS 2.0 or higher
+# only) make sure LOCAL_ZIP is stored in the ENVARC: directory
+# ( Copy ENV:LOCAL_ZIP ENVARC: )
+#
+
+local_zip:
+        @Execute < < (Local_Zip_smk.tmp)
+           Failat 21
+           If exists ENV:LOCAL_ZIP
+              Echo "Using environment variable LOCAL_ZIP !"
+              Copy >NIL: ENV:LOCAL_ZIP SASCOPTS
+           Else
+              Echo "You could use envvar ZIP_OPT to set your special compilation options."
+              Delete >nil: SASCOPTS quiet
+           Endif
+           ; Do not remove the lctosc command! If LOCAL_ZIP is unset, an
+           ; empty file is created which needed by CommonFlags !
+           lctosc >$(CWITHOPT)
+        <
+
+
+
+# Echo request to the user
+#
+request:
+        @Echo ""
+        @Echo " This makefile is for use with SAS/C version 6.58."
+        @Echo " If you still have an older version, please upgrade!"
+        @Echo " Patches are available on the Aminet under biz/patch/sc\#?."
+        @Echo ""
+        @Echo " Just a simple request..."
+        @Echo " Please give me a mail that you compiled whether you encounter any errors"
+        @Echo " or not. I'd just like to know how many Amiga users actually make use of"
+        @Echo " this makefile."
+        @Echo " If you mail me, I'll put you on my mailing-list and notify you whenever"
+        @Echo " new versions of Info-Zip are released."
+        @Echo " Have a look at the makefile for changes like CPU type, UtilLib, etc."
+        @Echo " Feel free to mail comments, suggestions, etc."
+        @Echo " Enjoy Info-Zip !"
+        @Echo " Haidinger Walter, <walthaid@unix.ict.tuwien.ac.at>"
+        @Echo ""
+
+
+# Echo help in case of an error
+#
+.ONERROR:
+        @Echo ""
+        @Echo "[sigh] An error running this makefile was detected."
+        @Echo "This message may also appear if you interrupted smake by pressing CTRL-C."
+        @Echo "Contact Info-Zip authors at Zip-Bugs@lists.wku.edu or me for help."
+        @Echo "Haidinger Walter, <walthaid@unix.ict.tuwien.ac.at>"
+
diff --git a/amiga/stat.c b/amiga/stat.c
new file mode 100644 (file)
index 0000000..6075c21
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* Here we have a handmade stat() function because Aztec's c.lib stat() */
+/* does not support an st_mode field, which we need... also a chmod().  */
+
+/* This stat() is by Paul Wells, modified by Paul Kienitz. */
+/* Originally for use with Aztec C >= 5.0 and Lattice C <= 4.01  */
+/* Adapted for SAS/C 6.5x by Haidinger Walter */
+
+/* POLICY DECISION: We will not attempt to remove global variables from */
+/* this source file for Aztec C.  These routines are essentially just   */
+/* augmentations of Aztec's c.lib, which is itself not reentrant.  If   */
+/* we want to produce a fully reentrant UnZip, we will have to use a    */
+/* suitable startup module, such as purify.a for Aztec by Paul Kienitz. */
+
+#ifndef __amiga_stat_c
+#define __amiga_stat_c
+
+#include <exec/types.h>
+#include <exec/memory.h>
+#include "amiga/z-stat.h"             /* fake version of stat.h */
+#include <string.h>
+
+#ifdef AZTEC_C
+#  include <libraries/dos.h>
+#  include <libraries/dosextens.h>
+#  include <clib/exec_protos.h>
+#  include <clib/dos_protos.h>
+#  include <pragmas/exec_lib.h>
+#  include <pragmas/dos_lib.h>
+#endif
+#ifdef __SASC
+#  include <sys/dir.h>               /* SAS/C dir function prototypes */
+#  include <sys/types.h>
+#  include <proto/exec.h>
+#  include <proto/dos.h>
+#endif
+
+#ifndef SUCCESS
+#  define SUCCESS (-1)
+#  define FAILURE (0)
+#endif
+
+
+void close_leftover_open_dirs(void);    /* prototype */
+
+static DIR *dir_cleanup_list = NULL;    /* for resource tracking */
+
+/* CALL THIS WHEN HANDLING CTRL-C OR OTHER UNEXPECTED EXIT! */
+void close_leftover_open_dirs(void)
+{
+    while (dir_cleanup_list)
+        closedir(dir_cleanup_list);
+}
+
+
+unsigned short disk_not_mounted;
+
+extern int stat(const char *file, struct stat *buf);
+
+stat(file,buf)
+const char *file;
+struct stat *buf;
+{
+
+        struct FileInfoBlock *inf;
+        BPTR lock;
+        time_t ftime;
+        struct tm local_tm;
+
+        if( (lock = Lock((char *)file,SHARED_LOCK))==0 )
+                /* file not found */
+                return(-1);
+
+        if( !(inf = (struct FileInfoBlock *)AllocMem(
+                (long)sizeof(struct FileInfoBlock),MEMF_PUBLIC|MEMF_CLEAR)) )
+        {
+                UnLock(lock);
+                return(-1);
+        }
+
+        if( Examine(lock,inf)==FAILURE )
+        {
+                FreeMem((char *)inf,(long)sizeof(*inf));
+                UnLock(lock);
+                return(-1);
+        }
+
+        /* fill in buf */
+        buf->st_dev         =
+        buf->st_nlink       =
+        buf->st_uid         =
+        buf->st_gid         =
+        buf->st_rdev        = 0;
+        buf->st_ino         = inf->fib_DiskKey;
+        buf->st_blocks      = inf->fib_NumBlocks;
+        buf->st_size        = inf->fib_Size;
+
+        /* now the date.  AmigaDOS has weird datestamps---
+         *      ds_Days is the number of days since 1-1-1978;
+         *      however, as Unix wants date since 1-1-1970...
+         */
+
+        ftime =
+                (inf->fib_Date.ds_Days * 86400 )                +
+                (inf->fib_Date.ds_Minute * 60 )                 +
+                (inf->fib_Date.ds_Tick / TICKS_PER_SECOND )     +
+                (86400 * 8 * 365 )                              +
+                (86400 * 2 );  /* two leap years */
+
+        /* tzset(); */  /* this should be handled by mktime(), instead */
+        /* ftime += timezone; */
+        local_tm = *gmtime(&ftime);
+        local_tm.tm_isdst = -1;
+        ftime = mktime(&local_tm);
+
+        buf->st_ctime =
+        buf->st_atime =
+        buf->st_mtime = ftime;
+
+        buf->st_mode = (inf->fib_DirEntryType < 0 ? S_IFREG : S_IFDIR);
+
+        /* lastly, throw in the protection bits */
+        buf->st_mode |= ((inf->fib_Protection ^ 0xF) & 0xFF);
+
+        FreeMem((char *)inf, (long)sizeof(*inf));
+        UnLock((BPTR)lock);
+
+        return(0);
+
+}
+
+int fstat(int handle, struct stat *buf)
+{
+    /* fake some reasonable values for stdin */
+    buf->st_mode = (S_IREAD|S_IWRITE|S_IFREG);
+    buf->st_size = -1;
+    buf->st_mtime = time(&buf->st_mtime);
+    return 0;
+}
+
+
+/* opendir(), readdir(), closedir(), rmdir(), and chmod() by Paul Kienitz. */
+
+DIR *opendir(const char *path)
+{
+    DIR *dd = AllocMem(sizeof(DIR), MEMF_PUBLIC);
+    if (!dd) return NULL;
+    if (!(dd->d_parentlock = Lock((char *)path, MODE_OLDFILE))) {
+        disk_not_mounted = IoErr() == ERROR_DEVICE_NOT_MOUNTED;
+        FreeMem(dd, sizeof(DIR));
+        return NULL;
+    } else
+        disk_not_mounted = 0;
+    if (!Examine(dd->d_parentlock, &dd->d_fib) || dd->d_fib.fib_EntryType < 0) {
+        UnLock(dd->d_parentlock);
+        FreeMem(dd, sizeof(DIR));
+        return NULL;
+    }
+    dd->d_cleanuplink = dir_cleanup_list;       /* track them resources */
+    if (dir_cleanup_list)
+        dir_cleanup_list->d_cleanupparent = &dd->d_cleanuplink;
+    dd->d_cleanupparent = &dir_cleanup_list;
+    dir_cleanup_list = dd;
+    return dd;
+}
+
+void closedir(DIR *dd)
+{
+    if (dd) {
+        if (dd->d_cleanuplink)
+            dd->d_cleanuplink->d_cleanupparent = dd->d_cleanupparent;
+        *(dd->d_cleanupparent) = dd->d_cleanuplink;
+        if (dd->d_parentlock)
+            UnLock(dd->d_parentlock);
+        FreeMem(dd, sizeof(DIR));
+    }
+}
+
+struct dirent *readdir(DIR *dd)
+{
+    return (ExNext(dd->d_parentlock, &dd->d_fib) ? (struct dirent *)dd : NULL);
+}
+
+
+#ifdef AZTEC_C
+
+int rmdir(const char *path)
+{
+    return (DeleteFile((char *)path) ? 0 : IoErr());
+}
+
+int chmod(const char *filename, int bits)       /* bits are as for st_mode */
+{
+    long protmask = (bits & 0xFF) ^ 0xF;
+    return !SetProtection((char *)filename, protmask);
+}
+
+
+/* This here removes unnecessary bulk from the executable with Aztec: */
+void _wb_parse(void)  { }
+
+/* fake a unix function that does not apply to amigados: */
+int umask(void)  { return 0; }
+
+
+#  include <signal.h>
+
+/* C library signal() messes up debugging yet adds no actual usefulness */
+typedef void (*__signal_return_type)(int);
+__signal_return_type signal()  { return SIG_ERR; }
+
+
+/* The following replaces Aztec's argv-parsing function for compatibility with
+Unix-like syntax used on other platforms.  It also fixes the problem the
+standard _cli_parse() has of accepting only lower-ascii characters. */
+
+int _argc, _arg_len;
+char **_argv, *_arg_lin;
+
+void _cli_parse(struct Process *pp, long alen, register UBYTE *aptr)
+{
+    register UBYTE *cp;
+    register struct CommandLineInterface *cli;
+    register short c;
+    register short starred = 0;
+#  ifdef PRESTART_HOOK
+    void Prestart_Hook(void);
+#  endif
+
+    cli = (struct CommandLineInterface *) (pp->pr_CLI << 2);
+    cp = (UBYTE *) (cli->cli_CommandName << 2);
+    _arg_len = cp[0] + alen + 2;
+    if (!(_arg_lin = AllocMem((long) _arg_len, 0L)))
+        return;
+    c = cp[0];
+    strncpy(_arg_lin, cp + 1, c);
+    _arg_lin[c] = 0;
+    for (cp = _arg_lin + c + 1; alen && (*aptr < '\n' || *aptr > '\r'); alen--)
+        *cp++ = *aptr++;
+    *cp = 0;
+    aptr = cp = _arg_lin + c + 1;
+    for (_argc = 1; ; _argc++) {
+        while (*cp == ' ' || *cp == '\t')
+            cp++;
+        if (!*cp)
+            break;
+        if (*cp == '"') {
+            cp++;
+            while (c = *cp++) {
+                if (c == '"' && !starred) {
+                    *aptr++ = 0;
+                    starred = 0;
+                    break;
+                } else if (c == '\\' && !starred)
+                    starred = 1;
+                else {
+                    *aptr++ = c;
+                    starred = 0;
+                }
+            }
+        } else {
+            while ((c = *cp++) && c != ' ' && c != '\t')
+                *aptr++ = c;
+            *aptr++ = 0;
+        }
+        if (c == 0)
+            --cp;
+    }
+    *aptr = 0;
+    if (!(_argv = AllocMem((_argc + 1) * sizeof(*_argv), 0L))) {
+        _argc = 0;
+        return;
+    }
+    for (c = 0, cp = _arg_lin; c < _argc; c++) {
+        _argv[c] = cp;
+        cp += strlen(cp) + 1;
+    }
+    _argv[c] = NULL;
+#  ifdef PRESTART_HOOK
+    Prestart_Hook();
+#  endif
+}
+
+#endif /* AZTEC_C */
+
+#endif /* __amiga_stat_c */
diff --git a/amiga/z-stat.h b/amiga/z-stat.h
new file mode 100644 (file)
index 0000000..53d6cd1
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __amiga_z_stat_h
+#define __amiga_z_stat_h
+
+/* Since older versions of the Lattice C compiler for Amiga, and all current */
+/* versions of the Manx Aztec C compiler for Amiga, either provide no stat() */
+/* function or provide one inadequate for unzip (Aztec's has no st_mode      */
+/* field), we provide our own stat() function in stat.c by Paul Wells, and   */
+/* this fake stat.h file by Paul Kienitz.  Paul Wells originally used the    */
+/* Lattice stat.h but that does not work for Aztec and is not distributable  */
+/* with this package, so I made a separate one.  This has to be pulled into  */
+/* unzip.h when compiling an Amiga version, as "amiga/z-stat.h".             */
+
+/* We also provide here a "struct dirent" for use with opendir() & readdir() */
+/* functions included in amiga/stat.c.  If you use amiga/stat.c, this must   */
+/* be included wherever you use either readdir() or stat().                  */
+
+#ifdef AZTEC_C
+#  define __STAT_H
+#else  /* __SASC */
+/* do not include the following header, replacement definitions are here */
+#  define _STAT_H      /* do not include SAS/C <stat.h> */
+#  define _DIRENT_H    /* do not include SAS/C <dirent.h> */
+#  define _SYS_DIR_H   /* do not include SAS/C <sys/dir.h> */
+#  define _COMMIFMT_H  /* do not include SAS/C <sys/commifmt.h> */
+#  include <dos.h>
+#endif
+#include <libraries/dos.h>
+#include <time.h>
+
+
+struct stat {
+    unsigned short st_mode;
+    time_t st_ctime, st_atime, st_mtime;
+    long st_size;
+    long st_ino;
+    long st_blocks;
+    short st_attr, st_dev, st_nlink, st_uid, st_gid, st_rdev;
+};
+
+#define S_IFDIR  (1<<11)
+#define S_IFREG  (1<<10)
+
+#if 0
+   /* these values here are totally random: */
+#  define S_IFLNK  (1<<14)
+#  define S_IFSOCK (1<<13)
+#  define S_IFCHR  (1<<8)
+#  define S_IFIFO  (1<<7)
+#  define S_IFMT   (S_IFDIR|S_IFREG|S_IFCHR|S_IFLNK)
+#else
+#  define S_IFMT   (S_IFDIR|S_IFREG)
+#endif
+
+#define S_IHIDDEN    (1<<7)
+#define S_ISCRIPT    (1<<6)
+#define S_IPURE      (1<<5)
+#define S_IARCHIVE   (1<<4)
+#define S_IREAD      (1<<3)
+#define S_IWRITE     (1<<2)
+#define S_IEXECUTE   (1<<1)
+#define S_IDELETE    (1<<0)
+
+int stat(const char *name, struct stat *buf);
+int fstat(int handle, struct stat *buf);      /* returns dummy values */
+
+typedef struct dirent {
+    struct dirent       *d_cleanuplink,
+                       **d_cleanupparent;
+    BPTR                 d_parentlock;
+    struct FileInfoBlock d_fib;
+} DIR;
+#define                  d_name  d_fib.fib_FileName
+
+extern unsigned short disk_not_mounted;         /* flag set by opendir() */
+
+DIR *opendir(const char *);
+void closedir(DIR *);
+void close_leftover_open_dirs(void);    /* call this if aborted in mid-run */
+struct dirent *readdir(DIR *);
+int umask(void);
+
+#ifdef AZTEC_C
+int rmdir(const char *);
+int chmod(const char *filename, int bits);
+#endif
+
+#endif /* __amiga_z_stat_h */
diff --git a/amiga/zipup.h b/amiga/zipup.h
new file mode 100644 (file)
index 0000000..c9316f4
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef __amiga_zipup_h
+#define __amiga_zipup_h
+
+#ifndef O_RAW
+#  define O_RAW      0
+#endif
+#define fhow         (O_RDONLY | O_RAW)
+#define fbad         (-1)
+typedef int          ftype;
+#define zopen(n,p)   open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f)    close(f)
+#define zerr(f)      (k == (extent)(-1L))
+#define zstdin       0
+
+#endif /* __amiga_zipup_h */
+
diff --git a/aosvs/aosvs.c b/aosvs/aosvs.c
new file mode 100644 (file)
index 0000000..f944ad1
--- /dev/null
@@ -0,0 +1,659 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include <dirent.h>
+#include <time.h>
+
+#include "zip.h"
+#include <paru.h>                 /* parameter definitions */
+#include <sys_calls.h>            /* AOS/VS system call interface */
+#include <packets/filestatus.h>   /* AOS/VS ?FSTAT packet defs */
+
+#ifndef UTIL            /* AOS/VS specific fileio code not needed for UTILs */
+
+#define PAD 0
+#define PATH_END ':'
+
+/*
+ * could probably avoid the union -
+ * all are same size & we're going to assume this
+ */
+typedef union zvsfstat_stru
+{
+     P_FSTAT        norm_fstat_packet;      /* normal fstat packet */
+     P_FSTAT_DIR    dir_fstat_packet;       /* DIR/CPD fstat packet */
+     P_FSTAT_UNIT   unit_fstat_packet;      /* unit (device) fstat packet */
+     P_FSTAT_IPC    ipc_fstat_packet;       /* IPC file fstat packet */
+} ZVSFSTAT_STRU;
+
+typedef struct zextrafld
+{
+     char           extra_header_id[2]; /* set to VS - in theory, an int */
+     char           extra_data_size[2]; /* size of rest, in Intel little-endian order */
+     char           extra_sentinel[4];  /* set to FCI w/ trailing null */
+     unsigned char  extra_rev;          /* set to 10 for rev 1.0 */
+     ZVSFSTAT_STRU  fstat_packet;       /* the fstat packet */
+     char           aclbuf[$MXACL];     /* raw ACL, or link-resolution name */
+} ZEXTRAFLD;
+
+#define ZEXTRA_HEADID   "VS"
+#define ZEXTRA_SENTINEL "FCI"
+#define ZEXTRA_REV      (unsigned char) 10
+
+local ZEXTRAFLD   zzextrafld;         /* buffer for extra field containing
+                                         ?FSTAT packet & ACL buffer */
+local char        zlinkres[$MXPL];    /* buf for link resolution contents */
+local char        znamebuf[$MXPL];    /* buf for AOS/VS filename */
+static char     vsnamebuf[$MXPL];
+static char     uxnamebuf[FNMAX];
+static P_FSTAT  vsfstatbuf;
+
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Local functions */
+local char *readd OF((DIR *));
+
+char *readd(d)
+DIR *d;                 /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+   no more entries or an error occurs. */
+{
+  struct dirent *e;
+
+  e = readdir(d);
+  return e == NULL ? (char *) NULL : e->d_name;
+}
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  DIR *d;               /* directory stream from opendir() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (LSSTAT(n, &s))
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  if ((s.st_mode & S_IFDIR) == 0)
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0, caseflag)) != ZE_OK)
+      return m;
+  } else {
+    /* Add trailing / to the directory name */
+    if ((p = malloc(strlen(n)+2)) == NULL)
+      return ZE_MEM;
+    if (strcmp(n, ".") == 0) {
+      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      strcpy(p, n);
+      a = p + strlen(p);
+      if (a[-1] != '/')
+        strcpy(a, "/");
+      if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+        free((zvoid *)p);
+        return m;
+      }
+    }
+    /* recurse into directory */
+    if (recurse && (d = opendir(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if (strcmp(e, ".") && strcmp(e, ".."))
+        {
+          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+          {
+            closedir(d);
+            free((zvoid *)p);
+            return ZE_MEM;
+          }
+          strcat(strcpy(a, p), e);
+          if ((m = procname(a, caseflag)) != ZE_OK)   /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", a);
+            else
+              ziperr(m, a);
+          }
+          free((zvoid *)a);
+        }
+      }
+      closedir(d);
+    }
+    free((zvoid *)p);
+  } /* (s.st_mode & S_IFDIR) == 0) */
+  return ZE_OK;
+}
+
+char *strlower(s)
+char *s;                /* string to convert */
+/* Convert all uppercase letters to lowercase in string s */
+{
+  char *p;              /* scans string */
+
+  for (p = s; *p; p++)
+    if (*p >= 'A' && *p <= 'Z')
+      *p += 'a' - 'A';
+  return s;
+}
+
+char *strupper(s)
+char *s;                /* string to convert */
+/* Convert all lowercase letters to uppercase in string s */
+{
+  char *p;              /* scans string */
+
+  for (p = s; *p; p++)
+    if (*p >= 'a' && *p <= 'z')
+      *p -= 'a' - 'A';
+  return s;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t;              /* shortened name */
+  int dosflag;
+
+  dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+  /* Find starting point in name before doing malloc */
+  for (t = x; *t == '/'; t++)
+    ;
+
+  if (*t == '=')                /* AOS/VS for ./ */
+    t++;
+  else if (*t == ':')           /* AOS/VS for / */
+    t++;
+
+  if (!pathput)
+    t = last(t, PATH_END);
+
+  if (*t == '^')        /* AOS/VS for ../ */
+  {
+    if ((n = malloc(strlen(t) + 3)) == NULL)
+      return NULL;
+    strcpy(n, "../");
+    strcpy(n + 3, t + 1);
+  }
+  else if (*t == '@')   /* AOS/VS for :PER:, kind of like /dev/ */
+  {
+    if ((n = malloc(strlen(t) + 5)) == NULL)
+      return NULL;
+    strcpy(n, "/PER/");
+    strcpy(n + 5, t + 1);
+  }
+  else
+  {
+    if ((n = malloc(strlen(t) + 1)) == NULL)
+      return NULL;
+    strcpy(n, t);
+  }
+  /* now turn AOS/VS dir separators (colons) into slashes */
+  for (t = n;  *t != '\0';  t++)
+    if (*t == ':')
+      *t = '/';
+  /*
+   * Convert filename to uppercase (for correct matching).
+   * (It may make more sense to patch the matching code, since
+   * we may want those filenames in uppercase on the target system,
+   * but this seems better at present.  If we're converting, uppercase
+   * also seems to make sense.)
+   */
+  strupper(n);
+
+
+  if (dosify)
+    msname(n);
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+  return n;
+}
+
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+      return NULL;
+  strcpy(x, n);
+
+  return x;
+}
+
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+  time_t u[2];          /* argument for utime() */
+
+  /* Convert DOS time to time_t format in u */
+  u[0] = u[1] = dos2unixtime(d);
+  utime(f, u);
+}
+
+ulg filetime(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  /* convert FNMAX to malloc - 11/8/04 EG */
+  char *name;
+  int len = strlen(f);
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+
+  if (strcmp(f, "-") == 0) {
+    if (fstat(fileno(stdin), &s) != 0)
+      error("fstat(stdin)");
+  } else if (LSSTAT(name, &s) != 0) {
+             /* Accept about any file kind including directories
+              * (stored with trailing / with -r option)
+              */
+    free(name);
+    return 0;
+  }
+  free(name);
+
+  if (a != NULL) {
+    *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+    if ((s.st_mode & S_IFDIR) != 0) {
+      *a |= MSDOS_DIR_ATTR;
+    }
+  }
+  if (n != NULL)
+    *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = s.st_ctime;
+  }
+
+  return unix2dostime(&s.st_ctime);
+}
+
+int deletedir(d)
+char *d;
+{
+   return rmdir(d);
+}
+
+int set_extra_field(z, z_utim)
+  struct zlist far *z;
+  iztimes *z_utim;
+  /* create extra field and change z->att if desired */
+  /* NOTE: this AOS/VS version assumes the pathname in z->name is an
+   * AOS/VS pathname, not a unix-style one.  Since you can zip up using
+   * unix-style pathnames, this may create problems occasionally.
+   * We COULD add code to parse back to AOS/VS format ...
+   * (This might also fail for other reasons such as access denied, but
+   * that should already have occurred.)
+   * We set the central-dir extra fld pointer & length here to the same data.
+   */
+{
+  int             aclend = 0;
+/*
+ * use this to simplify because different calls depending on
+ * whether links are resolved
+ */
+  unsigned short  errc;
+
+  z->ext = 0;               /* init to no extra field */
+/* get the ?FSTAT info & the acl - if no errors, get memory & store.
+ * (first, we have to cut off the trailing slash that was added if
+ * it's a dir, since AOS/VS doesn't accept that kind of thing)
+ */
+  strncpy(znamebuf, z->name, $MXPL);
+  znamebuf[$MXPL-1] = '\0';
+  if (znamebuf[strlen(znamebuf)-1] == '/')
+    znamebuf[strlen(znamebuf)-1] = '\0';
+  if (linkput)
+    errc = sys_fstat(znamebuf, BIT1, &(zzextrafld.fstat_packet));
+  else
+    errc = sys_fstat(znamebuf, 0, &(zzextrafld.fstat_packet));
+  if (errc)
+  {
+    fprintf(stderr,
+            "\n    Warning: can't get ?FSTAT info & acl of %s - error %d\n    ",
+            znamebuf, errc);
+    perror("sys_fstat()");
+  }
+  else
+  {
+    /* store the ACL - or, if a link (no ACL!), store the resolution name */
+    if (zzextrafld.fstat_packet.norm_fstat_packet.styp_type != $FLNK)
+    {
+      if ((errc = sys_gacl(znamebuf, zzextrafld.aclbuf)) != 0)
+      {
+        fprintf(stderr, "\n    Warning: can't get acl of %s - error %d\n    ",
+                z->name, errc);
+        perror("sys_gacl()");
+      }
+      else
+      {
+        /* find length of ACL - ends with double-null */
+        while (aclend++ < $MXACL  &&
+               (zzextrafld.aclbuf[aclend - 1] != '\0'  ||
+                zzextrafld.aclbuf[aclend] != '\0'))
+          /* EMPTY LOOP */ ;
+        if ((z->cextra = z->extra =
+             malloc(sizeof(ZEXTRAFLD) - $MXACL + aclend + 4)) != NULL)
+        {
+          strncpy(zzextrafld.extra_header_id, ZEXTRA_HEADID,
+                  sizeof(zzextrafld.extra_header_id));
+          strncpy(zzextrafld.extra_sentinel, ZEXTRA_SENTINEL,
+                  sizeof(zzextrafld.extra_sentinel));
+          zzextrafld.extra_rev = ZEXTRA_REV;    /* this is a char, no need
+                                                   to worry about byte order */
+          /* set size (Intel (little-endian)) 2-byte int, which we've set
+             as array to make it easier */
+          errc = (unsigned short) (sizeof(ZEXTRAFLD) - $MXACL + aclend + 4 -
+                                   sizeof(zzextrafld.extra_header_id) -
+                                   sizeof(zzextrafld.extra_data_size));
+          zzextrafld.extra_data_size[0] = errc & 0xFF;  /* low-order byte */
+          zzextrafld.extra_data_size[1] = errc >> 8;    /* high-order byte */
+          memcpy((char *) z->extra, (char *) &zzextrafld,
+                 sizeof(ZEXTRAFLD) - $MXACL + aclend + 4);
+          z->cext = z->ext = sizeof(ZEXTRAFLD) - $MXACL + aclend + 4;
+        }
+      }
+    }
+    else /* a link */
+    {
+      if ((errc = sys_glink(z->name, zzextrafld.aclbuf)) != 0)
+      {
+        fprintf(stderr,
+              "\n    Warning: can't get link-resolution of %s - error %d\n    ",
+                z->name, errc);
+        perror("sys_glink()");
+      }
+      else
+      {
+        aclend = strlen(zzextrafld.aclbuf) + 1;
+        if ((z->extra = malloc(sizeof(ZEXTRAFLD) - $MXACL + aclend + 4))
+            != NULL)
+        {
+          strncpy(zzextrafld.extra_header_id, ZEXTRA_HEADID,
+                  sizeof(zzextrafld.extra_header_id));
+          strncpy(zzextrafld.extra_sentinel, ZEXTRA_SENTINEL,
+                  sizeof(zzextrafld.extra_sentinel));
+          zzextrafld.extra_rev = ZEXTRA_REV;    /* this is a char, no need
+                                                   to worry about byte order */
+          /* set size (Intel (little-endian)) 2-byte int, which we've set
+             as array to make it easier */
+          errc = (unsigned short) (sizeof(ZEXTRAFLD) - $MXACL + aclend + 4 -
+                                   sizeof(zzextrafld.extra_header_id) -
+                                   sizeof(zzextrafld.extra_data_size));
+          zzextrafld.extra_data_size[0] = errc & 0xFF;  /* low-order byte */
+          zzextrafld.extra_data_size[1] = errc >> 8;    /* high-order byte */
+          memcpy((char *) z->extra, (char *) &zzextrafld,
+                 sizeof(ZEXTRAFLD) - $MXACL + aclend + 4);
+          z->ext = sizeof(ZEXTRAFLD) - $MXACL + aclend + 4;
+        }
+      }
+    }
+  }
+  return ZE_OK;
+}
+
+#endif /* !UTIL */
+
+void version_local()
+{
+    printf("Compiled with %s under %s.\n",
+      "a C compiler",
+      "AOS/VS"
+    );
+}
+
+
+/*
+ * This file defines for AOS/VS two Unix functions relating to links;
+ * the calling code should have the following defines:
+ *
+ *    #define       lstat(path,buf)             zvs_lstat(path,buf)
+ *    #define       readlink(path,buf,nbytes)   zvs_readlink(path,buf,nbytes)
+ *
+ * For these functions, I'm going to define yet 2 MORE filename buffers
+ * and also insert code to change pathnames to Unix & back.  This is
+ * easier than changing all the other places this kind of thing happens to
+ * be efficient.  This is a kludge.  I'm also going to put the functions
+ * here for my immediate convenience rather than somewhere else for
+ * someone else's.
+ *
+ * WARNING: the use of static buffers means that you'd better get your
+ * data out of these buffers before the next call to any of these functions!
+ *
+ */
+
+/* =========================================================================
+ * ZVS_LSTAT() - get (or simulate) stat information WITHOUT following symlinks
+ *      This is intended to look to the outside like the unix lstat()
+ *      function.  We do a quick-&-dirty filename conversion.
+ *
+ *      If the file is NOT a symbolic link, we can just do a stat() on it and
+ *      that should be fine.  But if it IS a link, we have to set the elements
+ *      of the stat struct ourselves, since AOS/VS doesn't have a built-in
+ *      lstat() function.
+ *
+ *      RETURNS: 0 on success, or -1 otherwise
+ *
+ */
+
+int zvs_lstat(char *path, struct stat *buf)
+{
+    char        *cp_vs = vsnamebuf;
+    char        *cp_ux = path;
+    int         mm, dd, yy;
+
+    /*
+     * Convert the Unix pathname to an AOS/VS pathname.
+     * This is quick & dirty; it won't handle (for instance) pathnames with
+     * ../ in the middle of them, and may choke on other Unixisms.  We hope
+     * they're unlikely.
+     */
+    if (!strncmp(cp_ux, "../", 3))
+    {
+        *cp_vs++ = '^';        /* AOS/VS for ../ */
+        cp_ux += 3;
+    }
+    else if (!strncmp(cp_ux, "./", 2))
+    {
+        *cp_vs++ = '=';        /* AOS/VS for ./ */
+        cp_ux += 2;
+    }
+
+    do
+    {
+        if (*cp_ux == '/')
+        {
+            *cp_vs++ = ':';
+        }
+        else
+        {
+            *cp_vs++ = (char) toupper(*cp_ux);
+        }
+
+    } while (*cp_ux++ != '\0'  &&  cp_vs - vsnamebuf < sizeof(vsnamebuf));
+
+    /* If Unix name was too long for our buffer, return an error return */
+    if (cp_vs - vsnamebuf >= sizeof(vsnamebuf)  &&  *(cp_vs - 1) != '\0')
+        return (-1);     /* error */
+
+    /* Make AOS/VS ?FSTAT call that won't follow links & see if we find
+     * anything.  If not, we return error.
+     */
+    if (sys_fstat(vsnamebuf,
+                  BIT1,                 /* BIT1 says to not resolve links */
+                  &vsfstatbuf))
+        return (-1);     /* error */
+
+    /* If we DID find the file but it's not a link,
+     * call stat() and return its value.
+     */
+    if (vsfstatbuf.styp_type != $FLNK)
+        return (stat(path, buf));        /* call with Unix pathname ... */
+
+    /* Otherwise, we have to kludge up values for the stat structure */
+    memset((char *) buf, 0, sizeof(*buf));   /* init to nulls (0 values) */
+    buf->st_mode = S_IFLNK | 0777;           /* link and rwxrwxrwx */
+    buf->st_uid = -1;                        /* this is what we get on AOS/VS
+                                                anyway (maybe unless we set up
+                                                a dummy password file?) */
+    buf->st_nlink = 1;
+    /* The DG date we've got is days since 12/31/67 and seconds/2.  So we
+     * need to subtract 732 days (if that's not negative), convert to seconds,
+     * and add adjusted seconds.
+     */
+    if (vsfstatbuf.stch.short_time[0] < 732)
+        buf->st_ctime = buf->st_mtime = buf->st_atime = 0L;
+    else
+    {
+        buf->st_ctime = buf->st_mtime = buf->st_atime =
+                ((long) vsfstatbuf.stch.short_time[0] - 732L) * 24L * 3600L +
+                2L * (long) vsfstatbuf.stch.short_time[1];
+    }
+
+    /* And we need to get the filename linked to and use its length as
+     * the file size.  We'll use the Unix pathname buffer for this - hope
+     * it's big enough.  (We won't overwrite anything, but we could get a
+     * truncated path.)  If there's an error, here's our last chance to
+     * say anything.
+     */
+    if ((buf->st_size = zvs_readlink(vsnamebuf, uxnamebuf, FNMAX)) < 0)
+        return (-1);
+    else
+        return (0);
+
+} /* end zvs_lstat() */
+
+/* =========================================================================
+ * ZVS_READLINK() - get pathname pointed to by an AOS/VS link file
+ *      This is intended to look to the outside like the unix readlink()
+ *      function.  We do a quick-&-dirty filename conversion.
+ *
+ *      RETURNS: the length of the output path (in bytes), or -1 if an error
+ *
+ */
+
+int zvs_readlink(char *path, char *buf, int nbytes)
+{
+    char    *cp_vs = vsnamebuf;
+    char    *cp_ux = buf;
+
+    /* This is called with z->name, the filename the user gave, so we'll get
+     * the link-resolution name on the assumption that it's a valid AOS/VS
+     * name. We're also assuming a reasonable value (> 5) for nbytes.
+     */
+    if (sys_glink(path, vsnamebuf))
+        return (-1);     /* readlink() is supposed to return -1 on error */
+
+    /* Now, convert the AOS/VS pathname to a Unix pathname.
+     * Note that sys_glink(), unlike readlink(), does add a null.
+     */
+    if (*cp_vs == '^')        /* AOS/VS for ../ */
+    {
+        strncpy(cp_ux, "../", 3);
+        cp_ux += 3;
+        cp_vs++;
+    }
+    else if (*cp_vs == '@')   /* AOS/VS for :PER:, kind of like /dev/ */
+    {
+        strncpy(cp_ux, "/PER/", 5);
+        cp_ux += 5;
+        cp_vs++;
+    }
+    else if (*cp_vs == '=')   /* AOS/VS for ./ */
+    {
+        strncpy(cp_ux, "./", 2);
+        cp_ux += 2;
+        cp_vs++;
+    }
+    while (*cp_vs != '\0'  &&  cp_ux - buf < nbytes)
+    {
+        if (*cp_vs == ':')
+        {
+            *cp_ux++ = '/';
+        }
+        else
+        {
+            *cp_ux++ = (char) toupper(*cp_vs);
+        }
+        cp_vs++;
+    }
+
+    return (cp_ux - buf);   /* # characters in Unix path (no trailing null) */
+
+} /* end zvs_readlink() */
diff --git a/aosvs/make.cli b/aosvs/make.cli
new file mode 100644 (file)
index 0000000..32b2624
--- /dev/null
@@ -0,0 +1,5 @@
+push
+prompt pop
+sea :c_4.10 :c_4.10:lang_rt [!sea]
+cc%0/%/link/NOUNX AOS_VS/DEFINE NODIR/DEFINE <ZIP CRC32 CRYPT DEFLATE FILEIO GLOBALS MKTIME TREES TTYIO UTIL ZIPFILE ZIPUP AOSVS>.C
+pop
diff --git a/api.c b/api.c
new file mode 100644 (file)
index 0000000..b6f57e7
--- /dev/null
+++ b/api.c
@@ -0,0 +1,718 @@
+/*
+  api.c - Zip 3
+
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+  api.c
+
+  This module supplies a Zip dll engine for use directly from C/C++
+  programs.
+
+  The entry points are:
+
+    ZpVer *ZpVersion(void);
+    int EXPENTRY ZpInit(LPZIPUSERFUNCTIONS lpZipUserFunc);
+    int EXPENTRY ZpArchive(ZCL C, LPZPOPT Opts);
+
+  This module is currently only used by the Windows dll, and is not used at
+  all by any of the other platforms, although it should be easy enough to
+  implement this on most platforms.
+
+  ---------------------------------------------------------------------------*/
+#define __API_C
+
+#include <malloc.h>
+#ifdef WINDLL
+#  include <windows.h>
+#  include "windll/windll.h"
+#endif
+
+#ifdef OS2
+#  define  INCL_DOSMEMMGR
+#  include <os2.h>
+#endif
+
+#ifdef __BORLANDC__
+#include <dir.h>
+#endif
+#include <direct.h>
+#include <ctype.h>
+#include "api.h"                /* this includes zip.h */
+#include "crypt.h"
+#include "revision.h"
+#ifdef USE_ZLIB
+#  include "zlib.h"
+#endif
+
+
+DLLPRNT *lpZipPrint;
+DLLPASSWORD *lpZipPassword;
+extern DLLCOMMENT *lpComment;
+ZIPUSERFUNCTIONS ZipUserFunctions, far * lpZipUserFunctions;
+
+int ZipRet;
+char szOrigDir[PATH_MAX];
+BOOL fNo_int64 = FALSE; /* flag for DLLSERVICE_NO_INT64 */
+
+/* Local forward declarations */
+extern int  zipmain OF((int, char **));
+int AllocMemory(unsigned int, char *, char *, BOOL);
+int ParseString(LPSTR, unsigned int);
+void FreeArgVee(void);
+
+ZPOPT Options;
+char **argVee;
+unsigned int argCee;
+
+/*---------------------------------------------------------------------------
+    Local functions
+  ---------------------------------------------------------------------------*/
+
+char szRootDir[PATH_MAX], szExcludeList[PATH_MAX], szIncludeList[PATH_MAX], szTempDir[PATH_MAX];
+
+int ParseString(LPSTR s, unsigned int ArgC)
+{
+unsigned int i;
+int root_flag, m, j;
+char *str1, *str2, *str3;
+size_t size;
+
+i = ArgC;
+str1 = (char *) malloc(lstrlen(s)+4);
+lstrcpy(str1, s);
+lstrcat(str1, " @");
+
+if ((szRootDir != NULL) && (szRootDir[0] != '\0'))
+    {
+    root_flag = TRUE;
+    if (szRootDir[lstrlen(szRootDir)-1] != '\\')
+        lstrcat(szRootDir, "\\");
+    }
+else
+    root_flag = FALSE;
+
+str2 = strchr(str1, '\"'); /* get first occurance of double quote */
+
+while ((str3 = strchr(str1, '\t')) != NULL)
+    {
+    str3[0] = ' '; /* Change tabs into a single space */
+    }
+
+/* Note that if a quoted string contains multiple adjacent spaces, they
+   will not be removed, because they could well point to a valid
+   folder/file name.
+*/
+while ((str2 = strchr(str1, '\"')) != NULL)
+    /* Found a double quote if not NULL */
+    {
+    str3 = strchr(str2+1, '\"'); /* Get the second quote */
+    if (str3 == NULL)
+        {
+        free(str1);
+        return ZE_PARMS; /* Something is screwy with the
+                            string, bail out */
+        }
+    str3[0] = '\0';  /* terminate str2 with a NULL */
+
+    /* strip unwanted fully qualified path from entry */
+    if (root_flag)
+        if ((_strnicmp(szRootDir, str2+1, lstrlen(szRootDir))) == 0)
+            {
+            m = 0;
+            str2++;
+            for (j = lstrlen(szRootDir); j < lstrlen(str2); j++)
+                str2[m++] = str2[j];
+            str2[m] = '\0';
+            str2--;
+            }
+    size = _msize(argVee);
+    if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
+        {
+        fprintf(stdout, "Unable to allocate memory in zip dll\n");
+        return ZE_MEM;
+        }
+    /* argCee is incremented in AllocMemory */
+    if (AllocMemory(i, str2+1, "Creating file list from string", TRUE) != ZE_OK)
+        {
+        free(str1);
+        return ZE_MEM;
+        }
+    i++;
+    str3+=2;        /* Point past the whitespace character */
+    str2[0] = '\0'; /* Terminate str1 */
+    lstrcat(str1, str3);
+    }    /* end while */
+
+/* points to first occurance of a space */
+str2 = strchr(str1, ' ');
+
+/*  Go through the string character by character, looking for instances
+    of two spaces together. Terminate when you find the trailing @
+*/
+while ((str2[0] != '\0') && (str2[0] != '@'))
+    {
+    while ((str2[0] == ' ') && (str2[1] == ' '))
+        {
+        str3 = &str2[1];
+        str2[0] = '\0';
+        lstrcat(str1, str3);
+        }
+    str2++;
+    }
+
+/* Do we still have a leading space? */
+if (str1[0] == ' ')
+    {
+    str3 = &str1[1];
+    lstrcpy(str1, str3); /* Dump the leading space */
+    }
+
+
+/* Okay, now we have gotten rid of any tabs and replaced them with
+   spaces, and have replaced multiple spaces with a single space. We
+   couldn't do this before because the folder names could have actually
+   contained these characters.
+*/
+
+str2 = str3 = str1;
+
+while ((str2[0] != '\0') && (str3[0] != '@'))
+    {
+    str3 = strchr(str2+1, ' ');
+    str3[0] = '\0';
+    /* strip unwanted fully qualified path from entry */
+    if (root_flag)
+        if ((_strnicmp(szRootDir, str2, lstrlen(szRootDir))) == 0)
+           {
+            m = 0;
+            for (j = lstrlen(Options.szRootDir); j < lstrlen(str2); j++)
+            str2[m++] = str2[j];
+            str2[m] = '\0';
+            }
+    size = _msize(argVee);
+    if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
+        {
+        fprintf(stdout, "Unable to allocate memory in zip dll\n");
+        return ZE_MEM;
+        }
+    if (AllocMemory(i, str2, "Creating file list from string", TRUE) != ZE_OK)
+        {
+        free(str1);
+        return ZE_MEM;
+        }
+    i++;
+    str3++;
+    str2 = str3;
+    }
+free(str1);
+return ZE_OK;
+}
+
+int AllocMemory(unsigned int i, char *cmd, char *str, BOOL IncrementArgCee)
+{
+if ((argVee[i] = (char *) malloc( sizeof(char) * strlen(cmd)+1 )) == NULL)
+   {
+   if (IncrementArgCee)
+       argCee++;
+   FreeArgVee();
+   fprintf(stdout, "Unable to allocate memory in zip library at %s\n", str);
+   return ZE_MEM;
+   }
+strcpy( argVee[i], cmd );
+argCee++;
+return ZE_OK;
+}
+
+void FreeArgVee(void)
+{
+unsigned i;
+
+/* Free the arguments in the array */
+for (i = 0; i < argCee; i++)
+    {
+    free (argVee[i]);
+    argVee[i] = NULL;
+    }
+/* Then free the array itself */
+free(argVee);
+
+/* Restore the original working directory */
+chdir(szOrigDir);
+#ifdef __BORLANDC__
+setdisk(toupper(szOrigDir[0]) - 'A');
+#endif
+
+}
+
+
+/*---------------------------------------------------------------------------
+    Documented API entry points
+  ---------------------------------------------------------------------------*/
+
+int EXPENTRY ZpInit(LPZIPUSERFUNCTIONS lpZipUserFunc)
+{
+ZipUserFunctions = *lpZipUserFunc;
+lpZipUserFunctions = &ZipUserFunctions;
+
+if (!lpZipUserFunctions->print ||
+    !lpZipUserFunctions->comment)
+    return FALSE;
+
+return TRUE;
+}
+
+int EXPENTRY ZpArchive(ZCL C, LPZPOPT Opts)
+/* Add, update, freshen, or delete zip entries in a zip file.  See the
+   command help in help() zip.c */
+{
+int k, j, m;
+size_t size;
+
+Options = *Opts; /* Save off options, and make them available locally */
+szRootDir[0] = '\0';
+szExcludeList[0] = '\0';
+szIncludeList[0] = '\0';
+szTempDir[0] = '\0';
+if (Options.szRootDir) lstrcpy(szRootDir, Options.szRootDir);
+if (Options.szExcludeList) lstrcpy(szExcludeList, Options.szExcludeList);
+if (Options.szIncludeList) lstrcpy(szIncludeList, Options.szIncludeList);
+if (Options.szTempDir) lstrcpy(szTempDir, Options.szTempDir);
+
+getcwd(szOrigDir, PATH_MAX); /* Save current drive and directory */
+
+if ((szRootDir != NULL) && (szRootDir[0] != '\0'))
+   {
+   /* Make sure there isn't a trailing slash */
+   if (szRootDir[lstrlen(szRootDir)-1] == '\\')
+       szRootDir[lstrlen(szRootDir)-1] = '\0';
+
+   chdir(szRootDir);
+#ifdef __BORLANDC__
+   setdisk(toupper(szRootDir[0]) - 'A');
+#endif
+   }
+
+argCee = 0;
+
+/* malloc additional 40 to allow for additional command line arguments. Note
+   that we are also adding in the count for the include lists as well as the
+   exclude list. */
+if ((argVee = (char **)malloc((C.argc+40)*sizeof(char *))) == NULL)
+   {
+   fprintf(stdout, "Unable to allocate memory in zip dll\n");
+   return ZE_MEM;
+   }
+if ((argVee[argCee] = (char *) malloc( sizeof(char) * strlen("wiz.exe")+1 )) == NULL)
+   {
+   free(argVee);
+   fprintf(stdout, "Unable to allocate memory in zip dll\n");
+   return ZE_MEM;
+   }
+strcpy( argVee[argCee], "wiz.exe" );
+argCee++;
+
+
+/* Set compression level efficacy -0...-9 */
+if (AllocMemory(argCee, "-0", "Compression", FALSE) != ZE_OK)
+    return ZE_MEM;
+
+/* Check to see if the compression level is set to a valid value. If
+ not, then set it to the default.
+*/
+if ((Options.fLevel < '0') || (Options.fLevel > '9'))
+    {
+    Options.fLevel = '6';
+    if (!Options.fDeleteEntries)
+        fprintf(stdout, "Compression level set to invalid value. Setting to default\n");
+    }
+
+argVee[argCee-1][1] = Options.fLevel;
+
+if (Options.fOffsets)    /* Update offsets for SFX prefix */
+   {
+   if (AllocMemory(argCee, "-A", "Offsets", FALSE) != ZE_OK)
+        return ZE_MEM;
+    }
+if (Options.fDeleteEntries)    /* Delete files from zip file -d */
+   {
+   if (AllocMemory(argCee, "-d", "Delete", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+if (Options.fNoDirEntries) /* Do not add directory entries -D */
+   {
+        if (AllocMemory(argCee, "-D", "No Dir Entries", FALSE) != ZE_OK)
+            return ZE_MEM;
+   }
+if (Options.fFreshen) /* Freshen zip file--overwrite only -f */
+   {
+   if (AllocMemory(argCee, "-f", "Freshen", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+if (Options.fRepair)  /* Fix archive -F or -FF */
+   {
+   if (Options.fRepair == 1)
+      {
+      if (AllocMemory(argCee, "-F", "Repair", FALSE) != ZE_OK)
+          return ZE_MEM;
+      }
+   else
+      {
+      if (AllocMemory(argCee, "-FF", "Repair", FALSE) != ZE_OK)
+        return ZE_MEM;
+      }
+   }
+if (Options.fGrow) /* Allow appending to a zip file -g */
+   {
+   if (AllocMemory(argCee, "-g", "Appending", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+if (Options.fJunkDir) /* Junk directory names -j */
+   {
+   if (AllocMemory(argCee, "-j", "Junk Dir Names", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+if (Options.fEncrypt) /* encrypt -e */
+   {
+   if (AllocMemory(argCee, "-e", "Encrypt", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+if (Options.fJunkSFX) /* Junk sfx prefix */
+   {
+   if (AllocMemory(argCee, "-J", "Junk SFX", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+
+if (Options.fForce) /* Make entries using DOS names (k for Katz) -k */
+   {
+   if (AllocMemory(argCee, "-k", "Force DOS", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+
+if (Options.fLF_CRLF) /* Translate LF_CRLF -l */
+   {
+   if (AllocMemory(argCee, "-l", "LF-CRLF", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+if (Options.fCRLF_LF) /* Translate CR/LF to LF -ll */
+   {
+   if (AllocMemory(argCee, "-ll", "CRLF-LF", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+if (Options.fMove) /* Delete files added to or updated in zip file -m */
+   {
+   if (AllocMemory(argCee, "-m", "Move", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+
+if (Options.fLatestTime) /* Set zip file time to time of latest file in it -o */
+   {
+   if (AllocMemory(argCee, "-o", "Time", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+
+if (Options.fComment) /* Add archive comment "-z" */
+   {
+   if (AllocMemory(argCee, "-z", "Comment", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+
+if (Options.fQuiet) /* quiet operation -q */
+   {
+   if (AllocMemory(argCee, "-q", "Quiet", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+if (Options.fRecurse == 1) /* recurse into subdirectories -r */
+   {
+   if (AllocMemory(argCee, "-r", "Recurse -r", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+else if (Options.fRecurse == 2) /* recurse into subdirectories -R */
+   {
+   if (AllocMemory(argCee, "-R", "Recurse -R", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+if (Options.fSystem)  /* include system and hidden files -S */
+   {
+   if (AllocMemory(argCee, "-S", "System", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+if (Options.fExcludeDate)    /* Exclude files newer than specified date -tt */
+   {
+     if ((Options.Date != NULL) && (Options.Date[0] != '\0'))
+        {
+        if (AllocMemory(argCee, "-tt", "Date", FALSE) != ZE_OK)
+            return ZE_MEM;
+        if (AllocMemory(argCee, Options.Date, "Date", FALSE) != ZE_OK)
+            return ZE_MEM;
+        }
+   }
+
+if (Options.fIncludeDate)    /* include files newer than specified date -t */
+   {
+     if ((Options.Date != NULL) && (Options.Date[0] != '\0'))
+        {
+        if (AllocMemory(argCee, "-t", "Date", FALSE) != ZE_OK)
+            return ZE_MEM;
+       if (AllocMemory(argCee, Options.Date, "Date", FALSE) != ZE_OK)
+            return ZE_MEM;
+        }
+   }
+
+if (Options.fUpdate) /* Update zip file--overwrite only if newer -u */
+    {
+    if (AllocMemory(argCee, "-u", "Update", FALSE) != ZE_OK)
+        return ZE_MEM;
+    }
+if (Options.fVerbose)  /* Mention oddities in zip file structure -v */
+    {
+    if (AllocMemory(argCee, "-v", "Verbose", FALSE) != ZE_OK)
+        return ZE_MEM;
+    }
+if (Options.fVolume)  /* Include volume label -$ */
+    {
+    if (AllocMemory(argCee, "-$", "Volume", FALSE) != ZE_OK)
+        return ZE_MEM;
+    }
+if (Options.szSplitSize != NULL)   /* Turn on archive splitting */
+    {
+    if (AllocMemory(argCee, "-s", "Splitting", FALSE) != ZE_OK)
+        return ZE_MEM;
+    if (AllocMemory(argCee, Options.szSplitSize, "Split size", FALSE) != ZE_OK)
+        return ZE_MEM;
+    }
+if (lpZipUserFunctions->split != NULL)   /* Turn on archive split destinations select */
+    {
+    if (AllocMemory(argCee, "-sp", "Split Pause Select Destination", FALSE) != ZE_OK)
+        return ZE_MEM;
+    }
+#ifdef WIN32
+if (Options.fPrivilege)  /* Use privileges -! */
+   {
+   if (AllocMemory(argCee, "-!", "Privileges", FALSE) != ZE_OK)
+        return ZE_MEM;
+   }
+#endif
+if (Options.fExtra)  /* Exclude extra attributes -X */
+    {
+    if (AllocMemory(argCee, "-X", "Extra", FALSE) != ZE_OK)
+        return ZE_MEM;
+    }
+if (Options.IncludeList != NULL) /* Include file list -i */
+    {
+    if (AllocMemory(argCee, "-i", "Include file list", FALSE) != ZE_OK)
+        return ZE_MEM;
+    k = 0;
+    if (Options.IncludeListCount > 0)
+        while ((Options.IncludeList[k] != NULL) && (Options.IncludeListCount != k+1))
+            {
+            size = _msize(argVee);
+            if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
+                {
+                fprintf(stdout, "Unable to allocate memory in zip dll\n");
+                return ZE_MEM;
+                }
+            if (AllocMemory(argCee, Options.IncludeList[k], "Include file list array", TRUE) != ZE_OK)
+                {
+                return ZE_MEM;
+                }
+            k++;
+            }
+    else
+        while (Options.IncludeList[k] != NULL)
+            {
+            size = _msize(argVee);
+            if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
+                {
+                FreeArgVee();
+                fprintf(stdout, "Unable to allocate memory in zip dll\n");
+                return ZE_MEM;
+                }
+            if (AllocMemory(argCee, Options.IncludeList[k], "Include file list array", TRUE) != ZE_OK)
+                return ZE_MEM;
+            k++;
+            }
+
+    if (AllocMemory(argCee, "@", "End of Include List", FALSE) != ZE_OK)
+        return ZE_MEM;
+    }
+if (Options.ExcludeList != NULL)  /* Exclude file list -x */
+    {
+    if (AllocMemory(argCee, "-x", "Exclude file list", FALSE) != ZE_OK)
+        return ZE_MEM;
+    k = 0;
+    if (Options.ExcludeListCount > 0)
+        while ((Options.ExcludeList[k] != NULL) && (Options.ExcludeListCount != k+1))
+            {
+            size = _msize(argVee);
+            if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
+                {
+                fprintf(stdout, "Unable to allocate memory in zip dll\n");
+                return ZE_MEM;
+                }
+            if (AllocMemory(argCee, Options.ExcludeList[k], "Exclude file list array", TRUE) != ZE_OK)
+                return ZE_MEM;
+            k++;
+            }
+    else
+        while (Options.ExcludeList[k] != NULL)
+            {
+            size = _msize(argVee);
+            if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
+                {
+                FreeArgVee();
+                fprintf(stdout, "Unable to allocate memory in zip dll\n");
+                return ZE_MEM;
+                }
+            if (AllocMemory(argCee, Options.ExcludeList[k], "Exclude file list array", TRUE) != ZE_OK)
+                return ZE_MEM;
+            k++;
+            }
+   if (AllocMemory(argCee, "@", "End of Exclude List", FALSE) != ZE_OK)
+        return ZE_MEM;
+    }
+
+if (szIncludeList != NULL && szIncludeList[0] != '\0') /* Include file list -i */
+    {
+    if (AllocMemory(argCee, "-i", "Include file list", FALSE) != ZE_OK)
+        return ZE_MEM;
+    if ((k = ParseString(szIncludeList, argCee)) != ZE_OK)
+        return k;  /* Something was screwy with the parsed string
+                      bail out */
+    if (AllocMemory(argCee, "@", "End of Include List", FALSE) != ZE_OK)
+        return ZE_MEM;
+    }
+if (szExcludeList != NULL && szExcludeList[0] != '\0')  /* Exclude file list -x */
+    {
+    if (AllocMemory(argCee, "-x", "Exclude file list", FALSE) != ZE_OK)
+        return ZE_MEM;
+
+    if ((k = ParseString(szExcludeList, argCee)) != ZE_OK)
+        return k;  /* Something was screwy with the parsed string
+                      bail out */
+
+    if (AllocMemory(argCee, "@", "End of Exclude List", FALSE) != ZE_OK)
+        return ZE_MEM;
+    }
+
+if ((szTempDir != NULL) && (szTempDir[0] != '\0')
+     && Options.fTemp) /* Use temporary directory -b */
+    {
+    if (AllocMemory(argCee, "-b", "Temp dir switch command", FALSE) != ZE_OK)
+        return ZE_MEM;
+    if (AllocMemory(argCee, szTempDir, "Temporary directory", FALSE) != ZE_OK)
+        return ZE_MEM;
+    }
+
+if (AllocMemory(argCee, C.lpszZipFN, "Zip file name", FALSE) != ZE_OK)
+    return ZE_MEM;
+
+if ((szRootDir != NULL) && (szRootDir[0] != '\0'))
+    {
+    if (szRootDir[lstrlen(szRootDir)-1] != '\\')
+         lstrcat(szRootDir, "\\"); /* append trailing \\ */
+    if (C.FNV != NULL)
+        {
+        for (k = 0; k < C.argc; k++)
+            {
+            if (AllocMemory(argCee, C.FNV[k], "Making argv", FALSE) != ZE_OK)
+                return ZE_MEM;
+            if ((_strnicmp(szRootDir, C.FNV[k], lstrlen(szRootDir))) == 0)
+                {
+                m = 0;
+                for (j = lstrlen(szRootDir); j < lstrlen(C.FNV[k]); j++)
+                    argVee[argCee-1][m++] = C.FNV[k][j];
+                argVee[argCee-1][m] = '\0';
+                }
+            }
+        }
+
+    }
+else
+  if (C.FNV != NULL)
+    for (k = 0; k < C.argc; k++)
+        {
+        if (AllocMemory(argCee, C.FNV[k], "Making argv", FALSE) != ZE_OK)
+            return ZE_MEM;
+        }
+
+if (C.lpszAltFNL != NULL)
+    {
+    if ((k = ParseString(C.lpszAltFNL, argCee)) != ZE_OK)
+        return k;  /* Something was screwy with the parsed string
+                      bail out
+                    */
+    }
+
+
+
+argVee[argCee] = NULL;
+
+ZipRet = zipmain(argCee, argVee);
+
+/* Free the arguments in the array. Note this also restores the
+   current directory
+ */
+FreeArgVee();
+
+return ZipRet;
+}
+
+#if CRYPT
+int encr_passwd(int modeflag, char *pwbuf, int size, const char *zfn)
+    {
+    return (*lpZipUserFunctions->password)(pwbuf, size, ((modeflag == ZP_PW_VERIFY) ?
+                  "Verify password: " : "Enter password: "),
+                  (char *)zfn);
+    }
+#endif /* CRYPT */
+
+void EXPENTRY ZpVersion(ZpVer far * p)   /* should be pointer to const struct */
+    {
+    p->structlen = ZPVER_LEN;
+
+#ifdef BETA
+    p->flag = 1;
+#else
+    p->flag = 0;
+#endif
+#ifdef CRYPT
+    p->fEncryption = TRUE;
+#else
+    p->fEncryption = FALSE;
+#endif
+    lstrcpy(p->betalevel, Z_BETALEVEL);
+    lstrcpy(p->date, REVDATE);
+
+#ifdef ZLIB_VERSION
+    lstrcpy(p->zlib_version, ZLIB_VERSION);
+    p->flag |= 2;
+#else
+    p->zlib_version[0] = '\0';
+#endif
+
+#ifdef ZIP64_SUPPORT
+    p->flag |= 4; /* Flag that ZIP64 was compiled in. */
+#endif
+
+    p->zip.major = Z_MAJORVER;
+    p->zip.minor = Z_MINORVER;
+    p->zip.patchlevel = Z_PATCHLEVEL;
+
+#ifdef OS2
+    p->os2dll.major = D2_MAJORVER;
+    p->os2dll.minor = D2_MINORVER;
+    p->os2dll.patchlevel = D2_PATCHLEVEL;
+#endif
+#ifdef WINDLL
+    p->windll.major = DW_MAJORVER;
+    p->windll.minor = DW_MINORVER;
+    p->windll.patchlevel = DW_PATCHLEVEL;
+#endif
+    }
diff --git a/api.h b/api.h
new file mode 100644 (file)
index 0000000..f609633
--- /dev/null
+++ b/api.h
@@ -0,0 +1,184 @@
+/*
+  api.h - Zip 3
+
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* Only the Windows DLL is currently supported */
+#ifndef _ZIPAPI_H
+#define _ZIPAPI_H
+
+#include "zip.h"
+
+#ifdef WIN32
+#   ifndef PATH_MAX
+#      define PATH_MAX 260
+#   endif
+#else
+#   ifndef PATH_MAX
+#      define PATH_MAX 128
+#   endif
+#endif
+
+#if defined(WINDLL) || defined(API)
+#include <windows.h>
+/* Porting definations between Win 3.1x and Win32 */
+#ifdef WIN32
+#  define far
+#  define _far
+#  define __far
+#  define near
+#  define _near
+#  define __near
+#endif
+
+/*---------------------------------------------------------------------------
+    Prototypes for public Zip API (DLL) functions.
+  ---------------------------------------------------------------------------*/
+
+#define ZPVER_LEN    sizeof(ZpVer)
+/* These defines are set to zero for now, until OS/2 comes out
+   with a dll.
+ */
+#define D2_MAJORVER 0
+#define D2_MINORVER 0
+#define D2_PATCHLEVEL 0
+
+/* intended to be a private struct: */
+typedef struct _zip_ver {
+    uch major;              /* e.g., integer 5 */
+    uch minor;              /* e.g., 2 */
+    uch patchlevel;         /* e.g., 0 */
+    uch not_used;
+} _zip_version_type;
+
+typedef struct _ZpVer {
+    ulg structlen;          /* length of the struct being passed */
+    ulg flag;               /* bit 0: is_beta   bit 1: uses_zlib */
+    char betalevel[10];     /* e.g., "g BETA" or "" */
+    char date[20];          /* e.g., "4 Sep 95" (beta) or "4 September 1995" */
+    char zlib_version[10];  /* e.g., "0.95" or NULL */
+    BOOL fEncryption;       /* TRUE if encryption enabled, FALSE otherwise */
+    _zip_version_type zip;
+    _zip_version_type os2dll;
+    _zip_version_type windll;
+} ZpVer;
+
+#  ifndef EXPENTRY
+#    define EXPENTRY WINAPI
+#  endif
+
+#ifndef DEFINED_ONCE
+#define DEFINED_ONCE
+typedef int (WINAPI DLLPRNT) (LPSTR, unsigned long);
+typedef int (WINAPI DLLPASSWORD) (LPSTR, int, LPCSTR, LPCSTR);
+#endif
+#ifdef ZIP64_SUPPORT
+typedef int (WINAPI DLLSERVICE) (LPCSTR, unsigned __int64);
+typedef int (WINAPI DLLSERVICE_NO_INT64) (LPCSTR, unsigned long, unsigned long);
+#else
+typedef int (WINAPI DLLSERVICE) (LPCSTR, unsigned long);
+#endif
+typedef int (WINAPI DLLSPLIT) (LPSTR);
+typedef int (WINAPI DLLCOMMENT)(LPSTR);
+
+/* Structures */
+
+typedef struct {        /* zip options */
+LPSTR Date;             /* Date to include after */
+LPSTR szRootDir;        /* Directory to use as base for zipping */
+LPSTR szTempDir;        /* Temporary directory used during zipping */
+BOOL fTemp;             /* Use temporary directory '-b' during zipping */
+BOOL fSuffix;           /* include suffixes (not implemented) */
+BOOL fEncrypt;          /* encrypt files */
+BOOL fSystem;           /* include system and hidden files */
+BOOL fVolume;           /* Include volume label */
+BOOL fExtra;            /* Exclude extra attributes */
+BOOL fNoDirEntries;     /* Do not add directory entries */
+BOOL fExcludeDate;      /* Exclude files newer than specified date */
+BOOL fIncludeDate;      /* Include only files newer than specified date */
+BOOL fVerbose;          /* Mention oddities in zip file structure */
+BOOL fQuiet;            /* Quiet operation */
+BOOL fCRLF_LF;          /* Translate CR/LF to LF */
+BOOL fLF_CRLF;          /* Translate LF to CR/LF */
+BOOL fJunkDir;          /* Junk directory names */
+BOOL fGrow;             /* Allow appending to a zip file */
+BOOL fForce;            /* Make entries using DOS names (k for Katz) */
+BOOL fMove;             /* Delete files added or updated in zip file */
+BOOL fDeleteEntries;    /* Delete files from zip file */
+BOOL fUpdate;           /* Update zip file--overwrite only if newer */
+BOOL fFreshen;          /* Freshen zip file--overwrite only */
+BOOL fJunkSFX;          /* Junk SFX prefix */
+BOOL fLatestTime;       /* Set zip file time to time of latest file in it */
+BOOL fComment;          /* Put comment in zip file */
+BOOL fOffsets;          /* Update archive offsets for SFX files */
+BOOL fPrivilege;        /* Use privileges (WIN32 only) */
+BOOL fEncryption;       /* TRUE if encryption supported, else FALSE.
+                           this is a read only flag */
+LPSTR szSplitSize;      /* This string contains the size that you want to
+                           split the archive into. i.e. 100 for 100 bytes,
+                           2K for 2 k bytes, where K is 1024, m for meg
+                           and g for gig. If this string is not NULL it
+                           will automatically be assumed that you wish to
+                           split an archive. */
+LPSTR szIncludeList;    /* Pointer to include file list string (for VB) */
+long IncludeListCount;  /* Count of file names in the include list array */
+char **IncludeList;     /* Pointer to include file list array. Note that the last
+                           entry in the array must be NULL */
+LPSTR szExcludeList;    /* Pointer to exclude file list (for VB) */
+long ExcludeListCount;  /* Count of file names in the include list array */
+char **ExcludeList;     /* Pointer to exclude file list array. Note that the last
+                           entry in the array must be NULL */
+int  fRecurse;          /* Recurse into subdirectories. 1 => -r, 2 => -R */
+int  fRepair;           /* Repair archive. 1 => -F, 2 => -FF */
+char fLevel;            /* Compression level (0 - 9) */
+} ZPOPT, _far *LPZPOPT;
+
+typedef struct {
+  int  argc;            /* Count of files to zip */
+  LPSTR lpszZipFN;      /* name of archive to create/update */
+  char **FNV;           /* array of file names to zip up */
+  LPSTR lpszAltFNL;     /* pointer to a string containing a list of file
+                           names to zip up, separated by whitespace. Intended
+                           for use only by VB users, all others should set this
+                           to NULL. */
+} ZCL, _far *LPZCL;
+
+typedef struct {
+  DLLPRNT *print;
+  DLLCOMMENT *comment;
+  DLLPASSWORD *password;
+  DLLSPLIT *split;      /* This MUST be set to NULL unless you want to be queried
+                           for a destination for each split archive. */
+#ifdef ZIP64_SUPPORT
+  DLLSERVICE *ServiceApplication64;
+  DLLSERVICE_NO_INT64 *ServiceApplication64_No_Int64;
+#else
+  DLLSERVICE *ServiceApplication;
+#endif
+} ZIPUSERFUNCTIONS, far * LPZIPUSERFUNCTIONS;
+
+extern LPZIPUSERFUNCTIONS lpZipUserFunctions;
+
+void  EXPENTRY ZpVersion(ZpVer far *);
+int   EXPENTRY ZpInit(LPZIPUSERFUNCTIONS lpZipUserFunc);
+int   EXPENTRY ZpArchive(ZCL C, LPZPOPT Opts);
+
+#if defined(ZIPLIB) || defined(COM_OBJECT)
+#   define ydays zp_ydays
+#endif
+
+
+
+/* Functions not yet supported */
+#if 0
+int      EXPENTRY ZpMain            (int argc, char **argv);
+int      EXPENTRY ZpAltMain         (int argc, char **argv, ZpInit *init);
+#endif
+#endif /* WINDLL? || API? */
+
+#endif /* _ZIPAPI_H */
diff --git a/atari/Makefile b/atari/Makefile
new file mode 100644 (file)
index 0000000..2c86196
--- /dev/null
@@ -0,0 +1,111 @@
+# Makefile for Zip, ZipNote, ZipCloak and ZipSplit
+
+MAKE = make
+SHELL = /bin/sh
+
+# (to use the Gnu compiler, change cc to gcc in CC and BIND)
+CC = cc
+BIND = $(CC)
+AS = $(CC) -c
+E =
+CPP = /lib/cpp
+
+# probably can change this to 'install' if you have it
+INSTALL = cp
+
+# target directories - where to install executables and man pages to
+BINDIR = /usr/local/bin
+manext=1
+MANDIR = /usr/local/man/man$(manext)
+
+# flags
+#   CFLAGS    flags for C compile
+#   LFLAGS1   flags after output file spec, before obj file list
+#   LFLAGS2   flags after obj file list (libraries, etc)
+CFLAGS = -O
+LFLAGS1 =
+LFLAGS2 = -s
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o crc32.o globals.o \
+       crypt.o ttyio.o atari.o
+
+OBJI = deflate.o trees.o
+OBJA =
+OBJU = zipfile_.o fileio_.o util_.o globals.o atari_.o
+OBJN = zipnote.o  $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h atari/osdep.h
+
+# suffix rules
+.SUFFIXES:
+.SUFFIXES: _.o .o .c .doc .1
+.c_.o:
+       rm -f $*_.c; ln $< $*_.c
+       $(CC) $(CFLAGS) -DUTIL -c $*_.c
+       rm -f $*_.c
+.c.o:
+       $(CC) $(CFLAGS) -c $<
+
+.1.doc:
+       nroff -man $< | col -b | uniq > $@
+
+# rules for zip, zipnote, zipcloak, zipsplit, and the Zip MANUAL.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o crc32.o crypt.o fileio.o zipfile.o zipup.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o:  crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: atari/zipup.h
+
+match.o: match.s
+       $(CPP) match.s > _match.s
+       $(AS) _match.s
+       mv _match.o match.o
+       rm -f _match.s
+
+ZIPS = zip$E zipnote$E zipsplit$E zipcloak$E
+
+zips: $(ZIPS)
+zipsman: $(ZIPS) $(ZIPMANUAL)
+
+zip$E: $(OBJZ) $(OBJI) $(OBJA)
+       $(BIND) -o zip$E $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote$E: $(OBJN)
+       $(BIND) -o zipnote$E $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak$E: $(OBJC)
+       $(BIND) -o zipcloak$E $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit$E: $(OBJS)
+       $(BIND) -o zipsplit$E $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+$(ZIPMANUAL): man/zip.1
+       nroff -man man/zip.1 | col -b | uniq > $(ZIPMANUAL)
+
+# install
+install:        $(ZIPS)
+       $(INSTALL) $(ZIPS) $(BINDIR)
+       $(INSTALL) man/zip.1 $(MANDIR)/zip.$(manext)
+
+uninstall:
+       -cd $(BINDIR); rm -f $(ZIPS)
+       -cd $(MANDIR); rm -f zip.$(manext)
+
+dist: $(ZIPMANUAL)
+       zip -u9T zip`sed -e '/VERSION/!d' -e 's/.*"\(.*\)".*/\1/' \
+                         -e s/[.]//g -e q revision.h` \
+         `awk '/^Makefile/,/vms_zip.rnh/ {print $$1}' < contents`
+
+# ATARI version (gcc 2.5.8 and Mintlibs PL46)
+atari:
+       $(MAKE) zips CFLAGS="-O -DATARI" OBJA=atari/atari.o CC=gcc E=.ttp
+
+# clean up after making stuff and installing it
+clean:
+       rm -f *.o $(ZIPS) flags
diff --git a/atari/README b/atari/README
new file mode 100644 (file)
index 0000000..cce4206
--- /dev/null
@@ -0,0 +1,5 @@
+From: harry@hal.westfalen.de (Harald Denker)
+
+The old zip ATARI port is based on TurboC which is no more
+supported (for more than 3 years). I used the GNU gcc 2.5.8 and
+MiNTlibs PL46.
diff --git a/atari/atari.c b/atari/atari.c
new file mode 100644 (file)
index 0000000..ce5196c
--- /dev/null
@@ -0,0 +1,681 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#ifndef UTIL    /* the companion #endif is a bit of ways down ... */
+
+#include <time.h>
+#include <errno.h>
+#include <dirent.h>
+#include <mintbind.h>
+#include <osbind.h>
+#include <ostruct.h>
+
+
+#define PAD 0
+#define PATH_END '/'
+
+extern char *label;     /* defined in fileio.c */
+
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+
+local char *readd(d)
+DIR *d;                 /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+   no more entries or an error occurs. */
+{
+  struct dirent *e;
+
+  e = readdir(d);
+  return e == NULL ? (char *) NULL : e->d_name;
+}
+
+local char *getVolumeLabel(drive, vtime, vmode, utim)
+  int drive;  /* drive name: 'A' .. 'Z' or '\0' for current drive */
+  ulg *vtime; /* volume label creation time (DOS format) */
+  ulg *vmode; /* volume label file mode */
+  time_t utim;/* volume label creation time (UNIX format) */
+
+/* If a volume label exists for the given drive, return its name and
+   set its time and mode. The returned name must be static data. */
+{
+  static char vol[14];
+  _DTA *dtaptr;
+
+  if (drive) {
+    vol[0] = (char)drive;
+    strcpy(vol+1, ":/");
+  } else {
+    strcpy(vol, "/");
+  }
+  strcat(vol, "*.*");
+  if (Fsfirst(vol, FA_LABEL) == 0) {
+    dtaptr = Fgetdta();
+    strncpy(vol, dtaptr->dta_name, sizeof(vol)-1);
+    *vtime = ((ulg)dtaptr->dta_date << 16) |
+             ((ulg)dtaptr->dta_time & 0xffff);
+    *vmode = (ulg)dtaptr->dta_attribute;
+    return vol;
+  }
+  return NULL;
+}
+
+char GetFileMode(char *name)
+{
+   struct stat sb;
+
+   sb.st_attr = 0;
+   Fxattr(linkput ? 1 : 0, name, &sb);
+   if (errno == EINVAL) {
+      _DTA *dtaptr, *old;
+      old = Fgetdta();
+      Fsfirst(name, FA_RDONLY+FA_HIDDEN+FA_SYSTEM+FA_DIR);
+      dtaptr = Fgetdta();
+      sb.st_attr = dtaptr->dta_attribute;
+      Fsetdta(old);
+   }
+   return sb.st_attr & 0x3f;
+}
+
+
+int wild2(w)
+char *w;                /* path/pattern to match */
+/* If not in exclude mode, expand the pattern based on the contents of the
+   file system.  Return an error code in the ZE_ class. */
+{
+  DIR *d;               /* stream for reading directory */
+  char *e;              /* name found in directory */
+  int r;                /* temporary variable */
+  char *n;              /* constructed name from directory */
+  int f;                /* true if there was a match */
+  char *a;              /* alloc'ed space for name */
+  char *p;              /* path */
+  char *q;              /* name */
+  char v[5];            /* space for device current directory */
+
+  if (volume_label == 1) {
+    volume_label = 2;
+    label = getVolumeLabel(w[1] == ':' ? to_up(w[0]) : '\0',
+                           &label_time, &label_mode, &label_utim);
+    if (label != NULL) {
+       newname(label, 0, 0);
+    }
+    if (w[1] == ':' && w[2] == '\0') return ZE_OK;
+    /* "zip -$ foo a:" can be used to force drive name */
+  }
+
+  /* special handling of stdin request */
+  if (strcmp(w, "-") == 0)   /* if compressing stdin */
+    return newname(w, 0, 0);
+
+  /* Allocate and copy pattern */
+  if ((p = a = malloc(strlen(w) + 1)) == NULL)
+    return ZE_MEM;
+  strcpy(p, w);
+
+  /* Normalize path delimiter as '/'. */
+  for (q = p; *q; q++)                  /* use / consistently */
+    if (*q == '\\')
+      *q = '/';
+
+  /* Only name can have special matching characters */
+  if ((q = isshexp(p)) != NULL &&
+      (strrchr(q, '/') != NULL || strrchr(q, ':') != NULL))
+  {
+    free((zvoid *)a);
+    return ZE_PARMS;
+  }
+
+  /* Separate path and name into p and q */
+  if ((q = strrchr(p, '/')) != NULL && (q == p || q[-1] != ':'))
+  {
+    *q++ = '\0';                        /* path/name -> path, name */
+    if (*p == '\0')                     /* path is just / */
+      p = strcpy(v, "/.");
+  }
+  else if ((q = strrchr(p, ':')) != NULL)
+  {                                     /* has device and no or root path */
+    *q++ = '\0';
+    p = strcat(strcpy(v, p), ":");      /* copy device as path */
+    if (*q == '/')                      /* -> device:/., name */
+    {
+      strcat(p, "/");
+      q++;
+    }
+    strcat(p, ".");
+  }
+  else if (recurse && (strcmp(p, ".") == 0 ||  strcmp(p, "..") == 0))
+  {                                    /* current or parent directory */
+    /* I can't understand Mark's code so I am adding a hack here to get
+     * "zip -r foo ." to work. Allow the dubious "zip -r foo .." but
+     * reject "zip -rm foo ..".
+     */
+    if (dispose && strcmp(p, "..") == 0)
+       ziperr(ZE_PARMS, "cannot remove parent directory");
+    q = "*.*";
+  }
+  else                                  /* no path or device */
+  {
+    q = p;
+    p = strcpy(v, ".");
+  }
+  if (recurse && *q == '\0') {
+    q = "*.*";
+  }
+  /* Search that level for matching names */
+  if ((d = opendir(p)) == NULL)
+  {
+    free((zvoid *)a);
+    return ZE_MISS;
+  }
+  if ((r = strlen(p)) > 1 &&
+      (strcmp(p + r - 2, ":.") == 0 || strcmp(p + r - 2, "/.") == 0))
+    *(p + r - 1) = '\0';
+  f = 0;
+  while ((e = readd(d)) != NULL) {
+    if (strcmp(e, ".") && strcmp(e, "..") && MATCH(q, e, 0))
+    {
+      f = 1;
+      if (strcmp(p, ".") == 0) {                /* path is . */
+        r = procname(e, 0);                     /* name is name */
+        if (r) {
+           f = 0;
+           break;
+        }
+      } else
+      {
+        if ((n = malloc(strlen(p) + strlen(e) + 2)) == NULL)
+        {
+          free((zvoid *)a);
+          closedir(d);
+          return ZE_MEM;
+        }
+        n = strcpy(n, p);
+        if (n[r = strlen(n) - 1] != '/' && n[r] != ':')
+          strcat(n, "/");
+        r = procname(strcat(n, e), 0);          /* name is path/name */
+        free((zvoid *)n);
+        if (r) {
+          f = 0;
+          break;
+        }
+      }
+    }
+  }
+  closedir(d);
+
+  /* Done */
+  free((zvoid *)a);
+  return f ? ZE_OK : ZE_MISS;
+}
+
+
+#include <regexp.h>
+#include <osbind.h>
+
+void regerror( char ZCONST *msg ) {
+   perror( msg );
+}
+
+static int    ret;
+static regexp *regptr;
+static short  is_w, ind_w;
+static char   fullpath[FILENAME_MAX], file_arg[FILENAME_MAX];
+
+#define FTW_F   0
+#define FTW_D   1
+#define FTW_DNR 2
+#define FTW_NS  3
+
+static int ftwfunc( struct stat *stats, int ftw_status )
+{
+   char *path = &fullpath[0];
+
+   if (strncmp(path, "./", 2) == 0) path += 2;
+   switch (ftw_status) {
+   case FTW_NS:
+      zipwarn("can't stat file: ", path);
+      ret = ZE_MISS;
+      return 0;
+   case FTW_F:
+      if (!is_w || regexec(regptr, path, 1)) {
+#if 0
+         char fn[FILENAME_MAX];
+         int  k;
+         if (S_ISLNK(stats->st_mode) &&
+             (k = readlink(path, fn, FILENAME_MAX)) > 0) {
+            int l = strlen(path);
+            fn[k] = '\0';
+            strcat(strcat(path, " -> "), fn);
+            ret = newname(path, 0, 0); /* procname(path, 0); */
+            path[l] = '\0';
+         } else
+#endif
+            ret = newname(path, 0, 0); /* procname(path, 0); */
+      }
+      return 0;
+   case FTW_DNR:
+      zipwarn("can't open directory: ", path);
+      ret = ZE_MISS;
+      return 0;
+   case FTW_D:
+      if (strcmp(path, ".") == 0) return 0;
+      if (is_w && ind_w > 0 && strncmp(path, file_arg, ind_w) != 0)
+         return 4;
+   }
+   return 0;
+}
+
+static int myftw( int depth )
+{
+   register DIR   *dirp;
+   struct dirent  *entp;
+   struct stat    stats;
+   register char  *p,*q;
+   register long  i;
+
+   if (LSSTAT(fullpath, &stats) < 0)
+      return ftwfunc(&stats, FTW_NS);
+
+   if (!S_ISDIR(stats.st_mode))
+      return ftwfunc(&stats, FTW_F);
+
+   if ((dirp = opendir(fullpath)) == NULL)
+      return ftwfunc(&stats, FTW_DNR);
+
+   if (i = ftwfunc(&stats, FTW_D)) {
+      closedir(dirp);
+      return (i == 4 ? 0 : (int)i);
+   }
+   i = strlen(fullpath);
+   p = &fullpath[i];
+   *p++ = '/'; *p = '\0';
+   if (dirnames && i > 1) {
+      q = (strncmp(fullpath, "./", 2) == 0 ? &fullpath[2] : &fullpath[0]);
+      ret = newname(q, 1, 0);
+   }
+   i = 0;
+   while (depth > 0 && (entp = readdir(dirp)) != 0)
+      if (strcmp(entp->d_name,".") != 0 && strcmp(entp->d_name,"..") != 0) {
+         strcpy(p, entp->d_name);
+         if (i = myftw(depth-1))
+            depth = 0;       /* force User's finish */
+      }
+   closedir(dirp);
+   return (int)i;
+}
+
+int wild( char *p )
+{
+   char *d;
+
+   ret = ZE_OK;
+   if (p == NULL) p = "*";
+
+   if (strcmp(p, "-") == 0)     /* if compressing stdin */
+      ret = newname(p, 0, 0);
+
+   strcpy(fullpath, p);
+   /* now turning UNIX-Wildcards into basic regular expressions */
+   for (is_w = ind_w = 0, d = &file_arg[0]; *p; d++, p++)
+      switch (*p) {
+      case '*': *d++ = '.'; *d = *p; is_w = 1;  break;
+      case '?': *d = '.';            is_w = 1;  break;
+      case '[': *d = *p;
+                if (*(p+1) == '!') {
+                   *++d = '^'; p++;
+                }                    is_w = 1;  break;
+      case '.': *d++ = '\\'; *d = *p;           break;
+      default : *d = *p;
+                if (!is_w) ind_w++;
+      }
+   *++d = '\0';
+   if (is_w) {
+      strcat( file_arg, "$" );           /* to get things like *.[ch] work */
+      if ((regptr = regcomp( file_arg )) == NULL)
+         return ZE_MEM;
+      strcpy( fullpath, "." );
+      myftw( recurse ? 99 : 1 );
+      free(regptr);
+   } else if (recurse) {
+      myftw( 99 );
+   } else
+      myftw( 1 ); /* ret = procname( fullpath, 0 ); */
+   return ret;
+}
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  DIR *d;               /* directory stream from opendir() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (LSSTAT(n, &s))
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  for (p = n; *p; p++)          /* use / consistently */
+    if (*p == '\\')
+      *p = '/';
+  if (!S_ISDIR(s.st_mode))
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0, caseflag)) != ZE_OK)
+      return m;
+  } else {
+    /* Add trailing / to the directory name */
+    if ((p = malloc(strlen(n)+2)) == NULL)
+      return ZE_MEM;
+    if (strcmp(n, ".") == 0) {
+      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      strcpy(p, n);
+      a = p + strlen(p);
+      if (a[-1] != '/')
+        strcpy(a, "/");
+      if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+        free((zvoid *)p);
+        return m;
+      }
+    }
+    /* recurse into directory */
+    if (recurse && (d = opendir(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if (strcmp(e, ".") && strcmp(e, ".."))
+        {
+          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+          {
+            closedir(d);
+            free((zvoid *)p);
+            return ZE_MEM;
+          }
+          strcat(strcpy(a, p), e);
+          if ((m = procname(a, caseflag)) != ZE_OK)   /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", a);
+            else
+              ziperr(m, a);
+          }
+          free((zvoid *)a);
+        }
+      }
+      closedir(d);
+    }
+    free((zvoid *)p);
+  } /* (s.st_mode & S_IFDIR) == 0) */
+  return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t, *p;          /* shortened name */
+  int dosflag;
+
+  dosflag = 0;
+
+  /* Find starting point in name before doing malloc */
+  t = *x && *(x + 1) == ':' ? x + 2 : x;
+  while (*t == '/' || *t == '\\')
+    t++;
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+  for (n = t; *n; n++)
+    if (*n == '\\')
+      *n = '/';
+
+  if (!pathput)
+    t = last(t, PATH_END);
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL)
+    return NULL;
+  strcpy(n, t);
+#if 0
+  if (p = strstr(t, " -> "))       /* shorten "link -> data" to "link" */
+    *p = '\0';
+#endif
+  if (dosify)
+    msname(n);
+
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+  return n;
+}
+
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+      return NULL;
+  strcpy(x, n);
+  return x;
+}
+
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+  struct utimbuf u;     /* argument for utime()  const ?? */
+
+  /* Convert DOS time to time_t format in u[0] and u[1] */
+  u.actime = u.modtime = dos2unixtime(d);
+
+  /* Set updated and accessed times of f */
+  utime(f, &u);
+}
+
+ulg filetime(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  /* convert FNMAX to malloc - 11/8/04 EG */
+  char *name;
+  int len = strlen(f);
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+
+  if (strcmp(f, "-") == 0) {
+    if (fstat(fileno(stdin), &s) != 0) {
+      free(name);
+      error("fstat(stdin)");
+    }
+  } else if (LSSTAT(name, &s) != 0) {
+             /* Accept about any file kind including directories
+              * (stored with trailing / with -r option)
+              */
+    free(name);
+    return 0;
+  }
+
+  if (a != NULL) {
+/*  *a = ((ulg)s.st_mode << 16) | (ulg)GetFileMode(name); */
+    *a = ((ulg)s.st_mode << 16) | (ulg)s.st_attr;
+  }
+  free(name);
+  if (n != NULL)
+    *n = S_ISREG(s.st_mode) ? s.st_size : -1L;
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = s.st_ctime;
+  }
+
+  return unix2dostime(&s.st_mtime);
+}
+
+int set_extra_field(z, z_utim)
+  struct zlist far *z;
+  iztimes *z_utim;
+  /* create extra field and change z->att if desired */
+{
+#ifdef USE_EF_UT_TIME
+#ifdef IZ_CHECK_TZ
+  if (!zp_tz_is_valid) return ZE_OK;    /* skip silently if no valid TZ info */
+#endif
+
+  if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(2))) == NULL)
+    return ZE_MEM;
+  if ((z->cextra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
+    return ZE_MEM;
+
+  z->extra[0]  = 'U';
+  z->extra[1]  = 'T';
+  z->extra[2]  = EB_UT_LEN(2);          /* length of data part of e.f. */
+  z->extra[3]  = 0;
+  z->extra[4]  = EB_UT_FL_MTIME | EB_UT_FL_ATIME;
+  z->extra[5]  = (char)(z_utim->mtime);
+  z->extra[6]  = (char)(z_utim->mtime >> 8);
+  z->extra[7]  = (char)(z_utim->mtime >> 16);
+  z->extra[8]  = (char)(z_utim->mtime >> 24);
+  z->extra[9]  = (char)(z_utim->atime);
+  z->extra[10] = (char)(z_utim->atime >> 8);
+  z->extra[11] = (char)(z_utim->atime >> 16);
+  z->extra[12] = (char)(z_utim->atime >> 24);
+
+  z->ext = (EB_HEADSIZE+EB_UX_LEN(2));
+
+  memcpy(z->cextra, z->extra, (EB_HEADSIZE+EB_UT_LEN(1)));
+  z->cextra[EB_LEN] = EB_UT_LEN(1);
+  z->cext = (EB_HEADSIZE+EB_UX_LEN(1));
+
+  return ZE_OK;
+#else /* !USE_EF_UT_TIME */
+  return (int)(z-z);
+#endif /* ?USE_EF_UT_TIME */
+}
+
+int deletedir(d)
+char *d;                /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+   Return the result of rmdir(), delete(), or system().
+   For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
+ */
+{
+    return rmdir(d);
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+void version_local()
+{
+    static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+#ifdef __TURBOC__
+    char buf[40];
+#endif
+
+    printf(CompiledWith,
+
+#ifdef __GNUC__
+      "gcc ", __VERSION__,
+#else
+#  if 0
+      "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
+#  else
+#  ifdef __TURBOC__
+      "Turbo C", (sprintf(buf, " (0x%04x = %d)", __TURBOC__, __TURBOC__), buf),
+#  else
+      "unknown compiler", "",
+#  endif
+#  endif
+#endif
+
+#ifdef __MINT__
+      "Atari TOS/MiNT",
+#else
+      "Atari TOS",
+#endif
+
+      " (Atari ST/TT/Falcon030)",
+
+#ifdef __DATE__
+      " on ", __DATE__
+#else
+      "", ""
+#endif
+      );
+
+} /* end function version_local() */
diff --git a/atari/make_all.mup b/atari/make_all.mup
new file mode 100644 (file)
index 0000000..5f8c4dc
--- /dev/null
@@ -0,0 +1,7 @@
+rm -f *.o *.sym *.ttp
+make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-O -DATARI" E=.ttp OBJA=atari.o zips
+#make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-g -D__NO_INLINE__ -DATARI" E=.ttp OBJA=atari.o zip.ttp
+#make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-g -D__NO_INLINE__ -DATARI" E=.sym OBJA=atari.o zip.sym LFLAGS2="-B/bin/sym-"
+#make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-O -DATARI" E=.ttp OBJA=atari.o -n zips > make_all.mup
+#fixstk 32K pgp.ttp
+prgflags 017 007 *.ttp
diff --git a/atari/make_zip.mup b/atari/make_zip.mup
new file mode 100644 (file)
index 0000000..4ea4c31
--- /dev/null
@@ -0,0 +1,7 @@
+#rm -f *.o *.sym *.ttp
+#make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-O -DATARI" E=.ttp OBJA=atari.o zips
+make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-g -D__NO_INLINE__ -DATARI" E=.ttp OBJA=atari.o zip.ttp
+make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-g -D__NO_INLINE__ -DATARI" E=.sym OBJA=atari.o zip.sym LFLAGS2="-B/bin/sym-"
+#make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-O -DATARI" E=.ttp OBJA=atari.o -n zips > make_all.mup
+#fixstk 32K pgp.ttp
+prgflags 017 007 *.ttp
diff --git a/atari/osdep.h b/atari/osdep.h
new file mode 100644 (file)
index 0000000..46387b6
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define FOPR "rb"
+#define FOPM "r+b"
+#define FOPW "wb"
+
+#define DIRENT
+#define NO_TERMIO
+#define USE_CASE_MAP
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+                     procname(n, 1))
+
+#include <sys/types.h>
+#include <sys/stat.h>
diff --git a/atari/zipup.h b/atari/zipup.h
new file mode 100644 (file)
index 0000000..1de3f61
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+#  define O_RDONLY 0
+#endif
+#define fhow O_RDONLY
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/atheos/Makefile b/atheos/Makefile
new file mode 100644 (file)
index 0000000..91df1c8
--- /dev/null
@@ -0,0 +1,146 @@
+######################################################################
+#
+# Makefile for Info-ZIP's zip, zipcloak, zipnote, and zipsplit on AtheOS
+#
+# Copyright (C) 1999-2007 Info-ZIP
+#                    Chris Herborth (chrish@pobox.com)
+#                    Ruslan Nickolaev (nruslan@hotbox.ru)
+#
+######################################################################
+# Things that don't change:
+
+# Punish people who don't have SMP hardware.
+MAKE  = make -j 4 -f atheos/Makefile
+SHELL = /bin/sh
+
+LN = ln -s
+RM = rm -f
+
+BIND = $(CC)
+AS   = as
+
+INSTALL = install
+
+# Target directories
+prefix = /usr
+BINDIR = $(prefix)/bin
+manext = 1
+MANDIR = $(prefix)/man/man$(manext)
+ZIPMANUAL = MANUAL
+
+VERSION = Version 2.3 of __DATE__
+
+######################################################################
+
+CC:=gcc
+CFLAGS:=-O3 -march=i586 -Wall -I. -DHAVE_DIRENT_H -DPASSWD_FROM_STDIN -DASMV -DASM_CRC
+LFLAGS1:=
+LFLAGS2:=
+TARGET=$(ZIPS)
+
+######################################################################
+# Helpful targets
+all:
+       $(MAKE) CC=$(CC) CFLAGS="$(CFLAGS)" \
+               LFLAGS1="$(LFLAGS1)" LFLAGS2="$(LFLAGS2)" \
+               $(TARGET)
+
+######################################################################
+# Object file lists and other build goodies
+
+# Object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crc32.o crypt.o \
+       ttyio.o atheos.o
+OBJI = deflate.o trees.o
+OBJA = match.o crc_i386.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o atheos_.o
+OBJN = zipnote.o  $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+# Headers
+ZIP_H = zip.h ziperr.h tailor.h atheos/osdep.h
+
+# What to build?
+ZIPS = zip zipnote zipsplit zipcloak
+
+# suffix rules
+.SUFFIXES:
+.SUFFIXES: _.o .o .c .doc .1
+.c_.o:
+       $(RM) $*_.c; $(LN) $< $*_.c
+       $(CC) -c $(CFLAGS) -DUTIL $*_.c
+       $(RM) $*_.c
+
+.c.o:
+       $(CC) -c $(CFLAGS) $<
+
+.1.doc:
+       groff -man -Tascii $< > $@
+
+# rules for zip, zipnote, zipcloak, zipsplit, and the Zip MANUAL.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o crc32.o crypt.o fileio.o zipfile.o zipup.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: atheos/zipup.h
+
+match.o: match.S
+       $(CC) -E match.S > matchs.s
+       $(AS) -o $@ matchs.s
+       $(RM) matchs.s
+
+crc_i386.o: crc_i386.S
+       $(CC) -E crc_i386.S > crc_i386s.s
+       $(AS) -o $@ crc_i386s.s
+       $(RM) crc_i386s.s
+
+atheos.o: atheos/atheos.c
+       $(CC) -c $(CFLAGS) atheos/atheos.c
+
+atheos_.o: atheos/atheos.c
+       $(RM) $*_.c; $(LN) atheos/atheos.c $*_.c
+       $(CC) -c $(CFLAGS) -DUTIL $*_.c
+       $(RM) $*_.c
+
+zips: $(ZIPS)
+zipsman: $(ZIPS) $(ZIPMANUAL)
+
+zip: $(OBJZ) $(OBJI) $(OBJA)
+       $(BIND) -o zip $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote: $(OBJN)
+       $(BIND) -o zipnote $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak: $(OBJC)
+       $(BIND) -o zipcloak $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit: $(OBJS)
+       $(BIND) -o zipsplit $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+$(ZIPMANUAL): man/zip.1
+       groff -man -Tascii man/zip.1 > $(ZIPMANUAL)
+
+# install
+install:        $(ZIPS)
+       $(INSTALL) -m755 $(ZIPS) $(BINDIR)
+       mkdir -p $(MANDIR)
+       $(INSTALL) -m644 man/zip.1 $(MANDIR)/zip.$(manext)
+
+uninstall:
+       -cd $(BINDIR); $(RM) $(ZIPS)
+       -cd $(MANDIR); $(RM) zip.$(manext)
+
+dist: $(ZIPMANUAL)
+       zip -u9T zip`sed -e '/VERSION/!d' -e 's/.*"\(.*\)".*/\1/' \
+                         -e s/[.]//g -e q revision.h` \
+         `awk '/^Makefile/,/vms_zip.rnh/ {print $$1}' < contents`
+
+# clean up after making stuff and installing it
+clean:
+       $(RM) *.o $(ZIPS) flags
+
+# end of Makefile
diff --git a/atheos/README b/atheos/README
new file mode 100644 (file)
index 0000000..a96fffc
--- /dev/null
@@ -0,0 +1,21 @@
+Info-ZIP's zip for AtheOS/Syllable
+
+FEATURES
+  stores AtheOS/Syllable file attributes, compressing them if possible
+
+TODO
+----
+There is only one thing to be fixed:
+  write_attr() should return count of writed bytes. However that's bug related with AFS only.
+
+Please report any bugs to Info-ZIP at www.info-zip.org.
+If this bug related with AtheOS/Syllable only, you can mail me directly: nruslan@hotbox.ru.
+
+Visit the Info-ZIP web site (http://www.info-zip.org) for all the
+latest zip and unzip information, FAQs, source code and ready-to-run
+executables.
+
+- Ruslan Nickolaev (nruslan@hotbox.ru)
+  Sep 06/2004
+
+(updated 12 November 2004)
diff --git a/atheos/atheos.c b/atheos/atheos.c
new file mode 100644 (file)
index 0000000..6f1c915
--- /dev/null
@@ -0,0 +1,885 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+
+  This AtheOS - specific file is based on unix.c and beos.c;
+  changes by Ruslan Nickolaev (nruslan@hotbox.ru)
+*/
+
+#include "zip.h"
+
+#ifndef UTIL    /* the companion #endif is a bit of ways down ... */
+
+#include <time.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atheos/fs_attribs.h>
+
+
+#define PAD 0
+#define PATH_END '/'
+
+/* Library functions not in (most) header files */
+
+#ifdef _POSIX_VERSION
+#  include <utime.h>
+#else
+   int utime OF((char *, time_t *));
+#endif
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Local functions */
+local char *readd OF((DIR *));
+local int get_attr_dir( const char *, char **, off_t * );
+local int add_UT_ef( struct zlist far * );
+local int add_Ux_ef( struct zlist far * );
+local int add_At_ef( struct zlist far * );
+
+local char *readd(d)
+DIR *d;                 /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+   no more entries or an error occurs. */
+{
+  struct dirent *e;
+
+  e = readdir(d);
+  return e == NULL ? (char *) NULL : e->d_name;
+}
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  DIR *d;               /* directory stream from opendir() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (LSSTAT(n, &s))
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  if ((s.st_mode & S_IFREG) == S_IFREG ||
+      (s.st_mode & S_IFLNK) == S_IFLNK)
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0, caseflag)) != ZE_OK)
+      return m;
+  }
+  else if ((s.st_mode & S_IFDIR) == S_IFDIR)
+  {
+    /* Add trailing / to the directory name */
+    if ((p = malloc(strlen(n)+2)) == NULL)
+      return ZE_MEM;
+    if (strcmp(n, ".") == 0) {
+      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      strcpy(p, n);
+      a = p + strlen(p);
+      if (a[-1] != '/')
+        strcpy(a, "/");
+      if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+        free((zvoid *)p);
+        return m;
+      }
+    }
+    /* recurse into directory */
+    if (recurse && (d = opendir(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if (strcmp(e, ".") && strcmp(e, ".."))
+        {
+          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+          {
+            closedir(d);
+            free((zvoid *)p);
+            return ZE_MEM;
+          }
+          strcat(strcpy(a, p), e);
+          if ((m = procname(a, caseflag)) != ZE_OK)   /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", a);
+            else
+              ziperr(m, a);
+          }
+          free((zvoid *)a);
+        }
+      }
+      closedir(d);
+    }
+    free((zvoid *)p);
+  } /* (s.st_mode & S_IFDIR) */
+  else
+    zipwarn("ignoring special file: ", n);
+  return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t = NULL;       /* shortened name */
+  int dosflag;
+
+  dosflag = dosify;  /* default for non-DOS and non-OS/2 */
+
+  /* Find starting point in name before doing malloc */
+  /* Strip "//host/share/" part of a UNC name */
+  if (!strncmp(x,"//",2) && (x[2] != '\0' && x[2] != '/')) {
+    n = x + 2;
+    while (*n != '\0' && *n != '/')
+      n++;              /* strip host name */
+    if (*n != '\0') {
+      n++;
+      while (*n != '\0' && *n != '/')
+        n++;            /* strip `share' name */
+    }
+    if (*n != '\0')
+      t = n + 1;
+  } else
+      t = x;
+  while (*t == '/')
+    t++;                /* strip leading '/' chars to get a relative path */
+  while (*t == '.' && t[1] == '/')
+    t += 2;             /* strip redundant leading "./" sections */
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+  if (!pathput)
+    t = last(t, PATH_END);
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL)
+    return NULL;
+  strcpy(n, t);
+
+  if (isdir == 42) return n;    /* avoid warning on unused variable */
+
+  if (dosify)
+    msname(n);
+
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+  return n;
+}
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+    return NULL;
+  strcpy(x, n);
+  return x;
+}
+
+/*
+ * XXX use ztimbuf in both POSIX and non POSIX cases ?
+ */
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+#ifdef _POSIX_VERSION
+  struct utimbuf u;     /* argument for utime()  const ?? */
+#else
+  time_t u[2];          /* argument for utime() */
+#endif
+
+  /* Convert DOS time to time_t format in u */
+#ifdef _POSIX_VERSION
+  u.actime = u.modtime = dos2unixtime(d);
+  utime(f, &u);
+#else
+  u[0] = u[1] = dos2unixtime(d);
+  utime(f, u);
+#endif
+
+}
+
+ulg filetime(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  char *name;
+  int len = strlen(f);
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+  if (strcmp(f, "-") == 0) {
+    if (fstat(fileno(stdin), &s) != 0) {
+      free(name);
+      error("fstat(stdin)");
+    }
+  }
+  else if (LSSTAT(name, &s) != 0) {
+    /* Accept about any file kind including directories
+     * (stored with trailing / with -r option)
+     */
+    free(name);
+    return 0;
+  }
+  free(name);
+
+  if (a != NULL) {
+#ifndef OS390
+    *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+#else
+/*
+**  The following defines are copied from the unizip source and represent the
+**  legacy Unix mode flags.  These fixed bit masks are no longer required
+**  by XOPEN standards - the S_IS### macros being the new recommended method.
+**  The approach here of setting the legacy flags by testing the macros should
+**  work under any _XOPEN_SOURCE environment (and will just rebuild the same bit
+**  mask), but is required if the legacy bit flags differ from legacy Unix.
+*/
+#define UNX_IFDIR      0040000     /* Unix directory */
+#define UNX_IFREG      0100000     /* Unix regular file */
+#define UNX_IFSOCK     0140000     /* Unix socket (BSD, not SysV or Amiga) */
+#define UNX_IFLNK      0120000     /* Unix symbolic link (not SysV, Amiga) */
+#define UNX_IFBLK      0060000     /* Unix block special       (not Amiga) */
+#define UNX_IFCHR      0020000     /* Unix character special   (not Amiga) */
+#define UNX_IFIFO      0010000     /* Unix fifo    (BCC, not MSC or Amiga) */
+    {
+    mode_t legacy_modes;
+
+    /* Initialize with permission bits - which are not implementation optional */
+    legacy_modes = s.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX);
+    if (S_ISDIR(s.st_mode))
+      legacy_modes |= UNX_IFDIR;
+    if (S_ISREG(s.st_mode))
+      legacy_modes |= UNX_IFREG;
+    if (S_ISLNK(s.st_mode))
+      legacy_modes |= UNX_IFLNK;
+    if (S_ISBLK(s.st_mode))
+      legacy_modes |= UNX_IFBLK;
+    if (S_ISCHR(s.st_mode))
+      legacy_modes |= UNX_IFCHR;
+    if (S_ISFIFO(s.st_mode))
+      legacy_modes |= UNX_IFIFO;
+    if (S_ISSOCK(s.st_mode))
+      legacy_modes |= UNX_IFSOCK;
+    *a = ((ulg)legacy_modes << 16) | !(s.st_mode & S_IWRITE);
+    }
+#endif
+    if ((s.st_mode & S_IFMT) == S_IFDIR) {
+      *a |= MSDOS_DIR_ATTR;
+    }
+  }
+  if (n != NULL)
+    *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = t->mtime;   /* best guess, (s.st_ctime: last status change!!) */
+  }
+  return unix2dostime(&s.st_mtime);
+}
+
+/* ----------------------------------------------------------------------
+
+Return a malloc()'d buffer containing all of the attributes and their names
+for the file specified in name.  You have to free() this yourself.  The length
+of the buffer is also returned.
+
+If get_attr_dir() fails, the buffer will be NULL, total_size will be 0,
+and an error will be returned:
+
+    EOK    - no errors occurred
+    EINVAL - attr_buff was pointing at a buffer
+    ENOMEM - insufficient memory for attribute buffer
+
+Other errors are possible (whatever is returned by the fs_attrib.h functions).
+
+PROBLEMS:
+
+- pointers are 32-bits; attributes are limited to ssize_t in size so it's
+  possible to overflow... in practice, this isn't too likely... your
+  machine will thrash like hell before that happens
+
+*/
+
+#define INITIAL_BUFF_SIZE 65536
+
+int get_attr_dir( const char *name, char **attr_buff, off_t *total_size )
+{
+    int               retval = EOK;
+    int               fd;
+    DIR              *fa_dir;
+    struct dirent    *fa_ent;
+    off_t             attrs_size = 0;
+    size_t           entname_size;
+    char             *ptr;
+    struct attr_info  fa_info;
+
+    *total_size = 0;
+
+    /* ----------------------------------------------------------------- */
+    /* Sanity-check.                                                     */
+    if( *attr_buff != NULL ) {
+        return EINVAL;
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Can we open the file/directory?                                   */
+    /*                                                                   */
+    /* linkput is a zip global; it's set to 1 if we're storing symbolic  */
+    /* links as symbolic links (instead of storing the thing the link    */
+    /* points to)... if we're storing the symbolic link as a link, we'll */
+    /* want the link's file attributes, otherwise we want the target's.  */
+
+    fd = open( name, linkput ? O_RDONLY | O_NOTRAVERSE : O_RDONLY );
+    if( fd < 0 ) {
+        return errno;
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Allocate an initial buffer; 64k should usually be enough.         */
+    *attr_buff = (char *)malloc( INITIAL_BUFF_SIZE );
+    ptr        = *attr_buff;
+    if( ptr == NULL ) {
+        close( fd );
+
+        return ENOMEM;
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Open the attributes directory for this file.                      */
+    fa_dir = open_attrdir( fd );
+    if( fa_dir == NULL ) {
+        close( fd );
+
+        free( ptr );
+        *attr_buff = NULL;
+
+        return retval;
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Read all the attributes; the buffer could grow > 64K if there are */
+    /* many and/or they are large.                                       */
+    while( ( fa_ent = read_attrdir( fa_dir ) ) != NULL ) {
+        retval = stat_attr( fd, fa_ent->d_name, &fa_info );
+        /* TODO: check retval != EOK */
+
+        entname_size = strlen( fa_ent->d_name ) + 1;
+        attrs_size += entname_size + sizeof( struct attr_info ) + fa_info.ai_size;
+
+        if( attrs_size > INITIAL_BUFF_SIZE ) {
+            unsigned long offset = ptr - *attr_buff;
+
+            *attr_buff = (char *)realloc( *attr_buff, attrs_size );
+            if( *attr_buff == NULL ) {
+                retval = close_attrdir( fa_dir );
+                /* TODO: check retval != EOK */
+                close( fd );
+                return ENOMEM;
+            }
+
+            ptr = *attr_buff + offset;
+        }
+
+        /* Now copy the data for this attribute into the buffer. */
+        strcpy( ptr, fa_ent->d_name );
+        ptr += entname_size;
+
+  memcpy( ptr, &fa_info, sizeof( struct attr_info ) );
+        ptr += sizeof( struct attr_info );
+
+        if( fa_info.ai_size > 0 ) {
+            ssize_t read_bytes = read_attr( fd, fa_ent->d_name, fa_info.ai_type, ptr, 0, fa_info.ai_size );
+            if( read_bytes != fa_info.ai_size ) {
+                /* print a warning about mismatched sizes */
+                char buff[80];
+                sprintf( buff, "read %d, expected %d", read_bytes, (ssize_t)fa_info.ai_size );
+                zipwarn( "attribute size mismatch: ", buff );
+            }
+
+            ptr += fa_info.ai_size;
+        }
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Close the attribute directory.                                    */
+    retval = close_attrdir( fa_dir );
+    /* TODO: check retval != EOK */
+
+    /* ----------------------------------------------------------------- */
+    /* If the buffer is too big, shrink it.                              */
+    if( attrs_size < INITIAL_BUFF_SIZE ) {
+        *attr_buff = (char *)realloc( *attr_buff, attrs_size );
+        if( *attr_buff == NULL ) {
+            close( fd );
+            return ENOMEM;
+        }
+    }
+
+    *total_size = attrs_size;
+
+    close( fd );
+
+    return EOK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'UT' extra field to the zlist data pointed to by z.              */
+
+#define EB_L_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(2))
+#define EB_C_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(1))
+
+local int add_UT_ef( struct zlist far *z )
+{
+    char        *l_ef = NULL;
+    char        *c_ef = NULL;
+    struct stat  s;
+
+#ifdef IZ_CHECK_TZ
+    if (!zp_tz_is_valid)
+        return ZE_OK;           /* skip silently if no valid TZ info */
+#endif
+
+    /* We can't work if there's no entry to work on. */
+    if( z == NULL ) {
+        return ZE_LOGIC;
+    }
+
+    /* Check to make sure we've got enough room in the extra fields. */
+    if( z->ext + EB_L_UT_SIZE > USHRT_MAX ||
+        z->cext + EB_C_UT_SIZE > USHRT_MAX ) {
+        return ZE_MEM;
+    }
+
+    /* stat() the file (or the symlink) to get the data; if we can't get */
+    /* the data, there's no point in trying to fill out the fields.      */
+    if(LSSTAT( z->name, &s ) ) {
+        return ZE_OPEN;
+    }
+
+    /* Allocate memory for the local and central extra fields. */
+    if( z->extra && z->ext != 0 ) {
+        l_ef = (char *)realloc( z->extra, z->ext + EB_L_UT_SIZE );
+    } else {
+        l_ef = (char *)malloc( EB_L_UT_SIZE );
+        z->ext = 0;
+    }
+    if( l_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->extra = l_ef;
+    l_ef += z->ext;
+
+    if( z->cextra && z->cext != 0 ) {
+        c_ef = (char *)realloc( z->cextra, z->cext + EB_C_UT_SIZE );
+    } else {
+        c_ef = (char *)malloc( EB_C_UT_SIZE );
+        z->cext = 0;
+    }
+    if( c_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->cextra = c_ef;
+    c_ef += z->cext;
+
+    /* Now add the local version of the field. */
+    *l_ef++ = 'U';
+    *l_ef++ = 'T';
+    *l_ef++ = (char)(EB_UT_LEN(2)); /* length of data in local EF */
+    *l_ef++ = (char)0;
+    *l_ef++ = (char)(EB_UT_FL_MTIME | EB_UT_FL_ATIME);
+    *l_ef++ = (char)(s.st_mtime);
+    *l_ef++ = (char)(s.st_mtime >> 8);
+    *l_ef++ = (char)(s.st_mtime >> 16);
+    *l_ef++ = (char)(s.st_mtime >> 24);
+    *l_ef++ = (char)(s.st_atime);
+    *l_ef++ = (char)(s.st_atime >> 8);
+    *l_ef++ = (char)(s.st_atime >> 16);
+    *l_ef++ = (char)(s.st_atime >> 24);
+
+    z->ext += EB_L_UT_SIZE;
+
+    /* Now add the central version. */
+    memcpy(c_ef, l_ef-EB_L_UT_SIZE, EB_C_UT_SIZE);
+    c_ef[EB_LEN] = (char)(EB_UT_LEN(1)); /* length of data in central EF */
+
+    z->cext += EB_C_UT_SIZE;
+
+    return ZE_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'Ux' extra field to the zlist data pointed to by z.              */
+
+#define EB_L_UX2_SIZE   (EB_HEADSIZE + EB_UX2_MINLEN)
+#define EB_C_UX2_SIZE   (EB_HEADSIZE)
+
+local int add_Ux_ef( struct zlist far *z )
+{
+    char        *l_ef = NULL;
+    char        *c_ef = NULL;
+    struct stat  s;
+
+    /* Check to make sure we've got enough room in the extra fields. */
+    if( z->ext + EB_L_UX2_SIZE > USHRT_MAX ||
+        z->cext + EB_C_UX2_SIZE > USHRT_MAX ) {
+        return ZE_MEM;
+    }
+
+    /* stat() the file (or the symlink) to get the data; if we can't get */
+    /* the data, there's no point in trying to fill out the fields.      */
+    if(LSSTAT( z->name, &s ) ) {
+        return ZE_OPEN;
+    }
+
+    /* Allocate memory for the local and central extra fields. */
+    if( z->extra && z->ext != 0 ) {
+        l_ef = (char *)realloc( z->extra, z->ext + EB_L_UX2_SIZE );
+    } else {
+        l_ef = (char *)malloc( EB_L_UX2_SIZE );
+        z->ext = 0;
+    }
+    if( l_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->extra = l_ef;
+    l_ef += z->ext;
+
+    if( z->cextra && z->cext != 0 ) {
+        c_ef = (char *)realloc( z->cextra, z->cext + EB_C_UX2_SIZE );
+    } else {
+        c_ef = (char *)malloc( EB_C_UX2_SIZE );
+        z->cext = 0;
+    }
+    if( c_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->cextra = c_ef;
+    c_ef += z->cext;
+
+    /* Now add the local version of the field. */
+    *l_ef++ = 'U';
+    *l_ef++ = 'x';
+    *l_ef++ = (char)(EB_UX2_MINLEN);
+    *l_ef++ = (char)(EB_UX2_MINLEN >> 8);
+    *l_ef++ = (char)(s.st_uid);
+    *l_ef++ = (char)(s.st_uid >> 8);
+    *l_ef++ = (char)(s.st_gid);
+    *l_ef++ = (char)(s.st_gid >> 8);
+
+    z->ext += EB_L_UX2_SIZE;
+
+    /* Now add the central version of the field. */
+    *c_ef++ = 'U';
+    *c_ef++ = 'x';
+    *c_ef++ = 0;
+    *c_ef++ = 0;
+
+    z->cext += EB_C_UX2_SIZE;
+
+    return ZE_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'At' extra field to the zlist data pointed to by z.              */
+
+#define EB_L_AT_SIZE    (EB_HEADSIZE + EB_L_AT_LEN) /* + attr size */
+#define EB_C_AT_SIZE    (EB_HEADSIZE + EB_C_AT_LEN)
+
+#define MEMCOMPRESS_HEADER      6   /* ush compression type, ulg CRC */
+#define DEFLAT_WORSTCASE_ADD    5   /* byte blocktype, 2 * ush blocklength */
+#define MEMCOMPRESS_OVERHEAD    (MEMCOMPRESS_HEADER + DEFLAT_WORSTCASE_ADD)
+
+local int add_At_ef( struct zlist far *z )
+{
+    char *l_ef       = NULL;
+    char *c_ef       = NULL;
+    char *attrbuff   = NULL;
+    off_t attrsize   = 0;
+    char *compbuff   = NULL;
+    ush   compsize   = 0;
+    uch   flags      = 0;
+
+    /* Check to make sure we've got enough room in the extra fields. */
+    if( z->ext + EB_L_AT_SIZE > USHRT_MAX ||
+        z->cext + EB_C_AT_SIZE > USHRT_MAX ) {
+        return ZE_MEM;
+    }
+
+    /* Attempt to load up a buffer full of the file's attributes. */
+    {
+        if (get_attr_dir( z->name, &attrbuff, &attrsize) != EOK ) {
+            return ZE_OPEN;
+        }
+        if (attrsize == 0) {
+            return ZE_OK;
+        }
+        if (attrbuff == NULL) {
+            return ZE_LOGIC;
+        }
+
+        /* Check for way too much data. */
+        if (attrsize > (off_t)ULONG_MAX) {
+            zipwarn( "uncompressed attributes truncated", "" );
+            attrsize = (off_t)(ULONG_MAX - MEMCOMPRESS_OVERHEAD);
+        }
+    }
+
+    if (verbose) {
+        printf( "\t[in=%lu]", (unsigned long)attrsize );
+    }
+
+    /* Try compressing the data */
+    compbuff = (char *)malloc( (size_t)attrsize + MEMCOMPRESS_OVERHEAD );
+    if( compbuff == NULL ) {
+        return ZE_MEM;
+    }
+    compsize = memcompress( compbuff,
+                            (size_t)attrsize + MEMCOMPRESS_OVERHEAD,
+                            attrbuff,
+                            (size_t)attrsize );
+    if (verbose) {
+        printf( " [out=%u]", compsize );
+    }
+
+    /* Attempt to optimise very small attributes. */
+    if (compsize > attrsize) {
+        free( compbuff );
+        compsize = (ush)attrsize;
+        compbuff = attrbuff;
+
+        flags = EB_AT_FL_NATURAL;
+    }
+
+    /* Check to see if we really have enough room in the EF for the data. */
+    if( ( z->ext + compsize + EB_L_AT_LEN ) > USHRT_MAX ) {
+        compsize = USHRT_MAX - EB_L_AT_LEN - z->ext;
+    }
+
+    /* Allocate memory for the local and central extra fields. */
+    if( z->extra && z->ext != 0 ) {
+        l_ef = (char *)realloc( z->extra, z->ext + EB_L_AT_SIZE + compsize );
+    } else {
+        l_ef = (char *)malloc( EB_L_AT_SIZE + compsize );
+        z->ext = 0;
+    }
+    if( l_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->extra = l_ef;
+    l_ef += z->ext;
+
+    if( z->cextra && z->cext != 0 ) {
+        c_ef = (char *)realloc( z->cextra, z->cext + EB_C_AT_SIZE );
+    } else {
+        c_ef = (char *)malloc( EB_C_AT_SIZE );
+        z->cext = 0;
+    }
+    if( c_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->cextra = c_ef;
+    c_ef += z->cext;
+
+    /* Now add the local version of the field. */
+    *l_ef++ = 'A';
+    *l_ef++ = 't';
+    *l_ef++ = (char)(compsize + EB_L_AT_LEN);
+    *l_ef++ = (char)((compsize + EB_L_AT_LEN) >> 8);
+    *l_ef++ = (char)((unsigned long)attrsize);
+    *l_ef++ = (char)((unsigned long)attrsize >> 8);
+    *l_ef++ = (char)((unsigned long)attrsize >> 16);
+    *l_ef++ = (char)((unsigned long)attrsize >> 24);
+    *l_ef++ = flags;
+    memcpy( l_ef, compbuff, (size_t)compsize );
+
+    z->ext += EB_L_AT_SIZE + compsize;
+
+    /* And the central version. */
+    *c_ef++ = 'A';
+    *c_ef++ = 't';
+    *c_ef++ = (char)(EB_C_AT_LEN);
+    *c_ef++ = (char)(EB_C_AT_LEN >> 8);
+    *c_ef++ = (char)compsize;
+    *c_ef++ = (char)(compsize >> 8);
+    *c_ef++ = (char)(compsize >> 16);
+    *c_ef++ = (char)(compsize >> 24);
+    *c_ef++ = flags;
+
+    z->cext += EB_C_AT_SIZE;
+
+    return ZE_OK;
+}
+
+/* Extra field info:
+   - 'UT' - UNIX time extra field
+   - 'Ux' - UNIX uid/gid extra field
+   - 'At' - AtheOS file attributes extra field
+
+   This is done the same way ../unix/unix.c stores the 'UT'/'Ux' fields
+   (full data in local header, only modification time in central header),
+   with the 'At' field added to the end and the size of the 'At' field
+   in the central header.
+
+   See the end of atheos/osdep.h for a simple explanation of the 'At' EF
+   layout.
+ */
+int set_extra_field(z, z_utim)
+  struct zlist far *z;
+  iztimes *z_utim;
+  /* store full data in local header but just modification time stamp info
+     in central header */
+{
+    int retval;
+
+    /* Check to make sure z is valid. */
+    if( z == NULL ) {
+        return ZE_LOGIC;
+    }
+
+    retval = add_UT_ef(z);
+    if( retval != ZE_OK ) {
+        return retval;
+    }
+
+    retval = add_Ux_ef(z);
+    if( retval != ZE_OK ) {
+        return retval;
+    }
+
+    return add_At_ef(z); /* last function; we can use return value directly */
+}
+
+/* ---------------------------------------------------------------------- */
+/* Set a file's MIME type.                                                */
+void setfiletype(const char *file, const char *type)
+{
+    int fd;
+    off_t nLen;
+    ssize_t nError;
+
+    fd = open( file, O_RDWR );
+
+    if (fd < 0) {
+        zipwarn( "can't open zipfile to write file type", "" );
+    }
+
+    else
+    {
+        nLen = strlen( type );
+        /* FIXME: write_attr() should return count of writed bytes */
+        nError = write_attr( fd, "os::MimeType", O_TRUNC, ATTR_TYPE_STRING, type, 0, nLen );
+        if (nError < 0) {
+            zipwarn( "couldn't write complete file type", "" );
+        }
+        close( fd );
+    }
+}
+
+#endif /* !UTIL */
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+void version_local()
+{
+    static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+
+    printf(CompiledWith,
+
+#ifdef __GNUC__
+      "gcc ", __VERSION__,
+#else
+      "(unknown compiler)", "",
+#endif
+
+      "Syllable",
+
+#if defined(i486) || defined(__i486) || defined(__i486__) || defined(i386) || defined(__i386) || defined(__i386__)
+      " (x86)",
+#else
+      " (unknown platform)",
+#endif
+
+#ifdef __DATE__
+      " on ", __DATE__
+#else
+      "", ""
+#endif
+    );
+
+} /* end function version_local() */
diff --git a/atheos/osdep.h b/atheos/osdep.h
new file mode 100644 (file)
index 0000000..0869f94
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+
+#ifndef _OSDEP_H_
+#define _OSDEP_H_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/unistd.h>
+
+#define USE_EF_UT_TIME          /* Enable use of "UT" extra field time info */
+
+#define EB_L_AT_LEN 5           /* min size is an unsigned long and flag */
+#define EB_C_AT_LEN 5           /* Length of data in local EF and flag.  */
+
+#define EB_AT_FL_NATURAL    0x01    /* data is 'natural' (not compressed) */
+#define EB_AT_FL_BADBITS    0xfe    /* bits currently undefined           */
+
+#ifndef ZP_NEED_MEMCOMPR
+  define ZP_NEED_MEMCOMPR
+#endif
+
+#define deletedir(d) rmdir(d);
+
+/* Set a file's MIME type. */
+void setfiletype( const char *file, const char *type );
+
+/*
+'At' extra-field layout:
+
+'At'      - signature
+ef_size   - size of data in this EF (little-endian unsigned short)
+full_size - uncompressed data size (little-endian unsigned long)
+flag      - flags (byte)
+            flags & EB_AT_FL_NATURAL    = the data is not compressed
+            flags & EB_AT_FL_BADBITS    = the data is corrupted or we
+                                          can't handle it properly
+data      - compressed or uncompressed file attribute data
+
+If flag & EB_AT_FL_NATURAL, the data is not compressed; this optimisation is
+necessary to prevent wasted space for files with small attributes. In this
+case, there should be ( ef_size - EB_L_AT_LEN ) bytes of data, and full_size
+should equal ( ef_size - EB_L_AT_LEN ).
+
+If the data is compressed, there will be ( ef_size - EB_L_AT_LEN ) bytes of
+compressed data, and full_size bytes of uncompressed data.
+
+If a file has absolutely no attributes, there will not be a 'At' extra field.
+
+The uncompressed data is arranged like this:
+
+attr_name\0 - C string
+struct attr_info (little-endian)
+attr_data (length in attr_info.ai_size)
+*/
+
+#endif
+
diff --git a/atheos/zipup.h b/atheos/zipup.h
new file mode 100644 (file)
index 0000000..d3d39a3
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef _ZIPUP_H_
+#define _ZIPUP_H_
+
+#ifndef O_RDONLY
+#  include <sys/fcntl.h>
+#endif
+#define fhow O_RDONLY
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
+
+#endif /* _ZIPUP_H_ */
diff --git a/beos/Contents b/beos/Contents
new file mode 100644 (file)
index 0000000..939a535
--- /dev/null
@@ -0,0 +1,14 @@
+Contents of the "beos" sub-directory for Zip 2.2 and later:
+
+  Contents      this file
+  README        Notes from the author of the BeOS port
+  Makefile      makefile for building (sorry, no project files)
+  beos.c        BeOS-specific routines (similar to the UNIX ones)
+  osdep.h       BeOS-specific includes and whatnot
+  zipup.h       Definitions for zip routines
+
+This port supports both Metrowerks CodeWarrior and GNU C as the compiler,
+and PowerPC and x86 architectures.
+
+- Chris Herborth (chrish@pobox.com)
+  June 24, 1998
diff --git a/beos/Makefile b/beos/Makefile
new file mode 100644 (file)
index 0000000..1b9e613
--- /dev/null
@@ -0,0 +1,182 @@
+######################################################################
+#
+# Makefile for Info-ZIP's zip, zipcloak, zipnote, and zipsplit on BeOS
+#
+# Copyright Â© 1999 Info-ZIP
+#             Chris Herborth (chrish@pobox.com)
+#
+# This is the new New and Improved Makefile for BeOS; it automatically
+# detects your platform and uses the appropriate compiler and compiler
+# flags.
+
+######################################################################
+# Things that don't change:
+
+# Punish people who don't have SMP hardware.
+MAKE  = make -j 4 -f beos/Makefile
+SHELL = /bin/sh
+
+LN = ln -s
+
+BIND = $(CC)
+AS   = $(CC) -c
+CPP  = $(CC) -E
+
+INSTALL = install
+
+# Target directories
+prefix = /boot/home/config
+BINDIR = $(prefix)/bin
+manext = 1
+MANDIR = $(prefix)/man/man$(manext)
+ZIPMANUAL = MANUAL
+
+VERSION = Version 2.3 of __DATE__
+
+######################################################################
+# Things that change:
+
+# PowerPC system
+ifeq "$(BE_HOST_CPU)" "ppc"
+
+CC:=mwcc
+
+ifeq "$(shell uname -r)" "4.0"
+
+CFLAGS:=-O7 -opt schedule604 -rostr -w9 \
+               -I. -DHAVE_DIRENT_H -DPASSWD_FROM_STDIN
+LFLAGS1:=-warn
+
+else
+
+CFLAGS:=-O7 -proc 604e -w9 -I. -DHAVE_DIRENT_H -DPASSWD_FROM_STDIN
+LFLAGS1:=-nodup
+
+endif
+
+LFLAGS2:=-L/boot/develop/lib/ppc -lbe -lroot
+OBJA =
+TARGET=$(ZIPS)
+
+# x86 system
+else
+
+CC:=gcc
+
+# Removed -Wconversion and -Wshadow because of the unnecessary warnings 
+# they generate. - Sept. 28, 1999
+CFLAGS:=-O3 -mpentiumpro \
+               -Wall -Wno-multichar -Wno-ctor-dtor-privacy \
+               -Wbad-function-cast -Woverloaded-virtual \
+               -I. -I/boot/develop/headers/be/support \
+           -I/boot/develop/headers/be/storage \
+           -DHAVE_DIRENT_H -DPASSWD_FROM_STDIN # -DASMV
+LFLAGS1:=
+LFLAGS2:=-L/boot/develop/lib/x86 -lbe -lroot
+OBJA = #match.o
+TARGET=$(ZIPS)
+
+endif
+
+######################################################################
+# Helpful targets
+all:
+       $(MAKE) CC=$(CC) CFLAGS="$(CFLAGS)" \
+               LFLAGS1="$(LFLAGS1)" LFLAGS2="$(LFLAGS2)" \
+               $(TARGET)
+
+######################################################################
+# Object file lists and other build goodies
+
+# Object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crypt.o ttyio.o \
+       beos.o crc32.o
+OBJI = deflate.o trees.o
+# OBJA moved into ifeq block above; we'll use assembly for x86
+OBJU = zipfile_.o fileio_.o util_.o globals.o beos_.o
+OBJN = zipnote.o  $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+# Headers
+ZIP_H = zip.h ziperr.h tailor.h beos/osdep.h
+
+# What to build?
+ZIPS = zip zipnote zipsplit zipcloak
+
+# suffix rules
+.SUFFIXES:
+.SUFFIXES: _.o .o .c .doc .1
+.c_.o:
+       rm -f $*_.c; $(LN) $< $*_.c
+       $(CC) -c $(CFLAGS) -DUTIL $*_.c
+       rm -f $*_.c
+
+.c.o:
+       $(CC) -c $(CFLAGS) $<
+
+.1.doc:
+       groff -man -Tascii $< > $@
+
+# rules for zip, zipnote, zipcloak, zipsplit, and the Zip MANUAL.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o crc32.o crypt.o fileio.o zipfile.o zipup.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: beos/zipup.h
+
+match.o: match.S
+       $(CPP) match.S > _match.s
+       $(AS) _match.s
+       mv -f _match.o match.o
+       rm -f _match.s
+
+beos.o: beos/beos.c
+       $(CC) -c $(CFLAGS) beos/beos.c
+
+beos_.o: beos/beos.c
+       rm -f $*_.c; $(LN) beos/beos.c $*_.c
+       $(CC) -c $(CFLAGS) -DUTIL $*_.c
+       rm -f $*_.c
+
+zips: $(ZIPS)
+zipsman: $(ZIPS) $(ZIPMANUAL)
+
+zip: $(OBJZ) $(OBJI) $(OBJA)
+       $(BIND) -o zip $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote: $(OBJN)
+       $(BIND) -o zipnote $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak: $(OBJC)
+       $(BIND) -o zipcloak $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit: $(OBJS)
+       $(BIND) -o zipsplit $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+$(ZIPMANUAL): man/zip.1
+       groff -man -Tascii man/zip.1 > $(ZIPMANUAL)
+
+# install
+install:        $(ZIPS)
+       $(INSTALL) -m755 $(ZIPS) $(BINDIR)
+       mkdir -p $(MANDIR)
+       $(INSTALL) -m644 man/zip.1 $(MANDIR)/zip.$(manext)
+
+uninstall:
+       -cd $(BINDIR); rm -f $(ZIPS)
+       -cd $(MANDIR); rm -f zip.$(manext)
+
+dist: $(ZIPMANUAL)
+       zip -u9T zip`sed -e '/VERSION/!d' -e 's/.*"\(.*\)".*/\1/' \
+                         -e s/[.]//g -e q revision.h` \
+         `awk '/^Makefile/,/vms_zip.rnh/ {print $$1}' < contents`
+
+# clean up after making stuff and installing it
+clean:
+       rm -f *.o $(ZIPS) flags
+
+# end of Makefile
diff --git a/beos/README b/beos/README
new file mode 100644 (file)
index 0000000..b985ea0
--- /dev/null
@@ -0,0 +1,31 @@
+Info-ZIP's zip for BeOS
+
+KNOWN BUGS
+
+- None! (as of zip 2.21)
+
+- building on x86 BeOS generates a hell of a lot of bugs; I'm not going to
+  worry about them until Be fixes their headers though...
+
+FEATURES
+
+- stores BeOS file attributes, compressing them if possible (as of 2.21,
+  this works properly for symbolic links, too; as of 2.3, this works
+  properly for symbolic links whether you're storing them as links or not)
+
+- zip files are created with the correct file type (application/zip)
+
+- supports both Metrowerks CodeWarrior (PowerPC platform) and GNU C
+  (x86 platform), automatically picking the default compiler for each
+  architecture
+
+Please report any bugs to the Zip-Bugs mailing list; our email address is
+zip-bugs@lists.wku.edu.  If it's something BeOS-specific, you could email
+me directly.
+
+Visit the Info-ZIP web site (http://www.cdrom.com/pub/infozip/) for all the
+latest zip and unzip information, FAQs, source code and ready-to-run
+executables.
+
+- Chris Herborth (chrish@pobox.com)
+  April 2/1999
diff --git a/beos/beos.c b/beos/beos.c
new file mode 100644 (file)
index 0000000..d8d16df
--- /dev/null
@@ -0,0 +1,945 @@
+/*
+  Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+
+ This BeOS-specific file is based on unix.c in the unix directory; changes
+ by Chris Herborth (chrish@pobox.com).
+
+*/
+
+#include "zip.h"
+
+#ifndef UTIL    /* the companion #endif is a bit of ways down ... */
+
+#include <time.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <dirent.h>
+
+#include <kernel/fs_attr.h>
+#include <storage/Mime.h>
+#include <support/byteorder.h>
+
+
+#define PAD 0
+#define PATH_END '/'
+
+/* Library functions not in (most) header files */
+
+#ifdef _POSIX_VERSION
+#  include <utime.h>
+#else
+   int utime OF((char *, time_t *));
+#endif
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Local functions */
+local char *readd OF((DIR *));
+local int get_attr_dir( const char *, char **, off_t * );
+local int add_UT_ef( struct zlist far * );
+local int add_Ux_ef( struct zlist far * );
+local int add_Be_ef( struct zlist far * );
+
+
+#ifdef NO_DIR                    /* for AT&T 3B1 */
+#include <sys/dir.h>
+#ifndef dirent
+#  define dirent direct
+#endif
+typedef FILE DIR;
+/*
+**  Apparently originally by Rich Salz.
+**  Cleaned up and modified by James W. Birdsall.
+*/
+
+#define opendir(path) fopen(path, "r")
+
+struct dirent *readdir(dirp)
+DIR *dirp;
+{
+  static struct dirent entry;
+
+  if (dirp == NULL)
+    return NULL;
+  for (;;)
+    if (fread (&entry, sizeof (struct dirent), 1, dirp) == 0)
+      return NULL;
+    else if (entry.d_ino)
+      return (&entry);
+} /* end of readdir() */
+
+#define closedir(dirp) fclose(dirp)
+#endif /* NO_DIR */
+
+
+local char *readd(d)
+DIR *d;                 /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+   no more entries or an error occurs. */
+{
+  struct dirent *e;
+
+  e = readdir(d);
+  return e == NULL ? (char *) NULL : e->d_name;
+}
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  DIR *d;               /* directory stream from opendir() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (LSSTAT(n, &s))
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  if ((s.st_mode & S_IFDIR) == 0)
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0, caseflag)) != ZE_OK)
+      return m;
+  } else {
+    /* Add trailing / to the directory name */
+    if ((p = malloc(strlen(n)+2)) == NULL)
+      return ZE_MEM;
+    if (strcmp(n, ".") == 0) {
+      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      strcpy(p, n);
+      a = p + strlen(p);
+      if (a[-1] != '/')
+        strcpy(a, "/");
+      if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+        free((zvoid *)p);
+        return m;
+      }
+    }
+    /* recurse into directory */
+    if (recurse && (d = opendir(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if (strcmp(e, ".") && strcmp(e, ".."))
+        {
+          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+          {
+            closedir(d);
+            free((zvoid *)p);
+            return ZE_MEM;
+          }
+          strcat(strcpy(a, p), e);
+          if ((m = procname(a, caseflag)) != ZE_OK)   /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", a);
+            else
+              ziperr(m, a);
+          }
+          free((zvoid *)a);
+        }
+      }
+      closedir(d);
+    }
+    free((zvoid *)p);
+  } /* (s.st_mode & S_IFDIR) == 0) */
+  return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t;              /* shortened name */
+  int dosflag;
+
+  dosflag = dosify;  /* default for non-DOS and non-OS/2 */
+
+  /* Find starting point in name before doing malloc */
+  for (t = x; *t == '/'; t++)
+    ;                   /* strip leading '/' chars to get a relative path */
+  while (*t == '.' && t[1] == '/')
+    t += 2;             /* strip redundant leading "./" sections */
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+  if (!pathput)
+    t = last(t, PATH_END);
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL)
+    return NULL;
+  strcpy(n, t);
+
+  if (isdir == 42) return n;    /* avoid warning on unused variable */
+
+  if (dosify)
+    msname(n);
+
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+  return n;
+}
+
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+    return NULL;
+  strcpy(x, n);
+  return x;
+}
+
+/*
+ * XXX use ztimbuf in both POSIX and non POSIX cases ?
+ */
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+#ifdef _POSIX_VERSION
+  struct utimbuf u;     /* argument for utime()  const ?? */
+#else
+  time_t u[2];          /* argument for utime() */
+#endif
+
+  /* Convert DOS time to time_t format in u */
+#ifdef _POSIX_VERSION
+  u.actime = u.modtime = dos2unixtime(d);
+  utime(f, &u);
+#else
+  u[0] = u[1] = dos2unixtime(d);
+  utime(f, u);
+#endif
+
+}
+
+ulg filetime(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  /* convert FNAMX to malloc - 11/8/04 EG */
+  char *name;
+  int len = strlen(f);
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+  if (strcmp(f, "-") == 0) {
+    if (fstat(fileno(stdin), &s) != 0) {
+      free(name);
+      error("fstat(stdin)");
+    }
+  } else if (LSSTAT(name, &s) != 0) {
+             /* Accept about any file kind including directories
+              * (stored with trailing / with -r option)
+              */
+    free(name);
+    return 0;
+  }
+  free(name);
+
+  if (a != NULL) {
+    *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+    if ((s.st_mode & S_IFMT) == S_IFDIR) {
+      *a |= MSDOS_DIR_ATTR;
+    }
+  }
+  if (n != NULL)
+    *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = s.st_mtime;   /* best guess (s.st_ctime: last status change!) */
+  }
+
+  return unix2dostime(&s.st_mtime);
+}
+
+/* ----------------------------------------------------------------------
+
+Return a malloc()'d buffer containing all of the attributes and their names
+for the file specified in name.  You have to free() this yourself.  The length
+of the buffer is also returned.
+
+If get_attr_dir() fails, the buffer will be NULL, total_size will be 0,
+and an error will be returned:
+
+    EOK    - no errors occurred
+    EINVAL - attr_buff was pointing at a buffer
+    ENOMEM - insufficient memory for attribute buffer
+
+Other errors are possible (whatever is returned by the fs_attr.h functions).
+
+PROBLEMS:
+
+- pointers are 32-bits; attributes are limited to off_t in size so it's
+  possible to overflow... in practice, this isn't too likely... your
+  machine will thrash like hell before that happens
+
+*/
+
+#define INITIAL_BUFF_SIZE 65536
+
+int get_attr_dir( const char *name, char **attr_buff, off_t *total_size )
+{
+    int               retval = EOK;
+    int               fd;
+    DIR              *fa_dir;
+    struct dirent    *fa_ent;
+    off_t             attrs_size;
+    off_t             this_size;
+    char             *ptr;
+    struct attr_info  fa_info;
+    struct attr_info  big_fa_info;
+
+    retval      = EOK;
+    attrs_size  = 0;    /* gcc still says this is used uninitialized... */
+    *total_size = 0;
+
+    /* ----------------------------------------------------------------- */
+    /* Sanity-check.                                                     */
+    if( *attr_buff != NULL ) {
+        return EINVAL;
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Can we open the file/directory?                                   */
+    /*                                                                   */
+    /* linkput is a zip global; it's set to 1 if we're storing symbolic  */
+    /* links as symbolic links (instead of storing the thing the link    */
+    /* points to)... if we're storing the symbolic link as a link, we'll */
+    /* want the link's file attributes, otherwise we want the target's.  */
+    if( linkput ) {
+        fd = open( name, O_RDONLY | O_NOTRAVERSE );
+    } else {
+        fd = open( name, O_RDONLY );
+    }
+    if( fd < 0 ) {
+        return errno;
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Allocate an initial buffer; 64k should usually be enough.         */
+    *attr_buff = (char *)malloc( INITIAL_BUFF_SIZE );
+    ptr        = *attr_buff;
+    if( ptr == NULL ) {
+        close( fd );
+
+        return ENOMEM;
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Open the attributes directory for this file.                      */
+    fa_dir = fs_fopen_attr_dir( fd );
+    if( fa_dir == NULL ) {
+        close( fd );
+
+        free( ptr );
+        *attr_buff = NULL;
+
+        return retval;
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Read all the attributes; the buffer could grow > 64K if there are */
+    /* many and/or they are large.                                       */
+    fa_ent = fs_read_attr_dir( fa_dir );
+    while( fa_ent != NULL ) {
+        retval = fs_stat_attr( fd, fa_ent->d_name, &fa_info );
+        /* TODO: check retval != EOK */
+
+        this_size  = strlen( fa_ent->d_name ) + 1;
+        this_size += sizeof( struct attr_info );
+        this_size += fa_info.size;
+
+        attrs_size += this_size;
+
+        if( attrs_size > INITIAL_BUFF_SIZE ) {
+            unsigned long offset = ptr - *attr_buff;
+
+            *attr_buff = (char *)realloc( *attr_buff, attrs_size );
+            if( *attr_buff == NULL ) {
+                retval = fs_close_attr_dir( fa_dir );
+                /* TODO: check retval != EOK */
+                close( fd );
+
+                return ENOMEM;
+            }
+
+            ptr = *attr_buff + offset;
+        }
+
+        /* Now copy the data for this attribute into the buffer. */
+        strcpy( ptr, fa_ent->d_name );
+        ptr += strlen( fa_ent->d_name );
+        *ptr++ = '\0';
+
+        /* We need to put a big-endian version of the fa_info data into */
+        /* the archive.                                                 */
+        big_fa_info.type = B_HOST_TO_BENDIAN_INT32( fa_info.type );
+        big_fa_info.size = B_HOST_TO_BENDIAN_INT64( fa_info.size );
+        memcpy( ptr, &big_fa_info, sizeof( struct attr_info ) );
+        ptr += sizeof( struct attr_info );
+
+        if( fa_info.size > 0 ) {
+            ssize_t read_bytes;
+
+            read_bytes = fs_read_attr( fd, fa_ent->d_name, fa_info.type, 0,
+                                       ptr, fa_info.size );
+            if( read_bytes != fa_info.size ) {
+                /* print a warning about mismatched sizes */
+                char buff[80];
+
+                sprintf( buff, "read %ld, expected %ld",
+                         (ssize_t)read_bytes, (ssize_t)fa_info.size );
+                zipwarn( "attribute size mismatch: ", buff );
+            }
+
+            /* Wave my magic wand... this swaps all the Be types to big- */
+            /* endian automagically.                                     */
+            (void)swap_data( fa_info.type, ptr, fa_info.size,
+                             B_SWAP_HOST_TO_BENDIAN );
+
+            ptr += fa_info.size;
+        }
+
+        fa_ent = fs_read_attr_dir( fa_dir );
+    }
+
+    /* ----------------------------------------------------------------- */
+    /* Close the attribute directory.                                    */
+    retval = fs_close_attr_dir( fa_dir );
+    /* TODO: check retval != EOK */
+
+    /* ----------------------------------------------------------------- */
+    /* If the buffer is too big, shrink it.                              */
+    if( attrs_size < INITIAL_BUFF_SIZE ) {
+        *attr_buff = (char *)realloc( *attr_buff, attrs_size );
+        if( *attr_buff == NULL ) {
+            /* This really shouldn't happen... */
+            close( fd );
+
+            return ENOMEM;
+        }
+    }
+
+    *total_size = attrs_size;
+
+    close( fd );
+
+    return EOK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'UT' extra field to the zlist data pointed to by z.              */
+
+#define EB_L_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(2))
+#define EB_C_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(1))
+
+local int add_UT_ef( struct zlist far *z )
+{
+    char        *l_ef = NULL;
+    char        *c_ef = NULL;
+    struct stat  s;
+
+#ifdef IZ_CHECK_TZ
+    if (!zp_tz_is_valid)
+        return ZE_OK;           /* skip silently if no valid TZ info */
+#endif
+
+    /* We can't work if there's no entry to work on. */
+    if( z == NULL ) {
+        return ZE_LOGIC;
+    }
+
+    /* Check to make sure we've got enough room in the extra fields. */
+    if( z->ext + EB_L_UT_SIZE > USHRT_MAX ||
+        z->cext + EB_C_UT_SIZE > USHRT_MAX ) {
+        return ZE_MEM;
+    }
+
+    /* stat() the file (or the symlink) to get the data; if we can't get */
+    /* the data, there's no point in trying to fill out the fields.      */
+    if(LSSTAT( z->name, &s ) ) {
+        return ZE_OPEN;
+    }
+
+    /* Allocate memory for the local and central extra fields. */
+    if( z->extra && z->ext != 0 ) {
+        l_ef = (char *)realloc( z->extra, z->ext + EB_L_UT_SIZE );
+    } else {
+        l_ef = (char *)malloc( EB_L_UT_SIZE );
+        z->ext = 0;
+    }
+    if( l_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->extra = l_ef;
+    l_ef += z->ext;
+
+    if( z->cextra && z->cext != 0 ) {
+        c_ef = (char *)realloc( z->cextra, z->cext + EB_C_UT_SIZE );
+    } else {
+        c_ef = (char *)malloc( EB_C_UT_SIZE );
+        z->cext = 0;
+    }
+    if( c_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->cextra = c_ef;
+    c_ef += z->cext;
+
+    /* Now add the local version of the field. */
+    *l_ef++ = 'U';
+    *l_ef++ = 'T';
+    *l_ef++ = (char)(EB_UT_LEN(2)); /* length of data in local EF */
+    *l_ef++ = (char)0;
+    *l_ef++ = (char)(EB_UT_FL_MTIME | EB_UT_FL_ATIME);
+    *l_ef++ = (char)(s.st_mtime);
+    *l_ef++ = (char)(s.st_mtime >> 8);
+    *l_ef++ = (char)(s.st_mtime >> 16);
+    *l_ef++ = (char)(s.st_mtime >> 24);
+    *l_ef++ = (char)(s.st_atime);
+    *l_ef++ = (char)(s.st_atime >> 8);
+    *l_ef++ = (char)(s.st_atime >> 16);
+    *l_ef++ = (char)(s.st_atime >> 24);
+
+    z->ext += EB_L_UT_SIZE;
+
+    /* Now add the central version. */
+    memcpy(c_ef, l_ef-EB_L_UT_SIZE, EB_C_UT_SIZE);
+    c_ef[EB_LEN] = (char)(EB_UT_LEN(1)); /* length of data in central EF */
+
+    z->cext += EB_C_UT_SIZE;
+
+    return ZE_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'Ux' extra field to the zlist data pointed to by z.              */
+
+#define EB_L_UX2_SIZE   (EB_HEADSIZE + EB_UX2_MINLEN)
+#define EB_C_UX2_SIZE   (EB_HEADSIZE)
+
+local int add_Ux_ef( struct zlist far *z )
+{
+    char        *l_ef = NULL;
+    char        *c_ef = NULL;
+    struct stat  s;
+
+    /* Check to make sure we've got enough room in the extra fields. */
+    if( z->ext + EB_L_UX2_SIZE > USHRT_MAX ||
+        z->cext + EB_C_UX2_SIZE > USHRT_MAX ) {
+        return ZE_MEM;
+    }
+
+    /* stat() the file (or the symlink) to get the data; if we can't get */
+    /* the data, there's no point in trying to fill out the fields.      */
+    if(LSSTAT( z->name, &s ) ) {
+        return ZE_OPEN;
+    }
+
+    /* Allocate memory for the local and central extra fields. */
+    if( z->extra && z->ext != 0 ) {
+        l_ef = (char *)realloc( z->extra, z->ext + EB_L_UX2_SIZE );
+    } else {
+        l_ef = (char *)malloc( EB_L_UX2_SIZE );
+        z->ext = 0;
+    }
+    if( l_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->extra = l_ef;
+    l_ef += z->ext;
+
+    if( z->cextra && z->cext != 0 ) {
+        c_ef = (char *)realloc( z->cextra, z->cext + EB_C_UX2_SIZE );
+    } else {
+        c_ef = (char *)malloc( EB_C_UX2_SIZE );
+        z->cext = 0;
+    }
+    if( c_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->cextra = c_ef;
+    c_ef += z->cext;
+
+    /* Now add the local version of the field. */
+    *l_ef++ = 'U';
+    *l_ef++ = 'x';
+    *l_ef++ = (char)(EB_UX2_MINLEN);
+    *l_ef++ = (char)(EB_UX2_MINLEN >> 8);
+    *l_ef++ = (char)(s.st_uid);
+    *l_ef++ = (char)(s.st_uid >> 8);
+    *l_ef++ = (char)(s.st_gid);
+    *l_ef++ = (char)(s.st_gid >> 8);
+
+    z->ext += EB_L_UX2_SIZE;
+
+    /* Now add the central version of the field. */
+    *c_ef++ = 'U';
+    *c_ef++ = 'x';
+    *c_ef++ = 0;
+    *c_ef++ = 0;
+
+    z->cext += EB_C_UX2_SIZE;
+
+    return ZE_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'Be' extra field to the zlist data pointed to by z.              */
+
+#define EB_L_BE_SIZE    (EB_HEADSIZE + EB_L_BE_LEN) /* + attr size */
+#define EB_C_BE_SIZE    (EB_HEADSIZE + EB_C_BE_LEN)
+
+/* maximum memcompress overhead is the sum of the compression header length */
+/* (6 = ush compression type, ulg CRC) and the worstcase deflate overhead   */
+/* when uncompressible data are kept in 2 "stored" blocks (5 per block =    */
+/* byte blocktype + 2 * ush blocklength) */
+#define MEMCOMPRESS_OVERHEAD    (EB_MEMCMPR_HSIZ + EB_DEFLAT_EXTRA)
+
+local int add_Be_ef( struct zlist far *z )
+{
+    char *l_ef       = NULL;
+    char *c_ef       = NULL;
+    char *attrbuff   = NULL;
+    off_t attrsize   = 0;
+    char *compbuff   = NULL;
+    ush   compsize   = 0;
+    uch   flags      = 0;
+
+    /* Check to make sure we've got enough room in the extra fields. */
+    if( z->ext + EB_L_BE_SIZE > USHRT_MAX ||
+        z->cext + EB_C_BE_SIZE > USHRT_MAX ) {
+        return ZE_MEM;
+    }
+
+    /* Attempt to load up a buffer full of the file's attributes. */
+    {
+        int retval;
+
+        retval = get_attr_dir( z->name, &attrbuff, &attrsize );
+        if( retval != EOK ) {
+            return ZE_OPEN;
+        }
+        if( attrsize == 0 ) {
+            return ZE_OK;
+        }
+        if( attrbuff == NULL ) {
+            return ZE_LOGIC;
+        }
+
+        /* Check for way too much data. */
+        if( attrsize > (off_t)ULONG_MAX ) {
+            zipwarn( "uncompressed attributes truncated", "" );
+            attrsize = (off_t)(ULONG_MAX - MEMCOMPRESS_OVERHEAD);
+        }
+    }
+
+    if( verbose ) {
+        printf( "\t[in=%lu]", (unsigned long)attrsize );
+    }
+
+    /* Try compressing the data */
+    compbuff = (char *)malloc( (size_t)attrsize + MEMCOMPRESS_OVERHEAD );
+    if( compbuff == NULL ) {
+        return ZE_MEM;
+    }
+    compsize = memcompress( compbuff,
+                            (size_t)attrsize + MEMCOMPRESS_OVERHEAD,
+                            attrbuff,
+                            (size_t)attrsize );
+    if( verbose ) {
+        printf( " [out=%u]", compsize );
+    }
+
+    /* Attempt to optimise very small attributes. */
+    if( compsize > attrsize ) {
+        free( compbuff );
+        compsize = (ush)attrsize;
+        compbuff = attrbuff;
+
+        flags = EB_BE_FL_NATURAL;
+    }
+
+    /* Check to see if we really have enough room in the EF for the data. */
+    if( ( z->ext + compsize + EB_L_BE_LEN ) > USHRT_MAX ) {
+        compsize = USHRT_MAX - EB_L_BE_LEN - z->ext;
+    }
+
+    /* Allocate memory for the local and central extra fields. */
+    if( z->extra && z->ext != 0 ) {
+        l_ef = (char *)realloc( z->extra, z->ext + EB_L_BE_SIZE + compsize );
+    } else {
+        l_ef = (char *)malloc( EB_L_BE_SIZE + compsize );
+        z->ext = 0;
+    }
+    if( l_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->extra = l_ef;
+    l_ef += z->ext;
+
+    if( z->cextra && z->cext != 0 ) {
+        c_ef = (char *)realloc( z->cextra, z->cext + EB_C_BE_SIZE );
+    } else {
+        c_ef = (char *)malloc( EB_C_BE_SIZE );
+        z->cext = 0;
+    }
+    if( c_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->cextra = c_ef;
+    c_ef += z->cext;
+
+    /* Now add the local version of the field. */
+    *l_ef++ = 'B';
+    *l_ef++ = 'e';
+    *l_ef++ = (char)(compsize + EB_L_BE_LEN);
+    *l_ef++ = (char)((compsize + EB_L_BE_LEN) >> 8);
+    *l_ef++ = (char)((unsigned long)attrsize);
+    *l_ef++ = (char)((unsigned long)attrsize >> 8);
+    *l_ef++ = (char)((unsigned long)attrsize >> 16);
+    *l_ef++ = (char)((unsigned long)attrsize >> 24);
+    *l_ef++ = flags;
+    memcpy( l_ef, compbuff, (size_t)compsize );
+
+    z->ext += EB_L_BE_SIZE + compsize;
+
+    /* And the central version. */
+    *c_ef++ = 'B';
+    *c_ef++ = 'e';
+    *c_ef++ = (char)(EB_C_BE_LEN);
+    *c_ef++ = (char)(EB_C_BE_LEN >> 8);
+    *c_ef++ = (char)compsize;
+    *c_ef++ = (char)(compsize >> 8);
+    *c_ef++ = (char)(compsize >> 16);
+    *c_ef++ = (char)(compsize >> 24);
+    *c_ef++ = flags;
+
+    z->cext += EB_C_BE_SIZE;
+
+    return ZE_OK;
+}
+
+/* Extra field info:
+   - 'UT' - UNIX time extra field
+   - 'Ux' - UNIX uid/gid extra field
+   - 'Be' - BeOS file attributes extra field
+
+   This is done the same way ../unix/unix.c stores the 'UT'/'Ux' fields
+   (full data in local header, only modification time in central header),
+   with the 'Be' field added to the end and the size of the 'Be' field
+   in the central header.
+
+   See the end of beos/osdep.h for a simple explanation of the 'Be' EF
+   layout.
+ */
+int set_extra_field(z, z_utim)
+  struct zlist far *z;
+  iztimes *z_utim;
+  /* store full data in local header but just modification time stamp info
+     in central header */
+{
+    int retval;
+
+    /* Tell picky compilers to shut up about unused variables. */
+    z_utim = z_utim;
+
+    /* Check to make sure z is valid. */
+    if( z == NULL ) {
+        return ZE_LOGIC;
+    }
+
+    /* This function is much simpler now that I've moved the extra fields */
+    /* out... it simplified the 'Be' code, too.                           */
+    retval = add_UT_ef( z );
+    if( retval != ZE_OK ) {
+        return retval;
+    }
+
+    retval = add_Ux_ef( z );
+    if( retval != ZE_OK ) {
+        return retval;
+    }
+
+    retval = add_Be_ef( z );
+    if( retval != ZE_OK ) {
+        return retval;
+    }
+
+    return ZE_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Set a file's MIME type.                                                */
+void setfiletype( const char *file, const char *type )
+{
+    int fd;
+    attr_info fa;
+    ssize_t wrote_bytes;
+
+    fd = open( file, O_RDWR );
+    if( fd < 0 ) {
+        zipwarn( "can't open zipfile to write file type", "" );
+        return;
+    }
+
+    fa.type = B_MIME_STRING_TYPE;
+    fa.size = (off_t)(strlen( type ) + 1);
+
+    wrote_bytes = fs_write_attr( fd, BE_FILE_TYPE_NAME, fa.type, 0,
+                                 type, fa.size );
+    if( wrote_bytes != (ssize_t)fa.size ) {
+        zipwarn( "couldn't write complete file type", "" );
+    }
+
+    close( fd );
+}
+
+int deletedir(d)
+char *d;                /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+   Return the result of rmdir(), delete(), or system().
+   For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
+ */
+{
+# ifdef NO_RMDIR
+    /* code from Greg Roelofs, who horked it from Mark Edwards (unzip) */
+    int r, len;
+    char *s;              /* malloc'd string for system command */
+
+    len = strlen(d);
+    if ((s = malloc(len + 34)) == NULL)
+      return 127;
+
+    sprintf(s, "IFS=\" \t\n\" /bin/rmdir %s 2>/dev/null", d);
+    r = system(s);
+    free(s);
+    return r;
+# else /* !NO_RMDIR */
+    return rmdir(d);
+# endif /* ?NO_RMDIR */
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+void version_local()
+{
+    static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+
+    printf(CompiledWith,
+
+#ifdef __MWERKS__
+      "Metrowerks CodeWarrior", "",
+#else
+#  ifdef __GNUC__
+      "gcc ", __VERSION__,
+#  endif
+#endif
+
+      "BeOS",
+
+#ifdef __POWERPC__
+      " (PowerPC)",
+#else
+#  ifdef __INTEL__
+      " (x86)",
+#  else
+      " (UNKNOWN!)",
+#  endif
+#endif
+
+#ifdef __DATE__
+      " on ", __DATE__
+#else
+      "", ""
+#endif
+    );
+
+} /* end function version_local() */
diff --git a/beos/osdep.h b/beos/osdep.h
new file mode 100644 (file)
index 0000000..0197903
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <support/Errors.h>     /* for B_NO_ERROR */
+
+#define USE_EF_UT_TIME          /* Enable use of "UT" extra field time info */
+
+#define EB_L_BE_LEN 5           /* min size is an unsigned long and flag */
+#define EB_C_BE_LEN 5           /* Length of data in local EF and flag.  */
+
+#define EB_BE_FL_NATURAL    0x01    /* data is 'natural' (not compressed) */
+#define EB_BE_FL_BADBITS    0xfe    /* bits currently undefined           */
+
+#ifndef ZP_NEED_MEMCOMPR
+#  define ZP_NEED_MEMCOMPR
+#endif
+
+/* Set a file's MIME type. */
+#define BE_FILE_TYPE_NAME   "BEOS:TYPE"
+void setfiletype( const char *file, const char *type );
+
+/*
+DR9 'Be' extra-field layout:
+
+'Be'      - signature
+ef_size   - size of data in this EF (little-endian unsigned short)
+full_size - uncompressed data size (little-endian unsigned long)
+flag      - flags (byte)
+            flags & EB_BE_FL_NATURAL    = the data is not compressed
+            flags & EB_BE_FL_BADBITS    = the data is corrupted or we
+                                          can't handle it properly
+data      - compressed or uncompressed file attribute data
+
+If flag & EB_BE_FL_NATURAL, the data is not compressed; this optimisation is
+necessary to prevent wasted space for files with small attributes (which
+appears to be quite common on the Advanced Access DR9 release).  In this
+case, there should be ( ef_size - EB_L_BE_LEN ) bytes of data, and full_size
+should equal ( ef_size - EB_L_BE_LEN ).
+
+If the data is compressed, there will be ( ef_size - EB_L_BE_LEN ) bytes of
+compressed data, and full_size bytes of uncompressed data.
+
+If a file has absolutely no attributes, there will not be a 'Be' extra field.
+
+The uncompressed data is arranged like this:
+
+attr_name\0 - C string
+struct attr_info (big-endian)
+attr_data (length in attr_info.size)
+*/
diff --git a/beos/zipup.h b/beos/zipup.h
new file mode 100644 (file)
index 0000000..40c79eb
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+#  include <fcntl.h>
+#endif
+#define fhow O_RDONLY
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/bzip2/install.txt b/bzip2/install.txt
new file mode 100644 (file)
index 0000000..87d45ad
--- /dev/null
@@ -0,0 +1,258 @@
+HOW TO ADD BZIP2 SUPPORT TO ZIP
+
+This document describes how to add bzip2 support to Zip.
+
+Compiling or linking in the bzip2 library adds an additional bzip2
+compression method to Zip.  This new method can be selected instead
+of the Zip traditional compression method deflation to compress files
+and often gives a better compression ratio (perhaps at the cost of
+greater CPU time).  The compression method is specified using the
+"-Z method" command-line option, where "method" may be either "deflate"
+(the default), or "bzip2" (if Zip is built with bzip2 support).  Zip
+has been tested with bzip2 library 1.0.5 and earlier.
+
+Notes
+
+Compression method bzip2 requires a modern unzip.  Before using bzip2
+compression in Zip, verify that a modern UnZip program with bzip2 support
+will be used to read the resulting zip archive so that entries compressed
+with bzip2 (compression method 12) can be read.  Older unzips probably
+won't recognize the compression method and will skip those entries.
+
+The Zip source kit does not include the bzip2 library or source files, but
+these can be found at "http://www.bzip.org/" for example.  See below for
+how to add bzip2 to Zip for various operating systems.
+
+Zip using bzip2 compression is not compatible with the bzip2 application,
+but instead provides an additional way to compress files before adding
+them to a Zip archive.  It does not replace the bzip2 program itself,
+which creates bzip2 archives in a different format that are not
+compatible with zip or unzip.
+The bzip2 code and algorithms are provided under the bzip2 license
+(provided in the bzip2 source kit) and what is not covered by that license
+is covered under the Info-ZIP license.  Info-ZIP will look at issues
+involving the use of bzip2 compression in Zip, but any questions about
+the bzip2 code and algorithms or bzip2 licensing, for example, should be
+directed to the bzip2 maintainer.
+
+
+Installation
+
+To build Zip with bzip2 support, Zip generally needs one bzip2 header
+file, "bzlib.h", and the object library, typically "libbz2.a", except
+in cases where the source files are compiled in directly.  If you
+are either compiling the bzip2 library or compiling in the bzip2
+source files, we recommend defining the C macro BZ_NO_STDIO, which
+excludes a lot of standalone error code (not used when bzip2 is
+used as a library and makes the library smaller) and provides hooks
+that Zip can use to provide better error handling.  However, a
+standard bzip2 object library will work, though any errors that bzip2
+generates may be more cryptic.
+
+Building the bzip2 library from the bzip2 source files (recommended):
+
+  Download the latest bzip2 package (from "http://www.bzip.org/", for
+  example).
+     
+  Unpack the bzip2 source kit (bzip2-1.0.5.tar.gz was current as of
+  this writing, but the latest should work).
+
+  Read the README file in the bzip2 source kit.
+
+  Compile the bzip2 library for your OS, preferably defining
+  BZ_NO_STDIO.  Note: On UNIX systems, this may be done automatically
+  when building Zip, as explained below.
+
+
+Installation on UNIX (see below for installation on other systems):
+
+  Note:  Zip on UNIX uses the "bzlib.h" include file and the compiled
+  "libbz2.a" library to static link to bzip2.  Currently we do not
+  support using the shared library (patches welcome).
+
+  The easiest approach may be to drop the two above files in the
+  bzip2 directory of the Zip source tree and build Zip using the
+  "generic" target, that is, using a command like
+    make -f unix/Makefile generic
+  If all goes well, make should confirm that it found the files and
+  will be compiling in bzip2 by setting the BZIP2_SUPPORT flag and
+  then including the libraries while compiling and linking Zip.
+
+  To use bzlib.h and libbz2.a from somewhere else on your system,
+  define the "make" macro IZ_BZIP2 to point to that directory.  For
+  example:
+    make -f unix/Makefile generic IZ_BZIP2=/mybz2
+  where /mybz2 might be "/usr/local/src/bzip2/bzip2-1.0.5" on some
+  systems.  Only a compiled bzip2 library can be pointed to using
+  IZ_BZIP2 and Zip will not compile bzip2 source in other than the
+  bzip2 directory.
+
+  If IZ_BZIP2 is not defined, Zip will look for the bzip2 files in
+  the "bzip2" directory in the Zip source directory.  The bzip2
+  directory is empty in the Zip source distribution (except for
+  this install.txt file) and is provided as a place to put the
+  bzip2 files.  To use this directory, either drop bzlib.h and
+  libbz2.a in it to use the compiled library as noted above or drop
+  the contents of the bzip2 source kit in this directory so that
+  bzlib.h is directly in the bzip2 directory and Zip will try to
+  compile it if no compiled library is already there.
+
+
+  Unpacking bzip2 so Zip compiles it:
+
+  To make this work, the bzip2 source kit must be unpacked directly
+  into the Zip "bzip2" directory.  For example:
+
+      # Unpack the Zip source kit.
+      gzip -cd zip30.tar-gz | tar xfo -
+      # Move down to the Zip kit's "bzip2" directory, ...
+      cd zip30/bzip2
+      # ... and unpack the bzip2 source kit there.
+      gzip -cd ../../bzip2-1.0.5.tar.gz | tar xfo -
+      # Move the bzip2 source files up to the Zip kit's bzip2 directory.
+      cd bzip2-1.0.5
+      mv * ..
+      # Return to the Zip source kit directory, ready to build.
+      cd ../..
+      # Build Zip.
+      make -f unix/Makefile generic
+
+
+  Using a system bzip2 library:
+
+  If IZ_BZIP2 is not defined and both a compiled library and the bzip2
+  source files are missing from the Zip bzip2 directory, Zip will test
+  to see if bzip2 is globally defined on the system in the default
+  include and library paths and, if found, link in the system bzip2
+  library.  This is automatic.
+
+
+  Preventing inclusion of bzip2:
+
+  To build Zip with _no_ bzip2 support on a system where the automatic
+  bzip2 detection scheme will find bzip2, you can specify a bad
+  IZ_BZIP2 directory.  For example:
+
+      make -f unix/Makefile generic IZ_BZIP2=no_such_directory
+
+  You can also define NO_BZIP2_SUPPORT to exclude bzip2.
+
+
+  Verifying bzip2 support in Zip:
+
+  When the Zip build is complete, verify that bzip2 support has been
+  enabled by checking the feature list:
+
+      ./zip -v
+
+  If all went well, bzip2 (and its library version) should be listed.
+
+
+Installation on other systems
+
+  MSDOS:
+
+  Thanks to Robert Riebisch, the DJGPP 2.x Zip port now supports bzip2.
+  To include bzip2, first install bzip2.  The new msdos/makebz2.dj2
+  makefile then looks in the standard bzip2 installation directories
+  for the needed files.  As he says:
+    It doesn't try to be clever about finding libbz2.a. It just
+    expects bzip2 stuff installed to the default include and library
+    folders, e.g., "C:\DJGPP\include" and "C:\DJGPP\lib" on DOS.
+
+  Given a standard DJGPP 2.x installation, this should create a
+  version of Zip 3.0 with bzip2 support.
+
+  The bzip2 library for DJGPP can be found on any DJGPP mirror in
+  "current/v2apps" (or "beta/v2apps/" for the latest beta). This
+  library has been ported to MSDOS/DJGPP by Juan Manuel Guerrero.
+
+
+  WIN32 (Windows NT/2K/XP/2K3/... and Windows 95/98/ME):
+
+  For Windows there seems to be two approaches, either use bzip2
+  as a dynamic link library or compile the bzip2 source in directly.
+  I have not gotten the static library libbz2.lib to work, but that
+  may be me.
+
+  Using bzip2 as a dynamic link library:
+
+    Building bzip2:
+
+    If you have the needed bzlib.h, libbz2.lib, and libbz2.dll files
+    you can skip building bzip2.  If not, open the libbz2.dsp project
+    and build libbz2.dll
+
+    This creates
+      debug/libbz2.lib
+    and
+      libbz2.dll
+
+
+    Building Zip:
+
+    Copy libbz2.lib to the bzip2 directory in the Zip source tree.  This
+    is needed to compile Zip with bzip2 support.  Also copy the matching
+    bzlib.h from the bzip2 source to the same directory.
+
+    Add libbz2.lib to the link list for whatever you are building.  Also
+    define the compiler define BZIP2_SUPPORT.
+
+    Build Zip.
+
+
+    Using Zip with bzip2 as dll:
+
+    Put libbz2.dll in your command path.  This is needed to run Zip with
+    bzip2 support.
+
+    Verify that bzip2 is enabled with the command
+
+      zip -v
+
+    You should see bzip2 listed.
+
+  Compiling in bzip2 from the bzip2 source:
+
+    This approach compiles in the bzip2 code directly.  No external
+    library is needed.
+
+    Get a copy of the bzip2 source and copy the contents to the bzip2
+    directory in the Zip source tree so that bzlib.h is directly in
+    the bzip2 directory.
+
+    Use the vc6bz2 project to build Zip.  This project knows of the
+    added bzip2 files.
+
+    Verify that bzip2 is enabled with the command
+
+      zip -v
+
+
+  Windows DLL (WIN32):
+
+  Nothing yet.
+
+
+  Mac OS X:
+
+  Follow the standard UNIX build procedure.  Mac OS X includes bzip2
+  and the UNIX builders should find the bzip2 files in the standard
+  places.  Note that the version of bzip2 on your OS may not be
+  current and you can instead specify a different library or compile
+  your own bzip2 library as noted in the Unix procedures above.
+
+
+  OS/2:
+
+  Nothing yet.
+
+
+  VMS (OpenVMS):
+
+  See [.vms]install_vms.txt for how to enable bzip2 support on VMS.
+
+
+Last updated 26 March 2007, 15 July 2007, 9 April 2008, 27 June 2008
+S. Schweda, E. Gordon
diff --git a/cmsmvs/README.CMS b/cmsmvs/README.CMS
new file mode 100644 (file)
index 0000000..a4425da
--- /dev/null
@@ -0,0 +1,434 @@
+Using ZIP and UNZIP on VM/CMS
+=============================
+
+
+Installing executables
+----------------------
+
+The following CMS MODULEs are available:
+   ZIP
+   ZIPNOTE
+   ZIPCLOAK
+   ZIPSPLIT
+   UNZIP
+
+In addition to these, each MODULE file also has an EXEC with the same
+name.  These EXECs are front-ends to the MODULES that will attempt to
+set up the required runtime libraries before running the MODULE.
+All the EXECs are identical.  Only their names are different.
+They are stored as plain text files.
+
+The CMS MODULE files have been packed using the COPYFILE command to
+allow their file format to be properly restored, since variable length
+binary files will not currently unzip properly (see below for details).
+The MODULEs are shipped with a filetype or extension of CMO (for CMS
+MODULE).  Their names may vary on the distribution disk to indicate
+their level, etc.
+
+To restore them to executable MODULEs on CMS, do the following:
+   1. Upload them to CMS with a Fixed record length with LRECL 1024.
+      Example, from a DOS or OS/2 window, type this:
+         SEND unzip.cmo A:unzip module a (RECFM F LRECL 1024
+
+      Example, using FTP from CMS, type this:
+         BINARY FIXED 1024
+         GET unzip.cmo unzip.module.a
+
+      Note:  Replace "unzip.cmo" with the actual name.
+
+   2. Use COPYFILE to unpack the file.
+      Example, in CMS type this:
+         COPYFILE UNZIP MODULE A (UNPACK REPLACE OLDDATE
+
+   3. Repeat steps 1-2 for each of the programs.
+
+   4. Build the ZIPINFO module by typing this:
+         COPYFILE UNZIP MODULE A ZIPINFO MODULE A (OLDDATE
+
+   5. Upload the EXECs to CMS as text files (with ASCII-to-EBCDIC
+      translation).
+      Example, from a DOS or OS/2 window, type this:
+         SEND unzip.exc A:unzip exec a (CRLF
+
+      Example, using FTP from CMS, type this:
+         GET unzip.exc unzip.exec.a
+
+   6. Repeat steps 4 for each of the EXECs.
+
+
+Preparing the environment
+-------------------------
+
+The executables provided were compiled with IBM C 3.1.0 and
+require the the Language Environment (LE) runtime libraries.
+
+To provide access to the runtime libraries:
+   1. Link to the disk containing the Language Environment files,
+      if necessary.
+
+   2. Use the command "GLOBAL LOADLIB SCEERUN"
+
+   These commands can be placed in your PROFILE EXEC.
+
+   Note:  EXECs have been provided called ZIP, UNZIP, etc. that
+   issue the GLOBAL LOADLIB statement.  This was done to alleviate
+   frustration of users that don't have the GLOBAL LOADLIB statement
+   in their PROFILE EXEC.  These EXECs may require changing for
+   your system.
+
+   Unfortunately, there is no way, using IBM C, to produce a MODULE
+   that doesn't require a runtime library.
+
+
+Testing
+-------
+
+To test the MODULEs, just type ZIP or UNZIP.  They should
+show help information on using the commands.
+
+If you see something like this:
+   DMSLIO201W The following names are undefined:
+    CEEEV003
+   DMSABE155T User abend 4093 called from 00DCD298 reason code 000003EB
+
+Then you don't have access to the proper runtime libraries, as
+described above.
+
+Here is additional information on the ZIP and UNZIP programs that
+may assist support personnel:
+   - Compiled with IBM C V3R1M0 on VM/ESA 2.2.0 with
+     CMS level 13 Service Level 702.
+
+   - Require the SCEERUN LOADLIB runtime library.  This is
+     part of the Language Environment (LE).
+
+   - Linked with options RMODE ANY AMODE ANY RLDSAVE.
+
+If you continue to have trouble, report the problem to Zip-Bugs
+(see the bottom of this document).
+
+
+
+Compiling the source on VM/CMS
+------------------------------
+
+The source has been successfully compiled previously using
+C/370 2.1 and 2.2.  The source has been recently compiled using
+IBM C 3.1.0 on VM/ESA 2.2.0 with CMS level 13.  I don't have
+access to an MVS system so the code hasn't been tested there
+in a while.
+
+ 1. Unzip the source files required for CMS.  The root-level files
+    inside the ZIP file and the files in the CMSMVS subdirectory are
+    needed.  Example (use both commands):
+       unzip -aj zip23.zip -x */*   -dc
+       unzip -aj zip23.zip cmsmvs/* -dc
+
+    This example unzips the files to the C-disk, while translating
+    character data and ignoring paths.
+
+    If you don't already have a working UNZIP MODULE on CMS you will
+    have to unzip the files on another system and transport them
+    to CMS.  All the required files are plain text so they can
+    be transferred with ASCII-to-EBCDIC translations.
+
+ 2. Repeat step 1 with the zip file containing the UNZIP code.
+    Unzip the files to a different disk than the disk used for the ZIP
+    code.
+
+ 3. To compile the ZIP code, run the supplied CCZIP EXEC.
+    To compile the UNZIP code, run the supplied CCUNZIP EXEC.
+
+NOTE:
+Some of the ZIP and UNZIP source files have the same name.  It is
+recommended that you keep the source from each on separate disks and
+move the disk you are building from ahead of the other in the search
+order.
+
+For example, you may have a 192 disk with the ZIP source code and
+a 193 disk with the UNZIP source code.  To compile ZIP, access
+the 192 disk as B, then run CCZIP.  This will create the following
+modules:  ZIP, ZIPNOTE, ZIPSPLIT, ZIPCLOAK.
+
+To compile UNZIP, access 193 as B, then run CCUNZIP.  This will create
+the following modules:  UNZIP, ZIPINFO (a copy of UNZIP).
+
+
+=========================================================================
+
+
+Using ZIP/UNZIP
+---------------
+
+Documentation for the commands is in MANUAL NONAME (for ZIP) and in
+UNZIP DOC UNZIP.  INFOZIP DOC describes the use of the -Z option of
+UNZIP.
+
+The rest of this section explains special notes concerning the VM/CMS
+version of ZIP and UNZIP.
+
+
+Filenames and directories
+-------------------------
+
+ 1. Specifying filenames
+
+    a. When specifying CMS files, use filename.filetype.filemode format
+       (separate the three parts of the name with a period and use no
+       spaces).  Example:  profile.exec.a
+
+       Unfortunately, this prevents you from using ZIP from
+       FILELIST.  To unzip a zip file, however, you can type something
+       like this next to it in FILELIST:
+          unzip /n -d c
+
+       This will unzip the contents of the current file to a C-disk.
+
+    b. It is possible to use DD names with ZIP and UNZIP on CMS, though
+       it can be cumbersome.  Example:
+          filedef out disk myzip zip a
+          zip dd:out file1.txt file2.txt
+
+       While you can also use a DD name for the input files, ZIP
+       currently does not correctly resolve the filename and will
+       store something like "dd:in" inside the ZIP file.  A file stored
+       in this manor cannot easily be unzipped, as "dd:in" is an invalid
+       filename.
+
+    c. In places where a directory name would be used on a PC, such as
+       for the ZIP -b (work path) option or the UNZIP -d (destination
+       path) options, use a filemode letter for CMS.  For example,
+       to unzip files onto a C-disk, you might type something like this:
+          unzip myzip.zip -d c
+
+       Currently, ZIP uses the A-disk for work files.  When zipping
+       large files, you may want to specify a larger disk for work files.
+       This example will use a C-disk for work files.
+          zip -b C myzip.zip.c test.dat.a
+
+
+ 2. Filename conversions
+
+    a. Filemode letters are never stored into the zip file or take from
+       a zip file.  Only the filename and filetype are used.
+       ZIP removes the filemode when storing the filename into the
+       zip file.  UNZIP assumes "A" for the filemode unless the -d
+       option is used.
+
+    b. When unzipping, any path names are removed from the fileid
+       and the last two period-separated words are used as the
+       filename and filetype.  These are truncated to a maximum of
+       eight characters, if necessary.  If the filetype (extension)
+       is missing, then UNZIP uses "NONAME" for the filetype.
+       Any '(' or ')' characters are removed from the fileid.
+
+    c. All files are created in upper-case.  Files in mixed-case
+       cannot currently be stored into a ZIP file.
+
+    d. Shared File System (SFS) directories are not supported.
+       Files are always accessed by fn.ft.fm.  To use an SFS disk,
+       Assign it a filemode, then it can be used.
+
+
+ 3. Wildcards in file names
+
+    a. Wildcards are not supported in the zip filename.  The full
+       filename of the zip file must be given (but the .zip is not
+       necessary).  So, you can't do this:
+          unzip -t *.zip
+
+    b. Wildcards CAN be used with UNZIP to select (or exclude) files
+       inside a zip file.  Examples:
+          unzip myzip *.c          - Unzip all .c files.
+          unzip myzip *.c -x z*.c  - Unzip all .c files but those
+                                     starting with Z.
+
+    c. Wildcards cannot currently be used to select files with ZIP.
+       So, you can't do this:
+          zip -a myzip *.exec
+
+       I expect to fix this for CMS in the future.
+
+
+ 4. File timestamps
+
+    a. The dates and times of files being zipped or unzipped are not
+       currently read or set.  When a file is zipped, the timestamp
+       inside the zip file will always be the current system date and
+       time.  Likewise, when unzipping, the date and time of files
+       being unzipped will always be the current system date/time.
+
+    b. Existing files are assumed to be newer than files inside a zip
+       file when using the -f freshen option of UNZIP.  This will prevent
+       overwriting files that may be newer than the files inside the
+       zip file, but also effectively prevents the -f option from working.
+
+
+ 5. ASCII, EBCDIC, and binary data
+
+    Background
+    ----------
+    Most systems create data files as just a stream of bytes.  Record
+    breaks happen when certain characters (new line and/or carriage
+    return characters) are encountered in the data.  How to interpret
+    the data in a file is up to the user.  The system must be told
+    to either notice new line characters in the data or to assume
+    that the data in the file is binary data and should be read or
+    written as-is.
+
+    CMS and MVS are record-based systems.  All files are composed
+    of data records.  These can be stored in fixed-length files or
+    in variable length files.  With fixed-length files, each record
+    is the same length.  The record breaks are implied by the
+    LRECL (logical record length) attribute associated with the file.
+    With variable-length files, each record contains the length of
+    that record.  The separation of records are not part of the
+    data, but part of the file structure.
+
+    This means you can store any type of data in either type of file
+    structure without having to worry about the data being interpreted
+    as a record break.  Fixed-length files may have padding at the
+    end of the file to make up a full record.  Variable-length files
+    have no padding, but require extra record length data be stored
+    with the file data.
+
+    Storing fixed-length files into a zip file is simple, because all
+    the data can just be dumped into the zip file and the record
+    format (RECFM) and logical record length (LRECL) can be stored
+    in the extra data area of the zip file so they can be restored
+    when UNZIP is used.
+
+    Storing variable-length data is harder.  There is no place to put
+    the record length data needed for each record of the file.  This
+    data could be written to the zip file as the first two bytes of
+    each record and interpreted that way by UNZIP.  That would make
+    the data unusable on systems other than CMS and MVS, though.
+
+    Currently, there isn't a solution to this problem.  Each record is
+    written to the zip file and the record length information is
+    discarded.  Binary data stored in variable-length files can't be put
+    into a zip file then later unzipped back into the proper records.
+    This is fine for binary data that will be read as a stream of bytes
+    but not OK where the records matter, such as with CMS MODULEs.
+
+    If the data is text (character data), there is a solution.
+    This data can be converted into ASCII when it's stored into
+    a zip file.  The end of each record is now marked in the file
+    by new line characters.  Another advantage of this method is
+    that the data is now accessible to non-EBCDIC systems.  When
+    the data is unzipped on CMS or MVS, it is converted back into
+    EBCDIC and the records are recreated into a variable-length file.
+
+
+    So, here's what we have...
+
+    a. To store readable text data into a zip file that can be used
+       on other platforms, use the -a option with ZIP to convert the
+       data to ASCII.  These files will unzip into variable-length
+       files on CMS and should not contain binary data or corruption
+       may occur.
+
+    b. Files that were zipped on an ASCII-based system will be
+       automatically translated to EBCDIC when unzipped.  To prevent
+       this (to unzip binary data on CMS that was sent from an
+       ASCII-based system), use the -B option with UNZIP to force Binary
+       mode.  To zip binary files on CMS, use the -B option with ZIP to
+       force Binary mode.  This will prevent any data conversions from
+       taking place.
+
+    c. When using the ZIP program without specifying the "-a" or "-B"
+       option, ZIP defaults to "native" (EBCDIC) mode and tries to
+       preserve the file information (RECFM, LRECL, and BLKSIZE).  So
+       when you unzip a file zipped with ZIP under CMS or MVS, UNZIP
+       restores the file info.  The output will be fixed-length if the
+       original was fixed and variable-length if the original was
+       variable.
+
+    If UNZIP gives a "write error (disk full?)"  message, you may be
+    trying to unzip a binary file that was zipped as a text file
+    (without using the -B option)
+
+
+    Summary
+    -------
+    Here's how to ZIP the different types of files.
+
+    RECFM F text
+       Use the -a option with ZIP to convert to ASCII for use with other
+       platforms or no options for use on EBCDIC systems only.
+
+    RECFM V text
+       Use the -a option with ZIP to convert to ASCII for use with other
+       platforms or no options for use on EBCDIC systems only.
+
+
+    RECFM F binary
+       Use the -B option with ZIP (upper-case "B").
+
+    RECFM V binary
+       Use the -B option with ZIP.  Can be zipped OK but the record
+       structure is destroyed when unzipped.  This is OK for data files
+       read as binary streams but not OK for files such as CMS MODULEs.
+
+
+ 6. Character Sets
+
+    If you are used to running UNZIP on systems like UNIX, DOS, OS/2 or
+    Windows, you will may have some problems with differences in the
+    character set.
+
+    There are a number of different EBCDIC code pages, like there are a
+    number of different ASCII code pages.  For example, there is a US
+    EBCDIC, a German EBCDIC, and a Swedish EBCDIC.  As long as you are
+    working with other people who use the same EBCDIC code page, you
+    will have no trouble.  If you work with people who use ASCII, or who
+    use a different EBCDIC code page, you may need to do some
+    translation.
+
+    UNZIP translates ASCII text files to and from Open Systems EBCDIC
+    (IBM-1047), which may not be the EBCDIC that you are using.  For
+    example, US EBCDIC (IBM-037) uses different character codes for
+    square brackets.  In such cases, you can use the ICONV utility
+    (supplied with IBM C) to translate between your EBCDIC character set
+    and IBM-1047.
+
+    If your installation does not use IBM-1047 EBCDIC, messages from
+    UNZIP may look a little odd.  For example, in a US EBCDIC
+    installation, an opening square bracket will become an i-acute and a
+    closing square bracket will become a u-grave.
+
+    The supplied ZIP and UNZIP EXECs attempt to correct this by setting
+    CMS INPUT and OUTPUT translations to adjust the display of left and
+    right brackets.  You may need to change this if brackets don't
+    display correctly on your system.
+
+
+ 7. You can unzip using VM/CMS PIPELINES so unzip can be used as
+    a pipeline filter.  Example:
+       'PIPE COMMAND UNZIP -p test.zip george.test | Count Lines | Cons'
+
+
+
+
+Please report all bugs and problems to:
+   Zip-Bugs@lists.wku.edu
+
+
+-----------------------------------------------------------------------
+Original CMS/MVS port by George Petrov.
+e-mail:  c888090@nlevdpsb.snads.philips.nl
+tel:     +31-40-781155
+
+Philips C&P
+Eindhoven
+The Netherlands
+
+-----------------------------------------------------------------------
+Additional fixes and README re-write (4/98) by Greg Hartwig.
+e-mail:  ghartwig@ix.netcom.com
+         ghartwig@vnet.ibm.com
+
+-----------------------------------------------------------------------
+Additional notes from Ian E. Gorman.
+e-mail:  ian@iosphere.net
+
diff --git a/cmsmvs/README.MVS b/cmsmvs/README.MVS
new file mode 100644 (file)
index 0000000..4d451db
--- /dev/null
@@ -0,0 +1,92 @@
+Thank you for trying this first port of ZIP for VM/CMS and MVS!
+
+
+                        Using under MVS:
+                    ---------------------------
+
+1. To use the Info-ZIP's ZIP under MVS you need:
+
+   - C/370 ver 2.1 compiler or another compatible compiler supporting
+     long names for function/variable names.
+
+2. To compile the program under MVS do :
+
+   - unzip all the files from zip22.zip file. They are stored as
+     ASCII format so you have to unzip them first on PC or other
+     system that already have UNZIP, and then upload them to the
+     mainframe with ASCII to EBCDIC conversion.
+
+   - Copy all the .C files in the PDS called youruserid.ZIP.C
+
+   - Copy all the .H files in the PDS called youruserid.ZIP.H
+
+   - adjust the job ZIPMVSC.JOB to work on your size. Change my
+     userid - C888090 to yours
+
+   - execute the job ZIPMVSC to compile and link all the sources.
+
+   - maybe you have to preallocate PDS datasets named:
+     youruserid.ZIP.OBJ and youruserid.ZIP.LOAD
+
+   - execute ZIPVMC to compile and link all the sources.
+
+   - if everything is ok you will get an ZIP MODULE
+
+   - the warnings about the duplicated ASCII and EBCDIC symbols
+     are OK :-)
+
+3. Using ZIP
+
+   - Just read MANUAL
+
+   - A few exceptions concerning MVS
+
+     3.1. if you want to make a portable zip file that is to be unzipped
+          on ASCII based systems use the -a option
+
+     3.2. If you want to zip the input files as binary ebcdic files
+          use the -B (capital letter) option
+
+     3.3. The date/end the time of the input files is set in the zip's
+          dir to the current system date/time
+
+     3.4. Without specifying the "-a" or "-B" option, the ZIP program
+          defaults to "native" (EBCDIC) mode and tries to preserve the
+          file information (LRECL,BLKSIZE..)
+          So when you UNZIP a file zipped with ZIP under VM/MVS it
+          restores the file info.
+
+          There currently some problems with file with RECFM=V*
+          I don't save the length of each record yet :-)
+
+     3.5. No wildcards are supported as input file names:
+
+          So you CAN'T use things like: zip myzip *.c
+
+     3.6. You can use DD names for zipfilename for example:
+
+          under tso/rexx:
+
+           "alloc fi(input) da('myzip.zip')"
+           "zip dd:input file1.txt file2.txt ..."
+
+          under Batch:
+
+           //MYZIP    JOB  (account)
+           //STEP1    EXEC PGM=ZIP,PARM='dd:input file1.txt file2.txt'
+           //STEPLIB  DD DSN=userid.UNZIP.LOAD,DISP=SHR
+           //INPUT    DD DSN=userid.MYZIP.ZIP,DISP=NEW,
+           //            SPACE=(15000,(15000,10000),RLSE),
+           //            DCB=(LRECL=80,RECFM=F)
+           //SYSPRINT DD SYSOUT=*
+
+
+Please report all bugs and problems to :
+     zip-bugs@lists.wku.edu
+
+That's all for now.
+
+Have fun!
+
+
+George Petrov
diff --git a/cmsmvs/README.MVS.LE b/cmsmvs/README.MVS.LE
new file mode 100644 (file)
index 0000000..f7dcb8a
--- /dev/null
@@ -0,0 +1,286 @@
+Notes on Zip under MVS Language Environment (LE).
+
+First see README.MVS.  This note describes just one beta test on OS/390
+V2R5 using IBM's C compiler (5647A01), V2R4.  The major difference is
+the use of LE on the beta site, together with some MVS native mode
+fixes.  Changes have not been tested on CMS.
+
+Some of the notes are to clarify things that were not clear from the
+MANUAL or README.MVS.
+
+1.  By default, IBM C generates the same csect name for each input
+    source.  The prelink stage does not rename them and the linkage
+    editor throws away all but the first occurrence of each duplicate.
+    Oops, my code just disappeared :(.
+
+    To get around this "feature", compile with the CSECT option to
+    force sensible names on the code and data sections of each csect.
+    The name of the static data csect defaults to the source name in
+    lower case, the code csect defaults to the source name in upper
+    case.  These csect names still have to be unique, they cannot be
+    the same as function names.  Of course, several csects have a
+    function which is the same name as the source in lower case, not
+    exactly an unusual occurrence.  Therefore to make the csect name
+    unique, some of the sources have
+
+    #ifdef MVS
+    #  pragma csect(STATIC,xxxx_s)
+    #endif
+
+    Where xxxx is an abbreviation of the source name.  There has to be
+    a better way!
+
+2.  The prelink step always gets cond code 4.  It complains about
+    unresolved references, ignore it unless the linker also complains.
+    Prelink also complains about duplicate @@PPA2 sections and so does
+    the linker, but it seems to do no harm.  Compile and link steps
+    should get 0, just prelink gets 4.  See JCL at the bottom.
+
+3.  Under MVS native mode (not Open Edition), tmpnam() returns a quoted
+    name of 5 qualifiers.  The first is a HLQ chosen according to the
+    MVS LE algorithm (see below), the other qualifiers are time stamps.
+    If running on MVS and tmpnam() returns a quoted name with at leat
+    one '.', it is only safe to let the user change the high level
+    qualifier.  Therefore -b insists on a single qualifier without '.'
+    in the MVS native environment.
+
+4.  In Open Edition (OE) mode, the manual says that tmpnam() returns a
+    fully qualified name in directory TMPDIR or /tmp if TMPDIR is not
+    set.  There is no point in zip trying to override that name so -b
+    is ignored in MVS OE mode (untested).  The user should specify
+    environment variable TMPDIR instead.
+
+5.  The MVS LE algorithm for choosing the high level qualifier for
+    native filenames is interesting, as in "May you live in interesting
+    times".  The HLQ varies according to the environment the program is
+    running in, sometimes it is userid, sometimes it is TSO prefix.
+    See OS/390 C/C++ Programming Guide, Using a Data Set Name,
+    somewhere around section 2.9.
+
+    If in doubt, use fully qualified and quoted names.  Instead of
+    archive.zip, use 'prefix.archive.zip'.  For input files, instead of
+    filename, use 'prefix.filename'.  For PARM= in JCL, double up the
+    quotes.  You even have to quote filenames in stdin.
+
+6.  If your PARM includes any '/', make sure the PARM starts with '/'.
+    LE assumes anything before the first '/' is LE run time parameters.
+    It does no harm to always code a leading '/' for LE parms.
+
+7.  JCL limits a PARM= to 100 characters total with approx. 65 on a
+    single line.  Alas the syntax for continuing PARM= always embeds an
+    extra ',' somewhere in the parameters that the program finally
+    gets.  No workaround, limit your PARM to a single line.  With the
+    extra quotes around filenames, that does not leave much room.  In
+    most cases, you will have to use '-@' to read the list of filenames
+    from SYSIN (stdin), it will not fit on a single PARM line.
+
+8.  Filenames can be dataset names or you can refer to a ddname with
+    'DD:name', case insensitive for external files, case sensitive for
+    OE files.  You can even specify 'dd:name(mem)'.  No wildcards, to
+    zip a complete pds you have to specify each member individually.
+    Directory recursion in OE does not appear to work at the moment.
+
+9.  Zip attempts to map MVS filenames to Unix style names.  It did not
+    work correctly for quoted names, fixed.  Although you can pick up
+    an external (non-OE) file with a name using any case, be aware that
+    the mapping to a Unix style name faithfully follows the case you
+    supply.
+
+10. The archive file was being created with recfm=V and lrecl=32760.
+    32760 is not valid for recfm=V under MVS, I originally changed it
+    to lrecl=32756.  Then zip broke trying to fseek() over a record
+    boundary, I do not know whether this was a zip or LE bug.  Trial
+    and error showed that recfm=U with byteseek seems to work on MVS.
+    No BDW or RDW, just a byte stream.  The blocksize is always 6144.
+
+    NOTE: This is an incompatible change from the previous beta,
+          archive files used to be recfm=V.  That should not matter
+          because we just transfer the data, ignoring BDW and RDW
+          anyway.
+
+11. Zip used to complain about preallocated but empty archives, wrong
+    length records, no signature etc.  The usual IBM/360 problem of no
+    end of file marker in a new, unopened dataset.  Fixed, see routine
+    readzipfile in zipfile.c for the gory details.  PARM= works fine.
+
+12. Several source files have records that are more than 80 bytes long.
+    It works if you transfer to mainframe datasets with a larger lrecl,
+    I used recfm=fb,lrecl=120 for the .C and .H files.  To compile with
+    anything longer than 72 bytes, you need MVS C options NOMARGINS and
+    NOSEQUENCE (NOMAR,NOSEQ).
+
+13. cmsmvs was still using zname instead of name for open.  Fixed.
+
+14. zip has to jump through a lot of hoops to see if an existing
+    zipfile actually contains data.  A side effect of this is that
+    creating a zipfile with the RLSE parameter is a waste of time.
+
+Keith Owens <kaos@ocs.com.au>.  Not a maintainer, just a beta tester.
+Mon Sep 14 19:31:30 EST 1998
+
+
+Sample JCL to compile Zip under MVS LE.  You might need a large region,
+I used REGION=128M on the job card.  Also watch the output lines,
+75,000 with OPT(2), 100,000+ with OPT(2) replaced with DEF(DEBUG).  You
+need to allocate prefix.ZIP.C.OBJ (recfm=FB, lrecl=80) and
+prefix.ZIP.LOAD (recfm=U, blksize is site defined).
+
+//CBC    JCLLIB ORDER=CBC.SCBCPRC
+//ZIP EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+//    INFILE='prefix.ZIP.C(ZIP)',
+//    OUTFILE='prefix.ZIP.C.OBJ(ZIP),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+//    CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//CRYPT EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+//    INFILE='prefix.ZIP.C(CRYPT)',
+//    OUTFILE='prefix.ZIP.C.OBJ(CRYPT),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+//    CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//TTYIO EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+//    INFILE='prefix.ZIP.C(TTYIO)',
+//    OUTFILE='prefix.ZIP.C.OBJ(TTYIO),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+//    CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//TREES EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+//    INFILE='prefix.ZIP.C(TREES)',
+//    OUTFILE='prefix.ZIP.C.OBJ(TREES),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+//    CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//DEFLATE EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+//    INFILE='prefix.ZIP.C(DEFLATE)',
+//    OUTFILE='prefix.ZIP.C.OBJ(DEFLATE),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+//    CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//FILEIO EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+//    INFILE='prefix.ZIP.C(FILEIO)',
+//    OUTFILE='prefix.ZIP.C.OBJ(FILEIO),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+//    CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//GLOBALS EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+//    INFILE='prefix.ZIP.C(GLOBALS)',
+//    OUTFILE='prefix.ZIP.C.OBJ(GLOBALS),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+//    CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//UTIL EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+//    INFILE='prefix.ZIP.C(UTIL)',
+//    OUTFILE='prefix.ZIP.C.OBJ(UTIL),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+//    CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//CRC32 EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+//    INFILE='prefix.ZIP.C(CRC32)',
+//    OUTFILE='prefix.ZIP.C.OBJ(CRC32),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+//    CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//CRCTAB EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+//    INFILE='prefix.ZIP.C(CRCTAB)',
+//    OUTFILE='prefix.ZIP.C.OBJ(CRCTAB),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+//    CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//ZIPFILE EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+//    INFILE='prefix.ZIP.C(ZIPFILE)',
+//    OUTFILE='prefix.ZIP.C.OBJ(ZIPFILE),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+//    CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//ZIPUP EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+//    INFILE='prefix.ZIP.C(ZIPUP)',
+//    OUTFILE='prefix.ZIP.C.OBJ(ZIPUP),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+//    CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//CMSMVS EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+//    INFILE='prefix.ZIP.C(CMSMVS)',
+//    OUTFILE='prefix.ZIP.C.OBJ(CMSMVS),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+//    CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//MVS EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+//    INFILE='prefix.ZIP.C(MVS)',
+//    OUTFILE='prefix.ZIP.C.OBJ(MVS),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+//    CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//PLINK   EXEC  PROC=EDCPL,
+//    OUTFILE='prefix.ZIP.LOAD(ZIP),DISP=SHR',
+//    PREGSIZ=6M,
+//    PPARM='NONCAL,MAP,MEMORY',
+//    LPARM='LIST,MAP,XREF'
+//PLKED.SYSIN   DD  DISP=SHR,DSN=prefix.ZIP.C.OBJ(ZIP)
+//              DD  DISP=SHR,DSN=prefix.ZIP.C.OBJ(CRYPT)
+//              DD  DISP=SHR,DSN=prefix.ZIP.C.OBJ(TREES)
+//              DD  DISP=SHR,DSN=prefix.ZIP.C.OBJ(DEFLATE)
+//              DD  DISP=SHR,DSN=prefix.ZIP.C.OBJ(FILEIO)
+//              DD  DISP=SHR,DSN=prefix.ZIP.C.OBJ(GLOBALS)
+//              DD  DISP=SHR,DSN=prefix.ZIP.C.OBJ(UTIL)
+//              DD  DISP=SHR,DSN=prefix.ZIP.C.OBJ(CRC32)
+//              DD  DISP=SHR,DSN=prefix.ZIP.C.OBJ(CRCTAB)
+//              DD  DISP=SHR,DSN=prefix.ZIP.C.OBJ(ZIPFILE)
+//              DD  DISP=SHR,DSN=prefix.ZIP.C.OBJ(ZIPUP)
+//              DD  DISP=SHR,DSN=prefix.ZIP.C.OBJ(MVS)
+//              DD  DISP=SHR,DSN=prefix.ZIP.C.OBJ(CMSMVS)
+//LKED.SYSLIB   DD  DISP=SHR,DSN=CEE.SCEELKED
+//SYSUT1   DD  UNIT=SYSDA,SPACE=(CYL,(2,2))
+//
+
+Sample JCL to zip the mainframe .C and .H files as ASCII (-a).  Delete
+any existing archive first, point the temporary file at a particular
+prefix (-b), use 'prefix.ARCHIVE.ZIP' for the archive file, read the
+list of files to zip from stdin (SYSIN).
+
+//DELETE  EXEC PGM=IDCAMS
+//SYSPRINT DD  SYSOUT=*
+//SYSIN    DD  *
+ DELETE prefix.ARCHIVE.ZIP
+ SET MAXCC = 0
+//ZIP     EXEC PGM=ZIP,
+// PARM='/-a -v -b temppref ''prefix.ARCHIVE.ZIP'' -@'
+//STEPLIB  DD  DSN=prefix.ZIP.LOAD,DISP=SHR
+//SYSPRINT DD  SYSOUT=*
+//SYSOUT   DD  SYSOUT=*
+//CEEDUMP  DD  SYSOUT=*
+//ZIPC     DD  DISP=SHR,DSN=prefix.ZIP.C
+//ZIPH     DD  DISP=SHR,DSN=prefix.ZIP.H
+//SYSIN    DD  *
+dd:zipc(api)
+dd:zipc(cms)
+dd:zipc(cmsmvs)
+dd:zipc(crctab)
+dd:zipc(crc32)
+dd:zipc(crypt)
+dd:zipc(deflate)
+dd:zipc(fileio)
+dd:zipc(globals)
+dd:zipc(mktime)
+dd:zipc(mvs)
+dd:zipc(trees)
+dd:zipc(ttyio)
+dd:zipc(util)
+dd:zipc(zip)
+dd:zipc(zipcloak)
+dd:zipc(zipfile)
+dd:zipc(zipnote)
+dd:zipc(zipsplit)
+dd:zipc(zipup)
+dd:ziph(api)
+dd:ziph(cmsmvs)
+dd:ziph(crypt)
+dd:ziph(cstat)
+dd:ziph(ebcdic)
+dd:ziph(mvs)
+dd:ziph(revision)
+dd:ziph(stat)
+dd:ziph(tailor)
+dd:ziph(ttyio)
+dd:ziph(zip)
+dd:ziph(ziperr)
+dd:ziph(zipup)
diff --git a/cmsmvs/cczip.exec b/cmsmvs/cczip.exec
new file mode 100644 (file)
index 0000000..86edb59
--- /dev/null
@@ -0,0 +1,123 @@
+/* CCZIP    EXEC   Compile zip for VM/CMS                           */
+/*                 Author: George Petrov, 11 Apr 1995 (VMCOMPIL EXEC) */
+/* Modified for IBM C V3R1 by Ian E. Gorman, 2 Nov 1998
+   Facilities for compiling and testing were provided by
+      OmniMark Technologies Corporation, Ottawa, Canada
+*/
+Address Command
+Signal On Error
+
+/* Allow longnames, compile re-entrant code.
+   globals.c and cmsmvs.c require EXTENDED features */
+CCopts = 'LONGNAME RENT LANGLVL(EXTENDED) NOEXECOPS'
+
+/* ZIP options -- VM_CMS, REENTRANT */
+CCopts = CCopts 'DEFINE(VM_CMS,REENTRANT)'
+
+/* Link the load module to run in more or less than 16MB memory */
+LINKopts = 'AMODE ANY RMODE ANY RLDSAVE'
+
+/* resources needed to build */
+'GLOBAL TXTLIB  SCEELKED CMSLIB'
+'GLOBAL LOADLIB SCEERUN'
+
+/* produce the TEXT (object) files */
+linklist=''
+modname='ZIP'
+Say 'Building' modname 'MODULE...'
+Call Compile 'ZIP'
+Call Compile 'CRC32'
+Call Compile 'CRYPT'
+Call Compile 'DEFLATE'
+Call Compile 'FILEIO'
+Call Compile 'GLOBALS'
+Call Compile 'TREES'
+Call Compile 'TTYIO'
+Call Compile 'UTIL'
+Call Compile 'ZIPUP'
+Call Compile 'ZIPFILE'
+Call Compile 'CMSMVS'
+Call Compile 'CMS'
+
+Say 'Linking...'
+'EXEC CMOD' linklist '(MODNAME' modname LINKopts
+Say modname 'built successfully.'
+
+
+/*---------------------------------------------------------------------*/
+/* Build utility programs                                              */
+/*---------------------------------------------------------------------*/
+CCopts = CCopts 'DEFINE(UTIL)'
+
+
+linklist=''
+modname='ZIPNOTE'
+Say
+Say 'Building' modname 'MODULE...'
+Call Compile 'ZIPNOTE'
+Call Compile 'ZIPFILE'
+Call Compile 'FILEIO'
+Call Compile 'UTIL'
+Call Compile 'GLOBALS'
+Call Compile 'CMSMVS'
+
+Say 'Linking...'
+'EXEC CMOD' linklist '(MODNAME' modname LINKopts
+Say modname 'built successfully.'
+
+
+linklist=''
+modname='ZIPSPLIT'
+Say
+Say 'Building' modname 'MODULE...'
+Call Compile 'ZIPSPLIT'
+Call Compile 'ZIPFILE'
+Call Compile 'FILEIO'
+Call Compile 'UTIL'
+Call Compile 'GLOBALS'
+Call Compile 'CMSMVS'
+
+Say 'Linking...'
+'EXEC CMOD' linklist '(MODNAME' modname LINKopts
+Say modname 'built successfully.'
+
+
+linklist=''
+modname='ZIPCLOAK'
+Say
+Say 'Building' modname 'MODULE...'
+Call Compile 'ZIPCLOAK'
+Call Compile 'ZIPFILE'
+Call Compile 'FILEIO'
+Call Compile 'UTIL'
+Call Compile 'GLOBALS'
+Call Compile 'CRC32'
+Call Compile 'CRYPT'
+Call Compile 'TTYIO'
+Call Compile 'CMSMVS'
+
+Say 'Linking...'
+'EXEC CMOD' linklist '(MODNAME' modname LINKopts
+Say modname 'built successfully.'
+Say 'Done.'
+
+Exit rc
+
+
+
+error:
+    Say 'Error' rc 'during compilation!'
+    Say 'Error in line' sigl':'
+    Say '   'Sourceline(sigl)
+    Exit rc
+
+
+
+Compile:  Procedure Expose CCopts LINKopts linklist
+    Parse arg filename filetype filemode .
+    If filetype='' Then filetype='C'
+    linklist = linklist filename
+
+    Say 'Compiling' filename filetype filemode '...'
+    'EXEC CC' filename filetype filemode '('CCopts
+    Return rc
diff --git a/cmsmvs/cms.c b/cmsmvs/cms.c
new file mode 100644 (file)
index 0000000..e69f5cb
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ * VM/CMS specific things.
+ */
+
+#include "zip.h"
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  FILE *stream;
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else {
+     if ((stream = fopen(n, "r")) != (FILE *)NULL)
+        {
+        fclose(stream);
+        return newname(n, 0, caseflag);
+        }
+     else return ZE_MISS;
+  }
+  return ZE_OK;
+}
diff --git a/cmsmvs/cmsmvs.c b/cmsmvs/cmsmvs.c
new file mode 100644 (file)
index 0000000..9c56de7
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ * routines common to VM/CMS and MVS
+ */
+
+#include "zip.h"
+
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+
+#ifndef MVS  /* MVS has perfectly good definitions of the following */
+int stat(const char *path, struct stat *buf)
+{
+   if ((buf->fp = fopen(path, "r")) != NULL) {
+      fldata_t fdata;
+      if (fldata( buf->fp, buf->fname, &fdata ) == 0) {
+         buf->st_dev  = fdata.__device;
+         buf->st_mode = *(short *)(&fdata);
+      }
+      strcpy( buf->fname, path );
+      fclose(buf->fp);
+   }
+   return (buf->fp != NULL ? 0 : 1);
+}
+#endif /* MVS */
+
+
+#ifndef UTIL    /* the companion #endif is a bit of ways down ... */
+
+#define PAD 0
+#define PATH_END '/'
+
+/* Library functions not in (most) header files */
+
+#ifdef USE_ZIPMAIN
+int main OF((void));
+#endif
+
+int utime OF((char *, ztimbuf *));
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+#ifndef MVS  /* MVS has perfectly good definitions of the following */
+int fstat(int fd, struct stat *buf)
+{
+   fldata_t fdata;
+
+   if ((fd != -1) && (fldata( (FILE *)fd, buf->fname, &fdata ) == 0)) {
+      buf->st_dev  = fdata.__device;
+      buf->st_mode = *(short *)(&fdata);
+      buf->fp      = (FILE *)fd;
+      return 0;
+   }
+   return -1;
+}
+#endif /* MVS */
+
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t;              /* shortened name */
+  int dosflag;
+  char mem[10] = "";    /* member name */
+  char ext[10] = "";     /* extension name */
+
+  dosflag = dosify;  /* default for non-DOS non-OS/2 */
+
+  /* Find starting point in name before doing malloc */
+  for (t = x; *t == '/'; t++)
+    ;
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+  if (!pathput)
+    t = last(t, PATH_END);
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL)
+    return NULL;
+  strcpy(n, t);
+
+#ifdef MVS
+  /* strip quotes from name, non-OE format */
+  if (*n == '\'' && (t = strrchr(n, '\'')) != n) {
+    if (!*(t+1)) {
+      /* yes, it is a quoted name */
+      int l = strlen(n) - 2;
+      memmove(n, n+1, l);
+      *(n+l) = '\0';
+    }
+  }
+  /* Change member names to fn.ext */
+  if (t = strrchr(n, '(')) {
+     *t = '\0';
+     strcpy(mem,t+1);        /* Save member name */
+     if (t = strchr(mem, ')')) *t = '\0';         /* Set end of mbr */
+     /* Save extension */
+     if (t = strrchr(n, '.')) t++;
+     else t = n;
+     strcpy(ext,t);
+     /* Build name as "member.ext" */
+     strcpy(t,mem);
+     strcat(t,".");
+     strcat(t,ext);
+  }
+
+  /* Change all but the last '.' to '/' */
+  if (t = strrchr(n, '.')) {
+     while (--t > n)
+        if (*t == '.')
+          *t = '/';
+  }
+#else
+  /* On CMS, remove the filemode (all past 2nd '.') */
+  if (t = strchr(n, '.'))
+     if (t = strchr(t+1, '.'))
+        *t = '\0';
+  t = n;
+#endif
+
+  strcpy(n, t);
+
+  if (isdir == 42) return n;    /* avoid warning on unused variable */
+
+  if (dosify)
+    msname(n);                  /* msname() needs string in native charset */
+
+  strtoasc(n, n);
+
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+  return n;
+}
+
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+    return NULL;
+  strtoebc(x, n);
+  return x;
+}
+
+
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+  ztimbuf u;            /* argument for utime() */
+
+  /* Convert DOS time to time_t format in u.actime and u.modtime */
+  u.actime = u.modtime = dos2unixtime(d);
+
+  utime(f, &u);
+}
+
+
+ulg filetime(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+{
+  FILE *stream;
+  time_t ltime;
+
+  if (strcmp(f, "-") != 0) {    /* if not compressing stdin */
+     Trace((mesg, "opening file '%s' with '%s'\n", f, FOPR));
+     if ((stream = fopen(f, FOPR)) == (FILE *)NULL) {
+        return 0;
+     } else {
+        if (n != NULL) {
+           /* With byteseek, this will work */
+           fseek(stream, 0L, SEEK_END);
+           *n = ftell(stream);
+           Trace((mesg, "file size = %lu\n", *((ulg *)n)));
+        }
+        fclose(stream);
+     }
+  }
+  else {
+     /* Reading from stdin */
+     if (n != NULL) {
+        *n = -1L;
+     }
+  }
+
+  /* Return current time for all the times -- for now */
+  time(&ltime);
+  if (t != NULL)
+     t->atime = t->mtime = t->ctime = ltime;
+
+  /* Set attributes (always a file) */
+  if (a != NULL)
+     *a = 0;
+
+  return unix2dostime(&ltime);
+}
+
+
+
+int set_extra_field(z, z_utim)
+struct zlist far *z;
+iztimes *z_utim;
+/* create extra field and change z->att if desired */
+{
+   fldata_t fdata;
+   FILE *stream;
+   char *eb_ptr;
+#ifdef USE_EF_UT_TIME
+   extent ef_l_len = (EB_HEADSIZE+EB_UT_LEN(1));
+#else /* !USE_EF_UT_TIME */
+   extent ef_l_len = 0;
+#endif /* ?USE_EF_UT_TIME */
+   int set_cmsmvs_eb = 0;
+
+/*translate_eol = 0;*/
+  if (aflag == ASCII) {
+     z->att = ASCII;
+  } else {
+    if (bflag)
+      z->att = BINARY;
+    else
+      z->att = __EBCDIC;
+    ef_l_len += sizeof(fdata)+EB_HEADSIZE;
+    set_cmsmvs_eb = 1;
+  }
+
+  if (ef_l_len > 0) {
+    z->extra = (char *)malloc(ef_l_len);
+    if (z->extra == NULL) {
+       printf("\nFLDATA : Unable to allocate memory !\n");
+       return ZE_MEM;
+    }
+    z->cext = z->ext = ef_l_len;
+    eb_ptr = z->cextra = z->extra;
+
+    if (set_cmsmvs_eb) {
+      if (bflag)
+/***    stream = fopen(z->zname,"rb,type=record");   $RGH$ ***/
+        stream = fopen(z->name,"rb");
+      else
+        stream = fopen(z->name,"r");
+      if (stream == NULL) {
+        printf("\nFLDATA : Could not open file : %s !\n",z->name);
+        printf("Error %d: '%s'\n", errno, strerror(errno));
+        return ZE_NONE;
+      }
+
+      fldata(stream,z->name,&fdata);
+      /*put the system ID */
+#ifdef VM_CMS
+      *(eb_ptr) = EF_VMCMS & 0xFF;
+      *(eb_ptr+1) = EF_VMCMS >> 8;
+#else
+      *(eb_ptr) = EF_MVS & 0xFF;
+      *(eb_ptr+1) = EF_MVS >> 8;
+#endif
+      *(eb_ptr+2) = sizeof(fdata) & 0xFF;
+      *(eb_ptr+3) = sizeof(fdata) >> 8;
+
+      memcpy(eb_ptr+EB_HEADSIZE,&fdata,sizeof(fdata));
+      fclose(stream);
+#ifdef USE_EF_UT_TIME
+      eb_ptr += (sizeof(fdata)+EB_HEADSIZE);
+#endif /* USE_EF_UT_TIME */
+    }
+#ifdef USE_EF_UT_TIME
+    eb_ptr[0]  = 0x55;                  /* ascii[(unsigned)('U')] */
+    eb_ptr[1]  = 0x54;                  /* ascii[(unsigned)('T')] */
+    eb_ptr[2]  = EB_UT_LEN(1);          /* length of data part of e.f. */
+    eb_ptr[3]  = 0;
+    eb_ptr[4]  = EB_UT_FL_MTIME;
+    eb_ptr[5]  = (char)(z_utim->mtime);
+    eb_ptr[6]  = (char)(z_utim->mtime >> 8);
+    eb_ptr[7]  = (char)(z_utim->mtime >> 16);
+    eb_ptr[8]  = (char)(z_utim->mtime >> 24);
+#endif /* USE_EF_UT_TIME */
+  }
+
+  return ZE_OK;
+}
+
+int deletedir(d)
+char *d;                /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+   Return the result of rmdir(), delete(), or system().
+   For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
+ */
+{
+    return 0;
+}
+
+#ifdef USE_ZIPMAIN
+/* This function is called as main() to parse arguments                */
+/* into argc and argv.  This is required for stand-alone               */
+/* execution.  This calls the "real" main() when done.                 */
+
+int main(void)
+   {
+    int  argc=0;
+    char *argv[50];
+
+    int  iArgLen;
+    char argstr[256];
+    char **pEPLIST, *pCmdStart, *pArgStart, *pArgEnd;
+
+   /* Get address of extended parameter list from S/370 Register 0 */
+   pEPLIST = (char **)__xregs(0);
+
+   /* Null-terminate the argument string */
+   pCmdStart = *(pEPLIST+0);
+   pArgStart = *(pEPLIST+1);
+   pArgEnd   = *(pEPLIST+2);
+   iArgLen   = pArgEnd - pCmdStart + 1;
+
+   /* Make a copy of the command string */
+   memcpy(argstr, pCmdStart, iArgLen);
+   argstr[iArgLen] = '\0';  /* Null-terminate */
+
+   /* Store first token (cmd) */
+   argv[argc++] = strtok(argstr, " ");
+
+   /* Store the rest (args) */
+   while (argv[argc-1])
+      argv[argc++] = strtok(NULL, " ");
+   argc--;  /* Back off last NULL entry */
+
+   /* Call "real" main() function */
+   return zipmain(argc, argv);
+
+}
+#endif /* USE_ZIPMAIN */
+
+#endif /* !UTIL */
+
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+void version_local()
+{
+    char liblvlmsg [50+1];
+    char *compiler = "?";
+    char *platform = "?";
+    char complevel[64];
+
+    /* Map the runtime library level information */
+    union {
+       unsigned int iVRM;
+       struct {
+          unsigned int pd:4;    /* Product designation */
+          unsigned int vv:4;    /* Version             */
+          unsigned int rr:8;    /* Release             */
+          unsigned int mm:16;   /* Modification level  */
+       } xVRM;
+    } VRM;
+
+
+    /* Break down the runtime library level */
+    VRM.iVRM = __librel();
+    sprintf(liblvlmsg, "Using runtime library level %s V%dR%dM%d",
+            (VRM.xVRM.pd==1 ? "LE" : "CE"),
+            VRM.xVRM.vv, VRM.xVRM.rr, VRM.xVRM.mm);
+    /* Note:  LE = Language Environment, CE = Common Env. (C/370). */
+    /* This refers ONLY to the current runtimes, not the compiler. */
+
+
+#ifdef VM_CMS
+    platform = "VM/CMS";
+    #ifdef __IBMC__
+       compiler = "IBM C";
+    #else
+       compiler  = "C/370";
+    #endif
+#endif
+
+#ifdef MVS
+    platform = "MVS";
+    #ifdef __IBMC__
+       compiler = "IBM C/C++";
+    #else
+       compiler = "C/370";
+    #endif
+#endif
+
+#ifdef __COMPILER_VER__
+    VRM.iVRM = __COMPILER_VER__;
+    sprintf(complevel," V%dR%dM%d",
+            VRM.xVRM.vv, VRM.xVRM.rr, VRM.xVRM.mm);
+#else
+#ifdef __IBMC__
+    sprintf(complevel," V%dR%d", __IBMC__ / 100, (__IBMC__ % 100)/10);
+#else
+    complevel[0] = '\0';
+#endif
+#endif
+
+
+    printf("Compiled with %s%s for %s%s%s.\n\n",
+
+    /* Add compiler name and level */
+    compiler, complevel,
+
+    /* Add platform */
+    platform,
+
+    /* Add timestamp */
+#ifdef __DATE__
+      " on " __DATE__
+#ifdef __TIME__
+      " at " __TIME__
+#endif
+#endif
+      ".\n",
+      liblvlmsg
+    );
+} /* end function version_local() */
diff --git a/cmsmvs/cmsmvs.h b/cmsmvs/cmsmvs.h
new file mode 100644 (file)
index 0000000..e2adb31
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/* Include file for VM/CMS and MVS */
+
+/* This is normally named osdep.h on most systems.  Since CMS       */
+/* generally doesn't support directories, it's been given a unique  */
+/* name to avoid confusion.                                         */
+
+
+#ifndef __cmsmvs_h   /* prevent multiple inclusions */
+#define __cmsmvs_h
+
+#ifdef MVS
+#  define _POSIX_SOURCE    /* tell MVS we want full definitions */
+#  include <features.h>
+#endif /* MVS */
+
+#include <time.h>               /* the usual non-BSD time functions */
+/* cstat.h is not required for MVS and actually gets in the way.  Is it
+ * needed for CMS?
+ */
+#ifdef MVS
+#  include <sys/stat.h>
+#  include <sys/modes.h>
+#else /* !MVS */
+#  include "cstat.h"
+#endif
+
+
+/* Newer compiler version defines something for us */
+#if defined(__VM__) && !defined(VM_CMS)
+#  define VM_CMS
+#endif
+
+#define CMS_MVS
+#define EBCDIC
+
+#ifndef MVS  /* MVS has perfectly good definitions for the following */
+#  define NO_UNISTD_H
+#  define NO_FCNTL_H
+#endif /*MVS */
+
+/* If we're generating a stand-alone CMS module, patch in        */
+/* a new main() function before the real main() for arg parsing. */
+#ifdef CMS_STAND_ALONE
+#  define USE_ZIPMAIN
+#endif
+
+#ifndef NULL
+#  define NULL 0
+#endif
+
+#define PASSWD_FROM_STDIN
+                  /* Kludge until we know how to open a non-echo tty channel */
+
+/* definition for ZIP */
+#define getch() getc(stdin)
+#define MAXPATHLEN 128
+#define NO_RMDIR
+#define NO_MKTEMP
+#define USE_CASE_MAP
+#define isatty(t) 1
+
+#ifndef MVS  /* MVS has perfectly good definitions for the following */
+#  define fileno(x) (char *)(x)
+#  define fdopen fopen
+#  define unlink remove
+#  define link rename
+#  define utime(f,t)
+#endif /*MVS */
+#ifdef ZCRYPT_INTERNAL
+#  define ZCR_SEED2     (unsigned)3141592654L   /* use PI as seed pattern */
+#endif
+
+#ifdef MVS
+#  if defined(__CRC32_C)
+#    pragma csect(STATIC,"crc32_s")
+#  elif defined(__DEFLATE_C)
+#    pragma csect(STATIC,"deflat_s")
+#  elif defined(__ZIPFILE_C)
+#    pragma csect(STATIC,"zipfil_s")
+#  elif defined(__ZIPUP_C)
+#    pragma csect(STATIC,"zipup_s")
+#  endif
+#endif /* MVS */
+
+/* end defines for ZIP */
+
+
+
+#if 0  /*$RGH$*/
+/* RECFM=F, LRECL=1 works for sure */
+#define FOPR "rb,recfm=fb"
+#define FOPM "r+"
+#define FOPW "wb,recfm=fb,lrecl=1"
+#define FOPWT "w"
+#endif
+
+/* Try allowing ZIP files to be RECFM=V with "byteseek" for CMS, recfm=U for MVS */
+#define FOPR "rb,byteseek"
+#define FOPM "r+,byteseek"
+#ifdef MVS
+  #define FOPW "wb,recfm=u,byteseek"
+#else /* !MVS */
+  #define FOPW "wb,recfm=v,lrecl=32760,byteseek"
+#endif /* MVS */
+
+#if 0
+#define FOPW_TMP "w,byteseek"
+#else
+#define FOPW_TMP "w,type=memory(hiperspace)"
+#endif
+
+#define CBSZ 0x40000
+#define ZBSZ 0x40000
+
+#endif /* !__cmsmvs_h */
diff --git a/cmsmvs/cstat.h b/cmsmvs/cstat.h
new file mode 100644 (file)
index 0000000..f02a5c3
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*  cstat.h
+
+    Definitions used for file status functions
+
+*/
+
+#ifndef __STAT_H
+#define __STAT_H
+
+#include <stdio.h>
+
+#define S_IFMT  0xF000  /* file type mask */
+#define S_IFDIR 0x4000  /* directory */
+#define S_IFIFO 0x1000  /* FIFO special */
+#define S_IFCHR 0x2000  /* character special */
+#define S_IFBLK 0x3000  /* block special */
+#define S_IFREG 0x8000  /* or just 0x0000, regular */
+#define S_IREAD 0x0100  /* owner may read */
+#define S_IWRITE 0x0080 /* owner may write */
+#define S_IEXEC 0x0040  /* owner may execute <directory search> */
+
+struct  stat
+{
+    short st_dev;      /* Drive number of disk containing the  */
+                       /* file or file handle if the file is   */
+                       /* on device                            */
+    short st_ino;      /* Not meaningfull for VM/CMS           */
+    short st_mode;     /* Bit mask giving information about    */
+                       /* the file's mode                      */
+    short st_nlink;    /* Set to the integer constant 1        */
+    int   st_uid;      /* Not meaningfull for VM/CMS           */
+    int   st_gid;      /* Not meaningfull for VM/CMS           */
+    short st_rdev;     /* Same as st_dev                       */
+    long  st_size;     /* Size of the file in bytes            */
+    long  st_atime;    /* Most recent access                   */
+    long  st_mtime;    /* Same as st_atime                     */
+    long  st_ctime;    /* Same as st_atime                     */
+    FILE  *fp;
+    char  fname[FILENAME_MAX];
+};
+
+int stat(const char *path, struct stat *sb);
+int fstat(int fd, struct stat *sb);
+
+#endif  /* __STAT_H */
diff --git a/cmsmvs/mc.exec b/cmsmvs/mc.exec
new file mode 100644 (file)
index 0000000..ca22a18
--- /dev/null
@@ -0,0 +1,95 @@
+/* MAKECPIP EXEC      Make program to build a C/370 module           */
+/*                    Author: George Petrov, 29 Sep 1994             */
+
+arg fn . '(' cparms                   /* Filter name                 */
+'pipe (end ?) < 'fn' makefile',       /* get all source files from   */
+    '| frlab GLOBALS:'||,
+    '| drop',
+    '| strip',
+    '| var globals'
+cparms = cparms globals
+say ''
+say 'Compile options : 'cparms
+say ''
+if pos('REB',cparms) > 0 then do
+parse var cparms cp1 'REB' . ' ' cp2  /* REBuild options specified ? */
+cparms = cp1||cp2
+pipe1=,
+'pipe (end ?) < 'fn' makefile',       /* get all source files from   */
+    '| nfind *'||,                    /* the makefile and compile    */
+    '| frlab TEXT:'||,                /* only the those who are      */
+    '| r: tolab MODULE:'||,           /* changed or never compiled   */
+    '| drop',
+    '| o: fanout',
+    '| chop before str /(/',
+    '| statew',
+    '| c: fanout',                    /* compiled                    */
+    '| specs /Compiling / 1 w1-3 n / .../ n',
+    '| cons'
+end
+else do
+pipe1=,
+'pipe (end ?) < 'fn' makefile',       /* get all source files from   */
+    '| nfind *'||,                    /* the makefile and compile    */
+    '| frlab TEXT:'||,                /* only the those who are      */
+    '| r: tolab MODULE:'||,           /* changed or never compiled   */
+    '| drop',
+    '| o: fanout',
+    '| specs w1 1 /C/ nw w3 nw write w1 1 /TEXT A/ nw',
+    '| chop before str /(/',
+    '| statew',
+    '| change (57 66) / /0/',
+    '| sort 1.8 d',                  /* sort the date and time      */
+    '| uniq 1-17 singles',           /* if the first is a source    */
+    '| sort 1.8 d 64.2 d 57.2 d 60.2 d 66.8 d',    /* sort the date */
+    '| uniq 1-8 first',          /*    if the first is a source    */
+    '| locate 9.8 /C      /',         /* program then it has to be   */
+    '| c: fanout',                    /* compiled                    */
+    '| specs /Compiling / 1 w1-3 n / .../ n',
+    '| cons'
+end
+pipe2= '?',
+    'r:',
+    '| drop',
+    '| specs w1 1',                 /* save the module name in var  */
+    '| var module',
+    '?',
+    'o:',
+    '| specs w1 1',
+    '| join * / /',
+    '| var texts',                  /* save all the text file names */
+    '?',                            /* for later include            */
+    'c:',
+    '| specs /CC / 1 w1-3 n /(NOTERM 'cparms'/ nw',   /* compile! */
+    '| err: cms | cons',
+    '?',
+    'err:',
+    '| strip both',
+    '| nfind 0'||,
+    '| var err',
+    '| specs /----> Errors found! RC=/ 1 1-* n',
+    '| cons'
+/*  '| g: gate'*/
+pipe1 pipe2
+say ''
+if symbol('err') = 'VAR' & err ^= 0 then do
+      say 'Errors found in source files - link aborted! RC = 'err
+      exit err
+end
+say 'Generating module 'module
+'pipe cms cmod' fn texts' DMSCSL | > 'fn' LINK A'
+'set cmstype ht'
+'state 'fn' LINK A'
+rcc = rc
+'set cmstype rt'
+if rcc = 0 then do
+   say ''
+   say 'ERRORS discovered during linking!'
+   say 'See: 'fn' LINK A for more info'
+end
+exit rc
+error:
+say 'Error in REXX detected!'
+Say 'Syntax error on line' Sigl':' Sourceline(Sigl)
+Say 'Error was:' Errortext(RC)
+return rc
diff --git a/cmsmvs/mvs.c b/cmsmvs/mvs.c
new file mode 100644 (file)
index 0000000..d7f7437
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ * MVS specific things
+ */
+#include "zip.h"
+#include "mvs.h"
+#include <errno.h>
+
+static int gen_node( DIR *dirp, RECORD *recptr )
+{
+   char *ptr, *name, ttr[TTRLEN];
+   int skip, count = 2;
+   unsigned int info_byte, alias, ttrn;
+   struct dirent *new;
+
+   ptr = recptr->rest;
+   while (count < recptr->count) {
+      if (!memcmp( ptr, endmark, NAMELEN ))
+         return 1;
+      name = ptr;                    /* member name */
+      ptr += NAMELEN;
+      memcpy( ttr, ptr, TTRLEN );    /* ttr name    */
+      ptr += TTRLEN;
+      info_byte = (unsigned int) (*ptr);   /* info byte */
+      if ( !(info_byte & ALIAS_MASK) ) {   /* no alias  */
+         new = malloc( sizeof(struct dirent) );
+         if (dirp->D_list == NULL)
+            dirp->D_list = dirp->D_curpos = new;
+         else
+            dirp->D_curpos = (dirp->D_curpos->d_next = new);
+         new->d_next = NULL;
+         memcpy( new->d_name, name, NAMELEN );
+         new->d_name[NAMELEN] = '\0';
+         if ((name = strchr( new->d_name, ' ' )) != NULL)
+            *name = '\0';      /* skip trailing blanks */
+      }
+      skip = (info_byte & SKIP_MASK) * 2 + 1;
+      ptr += skip;
+      count += (TTRLEN + NAMELEN + skip);
+   }
+   return 0;
+}
+
+DIR *opendir(const char *dirname)
+{
+   int bytes, list_end = 0;
+   DIR *dirp;
+   FILE *fp;
+   RECORD rec;
+
+   fp = fopen( dirname, "rb" );
+   if (fp != NULL) {
+      dirp = malloc( sizeof(DIR) );
+      if (dirp != NULL) {
+         dirp->D_list = dirp->D_curpos = NULL;
+         strcpy( dirp->D_path, dirname );
+         do {
+            bytes = fread( &rec, 1, sizeof(rec), fp );
+            if (bytes == sizeof(rec))
+               list_end = gen_node( dirp, &rec );
+         } while (!feof(fp) && !list_end);
+         fclose( fp );
+         dirp->D_curpos = dirp->D_list;
+         return dirp;
+      }
+      fclose( fp );
+   }
+   return NULL;
+}
+
+struct dirent *readdir(DIR *dirp)
+{
+   struct dirent *cur;
+
+   cur = dirp->D_curpos;
+   dirp->D_curpos = dirp->D_curpos->d_next;
+   return cur;
+}
+
+void rewinddir(DIR *dirp)
+{
+   dirp->D_curpos = dirp->D_list;
+}
+
+int closedir(DIR *dirp)
+{
+   struct dirent *node;
+
+   while (dirp->D_list != NULL) {
+      node = dirp->D_list;
+      dirp->D_list = dirp->D_list->d_next;
+      free( node );
+   }
+   free( dirp );
+   return 0;
+}
+
+local char *readd(d)
+DIR *d;                 /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+   no more entries or an error occurs. */
+{
+  struct dirent *e;
+
+  e = readdir(d);
+  return e == NULL ? (char *) NULL : e->d_name;
+}
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  DIR *d;               /* directory stream from opendir() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+  int exists;           /* 1 if file exists */
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (!(exists = (LSSTAT(n, &s) == 0)))
+  {
+#ifdef MVS
+    /* special case for MVS.  stat does not work on non-HFS files so if
+     * stat fails with ENOENT, try to open the file for reading anyway.
+     * If the user has no OMVS segment, stat gets an initialization error,
+     * even on external files.
+     */
+    if (errno == ENOENT || errno == EMVSINITIAL) {
+      FILE *f = fopen(n, "r");
+      if (f) {
+        /* stat got ENOENT but fopen worked, external file */
+        fclose(f);
+        exists = 1;
+        memset(&s, '\0', sizeof(s));   /* stat data is unreliable for externals */
+        s.st_mode = S_IFREG;           /* fudge it */
+      }
+    }
+#endif /* MVS */
+  }
+  if (! exists) {
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  if (!S_ISDIR(s.st_mode))
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0, caseflag)) != ZE_OK)
+      return m;
+  } else {
+    /* Add trailing / to the directory name */
+    if ((p = malloc(strlen(n)+2)) == NULL)
+      return ZE_MEM;
+    if (strcmp(n, ".") == 0) {
+      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      strcpy(p, n);
+      a = p + strlen(p);
+      if (a[-1] != '/')
+        strcpy(a, "/");
+      if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+        free((zvoid *)p);
+        return m;
+      }
+    }
+    /* recurse into directory */
+    if (recurse && (d = opendir(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if (strcmp(e, ".") && strcmp(e, ".."))
+        {
+          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+          {
+            closedir(d);
+            free((zvoid *)p);
+            return ZE_MEM;
+          }
+          strcat(strcpy(a, p), e);
+          if ((m = procname(a, caseflag)) != ZE_OK)   /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", a);
+            else
+              ziperr(m, a);
+          }
+          free((zvoid *)a);
+        }
+      }
+      closedir(d);
+    }
+    free((zvoid *)p);
+  } /* (s.st_mode & S_IFDIR) == 0) */
+  return ZE_OK;
+}
diff --git a/cmsmvs/mvs.h b/cmsmvs/mvs.h
new file mode 100644 (file)
index 0000000..b2f9760
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/* <dirent.h> definitions */
+
+#define NAMELEN     8
+
+struct dirent {
+   struct dirent *d_next;
+   char   d_name[NAMELEN+1];
+};
+
+typedef struct _DIR {
+   struct  dirent *D_list;
+   struct  dirent *D_curpos;
+   char            D_path[FILENAME_MAX];
+} DIR;
+
+DIR *          opendir(const char *dirname);
+struct dirent *readdir(DIR *dirp);
+void           rewinddir(DIR *dirp);
+int            closedir(DIR *dirp);
+char *         readd(DIR *dirp);
+
+#define ALIAS_MASK  (unsigned int) 0x80
+#define SKIP_MASK   (unsigned int) 0x1F
+#define TTRLEN      3
+#define RECLEN      254
+
+typedef _Packed struct {
+   unsigned short int count;
+   char rest[RECLEN];
+} RECORD;
+
+char    *endmark = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
diff --git a/cmsmvs/mvs.mki b/cmsmvs/mvs.mki
new file mode 100644 (file)
index 0000000..316d064
--- /dev/null
@@ -0,0 +1,125 @@
+# Makefile for the MVS (OS/390 Base) version of ZIP 2.3
+# Produced for C/C++ V3R2 in OS/390 1.2.0 by Ian E. Gorman, 2 Nov 1998
+# Facilities for compiling and testing were made available by
+#     OmniMark Technologies Corporation, Ottawa, Canada
+
+# NOTES
+#
+# The only tabs in this file are in the first character of each recipe
+# line, where they are required by make.
+#
+# Run this makefile in OpenMVS (OS/390 POSIX) using source files in the
+# HFS file system.  You can write the load module to either HFS file
+# system or to a PDS in the native MVS file system.  The PDS must have
+# sufficient free space to hold the load module.
+#
+# To compile to a member of a PDS:
+#   make
+# or
+#   make zip.mvs
+#
+# To compile a test version into the HFS file system:
+#   make hfs
+
+# ZIP options -- MVS, REENTRANT
+ZIPOPTS=-DMVS -DREENTRANT
+
+# directories
+
+# generic source code
+SRC=..
+SRC_P=$(SRC)/
+
+# source code for MVS
+CMSMVS=../cmsmvs
+CMSMVS_P=$(CMSMVS)/
+
+# include files
+INCLS=-I$(SRC) -I$(CMSMVS)
+
+# object files and load modules
+BLD_P=../mvs/
+
+# Other options
+
+# Suffixes (E and O must be different)
+E=
+O=.o
+
+# Need EXTENDED features for global.c and vmvms.c, so not using c89
+CC=cc
+CFLAGS=-D_OPEN_SYS $(ZIPOPTS) $(INCLS)
+
+LD=cc
+LDFLAGS=
+
+# Files
+
+# object (TEXT) files
+OBJECTS= $(BLD_P)zip$(O) $(BLD_P)trees$(O) \
+   $(BLD_P)crypt$(O)  $(BLD_P)ttyio$(O)   $(BLD_P)deflate$(O) \
+   $(BLD_P)fileio$(O) $(BLD_P)globals$(O) $(BLD_P)util$(O) \
+   $(BLD_P)crc32$(O)  $(BLD_P)zipfile$(O) \
+   $(BLD_P)zipup$(O)  $(BLD_P)cmsmvs$(O)  $(BLD_P)mvs$(O)
+
+# Header files
+HFILES= $(SRC_P)api.h $(SRC_P)crc32.h $(SRC_P)crypt.h $(SRC_P)ebcdic.h \
+    $(SRC_P)revision.h $(SRC_P)tailor.h $(SRC_P)ttyio.h \
+    $(SRC_P)zip.h $(SRC_P)ziperr.h $(CMSMVS_P)cmsmvs.h \
+    $(CMSMVS_P)cstat.h $(CMSMVS_P)mvs.h $(CMSMVS_P)zipup.h
+
+# Rules
+
+all:  $(BLD_P)zip.mvs$(E)
+hfs:  $(BLD_P)zip$(E)
+
+# link
+
+$(BLD_P)zip.mvs$(E):     $(OBJECTS)
+       $(LD) -o "//INFOZIP.LOAD(ZIP)" $(LDFLAGS) $^
+       echo "tso call \"infozip(zip)\" \"'\"\"""$$""@""\"\"'\"" > $%
+       chmod a+x $%
+
+$(BLD_P)zip$(E):     $(OBJECTS)
+       $(LD) -o $% $(LDFLAGS) $^
+
+# compile
+
+$(BLD_P)trees$(O):   $(SRC_P)trees.c        $(HFILES)
+       $(CC) -c -o $% $(CFLAGS) $(SRC_P)trees.c
+
+$(BLD_P)crypt$(O):   $(SRC_P)crypt.c        $(HFILES)
+       $(CC) -c -o $% $(CFLAGS) $(SRC_P)crypt.c
+
+$(BLD_P)ttyio$(O):   $(SRC_P)ttyio.c        $(HFILES)
+       $(CC) -c -o $% $(CFLAGS) $(SRC_P)ttyio.c
+
+$(BLD_P)deflate$(O): $(SRC_P)deflate.c      $(HFILES)
+       $(CC) -c -o $% $(CFLAGS) $(SRC_P)deflate.c
+
+$(BLD_P)fileio$(O):  $(SRC_P)fileio.c       $(HFILES)
+       $(CC) -c -o $% $(CFLAGS) $(SRC_P)fileio.c
+
+$(BLD_P)globals$(O): $(SRC_P)globals.c      $(HFILES)
+       $(CC) -c -o $% $(CFLAGS) $(SRC_P)globals.c
+
+$(BLD_P)zip$(O):     $(SRC_P)zip.c          $(HFILES)
+       $(CC) -c -o $% $(CFLAGS) $(SRC_P)zip.c
+
+$(BLD_P)util$(O):    $(SRC_P)util.c         $(HFILES)
+       $(CC) -c -o $% $(CFLAGS) $(SRC_P)util.c
+
+$(BLD_P)crc32$(O):   $(SRC_P)crc32.c        $(HFILES)
+       $(CC) -c -o $% $(CFLAGS) $(SRC_P)crc32.c
+
+$(BLD_P)zipfile$(O): $(SRC_P)zipfile.c      $(HFILES)
+       $(CC) -c -o $% $(CFLAGS) $(SRC_P)zipfile.c
+
+$(BLD_P)zipup$(O):   $(SRC_P)zipup.c        $(HFILES)
+       $(CC) -c -o $% $(CFLAGS) $(SRC_P)zipup.c
+
+$(BLD_P)cmsmvs$(O):  $(CMSMVS_P)cmsmvs.c    $(HFILES)
+       $(CC) -c -o $% $(CFLAGS) $(CMSMVS_P)cmsmvs.c
+
+$(BLD_P)mvs$(O):     $(CMSMVS_P)mvs.c       $(HFILES)
+       $(CC) -c -o $% $(CFLAGS) $(CMSMVS_P)mvs.c
diff --git a/cmsmvs/pipzip.rexx b/cmsmvs/pipzip.rexx
new file mode 100644 (file)
index 0000000..4249ded
--- /dev/null
@@ -0,0 +1,27 @@
+/* PIPZIP REXX     Rexx filter to use ZIP                             */
+/*                 Author : George Petrov, 8 May 1995                 */
+
+parse arg opts
+'callpipe *:',
+   '| specs w1 1 /./ n w2 n',
+   '| join * / /',
+   '| specs /zip 'opts'/ 1 1-* nw',
+   '| cms',
+   '| *:'
+
+exit rc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmsmvs/zip.exec b/cmsmvs/zip.exec
new file mode 100644 (file)
index 0000000..0b9de97
--- /dev/null
@@ -0,0 +1,66 @@
+/***********************************************************************/
+/*                                                                     */
+/* Front-end EXEC to set up linkage to the C runtime libraries         */
+/* before executing a MODULE generated from C code.                    */
+/*                                                                     */
+/* Copy this file as an EXEC with a filename matching the C MODULE.    */
+/*                                                                     */
+/* Greg Hartwig (ghartwig@vnet.ibm.com)   7/31/97, 4/24/98.            */
+/*                                                                     */
+/***********************************************************************/
+Address Command
+Parse Arg argstring
+Parse Source . . myname .
+
+/* Set output and input character translation so brackets show up */
+'SET OUTPUT AD' 'BA'x
+'SET OUTPUT BD' 'BB'x
+'SET INPUT  BA   AD'
+'SET INPUT  BB   BD'
+
+Call CLIB
+If rc<>0 Then Do
+   Say 'The required C runtime libraries don''t appear to be available.'
+   Say myname 'can not run.'
+   Exit 12
+End
+
+/* Run the command */
+myname argstring
+Exit rc
+
+
+
+
+/* Contents of the CLIB EXEC, modified for RC checking.        */
+/* Removed TXTLIB setting.  Only LOADLIB needed for execution. */
+CLIB:
+/***************************************************/
+/*      SET UP LIBRARIES FOR LE for MVS & VM       */
+/***************************************************/
+Address COMMAND
+
+loadlib  ='EDCLINK'               /* C/370 runtime                 */
+loadlib  ='SCEERUN'               /* LE runtime                    */
+
+
+theirs=queued()                           /* old stack contentsM068*/
+ 'QUERY LOADLIB ( LIFO'                   /* old setting       M068*/
+ LoadlibList=''                           /* init list         M068*/
+rc=0
+ Do while queued()^=theirs                /* all lines from cmdM068*/
+   Parse upper pull 'LOADLIB' '=' Ltemp   /* get one line      M068*/
+   LoadlibList= Ltemp Loadliblist         /* was stacked LIFO  M068*/
+ End                                                         /*M068*/
+ If loadlibList='NONE' ,
+ Then Do
+  'GLOBAL LOADLIB' Loadlib          /* enforce what we need         */
+ End
+ Else Do
+  Do xx=1 to Words(loadlib)
+  If Find(loadliblist,word(loadlib,xx)) = 0 ,
+   then loadliblist = loadliblist word(loadlib,xx)
+  End
+  'GLOBAL LOADLIB' loadliblist       /* enforce what we need         */
+ End
+Return
diff --git a/cmsmvs/zip.makefile b/cmsmvs/zip.makefile
new file mode 100644 (file)
index 0000000..85bef22
--- /dev/null
@@ -0,0 +1,21 @@
+* This is a comment
+* this makefile compiles filter ZIPME
+
+GLOBALS:
+   long def(VM_CMS)
+TEXT:
+   trees c
+   crypt c
+   ttyio c
+   deflate c
+   fileio c
+   globals c
+   zip c
+   util c
+   crc32.c
+   zipfile c
+   zipup c
+   cmsmvs c
+   cms c
+MODULE:
+   zip module
diff --git a/cmsmvs/zipcloak.exec b/cmsmvs/zipcloak.exec
new file mode 100644 (file)
index 0000000..0b9de97
--- /dev/null
@@ -0,0 +1,66 @@
+/***********************************************************************/
+/*                                                                     */
+/* Front-end EXEC to set up linkage to the C runtime libraries         */
+/* before executing a MODULE generated from C code.                    */
+/*                                                                     */
+/* Copy this file as an EXEC with a filename matching the C MODULE.    */
+/*                                                                     */
+/* Greg Hartwig (ghartwig@vnet.ibm.com)   7/31/97, 4/24/98.            */
+/*                                                                     */
+/***********************************************************************/
+Address Command
+Parse Arg argstring
+Parse Source . . myname .
+
+/* Set output and input character translation so brackets show up */
+'SET OUTPUT AD' 'BA'x
+'SET OUTPUT BD' 'BB'x
+'SET INPUT  BA   AD'
+'SET INPUT  BB   BD'
+
+Call CLIB
+If rc<>0 Then Do
+   Say 'The required C runtime libraries don''t appear to be available.'
+   Say myname 'can not run.'
+   Exit 12
+End
+
+/* Run the command */
+myname argstring
+Exit rc
+
+
+
+
+/* Contents of the CLIB EXEC, modified for RC checking.        */
+/* Removed TXTLIB setting.  Only LOADLIB needed for execution. */
+CLIB:
+/***************************************************/
+/*      SET UP LIBRARIES FOR LE for MVS & VM       */
+/***************************************************/
+Address COMMAND
+
+loadlib  ='EDCLINK'               /* C/370 runtime                 */
+loadlib  ='SCEERUN'               /* LE runtime                    */
+
+
+theirs=queued()                           /* old stack contentsM068*/
+ 'QUERY LOADLIB ( LIFO'                   /* old setting       M068*/
+ LoadlibList=''                           /* init list         M068*/
+rc=0
+ Do while queued()^=theirs                /* all lines from cmdM068*/
+   Parse upper pull 'LOADLIB' '=' Ltemp   /* get one line      M068*/
+   LoadlibList= Ltemp Loadliblist         /* was stacked LIFO  M068*/
+ End                                                         /*M068*/
+ If loadlibList='NONE' ,
+ Then Do
+  'GLOBAL LOADLIB' Loadlib          /* enforce what we need         */
+ End
+ Else Do
+  Do xx=1 to Words(loadlib)
+  If Find(loadliblist,word(loadlib,xx)) = 0 ,
+   then loadliblist = loadliblist word(loadlib,xx)
+  End
+  'GLOBAL LOADLIB' loadliblist       /* enforce what we need         */
+ End
+Return
diff --git a/cmsmvs/zipmvsc.job b/cmsmvs/zipmvsc.job
new file mode 100644 (file)
index 0000000..3c786d7
--- /dev/null
@@ -0,0 +1,89 @@
+//CCZIP JOB (BI09255),
+//        MSGLEVEL=(1,1),MSGCLASS=C,CLASS=D,NOTIFY=C888090
+//PROCLIB JCLLIB ORDER=(SYS1.C370.PROCLIB.M24)
+//ZIP EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+//    INFILE='C888090.ZIP.C(ZIP)',
+//    OUTFILE='C888090.ZIP.C.OBJ(ZIP),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//CRYPT EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+//    INFILE='C888090.ZIP.C(CRYPT)',
+//    OUTFILE='C888090.ZIP.C.OBJ(CRYPT),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//TTYIO EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+//    INFILE='C888090.ZIP.C(TTYIO)',
+//    OUTFILE='C888090.ZIP.C.OBJ(TTYIO),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//TREES EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+//    INFILE='C888090.ZIP.C(TREES)',
+//    OUTFILE='C888090.ZIP.C.OBJ(TREES),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//DEFLATE EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+//    INFILE='C888090.ZIP.C(DEFLATE)',
+//    OUTFILE='C888090.ZIP.C.OBJ(DEFLATE),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//FILEIO EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+//    INFILE='C888090.ZIP.C(FILEIO)',
+//    OUTFILE='C888090.ZIP.C.OBJ(FILEIO),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//GLOBALS EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+//    INFILE='C888090.ZIP.C(GLOBALS)',
+//    OUTFILE='C888090.ZIP.C.OBJ(GLOBALS),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//UTIL EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+//    INFILE='C888090.ZIP.C(UTIL)',
+//    OUTFILE='C888090.ZIP.C.OBJ(UTIL),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//CRC32 EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+//    INFILE='C888090.ZIP.C(CRC32)',
+//    OUTFILE='C888090.ZIP.C.OBJ(CRC32),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//ZIPFILE EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+//    INFILE='C888090.ZIP.C(ZIPFILE)',
+//    OUTFILE='C888090.ZIP.C.OBJ(ZIPFILE),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//ZIPUP EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+//    INFILE='C888090.ZIP.C(ZIPUP)',
+//    OUTFILE='C888090.ZIP.C.OBJ(ZIPUP),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//CMSMVS EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+//    INFILE='C888090.ZIP.C(CMSMVS)',
+//    OUTFILE='C888090.ZIP.C.OBJ(CMSMVS),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//MVS EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+//    INFILE='C888090.ZIP.C(MVS)',
+//    OUTFILE='C888090.ZIP.C.OBJ(MVS),DISP=SHR',
+//    CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//PLINK   EXEC  PROC=EDCPL,COND=(12,LE),
+//    OUTFILE='C888090.ZIP.LOAD(ZIP),DISP=SHR',
+//    PPARM='NONCAL,MAP',
+//    LPARM='LIST,MAP,XREF'
+//SYSPRINT DD  SYSOUT=*
+//PLKED.SYSIN   DD  DSN=C888090.ZIP.C.OBJ(ZIP),DISP=SHR
+//              DD  DSN=C888090.ZIP.C.OBJ(BITS),DISP=SHR
+//              DD  DSN=C888090.ZIP.C.OBJ(CRYPT),DISP=SHR
+//              DD  DSN=C888090.ZIP.C.OBJ(TREES),DISP=SHR
+//              DD  DSN=C888090.ZIP.C.OBJ(DEFLATE),DISP=SHR
+//              DD  DSN=C888090.ZIP.C.OBJ(FILEIO),DISP=SHR
+//              DD  DSN=C888090.ZIP.C.OBJ(GLOBALS),DISP=SHR
+//              DD  DSN=C888090.ZIP.C.OBJ(UTIL),DISP=SHR
+//              DD  DSN=C888090.ZIP.C.OBJ(CRC32),DISP=SHR
+//              DD  DSN=C888090.ZIP.C.OBJ(ZIPFILE),DISP=SHR
+//              DD  DSN=C888090.ZIP.C.OBJ(ZIPUP),DISP=SHR
+//              DD  DSN=C888090.ZIP.C.OBJ(CMSMVS),DISP=SHR
+//              DD  DSN=C888090.ZIP.C.OBJ(MVS),DISP=SHR
+//PLKED.SYSLIB  DD  DSN=SYS1.C370.SEDCBASE,DISP=SHR
+//              DD  DSN=SYS1.PL1.SIBMBASE,DISP=SHR
+//SYSUT1   DD  UNIT=SYSDA,SPACE=(CYL,(2,2)),DISP=NEW
diff --git a/cmsmvs/zipname.conven b/cmsmvs/zipname.conven
new file mode 100644 (file)
index 0000000..e17fe9c
--- /dev/null
@@ -0,0 +1,200 @@
+
+         Zip file/directories name convention under MVS
+       ---------------------------------------------------
+                           Draft 1.1
+
+
+1. Translating native file names to Zip filenames.
+
+1.1 Zipping a PDS
+
+On MVS there are directories called PDS (Partition Data Set) which have
+the following format :   name1.name2.name3(mname)
+for example:             myuserid.unzip.c(unzip)
+
+So as you see the path delimiter is '.'. Each dir name can be max 8
+chars long beginning with a number.
+
+Between '(' and ')' there is the so called member name - it is also 8
+chars long. This is the actual file name.
+
+
+1.1.1 Converting MVS PDS name to zip path/filename  (status: not implemented)
+
+The PDS name is converted to zippath as follows:
+in the zip :     name1/name2/mname.name3
+becomes on MVS:  name1.name2.name3(mname)
+
+
+1.2 Unzipping as PDS                                (status: implemented)
+
+When you unzip the file name myuserid/unzip/unzip.c the same process
+is done backwards, so you get : myuserid.unzip.c(unzip)
+
+Notice that the file extension is used as last dirname!
+
+
+1.2 Unzipping to a different PDS                    (status: implemented)
+
+You can also use -d option while unzipping for example:
+unzip mytest myuserid/unzip/unzip.c -dnewdest.test
+
+then the new name will become:
+newdest.test.myuserid.unzip.c(unzip)
+
+              Second example:
+
+unzip mytest myuserid/unzip/*.c -dnewdest.test
+
+then you get a PDS:
+newdest.test.myuserid.unzip.c(...)
+
+with all *.c files in it.
+
+
+1.3 Zipping a Sequential Dataset               (status: not implemented)
+
+  Sequential dataset is a dataset with NO members.
+Such a dataset is translated from native MVS to zip format by replacing
+the '.' (points) with '/' (backslash).
+
+Example:
+on MVS:                  name1.name2.name3
+becomes in the zip :     name1/name2/name3
+
+NOTE : The new filename in the zip has NO extension this way it can be
+       recognised as a Sequential dataset and not a PDS.
+       But this also means that all files in the zip archive that have
+       no extension will be unzipped as Sequential datasets!
+
+
+1.4 Using a DDNAMES for input.                  (status: not implemented)
+
+To use DDNAMES as input file names put a 'dd:' before the ddname:
+example: zip myzip dd:name1 dd:name2 dd:sales
+
+In the Zip archive the ddnames are saved as name.DDNAME so if you try
+the example above you will get in your zip file (when listing it) :
+
+..size .. date time .. crc .. NAME1.DDNAME
+..size .. date time .. crc .. NAME2.DDNAME
+..size .. date time .. crc .. SALES.DDNAME
+
+
+1.4 Using a DDNAMES as zip name                    (status: implemented)
+
+It is allowed to use a DDNAME as zipfile, just put dd: before it
+example: unzip dd:myzip *.c
+   this will unzip all .c files from ddname myzip
+
+example2:   ZIP DD:MYZIP DD:MANE1 MYSOURCE.C MYDOC.TEXT(ZIPPING)
+   this will zip ddname name1 file mysource.c and PDS mydoc.text(zipping)
+   into as a zip file in the ddname myzip
+
+
+2. Converting longer path names (unix like)     (status: not implemented)
+   to native MVS names.
+
+When in the zip archive there are dirnames longer that 8 chars they are
+chopped at the 8 position. For example
+        MyLongZippath/WithLongFileName.text
+is translated to:
+        MYLONGZI.TEXT(WITHLONG)
+
+Notice that all chars are converted to uppercase.
+
+
+2.1 Using special characters                     (status: implemented)
+
+Also all '_' (underscore), '+' (plus), '-' (minus), '(' and ')'
+from the file name/path in the zip archive are skipped because they
+are not valid in the MVS filenames.
+
+
+2.2 Numeric file names                        (status: not implemented)
+
+On MVS no name can begin with a number, so when a dir/file name begins with
+one, a leading letter 'N' is inserted.  For example:
+          Contents.512
+becomes:
+          CONTENTS.N512
+
+
+
+
+        Zip file/directories name convention under VM/CMS
+       ---------------------------------------------------
+
+1. Translating native file names to Zip filenames.
+
+On VM/CMS (not ESA ) there are NO directories so you got only disks
+and files.
+
+The file names are delimited with spaces. But for use with unzip/zip
+you have to use '.' points as delimiters.
+
+For example on your A disk you have file called PROFILE EXEC
+if you want to zip it type : zip myzip profile.exec
+
+If the same file is on your F disk you have to type:
+zip myzip profile.exec.f
+
+So as you can see the general format is fname.ftype.fmode
+
+In the zipfile the disk from which the file comes is not saved!
+So only the fname.ftype is saved.
+
+If you unzip and you want to give a different destination disk just use
+the -d option like:
+
+                     unzip mytest *.c -df
+
+This will unzip all *.c files to your F disk.
+
+
+2. Converting longer path names (unix like) to native VM/CMS names.
+
+When in the zip archive there are dirnames longer that 8 chars they are
+chopped at the 8 position. Also the path is removed. For example
+        Zippath/WithLongFileName.text
+is translated to:
+        WITHLONG.TEXT
+
+Notice that all chars are converted to uppercase.
+
+Also all '+' (plus), '-' (minus), '(' and ')'
+from the file name/path in the zip archive are skipped because they
+are not valid in the VM/CMS filenames.
+
+If there is no extension for the file name in the zip archive, unzip
+will add .NONAME for example:
+        mypath/dir1/testfile
+becomes:
+        TESTFILE.NONAME
+
+3. Future?
+
+There is also discussion for a new option on ZIP that you can give
+a virtual directory to be added before each file name that is zipped.
+
+For example you want to zip a few .c file and put them in the zip
+structure under the directory 'mydir/test', but you can't create dirs on
+VM/CMS so you have to the something like:
+
+ZIP myzip file1.c file2.c -dmydir/test
+
+and you get in the zip archive files:
+
+       mydir/test/file1.c
+       mydir/test/file2.c
+
+-------------------------------------------------------------------------
+
+
+NOTE: Not all of those functions are implemented in the first beta
+      release of VM/MVS UNZIP/ZIP.
+
+Every ideas/corrections/bugs will be appreciated.
+Mail to maillist:  Info-ZIP@LISTS.WKU.EDU
+
+George Petrov
diff --git a/cmsmvs/zipnote.exec b/cmsmvs/zipnote.exec
new file mode 100644 (file)
index 0000000..0b9de97
--- /dev/null
@@ -0,0 +1,66 @@
+/***********************************************************************/
+/*                                                                     */
+/* Front-end EXEC to set up linkage to the C runtime libraries         */
+/* before executing a MODULE generated from C code.                    */
+/*                                                                     */
+/* Copy this file as an EXEC with a filename matching the C MODULE.    */
+/*                                                                     */
+/* Greg Hartwig (ghartwig@vnet.ibm.com)   7/31/97, 4/24/98.            */
+/*                                                                     */
+/***********************************************************************/
+Address Command
+Parse Arg argstring
+Parse Source . . myname .
+
+/* Set output and input character translation so brackets show up */
+'SET OUTPUT AD' 'BA'x
+'SET OUTPUT BD' 'BB'x
+'SET INPUT  BA   AD'
+'SET INPUT  BB   BD'
+
+Call CLIB
+If rc<>0 Then Do
+   Say 'The required C runtime libraries don''t appear to be available.'
+   Say myname 'can not run.'
+   Exit 12
+End
+
+/* Run the command */
+myname argstring
+Exit rc
+
+
+
+
+/* Contents of the CLIB EXEC, modified for RC checking.        */
+/* Removed TXTLIB setting.  Only LOADLIB needed for execution. */
+CLIB:
+/***************************************************/
+/*      SET UP LIBRARIES FOR LE for MVS & VM       */
+/***************************************************/
+Address COMMAND
+
+loadlib  ='EDCLINK'               /* C/370 runtime                 */
+loadlib  ='SCEERUN'               /* LE runtime                    */
+
+
+theirs=queued()                           /* old stack contentsM068*/
+ 'QUERY LOADLIB ( LIFO'                   /* old setting       M068*/
+ LoadlibList=''                           /* init list         M068*/
+rc=0
+ Do while queued()^=theirs                /* all lines from cmdM068*/
+   Parse upper pull 'LOADLIB' '=' Ltemp   /* get one line      M068*/
+   LoadlibList= Ltemp Loadliblist         /* was stacked LIFO  M068*/
+ End                                                         /*M068*/
+ If loadlibList='NONE' ,
+ Then Do
+  'GLOBAL LOADLIB' Loadlib          /* enforce what we need         */
+ End
+ Else Do
+  Do xx=1 to Words(loadlib)
+  If Find(loadliblist,word(loadlib,xx)) = 0 ,
+   then loadliblist = loadliblist word(loadlib,xx)
+  End
+  'GLOBAL LOADLIB' loadliblist       /* enforce what we need         */
+ End
+Return
diff --git a/cmsmvs/zipsplit.exec b/cmsmvs/zipsplit.exec
new file mode 100644 (file)
index 0000000..0b9de97
--- /dev/null
@@ -0,0 +1,66 @@
+/***********************************************************************/
+/*                                                                     */
+/* Front-end EXEC to set up linkage to the C runtime libraries         */
+/* before executing a MODULE generated from C code.                    */
+/*                                                                     */
+/* Copy this file as an EXEC with a filename matching the C MODULE.    */
+/*                                                                     */
+/* Greg Hartwig (ghartwig@vnet.ibm.com)   7/31/97, 4/24/98.            */
+/*                                                                     */
+/***********************************************************************/
+Address Command
+Parse Arg argstring
+Parse Source . . myname .
+
+/* Set output and input character translation so brackets show up */
+'SET OUTPUT AD' 'BA'x
+'SET OUTPUT BD' 'BB'x
+'SET INPUT  BA   AD'
+'SET INPUT  BB   BD'
+
+Call CLIB
+If rc<>0 Then Do
+   Say 'The required C runtime libraries don''t appear to be available.'
+   Say myname 'can not run.'
+   Exit 12
+End
+
+/* Run the command */
+myname argstring
+Exit rc
+
+
+
+
+/* Contents of the CLIB EXEC, modified for RC checking.        */
+/* Removed TXTLIB setting.  Only LOADLIB needed for execution. */
+CLIB:
+/***************************************************/
+/*      SET UP LIBRARIES FOR LE for MVS & VM       */
+/***************************************************/
+Address COMMAND
+
+loadlib  ='EDCLINK'               /* C/370 runtime                 */
+loadlib  ='SCEERUN'               /* LE runtime                    */
+
+
+theirs=queued()                           /* old stack contentsM068*/
+ 'QUERY LOADLIB ( LIFO'                   /* old setting       M068*/
+ LoadlibList=''                           /* init list         M068*/
+rc=0
+ Do while queued()^=theirs                /* all lines from cmdM068*/
+   Parse upper pull 'LOADLIB' '=' Ltemp   /* get one line      M068*/
+   LoadlibList= Ltemp Loadliblist         /* was stacked LIFO  M068*/
+ End                                                         /*M068*/
+ If loadlibList='NONE' ,
+ Then Do
+  'GLOBAL LOADLIB' Loadlib          /* enforce what we need         */
+ End
+ Else Do
+  Do xx=1 to Words(loadlib)
+  If Find(loadliblist,word(loadlib,xx)) = 0 ,
+   then loadliblist = loadliblist word(loadlib,xx)
+  End
+  'GLOBAL LOADLIB' loadliblist       /* enforce what we need         */
+ End
+Return
diff --git a/cmsmvs/zipup.h b/cmsmvs/zipup.h
new file mode 100644 (file)
index 0000000..0ea8962
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define fhow  "r,byteseek"
+#define fhowb "rb,byteseek"
+
+#define fbad NULL
+typedef FILE *ftype;
+#define zopen(n,p)   (ftype)fopen((n),(p))
+#define zread(f,b,n) fread((b),1,(n),(FILE*)(f))
+#define zclose(f)    fclose((FILE*)(f))
+#define zerr(f)      ferror((FILE*)(f))
+#define zstdin       stdin
diff --git a/cmsmvs/zipvmc.exec b/cmsmvs/zipvmc.exec
new file mode 100644 (file)
index 0000000..3fdd800
--- /dev/null
@@ -0,0 +1,48 @@
+/* VMCOMPIL EXEC   Unzip compile for VM/CMS                           */
+/*                 Author : George Petrov, 11 Apr 1995                */
+
+signal on error
+
+parms = '(long def(VM_CMS)'
+
+/* Add local parms */
+parms = parms 'TARGET(COMPAT) SOURCE'
+
+
+say 'Compiling TREES C...'
+'cc trees c 'parms
+say 'Compiling CRYPT C...'
+'cc crypt c 'parms
+say 'Compiling TTYIO C...'
+'cc ttyio c 'parms
+say 'Compiling DEFLATE C...'
+'cc deflate c 'parms
+say 'Compiling FILEIO C...'
+'cc fileio c 'parms
+say 'Compiling GLOBALS C...'
+'cc globals c 'parms
+say 'Compiling ZIP C...'
+'cc zip c 'parms
+say 'Compiling UTIL C...'
+'cc util c 'parms
+say 'Compiling CRC32 C...'
+'cc crc32 c 'parms
+say 'Compiling ZIPFILE C...'
+'cc zipfile c 'parms
+say 'Compiling ZIPUP C...'
+'cc zipup c 'parms
+say 'Compiling CMSMVS C...'
+'cc cmsmvs c 'parms
+say 'Compiling CMS C...'
+'cc cms c 'parms
+
+say 'Linking all files...'
+'cmod zip zip trees crypt deflate fileio globals ttyio',
+           'util crc32 zipfile zipup cmsmvs cms'
+say 'All Done!'
+say "To run enter : ZIP parms"
+exit rc
+
+error:
+say 'Error durring compilation!'
+exit rc
diff --git a/crc32.c b/crc32.c
new file mode 100644 (file)
index 0000000..6b2403b
--- /dev/null
+++ b/crc32.c
@@ -0,0 +1,732 @@
+/*
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors.  This results about a factor
+ * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* $Id: crc32.c,v 2.0 2007/01/07 05:20:36 spc Exp $ */
+
+#define __CRC32_C       /* identifies this source module */
+
+#include "zip.h"
+
+#if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB))
+
+#ifndef ZCONST
+#  define ZCONST const
+#endif
+
+#include "crc32.h"
+
+/* When only the table of precomputed CRC values is needed, only the basic
+   system-independent table containing 256 entries is created; any support
+   for "unfolding" optimization is disabled.
+ */
+#if (defined(USE_ZLIB) || defined(CRC_TABLE_ONLY))
+#  ifdef IZ_CRCOPTIM_UNFOLDTBL
+#    undef IZ_CRCOPTIM_UNFOLDTBL
+#  endif
+#endif /* (USE_ZLIB || CRC_TABLE_ONLY) */
+
+#if defined(IZ_CRCOPTIM_UNFOLDTBL)
+#  define CRC_TBLS  4
+#else
+#  define CRC_TBLS  1
+#endif
+
+
+/*
+  Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient,
+  with the lowest powers in the most significant bit.  Then adding polynomials
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by
+  one.  If we call the above polynomial p, and represent a byte as the
+  polynomial q, also with the lowest power in the most significant bit (so the
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+  where a mod b means the remainder after dividing a by b.
+
+  This calculation is done using the shift-register method of multiplying and
+  taking the remainder.  The register is initialized to zero, and for each
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted
+  out is a one).  We start with the highest power (least significant bit) of
+  q and repeat for all eight bits of q.
+
+  The first (or only) table is simply the CRC of all possible eight bit values.
+  This is all the information needed to generate CRC's on data a byte-at-a-time
+  for all combinations of CRC register values and incoming bytes.
+  The remaining 3 tables (if IZ_CRCOPTIM_UNFOLDTBL is enabled) allow for
+  word-at-a-time CRC calculation, where a word is four bytes.
+*/
+
+#ifdef DYNAMIC_CRC_TABLE
+
+/* =========================================================================
+ * Make the crc table. This function is needed only if you want to compute
+ * the table dynamically.
+ */
+
+local void make_crc_table OF((void));
+
+#if (defined(DYNALLOC_CRCTAB) && defined(REENTRANT))
+   error: Dynamic allocation of CRC table not safe with reentrant code.
+#endif /* DYNALLOC_CRCTAB && REENTRANT */
+
+#ifdef DYNALLOC_CRCTAB
+   local ulg near *crc_table = NULL;
+# if 0          /* not used, since sizeof("near *") <= sizeof(int) */
+   /* Use this section when access to a "local int" is faster than access to
+      a "local pointer" (e.g.: i86 16bit code with far pointers). */
+   local int crc_table_empty = 1;
+#  define CRC_TABLE_IS_EMPTY    (crc_table_empty != 0)
+#  define MARK_CRCTAB_FILLED    crc_table_empty = 0
+#  define MARK_CRCTAB_EMPTY     crc_table_empty = 1
+# else
+   /* Use this section on systems where the size of pointers and ints is
+      equal (e.g.: all 32bit systems). */
+#  define CRC_TABLE_IS_EMPTY    (crc_table == NULL)
+#  define MARK_CRCTAB_FILLED    crc_table = crctab_p
+#  define MARK_CRCTAB_EMPTY     crc_table = NULL
+# endif
+#else /* !DYNALLOC_CRCTAB */
+   local ulg near crc_table[CRC_TBLS*256];
+   local int crc_table_empty = 1;
+#  define CRC_TABLE_IS_EMPTY    (crc_table_empty != 0)
+#  define MARK_CRCTAB_FILLED    crc_table_empty = 0
+#endif /* ?DYNALLOC_CRCTAB */
+
+
+local void make_crc_table()
+{
+  ulg c;                /* crc shift register */
+  int n;                /* counter for all possible eight bit values */
+  int k;                /* byte being shifted into crc apparatus */
+#ifdef DYNALLOC_CRCTAB
+  ulg near *crctab_p;   /* temporary pointer to allocated crc_table area */
+#else /* !DYNALLOC_CRCTAB */
+# define crctab_p crc_table
+#endif /* DYNALLOC_CRCTAB */
+
+#ifdef COMPUTE_XOR_PATTERN
+  /* This piece of code has been left here to explain how the XOR pattern
+   * used in the creation of the crc_table values can be recomputed.
+   * For production versions of this function, it is more efficient to
+   * supply the resultant pattern at compile time.
+   */
+  ulg xor;              /* polynomial exclusive-or pattern */
+  /* terms of polynomial defining this crc (except x^32): */
+  static ZCONST uch p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+  /* make exclusive-or pattern from polynomial (0xedb88320L) */
+  xor = 0L;
+  for (n = 0; n < sizeof(p)/sizeof(uch); n++)
+    xor |= 1L << (31 - p[n]);
+#else
+# define xor 0xedb88320L
+#endif
+
+#ifdef DYNALLOC_CRCTAB
+  crctab_p = (ulg near *) nearmalloc (CRC_TBLS*256*sizeof(ulg));
+  if (crctab_p == NULL) {
+    ziperr(ZE_MEM, "crc_table allocation");
+  }
+#endif /* DYNALLOC_CRCTAB */
+
+  /* generate a crc for every 8-bit value */
+  for (n = 0; n < 256; n++) {
+    c = (ulg)n;
+    for (k = 8; k; k--)
+      c = c & 1 ? xor ^ (c >> 1) : c >> 1;
+    crctab_p[n] = REV_BE(c);
+  }
+
+#ifdef IZ_CRCOPTIM_UNFOLDTBL
+  /* generate crc for each value followed by one, two, and three zeros */
+  for (n = 0; n < 256; n++) {
+      c = crctab_p[n];
+      for (k = 1; k < 4; k++) {
+          c = CRC32(c, 0, crctab_p);
+          crctab_p[k*256+n] = c;
+      }
+  }
+#endif /* IZ_CRCOPTIM_UNFOLDTBL */
+
+  MARK_CRCTAB_FILLED;
+}
+
+#else /* !DYNAMIC_CRC_TABLE */
+
+#ifdef DYNALLOC_CRCTAB
+   error: Inconsistent flags, DYNALLOC_CRCTAB without DYNAMIC_CRC_TABLE.
+#endif
+
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+local ZCONST ulg near crc_table[CRC_TBLS*256] = {
+# ifdef IZ_CRC_BE_OPTIMIZ
+    0x00000000L, 0x96300777L, 0x2c610eeeL, 0xba510999L, 0x19c46d07L,
+    0x8ff46a70L, 0x35a563e9L, 0xa395649eL, 0x3288db0eL, 0xa4b8dc79L,
+    0x1ee9d5e0L, 0x88d9d297L, 0x2b4cb609L, 0xbd7cb17eL, 0x072db8e7L,
+    0x911dbf90L, 0x6410b71dL, 0xf220b06aL, 0x4871b9f3L, 0xde41be84L,
+    0x7dd4da1aL, 0xebe4dd6dL, 0x51b5d4f4L, 0xc785d383L, 0x56986c13L,
+    0xc0a86b64L, 0x7af962fdL, 0xecc9658aL, 0x4f5c0114L, 0xd96c0663L,
+    0x633d0ffaL, 0xf50d088dL, 0xc8206e3bL, 0x5e10694cL, 0xe44160d5L,
+    0x727167a2L, 0xd1e4033cL, 0x47d4044bL, 0xfd850dd2L, 0x6bb50aa5L,
+    0xfaa8b535L, 0x6c98b242L, 0xd6c9bbdbL, 0x40f9bcacL, 0xe36cd832L,
+    0x755cdf45L, 0xcf0dd6dcL, 0x593dd1abL, 0xac30d926L, 0x3a00de51L,
+    0x8051d7c8L, 0x1661d0bfL, 0xb5f4b421L, 0x23c4b356L, 0x9995bacfL,
+    0x0fa5bdb8L, 0x9eb80228L, 0x0888055fL, 0xb2d90cc6L, 0x24e90bb1L,
+    0x877c6f2fL, 0x114c6858L, 0xab1d61c1L, 0x3d2d66b6L, 0x9041dc76L,
+    0x0671db01L, 0xbc20d298L, 0x2a10d5efL, 0x8985b171L, 0x1fb5b606L,
+    0xa5e4bf9fL, 0x33d4b8e8L, 0xa2c90778L, 0x34f9000fL, 0x8ea80996L,
+    0x18980ee1L, 0xbb0d6a7fL, 0x2d3d6d08L, 0x976c6491L, 0x015c63e6L,
+    0xf4516b6bL, 0x62616c1cL, 0xd8306585L, 0x4e0062f2L, 0xed95066cL,
+    0x7ba5011bL, 0xc1f40882L, 0x57c40ff5L, 0xc6d9b065L, 0x50e9b712L,
+    0xeab8be8bL, 0x7c88b9fcL, 0xdf1ddd62L, 0x492dda15L, 0xf37cd38cL,
+    0x654cd4fbL, 0x5861b24dL, 0xce51b53aL, 0x7400bca3L, 0xe230bbd4L,
+    0x41a5df4aL, 0xd795d83dL, 0x6dc4d1a4L, 0xfbf4d6d3L, 0x6ae96943L,
+    0xfcd96e34L, 0x468867adL, 0xd0b860daL, 0x732d0444L, 0xe51d0333L,
+    0x5f4c0aaaL, 0xc97c0dddL, 0x3c710550L, 0xaa410227L, 0x10100bbeL,
+    0x86200cc9L, 0x25b56857L, 0xb3856f20L, 0x09d466b9L, 0x9fe461ceL,
+    0x0ef9de5eL, 0x98c9d929L, 0x2298d0b0L, 0xb4a8d7c7L, 0x173db359L,
+    0x810db42eL, 0x3b5cbdb7L, 0xad6cbac0L, 0x2083b8edL, 0xb6b3bf9aL,
+    0x0ce2b603L, 0x9ad2b174L, 0x3947d5eaL, 0xaf77d29dL, 0x1526db04L,
+    0x8316dc73L, 0x120b63e3L, 0x843b6494L, 0x3e6a6d0dL, 0xa85a6a7aL,
+    0x0bcf0ee4L, 0x9dff0993L, 0x27ae000aL, 0xb19e077dL, 0x44930ff0L,
+    0xd2a30887L, 0x68f2011eL, 0xfec20669L, 0x5d5762f7L, 0xcb676580L,
+    0x71366c19L, 0xe7066b6eL, 0x761bd4feL, 0xe02bd389L, 0x5a7ada10L,
+    0xcc4add67L, 0x6fdfb9f9L, 0xf9efbe8eL, 0x43beb717L, 0xd58eb060L,
+    0xe8a3d6d6L, 0x7e93d1a1L, 0xc4c2d838L, 0x52f2df4fL, 0xf167bbd1L,
+    0x6757bca6L, 0xdd06b53fL, 0x4b36b248L, 0xda2b0dd8L, 0x4c1b0aafL,
+    0xf64a0336L, 0x607a0441L, 0xc3ef60dfL, 0x55df67a8L, 0xef8e6e31L,
+    0x79be6946L, 0x8cb361cbL, 0x1a8366bcL, 0xa0d26f25L, 0x36e26852L,
+    0x95770cccL, 0x03470bbbL, 0xb9160222L, 0x2f260555L, 0xbe3bbac5L,
+    0x280bbdb2L, 0x925ab42bL, 0x046ab35cL, 0xa7ffd7c2L, 0x31cfd0b5L,
+    0x8b9ed92cL, 0x1daede5bL, 0xb0c2649bL, 0x26f263ecL, 0x9ca36a75L,
+    0x0a936d02L, 0xa906099cL, 0x3f360eebL, 0x85670772L, 0x13570005L,
+    0x824abf95L, 0x147ab8e2L, 0xae2bb17bL, 0x381bb60cL, 0x9b8ed292L,
+    0x0dbed5e5L, 0xb7efdc7cL, 0x21dfdb0bL, 0xd4d2d386L, 0x42e2d4f1L,
+    0xf8b3dd68L, 0x6e83da1fL, 0xcd16be81L, 0x5b26b9f6L, 0xe177b06fL,
+    0x7747b718L, 0xe65a0888L, 0x706a0fffL, 0xca3b0666L, 0x5c0b0111L,
+    0xff9e658fL, 0x69ae62f8L, 0xd3ff6b61L, 0x45cf6c16L, 0x78e20aa0L,
+    0xeed20dd7L, 0x5483044eL, 0xc2b30339L, 0x612667a7L, 0xf71660d0L,
+    0x4d476949L, 0xdb776e3eL, 0x4a6ad1aeL, 0xdc5ad6d9L, 0x660bdf40L,
+    0xf03bd837L, 0x53aebca9L, 0xc59ebbdeL, 0x7fcfb247L, 0xe9ffb530L,
+    0x1cf2bdbdL, 0x8ac2bacaL, 0x3093b353L, 0xa6a3b424L, 0x0536d0baL,
+    0x9306d7cdL, 0x2957de54L, 0xbf67d923L, 0x2e7a66b3L, 0xb84a61c4L,
+    0x021b685dL, 0x942b6f2aL, 0x37be0bb4L, 0xa18e0cc3L, 0x1bdf055aL,
+    0x8def022dL
+#  ifdef IZ_CRCOPTIM_UNFOLDTBL
+    ,
+    0x00000000L, 0x41311b19L, 0x82623632L, 0xc3532d2bL, 0x04c56c64L,
+    0x45f4777dL, 0x86a75a56L, 0xc796414fL, 0x088ad9c8L, 0x49bbc2d1L,
+    0x8ae8effaL, 0xcbd9f4e3L, 0x0c4fb5acL, 0x4d7eaeb5L, 0x8e2d839eL,
+    0xcf1c9887L, 0x5112c24aL, 0x1023d953L, 0xd370f478L, 0x9241ef61L,
+    0x55d7ae2eL, 0x14e6b537L, 0xd7b5981cL, 0x96848305L, 0x59981b82L,
+    0x18a9009bL, 0xdbfa2db0L, 0x9acb36a9L, 0x5d5d77e6L, 0x1c6c6cffL,
+    0xdf3f41d4L, 0x9e0e5acdL, 0xa2248495L, 0xe3159f8cL, 0x2046b2a7L,
+    0x6177a9beL, 0xa6e1e8f1L, 0xe7d0f3e8L, 0x2483dec3L, 0x65b2c5daL,
+    0xaaae5d5dL, 0xeb9f4644L, 0x28cc6b6fL, 0x69fd7076L, 0xae6b3139L,
+    0xef5a2a20L, 0x2c09070bL, 0x6d381c12L, 0xf33646dfL, 0xb2075dc6L,
+    0x715470edL, 0x30656bf4L, 0xf7f32abbL, 0xb6c231a2L, 0x75911c89L,
+    0x34a00790L, 0xfbbc9f17L, 0xba8d840eL, 0x79dea925L, 0x38efb23cL,
+    0xff79f373L, 0xbe48e86aL, 0x7d1bc541L, 0x3c2ade58L, 0x054f79f0L,
+    0x447e62e9L, 0x872d4fc2L, 0xc61c54dbL, 0x018a1594L, 0x40bb0e8dL,
+    0x83e823a6L, 0xc2d938bfL, 0x0dc5a038L, 0x4cf4bb21L, 0x8fa7960aL,
+    0xce968d13L, 0x0900cc5cL, 0x4831d745L, 0x8b62fa6eL, 0xca53e177L,
+    0x545dbbbaL, 0x156ca0a3L, 0xd63f8d88L, 0x970e9691L, 0x5098d7deL,
+    0x11a9ccc7L, 0xd2fae1ecL, 0x93cbfaf5L, 0x5cd76272L, 0x1de6796bL,
+    0xdeb55440L, 0x9f844f59L, 0x58120e16L, 0x1923150fL, 0xda703824L,
+    0x9b41233dL, 0xa76bfd65L, 0xe65ae67cL, 0x2509cb57L, 0x6438d04eL,
+    0xa3ae9101L, 0xe29f8a18L, 0x21cca733L, 0x60fdbc2aL, 0xafe124adL,
+    0xeed03fb4L, 0x2d83129fL, 0x6cb20986L, 0xab2448c9L, 0xea1553d0L,
+    0x29467efbL, 0x687765e2L, 0xf6793f2fL, 0xb7482436L, 0x741b091dL,
+    0x352a1204L, 0xf2bc534bL, 0xb38d4852L, 0x70de6579L, 0x31ef7e60L,
+    0xfef3e6e7L, 0xbfc2fdfeL, 0x7c91d0d5L, 0x3da0cbccL, 0xfa368a83L,
+    0xbb07919aL, 0x7854bcb1L, 0x3965a7a8L, 0x4b98833bL, 0x0aa99822L,
+    0xc9fab509L, 0x88cbae10L, 0x4f5def5fL, 0x0e6cf446L, 0xcd3fd96dL,
+    0x8c0ec274L, 0x43125af3L, 0x022341eaL, 0xc1706cc1L, 0x804177d8L,
+    0x47d73697L, 0x06e62d8eL, 0xc5b500a5L, 0x84841bbcL, 0x1a8a4171L,
+    0x5bbb5a68L, 0x98e87743L, 0xd9d96c5aL, 0x1e4f2d15L, 0x5f7e360cL,
+    0x9c2d1b27L, 0xdd1c003eL, 0x120098b9L, 0x533183a0L, 0x9062ae8bL,
+    0xd153b592L, 0x16c5f4ddL, 0x57f4efc4L, 0x94a7c2efL, 0xd596d9f6L,
+    0xe9bc07aeL, 0xa88d1cb7L, 0x6bde319cL, 0x2aef2a85L, 0xed796bcaL,
+    0xac4870d3L, 0x6f1b5df8L, 0x2e2a46e1L, 0xe136de66L, 0xa007c57fL,
+    0x6354e854L, 0x2265f34dL, 0xe5f3b202L, 0xa4c2a91bL, 0x67918430L,
+    0x26a09f29L, 0xb8aec5e4L, 0xf99fdefdL, 0x3accf3d6L, 0x7bfde8cfL,
+    0xbc6ba980L, 0xfd5ab299L, 0x3e099fb2L, 0x7f3884abL, 0xb0241c2cL,
+    0xf1150735L, 0x32462a1eL, 0x73773107L, 0xb4e17048L, 0xf5d06b51L,
+    0x3683467aL, 0x77b25d63L, 0x4ed7facbL, 0x0fe6e1d2L, 0xccb5ccf9L,
+    0x8d84d7e0L, 0x4a1296afL, 0x0b238db6L, 0xc870a09dL, 0x8941bb84L,
+    0x465d2303L, 0x076c381aL, 0xc43f1531L, 0x850e0e28L, 0x42984f67L,
+    0x03a9547eL, 0xc0fa7955L, 0x81cb624cL, 0x1fc53881L, 0x5ef42398L,
+    0x9da70eb3L, 0xdc9615aaL, 0x1b0054e5L, 0x5a314ffcL, 0x996262d7L,
+    0xd85379ceL, 0x174fe149L, 0x567efa50L, 0x952dd77bL, 0xd41ccc62L,
+    0x138a8d2dL, 0x52bb9634L, 0x91e8bb1fL, 0xd0d9a006L, 0xecf37e5eL,
+    0xadc26547L, 0x6e91486cL, 0x2fa05375L, 0xe836123aL, 0xa9070923L,
+    0x6a542408L, 0x2b653f11L, 0xe479a796L, 0xa548bc8fL, 0x661b91a4L,
+    0x272a8abdL, 0xe0bccbf2L, 0xa18dd0ebL, 0x62defdc0L, 0x23efe6d9L,
+    0xbde1bc14L, 0xfcd0a70dL, 0x3f838a26L, 0x7eb2913fL, 0xb924d070L,
+    0xf815cb69L, 0x3b46e642L, 0x7a77fd5bL, 0xb56b65dcL, 0xf45a7ec5L,
+    0x370953eeL, 0x763848f7L, 0xb1ae09b8L, 0xf09f12a1L, 0x33cc3f8aL,
+    0x72fd2493L
+    ,
+    0x00000000L, 0x376ac201L, 0x6ed48403L, 0x59be4602L, 0xdca80907L,
+    0xebc2cb06L, 0xb27c8d04L, 0x85164f05L, 0xb851130eL, 0x8f3bd10fL,
+    0xd685970dL, 0xe1ef550cL, 0x64f91a09L, 0x5393d808L, 0x0a2d9e0aL,
+    0x3d475c0bL, 0x70a3261cL, 0x47c9e41dL, 0x1e77a21fL, 0x291d601eL,
+    0xac0b2f1bL, 0x9b61ed1aL, 0xc2dfab18L, 0xf5b56919L, 0xc8f23512L,
+    0xff98f713L, 0xa626b111L, 0x914c7310L, 0x145a3c15L, 0x2330fe14L,
+    0x7a8eb816L, 0x4de47a17L, 0xe0464d38L, 0xd72c8f39L, 0x8e92c93bL,
+    0xb9f80b3aL, 0x3cee443fL, 0x0b84863eL, 0x523ac03cL, 0x6550023dL,
+    0x58175e36L, 0x6f7d9c37L, 0x36c3da35L, 0x01a91834L, 0x84bf5731L,
+    0xb3d59530L, 0xea6bd332L, 0xdd011133L, 0x90e56b24L, 0xa78fa925L,
+    0xfe31ef27L, 0xc95b2d26L, 0x4c4d6223L, 0x7b27a022L, 0x2299e620L,
+    0x15f32421L, 0x28b4782aL, 0x1fdeba2bL, 0x4660fc29L, 0x710a3e28L,
+    0xf41c712dL, 0xc376b32cL, 0x9ac8f52eL, 0xada2372fL, 0xc08d9a70L,
+    0xf7e75871L, 0xae591e73L, 0x9933dc72L, 0x1c259377L, 0x2b4f5176L,
+    0x72f11774L, 0x459bd575L, 0x78dc897eL, 0x4fb64b7fL, 0x16080d7dL,
+    0x2162cf7cL, 0xa4748079L, 0x931e4278L, 0xcaa0047aL, 0xfdcac67bL,
+    0xb02ebc6cL, 0x87447e6dL, 0xdefa386fL, 0xe990fa6eL, 0x6c86b56bL,
+    0x5bec776aL, 0x02523168L, 0x3538f369L, 0x087faf62L, 0x3f156d63L,
+    0x66ab2b61L, 0x51c1e960L, 0xd4d7a665L, 0xe3bd6464L, 0xba032266L,
+    0x8d69e067L, 0x20cbd748L, 0x17a11549L, 0x4e1f534bL, 0x7975914aL,
+    0xfc63de4fL, 0xcb091c4eL, 0x92b75a4cL, 0xa5dd984dL, 0x989ac446L,
+    0xaff00647L, 0xf64e4045L, 0xc1248244L, 0x4432cd41L, 0x73580f40L,
+    0x2ae64942L, 0x1d8c8b43L, 0x5068f154L, 0x67023355L, 0x3ebc7557L,
+    0x09d6b756L, 0x8cc0f853L, 0xbbaa3a52L, 0xe2147c50L, 0xd57ebe51L,
+    0xe839e25aL, 0xdf53205bL, 0x86ed6659L, 0xb187a458L, 0x3491eb5dL,
+    0x03fb295cL, 0x5a456f5eL, 0x6d2fad5fL, 0x801b35e1L, 0xb771f7e0L,
+    0xeecfb1e2L, 0xd9a573e3L, 0x5cb33ce6L, 0x6bd9fee7L, 0x3267b8e5L,
+    0x050d7ae4L, 0x384a26efL, 0x0f20e4eeL, 0x569ea2ecL, 0x61f460edL,
+    0xe4e22fe8L, 0xd388ede9L, 0x8a36abebL, 0xbd5c69eaL, 0xf0b813fdL,
+    0xc7d2d1fcL, 0x9e6c97feL, 0xa90655ffL, 0x2c101afaL, 0x1b7ad8fbL,
+    0x42c49ef9L, 0x75ae5cf8L, 0x48e900f3L, 0x7f83c2f2L, 0x263d84f0L,
+    0x115746f1L, 0x944109f4L, 0xa32bcbf5L, 0xfa958df7L, 0xcdff4ff6L,
+    0x605d78d9L, 0x5737bad8L, 0x0e89fcdaL, 0x39e33edbL, 0xbcf571deL,
+    0x8b9fb3dfL, 0xd221f5ddL, 0xe54b37dcL, 0xd80c6bd7L, 0xef66a9d6L,
+    0xb6d8efd4L, 0x81b22dd5L, 0x04a462d0L, 0x33cea0d1L, 0x6a70e6d3L,
+    0x5d1a24d2L, 0x10fe5ec5L, 0x27949cc4L, 0x7e2adac6L, 0x494018c7L,
+    0xcc5657c2L, 0xfb3c95c3L, 0xa282d3c1L, 0x95e811c0L, 0xa8af4dcbL,
+    0x9fc58fcaL, 0xc67bc9c8L, 0xf1110bc9L, 0x740744ccL, 0x436d86cdL,
+    0x1ad3c0cfL, 0x2db902ceL, 0x4096af91L, 0x77fc6d90L, 0x2e422b92L,
+    0x1928e993L, 0x9c3ea696L, 0xab546497L, 0xf2ea2295L, 0xc580e094L,
+    0xf8c7bc9fL, 0xcfad7e9eL, 0x9613389cL, 0xa179fa9dL, 0x246fb598L,
+    0x13057799L, 0x4abb319bL, 0x7dd1f39aL, 0x3035898dL, 0x075f4b8cL,
+    0x5ee10d8eL, 0x698bcf8fL, 0xec9d808aL, 0xdbf7428bL, 0x82490489L,
+    0xb523c688L, 0x88649a83L, 0xbf0e5882L, 0xe6b01e80L, 0xd1dadc81L,
+    0x54cc9384L, 0x63a65185L, 0x3a181787L, 0x0d72d586L, 0xa0d0e2a9L,
+    0x97ba20a8L, 0xce0466aaL, 0xf96ea4abL, 0x7c78ebaeL, 0x4b1229afL,
+    0x12ac6fadL, 0x25c6adacL, 0x1881f1a7L, 0x2feb33a6L, 0x765575a4L,
+    0x413fb7a5L, 0xc429f8a0L, 0xf3433aa1L, 0xaafd7ca3L, 0x9d97bea2L,
+    0xd073c4b5L, 0xe71906b4L, 0xbea740b6L, 0x89cd82b7L, 0x0cdbcdb2L,
+    0x3bb10fb3L, 0x620f49b1L, 0x55658bb0L, 0x6822d7bbL, 0x5f4815baL,
+    0x06f653b8L, 0x319c91b9L, 0xb48adebcL, 0x83e01cbdL, 0xda5e5abfL,
+    0xed3498beL
+    ,
+    0x00000000L, 0x6567bcb8L, 0x8bc809aaL, 0xeeafb512L, 0x5797628fL,
+    0x32f0de37L, 0xdc5f6b25L, 0xb938d79dL, 0xef28b4c5L, 0x8a4f087dL,
+    0x64e0bd6fL, 0x018701d7L, 0xb8bfd64aL, 0xddd86af2L, 0x3377dfe0L,
+    0x56106358L, 0x9f571950L, 0xfa30a5e8L, 0x149f10faL, 0x71f8ac42L,
+    0xc8c07bdfL, 0xada7c767L, 0x43087275L, 0x266fcecdL, 0x707fad95L,
+    0x1518112dL, 0xfbb7a43fL, 0x9ed01887L, 0x27e8cf1aL, 0x428f73a2L,
+    0xac20c6b0L, 0xc9477a08L, 0x3eaf32a0L, 0x5bc88e18L, 0xb5673b0aL,
+    0xd00087b2L, 0x6938502fL, 0x0c5fec97L, 0xe2f05985L, 0x8797e53dL,
+    0xd1878665L, 0xb4e03addL, 0x5a4f8fcfL, 0x3f283377L, 0x8610e4eaL,
+    0xe3775852L, 0x0dd8ed40L, 0x68bf51f8L, 0xa1f82bf0L, 0xc49f9748L,
+    0x2a30225aL, 0x4f579ee2L, 0xf66f497fL, 0x9308f5c7L, 0x7da740d5L,
+    0x18c0fc6dL, 0x4ed09f35L, 0x2bb7238dL, 0xc518969fL, 0xa07f2a27L,
+    0x1947fdbaL, 0x7c204102L, 0x928ff410L, 0xf7e848a8L, 0x3d58149bL,
+    0x583fa823L, 0xb6901d31L, 0xd3f7a189L, 0x6acf7614L, 0x0fa8caacL,
+    0xe1077fbeL, 0x8460c306L, 0xd270a05eL, 0xb7171ce6L, 0x59b8a9f4L,
+    0x3cdf154cL, 0x85e7c2d1L, 0xe0807e69L, 0x0e2fcb7bL, 0x6b4877c3L,
+    0xa20f0dcbL, 0xc768b173L, 0x29c70461L, 0x4ca0b8d9L, 0xf5986f44L,
+    0x90ffd3fcL, 0x7e5066eeL, 0x1b37da56L, 0x4d27b90eL, 0x284005b6L,
+    0xc6efb0a4L, 0xa3880c1cL, 0x1ab0db81L, 0x7fd76739L, 0x9178d22bL,
+    0xf41f6e93L, 0x03f7263bL, 0x66909a83L, 0x883f2f91L, 0xed589329L,
+    0x546044b4L, 0x3107f80cL, 0xdfa84d1eL, 0xbacff1a6L, 0xecdf92feL,
+    0x89b82e46L, 0x67179b54L, 0x027027ecL, 0xbb48f071L, 0xde2f4cc9L,
+    0x3080f9dbL, 0x55e74563L, 0x9ca03f6bL, 0xf9c783d3L, 0x176836c1L,
+    0x720f8a79L, 0xcb375de4L, 0xae50e15cL, 0x40ff544eL, 0x2598e8f6L,
+    0x73888baeL, 0x16ef3716L, 0xf8408204L, 0x9d273ebcL, 0x241fe921L,
+    0x41785599L, 0xafd7e08bL, 0xcab05c33L, 0x3bb659edL, 0x5ed1e555L,
+    0xb07e5047L, 0xd519ecffL, 0x6c213b62L, 0x094687daL, 0xe7e932c8L,
+    0x828e8e70L, 0xd49eed28L, 0xb1f95190L, 0x5f56e482L, 0x3a31583aL,
+    0x83098fa7L, 0xe66e331fL, 0x08c1860dL, 0x6da63ab5L, 0xa4e140bdL,
+    0xc186fc05L, 0x2f294917L, 0x4a4ef5afL, 0xf3762232L, 0x96119e8aL,
+    0x78be2b98L, 0x1dd99720L, 0x4bc9f478L, 0x2eae48c0L, 0xc001fdd2L,
+    0xa566416aL, 0x1c5e96f7L, 0x79392a4fL, 0x97969f5dL, 0xf2f123e5L,
+    0x05196b4dL, 0x607ed7f5L, 0x8ed162e7L, 0xebb6de5fL, 0x528e09c2L,
+    0x37e9b57aL, 0xd9460068L, 0xbc21bcd0L, 0xea31df88L, 0x8f566330L,
+    0x61f9d622L, 0x049e6a9aL, 0xbda6bd07L, 0xd8c101bfL, 0x366eb4adL,
+    0x53090815L, 0x9a4e721dL, 0xff29cea5L, 0x11867bb7L, 0x74e1c70fL,
+    0xcdd91092L, 0xa8beac2aL, 0x46111938L, 0x2376a580L, 0x7566c6d8L,
+    0x10017a60L, 0xfeaecf72L, 0x9bc973caL, 0x22f1a457L, 0x479618efL,
+    0xa939adfdL, 0xcc5e1145L, 0x06ee4d76L, 0x6389f1ceL, 0x8d2644dcL,
+    0xe841f864L, 0x51792ff9L, 0x341e9341L, 0xdab12653L, 0xbfd69aebL,
+    0xe9c6f9b3L, 0x8ca1450bL, 0x620ef019L, 0x07694ca1L, 0xbe519b3cL,
+    0xdb362784L, 0x35999296L, 0x50fe2e2eL, 0x99b95426L, 0xfcdee89eL,
+    0x12715d8cL, 0x7716e134L, 0xce2e36a9L, 0xab498a11L, 0x45e63f03L,
+    0x208183bbL, 0x7691e0e3L, 0x13f65c5bL, 0xfd59e949L, 0x983e55f1L,
+    0x2106826cL, 0x44613ed4L, 0xaace8bc6L, 0xcfa9377eL, 0x38417fd6L,
+    0x5d26c36eL, 0xb389767cL, 0xd6eecac4L, 0x6fd61d59L, 0x0ab1a1e1L,
+    0xe41e14f3L, 0x8179a84bL, 0xd769cb13L, 0xb20e77abL, 0x5ca1c2b9L,
+    0x39c67e01L, 0x80fea99cL, 0xe5991524L, 0x0b36a036L, 0x6e511c8eL,
+    0xa7166686L, 0xc271da3eL, 0x2cde6f2cL, 0x49b9d394L, 0xf0810409L,
+    0x95e6b8b1L, 0x7b490da3L, 0x1e2eb11bL, 0x483ed243L, 0x2d596efbL,
+    0xc3f6dbe9L, 0xa6916751L, 0x1fa9b0ccL, 0x7ace0c74L, 0x9461b966L,
+    0xf10605deL
+#  endif /* IZ_CRCOPTIM_UNFOLDTBL */
+# else /* !IZ_CRC_BE_OPTIMIZ */
+    0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+    0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+    0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+    0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+    0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+    0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+    0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+    0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+    0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+    0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+    0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+    0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+    0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+    0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+    0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+    0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+    0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+    0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+    0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+    0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+    0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+    0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+    0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+    0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+    0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+    0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+    0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+    0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+    0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+    0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+    0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+    0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+    0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+    0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+    0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+    0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+    0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+    0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+    0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+    0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+    0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+    0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+    0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+    0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+    0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+    0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+    0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+    0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+    0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+    0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+    0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+    0x2d02ef8dL
+#  ifdef IZ_CRCOPTIM_UNFOLDTBL
+    ,
+    0x00000000L, 0x191b3141L, 0x32366282L, 0x2b2d53c3L, 0x646cc504L,
+    0x7d77f445L, 0x565aa786L, 0x4f4196c7L, 0xc8d98a08L, 0xd1c2bb49L,
+    0xfaefe88aL, 0xe3f4d9cbL, 0xacb54f0cL, 0xb5ae7e4dL, 0x9e832d8eL,
+    0x87981ccfL, 0x4ac21251L, 0x53d92310L, 0x78f470d3L, 0x61ef4192L,
+    0x2eaed755L, 0x37b5e614L, 0x1c98b5d7L, 0x05838496L, 0x821b9859L,
+    0x9b00a918L, 0xb02dfadbL, 0xa936cb9aL, 0xe6775d5dL, 0xff6c6c1cL,
+    0xd4413fdfL, 0xcd5a0e9eL, 0x958424a2L, 0x8c9f15e3L, 0xa7b24620L,
+    0xbea97761L, 0xf1e8e1a6L, 0xe8f3d0e7L, 0xc3de8324L, 0xdac5b265L,
+    0x5d5daeaaL, 0x44469febL, 0x6f6bcc28L, 0x7670fd69L, 0x39316baeL,
+    0x202a5aefL, 0x0b07092cL, 0x121c386dL, 0xdf4636f3L, 0xc65d07b2L,
+    0xed705471L, 0xf46b6530L, 0xbb2af3f7L, 0xa231c2b6L, 0x891c9175L,
+    0x9007a034L, 0x179fbcfbL, 0x0e848dbaL, 0x25a9de79L, 0x3cb2ef38L,
+    0x73f379ffL, 0x6ae848beL, 0x41c51b7dL, 0x58de2a3cL, 0xf0794f05L,
+    0xe9627e44L, 0xc24f2d87L, 0xdb541cc6L, 0x94158a01L, 0x8d0ebb40L,
+    0xa623e883L, 0xbf38d9c2L, 0x38a0c50dL, 0x21bbf44cL, 0x0a96a78fL,
+    0x138d96ceL, 0x5ccc0009L, 0x45d73148L, 0x6efa628bL, 0x77e153caL,
+    0xbabb5d54L, 0xa3a06c15L, 0x888d3fd6L, 0x91960e97L, 0xded79850L,
+    0xc7cca911L, 0xece1fad2L, 0xf5facb93L, 0x7262d75cL, 0x6b79e61dL,
+    0x4054b5deL, 0x594f849fL, 0x160e1258L, 0x0f152319L, 0x243870daL,
+    0x3d23419bL, 0x65fd6ba7L, 0x7ce65ae6L, 0x57cb0925L, 0x4ed03864L,
+    0x0191aea3L, 0x188a9fe2L, 0x33a7cc21L, 0x2abcfd60L, 0xad24e1afL,
+    0xb43fd0eeL, 0x9f12832dL, 0x8609b26cL, 0xc94824abL, 0xd05315eaL,
+    0xfb7e4629L, 0xe2657768L, 0x2f3f79f6L, 0x362448b7L, 0x1d091b74L,
+    0x04122a35L, 0x4b53bcf2L, 0x52488db3L, 0x7965de70L, 0x607eef31L,
+    0xe7e6f3feL, 0xfefdc2bfL, 0xd5d0917cL, 0xcccba03dL, 0x838a36faL,
+    0x9a9107bbL, 0xb1bc5478L, 0xa8a76539L, 0x3b83984bL, 0x2298a90aL,
+    0x09b5fac9L, 0x10aecb88L, 0x5fef5d4fL, 0x46f46c0eL, 0x6dd93fcdL,
+    0x74c20e8cL, 0xf35a1243L, 0xea412302L, 0xc16c70c1L, 0xd8774180L,
+    0x9736d747L, 0x8e2de606L, 0xa500b5c5L, 0xbc1b8484L, 0x71418a1aL,
+    0x685abb5bL, 0x4377e898L, 0x5a6cd9d9L, 0x152d4f1eL, 0x0c367e5fL,
+    0x271b2d9cL, 0x3e001cddL, 0xb9980012L, 0xa0833153L, 0x8bae6290L,
+    0x92b553d1L, 0xddf4c516L, 0xc4eff457L, 0xefc2a794L, 0xf6d996d5L,
+    0xae07bce9L, 0xb71c8da8L, 0x9c31de6bL, 0x852aef2aL, 0xca6b79edL,
+    0xd37048acL, 0xf85d1b6fL, 0xe1462a2eL, 0x66de36e1L, 0x7fc507a0L,
+    0x54e85463L, 0x4df36522L, 0x02b2f3e5L, 0x1ba9c2a4L, 0x30849167L,
+    0x299fa026L, 0xe4c5aeb8L, 0xfdde9ff9L, 0xd6f3cc3aL, 0xcfe8fd7bL,
+    0x80a96bbcL, 0x99b25afdL, 0xb29f093eL, 0xab84387fL, 0x2c1c24b0L,
+    0x350715f1L, 0x1e2a4632L, 0x07317773L, 0x4870e1b4L, 0x516bd0f5L,
+    0x7a468336L, 0x635db277L, 0xcbfad74eL, 0xd2e1e60fL, 0xf9ccb5ccL,
+    0xe0d7848dL, 0xaf96124aL, 0xb68d230bL, 0x9da070c8L, 0x84bb4189L,
+    0x03235d46L, 0x1a386c07L, 0x31153fc4L, 0x280e0e85L, 0x674f9842L,
+    0x7e54a903L, 0x5579fac0L, 0x4c62cb81L, 0x8138c51fL, 0x9823f45eL,
+    0xb30ea79dL, 0xaa1596dcL, 0xe554001bL, 0xfc4f315aL, 0xd7626299L,
+    0xce7953d8L, 0x49e14f17L, 0x50fa7e56L, 0x7bd72d95L, 0x62cc1cd4L,
+    0x2d8d8a13L, 0x3496bb52L, 0x1fbbe891L, 0x06a0d9d0L, 0x5e7ef3ecL,
+    0x4765c2adL, 0x6c48916eL, 0x7553a02fL, 0x3a1236e8L, 0x230907a9L,
+    0x0824546aL, 0x113f652bL, 0x96a779e4L, 0x8fbc48a5L, 0xa4911b66L,
+    0xbd8a2a27L, 0xf2cbbce0L, 0xebd08da1L, 0xc0fdde62L, 0xd9e6ef23L,
+    0x14bce1bdL, 0x0da7d0fcL, 0x268a833fL, 0x3f91b27eL, 0x70d024b9L,
+    0x69cb15f8L, 0x42e6463bL, 0x5bfd777aL, 0xdc656bb5L, 0xc57e5af4L,
+    0xee530937L, 0xf7483876L, 0xb809aeb1L, 0xa1129ff0L, 0x8a3fcc33L,
+    0x9324fd72L
+    ,
+    0x00000000L, 0x01c26a37L, 0x0384d46eL, 0x0246be59L, 0x0709a8dcL,
+    0x06cbc2ebL, 0x048d7cb2L, 0x054f1685L, 0x0e1351b8L, 0x0fd13b8fL,
+    0x0d9785d6L, 0x0c55efe1L, 0x091af964L, 0x08d89353L, 0x0a9e2d0aL,
+    0x0b5c473dL, 0x1c26a370L, 0x1de4c947L, 0x1fa2771eL, 0x1e601d29L,
+    0x1b2f0bacL, 0x1aed619bL, 0x18abdfc2L, 0x1969b5f5L, 0x1235f2c8L,
+    0x13f798ffL, 0x11b126a6L, 0x10734c91L, 0x153c5a14L, 0x14fe3023L,
+    0x16b88e7aL, 0x177ae44dL, 0x384d46e0L, 0x398f2cd7L, 0x3bc9928eL,
+    0x3a0bf8b9L, 0x3f44ee3cL, 0x3e86840bL, 0x3cc03a52L, 0x3d025065L,
+    0x365e1758L, 0x379c7d6fL, 0x35dac336L, 0x3418a901L, 0x3157bf84L,
+    0x3095d5b3L, 0x32d36beaL, 0x331101ddL, 0x246be590L, 0x25a98fa7L,
+    0x27ef31feL, 0x262d5bc9L, 0x23624d4cL, 0x22a0277bL, 0x20e69922L,
+    0x2124f315L, 0x2a78b428L, 0x2bbade1fL, 0x29fc6046L, 0x283e0a71L,
+    0x2d711cf4L, 0x2cb376c3L, 0x2ef5c89aL, 0x2f37a2adL, 0x709a8dc0L,
+    0x7158e7f7L, 0x731e59aeL, 0x72dc3399L, 0x7793251cL, 0x76514f2bL,
+    0x7417f172L, 0x75d59b45L, 0x7e89dc78L, 0x7f4bb64fL, 0x7d0d0816L,
+    0x7ccf6221L, 0x798074a4L, 0x78421e93L, 0x7a04a0caL, 0x7bc6cafdL,
+    0x6cbc2eb0L, 0x6d7e4487L, 0x6f38fadeL, 0x6efa90e9L, 0x6bb5866cL,
+    0x6a77ec5bL, 0x68315202L, 0x69f33835L, 0x62af7f08L, 0x636d153fL,
+    0x612bab66L, 0x60e9c151L, 0x65a6d7d4L, 0x6464bde3L, 0x662203baL,
+    0x67e0698dL, 0x48d7cb20L, 0x4915a117L, 0x4b531f4eL, 0x4a917579L,
+    0x4fde63fcL, 0x4e1c09cbL, 0x4c5ab792L, 0x4d98dda5L, 0x46c49a98L,
+    0x4706f0afL, 0x45404ef6L, 0x448224c1L, 0x41cd3244L, 0x400f5873L,
+    0x4249e62aL, 0x438b8c1dL, 0x54f16850L, 0x55330267L, 0x5775bc3eL,
+    0x56b7d609L, 0x53f8c08cL, 0x523aaabbL, 0x507c14e2L, 0x51be7ed5L,
+    0x5ae239e8L, 0x5b2053dfL, 0x5966ed86L, 0x58a487b1L, 0x5deb9134L,
+    0x5c29fb03L, 0x5e6f455aL, 0x5fad2f6dL, 0xe1351b80L, 0xe0f771b7L,
+    0xe2b1cfeeL, 0xe373a5d9L, 0xe63cb35cL, 0xe7fed96bL, 0xe5b86732L,
+    0xe47a0d05L, 0xef264a38L, 0xeee4200fL, 0xeca29e56L, 0xed60f461L,
+    0xe82fe2e4L, 0xe9ed88d3L, 0xebab368aL, 0xea695cbdL, 0xfd13b8f0L,
+    0xfcd1d2c7L, 0xfe976c9eL, 0xff5506a9L, 0xfa1a102cL, 0xfbd87a1bL,
+    0xf99ec442L, 0xf85cae75L, 0xf300e948L, 0xf2c2837fL, 0xf0843d26L,
+    0xf1465711L, 0xf4094194L, 0xf5cb2ba3L, 0xf78d95faL, 0xf64fffcdL,
+    0xd9785d60L, 0xd8ba3757L, 0xdafc890eL, 0xdb3ee339L, 0xde71f5bcL,
+    0xdfb39f8bL, 0xddf521d2L, 0xdc374be5L, 0xd76b0cd8L, 0xd6a966efL,
+    0xd4efd8b6L, 0xd52db281L, 0xd062a404L, 0xd1a0ce33L, 0xd3e6706aL,
+    0xd2241a5dL, 0xc55efe10L, 0xc49c9427L, 0xc6da2a7eL, 0xc7184049L,
+    0xc25756ccL, 0xc3953cfbL, 0xc1d382a2L, 0xc011e895L, 0xcb4dafa8L,
+    0xca8fc59fL, 0xc8c97bc6L, 0xc90b11f1L, 0xcc440774L, 0xcd866d43L,
+    0xcfc0d31aL, 0xce02b92dL, 0x91af9640L, 0x906dfc77L, 0x922b422eL,
+    0x93e92819L, 0x96a63e9cL, 0x976454abL, 0x9522eaf2L, 0x94e080c5L,
+    0x9fbcc7f8L, 0x9e7eadcfL, 0x9c381396L, 0x9dfa79a1L, 0x98b56f24L,
+    0x99770513L, 0x9b31bb4aL, 0x9af3d17dL, 0x8d893530L, 0x8c4b5f07L,
+    0x8e0de15eL, 0x8fcf8b69L, 0x8a809decL, 0x8b42f7dbL, 0x89044982L,
+    0x88c623b5L, 0x839a6488L, 0x82580ebfL, 0x801eb0e6L, 0x81dcdad1L,
+    0x8493cc54L, 0x8551a663L, 0x8717183aL, 0x86d5720dL, 0xa9e2d0a0L,
+    0xa820ba97L, 0xaa6604ceL, 0xaba46ef9L, 0xaeeb787cL, 0xaf29124bL,
+    0xad6fac12L, 0xacadc625L, 0xa7f18118L, 0xa633eb2fL, 0xa4755576L,
+    0xa5b73f41L, 0xa0f829c4L, 0xa13a43f3L, 0xa37cfdaaL, 0xa2be979dL,
+    0xb5c473d0L, 0xb40619e7L, 0xb640a7beL, 0xb782cd89L, 0xb2cddb0cL,
+    0xb30fb13bL, 0xb1490f62L, 0xb08b6555L, 0xbbd72268L, 0xba15485fL,
+    0xb853f606L, 0xb9919c31L, 0xbcde8ab4L, 0xbd1ce083L, 0xbf5a5edaL,
+    0xbe9834edL
+   ,
+    0x00000000L, 0xb8bc6765L, 0xaa09c88bL, 0x12b5afeeL, 0x8f629757L,
+    0x37def032L, 0x256b5fdcL, 0x9dd738b9L, 0xc5b428efL, 0x7d084f8aL,
+    0x6fbde064L, 0xd7018701L, 0x4ad6bfb8L, 0xf26ad8ddL, 0xe0df7733L,
+    0x58631056L, 0x5019579fL, 0xe8a530faL, 0xfa109f14L, 0x42acf871L,
+    0xdf7bc0c8L, 0x67c7a7adL, 0x75720843L, 0xcdce6f26L, 0x95ad7f70L,
+    0x2d111815L, 0x3fa4b7fbL, 0x8718d09eL, 0x1acfe827L, 0xa2738f42L,
+    0xb0c620acL, 0x087a47c9L, 0xa032af3eL, 0x188ec85bL, 0x0a3b67b5L,
+    0xb28700d0L, 0x2f503869L, 0x97ec5f0cL, 0x8559f0e2L, 0x3de59787L,
+    0x658687d1L, 0xdd3ae0b4L, 0xcf8f4f5aL, 0x7733283fL, 0xeae41086L,
+    0x525877e3L, 0x40edd80dL, 0xf851bf68L, 0xf02bf8a1L, 0x48979fc4L,
+    0x5a22302aL, 0xe29e574fL, 0x7f496ff6L, 0xc7f50893L, 0xd540a77dL,
+    0x6dfcc018L, 0x359fd04eL, 0x8d23b72bL, 0x9f9618c5L, 0x272a7fa0L,
+    0xbafd4719L, 0x0241207cL, 0x10f48f92L, 0xa848e8f7L, 0x9b14583dL,
+    0x23a83f58L, 0x311d90b6L, 0x89a1f7d3L, 0x1476cf6aL, 0xaccaa80fL,
+    0xbe7f07e1L, 0x06c36084L, 0x5ea070d2L, 0xe61c17b7L, 0xf4a9b859L,
+    0x4c15df3cL, 0xd1c2e785L, 0x697e80e0L, 0x7bcb2f0eL, 0xc377486bL,
+    0xcb0d0fa2L, 0x73b168c7L, 0x6104c729L, 0xd9b8a04cL, 0x446f98f5L,
+    0xfcd3ff90L, 0xee66507eL, 0x56da371bL, 0x0eb9274dL, 0xb6054028L,
+    0xa4b0efc6L, 0x1c0c88a3L, 0x81dbb01aL, 0x3967d77fL, 0x2bd27891L,
+    0x936e1ff4L, 0x3b26f703L, 0x839a9066L, 0x912f3f88L, 0x299358edL,
+    0xb4446054L, 0x0cf80731L, 0x1e4da8dfL, 0xa6f1cfbaL, 0xfe92dfecL,
+    0x462eb889L, 0x549b1767L, 0xec277002L, 0x71f048bbL, 0xc94c2fdeL,
+    0xdbf98030L, 0x6345e755L, 0x6b3fa09cL, 0xd383c7f9L, 0xc1366817L,
+    0x798a0f72L, 0xe45d37cbL, 0x5ce150aeL, 0x4e54ff40L, 0xf6e89825L,
+    0xae8b8873L, 0x1637ef16L, 0x048240f8L, 0xbc3e279dL, 0x21e91f24L,
+    0x99557841L, 0x8be0d7afL, 0x335cb0caL, 0xed59b63bL, 0x55e5d15eL,
+    0x47507eb0L, 0xffec19d5L, 0x623b216cL, 0xda874609L, 0xc832e9e7L,
+    0x708e8e82L, 0x28ed9ed4L, 0x9051f9b1L, 0x82e4565fL, 0x3a58313aL,
+    0xa78f0983L, 0x1f336ee6L, 0x0d86c108L, 0xb53aa66dL, 0xbd40e1a4L,
+    0x05fc86c1L, 0x1749292fL, 0xaff54e4aL, 0x322276f3L, 0x8a9e1196L,
+    0x982bbe78L, 0x2097d91dL, 0x78f4c94bL, 0xc048ae2eL, 0xd2fd01c0L,
+    0x6a4166a5L, 0xf7965e1cL, 0x4f2a3979L, 0x5d9f9697L, 0xe523f1f2L,
+    0x4d6b1905L, 0xf5d77e60L, 0xe762d18eL, 0x5fdeb6ebL, 0xc2098e52L,
+    0x7ab5e937L, 0x680046d9L, 0xd0bc21bcL, 0x88df31eaL, 0x3063568fL,
+    0x22d6f961L, 0x9a6a9e04L, 0x07bda6bdL, 0xbf01c1d8L, 0xadb46e36L,
+    0x15080953L, 0x1d724e9aL, 0xa5ce29ffL, 0xb77b8611L, 0x0fc7e174L,
+    0x9210d9cdL, 0x2aacbea8L, 0x38191146L, 0x80a57623L, 0xd8c66675L,
+    0x607a0110L, 0x72cfaefeL, 0xca73c99bL, 0x57a4f122L, 0xef189647L,
+    0xfdad39a9L, 0x45115eccL, 0x764dee06L, 0xcef18963L, 0xdc44268dL,
+    0x64f841e8L, 0xf92f7951L, 0x41931e34L, 0x5326b1daL, 0xeb9ad6bfL,
+    0xb3f9c6e9L, 0x0b45a18cL, 0x19f00e62L, 0xa14c6907L, 0x3c9b51beL,
+    0x842736dbL, 0x96929935L, 0x2e2efe50L, 0x2654b999L, 0x9ee8defcL,
+    0x8c5d7112L, 0x34e11677L, 0xa9362eceL, 0x118a49abL, 0x033fe645L,
+    0xbb838120L, 0xe3e09176L, 0x5b5cf613L, 0x49e959fdL, 0xf1553e98L,
+    0x6c820621L, 0xd43e6144L, 0xc68bceaaL, 0x7e37a9cfL, 0xd67f4138L,
+    0x6ec3265dL, 0x7c7689b3L, 0xc4caeed6L, 0x591dd66fL, 0xe1a1b10aL,
+    0xf3141ee4L, 0x4ba87981L, 0x13cb69d7L, 0xab770eb2L, 0xb9c2a15cL,
+    0x017ec639L, 0x9ca9fe80L, 0x241599e5L, 0x36a0360bL, 0x8e1c516eL,
+    0x866616a7L, 0x3eda71c2L, 0x2c6fde2cL, 0x94d3b949L, 0x090481f0L,
+    0xb1b8e695L, 0xa30d497bL, 0x1bb12e1eL, 0x43d23e48L, 0xfb6e592dL,
+    0xe9dbf6c3L, 0x516791a6L, 0xccb0a91fL, 0x740cce7aL, 0x66b96194L,
+    0xde0506f1L
+#  endif /* IZ_CRCOPTIM_UNFOLDTBL */
+# endif /* ? IZ_CRC_BE_OPTIMIZ */
+};
+#endif /* ?DYNAMIC_CRC_TABLE */
+
+/* use "OF((void))" here to work around a Borland TC++ 1.0 problem */
+#ifdef USE_ZLIB
+ZCONST uLongf *get_crc_table OF((void))
+#else
+ZCONST ulg near *get_crc_table OF((void))
+#endif
+{
+#ifdef DYNAMIC_CRC_TABLE
+  if (CRC_TABLE_IS_EMPTY)
+    make_crc_table();
+#endif
+#ifdef USE_ZLIB
+  return (ZCONST uLongf *)crc_table;
+#else
+  return crc_table;
+#endif
+}
+
+#ifdef DYNALLOC_CRCTAB
+void free_crc_table()
+{
+  if (!CRC_TABLE_IS_EMPTY)
+  {
+    nearfree((ulg near *)crc_table);
+    MARK_CRCTAB_EMPTY;
+  }
+}
+#endif
+
+#ifndef USE_ZLIB
+#ifndef CRC_TABLE_ONLY
+#ifndef ASM_CRC
+
+#define DO1(crc, buf)  crc = CRC32(crc, *buf++, crc_32_tab)
+#define DO2(crc, buf)  DO1(crc, buf); DO1(crc, buf)
+#define DO4(crc, buf)  DO2(crc, buf); DO2(crc, buf)
+#define DO8(crc, buf)  DO4(crc, buf); DO4(crc, buf)
+
+#if (defined(IZ_CRC_BE_OPTIMIZ) || defined(IZ_CRC_LE_OPTIMIZ))
+
+# ifdef IZ_CRCOPTIM_UNFOLDTBL
+#  ifdef IZ_CRC_BE_OPTIMIZ
+#    define DO_OPT4(c, buf4)  c ^= *(buf4)++; \
+        c = crc_32_tab[c & 0xff] ^ crc_32_tab[256+((c>>8) & 0xff)] ^ \
+            crc_32_tab[2*256+((c>>16) & 0xff)] ^ crc_32_tab[3*256+(c>>24)]
+#  else /* !IZ_CRC_BE_OPTIMIZ */
+#    define DO_OPT4(c, buf4)  c ^= *(buf4)++; \
+        c = crc_32_tab[3*256+(c & 0xff)] ^ crc_32_tab[2*256+((c>>8) & 0xff)] \
+           ^ crc_32_tab[256+((c>>16) & 0xff)] ^ crc_32_tab[c>>24]
+#  endif /* ?IZ_CRC_BE_OPTIMIZ */
+# else /* !IZ_CRCOPTIM_UNFOLDTBL */
+#    define DO_OPT4(c, buf4)  c ^= *(buf4)++; \
+       c = CRC32UPD(c, crc_32_tab); \
+       c = CRC32UPD(c, crc_32_tab); \
+       c = CRC32UPD(c, crc_32_tab); \
+       c = CRC32UPD(c, crc_32_tab)
+# endif /* ?IZ_CRCOPTIM_UNFOLDTBL */
+
+# define DO_OPT16(crc, buf4) DO_OPT4(crc, buf4); DO_OPT4(crc, buf4); \
+                             DO_OPT4(crc, buf4); DO_OPT4(crc, buf4);
+
+#endif /* (IZ_CRC_BE_OPTIMIZ || IZ_CRC_LE_OPTIMIZ) */
+
+
+/* ========================================================================= */
+ulg crc32(crc, buf, len)
+    ulg crc;                    /* crc shift register */
+    register ZCONST uch *buf;   /* pointer to bytes to pump through */
+    extent len;                 /* number of bytes in buf[] */
+/* Run a set of bytes through the crc shift register.  If buf is a NULL
+   pointer, then initialize the crc shift register contents instead.
+   Return the current crc in either case. */
+{
+  register z_uint4 c;
+  register ZCONST ulg near *crc_32_tab;
+
+  if (buf == NULL) return 0L;
+
+  crc_32_tab = get_crc_table();
+
+  c = (REV_BE((z_uint4)crc) ^ 0xffffffffL);
+
+#if (defined(IZ_CRC_BE_OPTIMIZ) || defined(IZ_CRC_LE_OPTIMIZ))
+  /* Align buf pointer to next DWORD boundary. */
+  while (len && ((ptrdiff_t)buf & 3)) {
+    DO1(c, buf);
+    len--;
+  }
+  {
+    ZCONST z_uint4 *buf4 = (ZCONST z_uint4 *)buf;
+    while (len >= 16) {
+      DO_OPT16(c, buf4);
+      len -= 16;
+    }
+    while (len >= 4) {
+      DO_OPT4(c, buf4);
+      len -= 4;
+    }
+    buf = (ZCONST uch *)buf4;
+  }
+#else /* !(IZ_CRC_BE_OPTIMIZ || IZ_CRC_LE_OPTIMIZ) */
+#ifndef NO_UNROLLED_LOOPS
+  while (len >= 8) {
+    DO8(c, buf);
+    len -= 8;
+  }
+#endif /* !NO_UNROLLED_LOOPS */
+#endif /* ?(IZ_CRC_BE_OPTIMIZ || IZ_CRC_LE_OPTIMIZ) */
+  if (len) do {
+    DO1(c, buf);
+  } while (--len);
+
+  return REV_BE(c) ^ 0xffffffffL;   /* (instead of ~c for 64-bit machines) */
+}
+#endif /* !ASM_CRC */
+#endif /* !CRC_TABLE_ONLY */
+#endif /* !USE_ZLIB */
+#endif /* !USE_ZLIB || USE_OWN_CRCTAB */
diff --git a/crc32.h b/crc32.h
new file mode 100644 (file)
index 0000000..83af240
--- /dev/null
+++ b/crc32.h
@@ -0,0 +1,60 @@
+/*
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* crc32.h -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#ifndef __crc32_h
+#define __crc32_h       /* identifies this source module */
+
+/* This header should be read AFTER zip.h resp. unzip.h
+ * (the latter with UNZIP_INTERNAL defined...).
+ */
+
+#ifndef OF
+#  define OF(a) a
+#endif
+#ifndef ZCONST
+#  define ZCONST const
+#endif
+
+#ifdef DYNALLOC_CRCTAB
+   void     free_crc_table  OF((void));
+#endif
+#ifndef USE_ZLIB
+   ZCONST ulg near *get_crc_table  OF((void));
+#endif
+#if (defined(USE_ZLIB) || defined(CRC_TABLE_ONLY))
+#  ifdef IZ_CRC_BE_OPTIMIZ
+#    undef IZ_CRC_BE_OPTIMIZ
+#  endif
+#else /* !(USE_ZLIB || CRC_TABLE_ONLY) */
+   ulg      crc32           OF((ulg crc, ZCONST uch *buf, extent len));
+#endif /* ?(USE_ZLIB || CRC_TABLE_ONLY) */
+
+#ifndef CRC_32_TAB
+#  define CRC_32_TAB     crc_32_tab
+#endif
+
+#ifdef CRC32
+#  undef CRC32
+#endif
+#ifdef IZ_CRC_BE_OPTIMIZ
+#  define CRC32UPD(c, crctab) (crctab[((c) >> 24)] ^ ((c) << 8))
+#  define CRC32(c, b, crctab) (crctab[(((int)(c) >> 24) ^ (b))] ^ ((c) << 8))
+#  define REV_BE(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+                    (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+#else
+#  define CRC32UPD(c, crctab) (crctab[((int)(c)) & 0xff] ^ ((c) >> 8))
+#  define CRC32(c, b, crctab) (crctab[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
+#  define REV_BE(w) w
+#endif
+
+#endif /* !__crc32_h */
diff --git a/crc_i386.S b/crc_i386.S
new file mode 100644 (file)
index 0000000..38dbc86
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * crc_i386.S, optimized CRC calculation function for Zip and UnZip,
+ * created by Paul Kienitz and Christian Spieler.  Last revised 07 Jan 2007.
+ *
+ * GRR 961110:  incorporated Scott Field optimizations from win32/crc_i386.asm
+ *              => overall 6% speedup in "unzip -tq" on 9MB zipfile (486-66)
+ *
+ * SPC 970402:  revised for Rodney Brown's optimizations (32-bit-wide
+ *              aligned reads for most of the data from buffer), can be
+ *              disabled by defining the macro NO_32_BIT_LOADS
+ *
+ * SPC 971012:  added Rodney Brown's additional tweaks for 32-bit-optimized
+ *              CPUs (like the Pentium Pro, Pentium II, and probably some
+ *              Pentium clones). This optimization is controlled by the
+ *              preprocessor switch "__686" and is disabled by default.
+ *              (This default is based on the assumption that most users
+ *              do not yet work on a Pentium Pro or Pentium II machine ...)
+ *
+ * COS 050116:  Enabled the 686 build by default, because there are hardly any
+ *              pre-686 CPUs in serious use nowadays. (See SPC 970402 above.)
+ *
+ * SPC 060103:  Updated code to incorporate newer optimizations found in zlib.
+ *
+ * SPC 070107:  Added conditional switch to deactivate crc32() compilation.
+ *
+ * FLAT memory model assumed.  Calling interface:
+ *   - args are pushed onto the stack from right to left,
+ *   - return value is given in the EAX register,
+ *   - all other registers (with exception of EFLAGS) are preserved. (With
+ *     GNU C 2.7.x, %edx and %ecx are `scratch' registers, but preserving
+ *     them nevertheless adds only 4 single byte instructions.)
+ *
+ * This source generates the function
+ * ulg crc32(ulg crc, ZCONST uch *buf, extent len).
+ *
+ * Loop unrolling can be disabled by defining the macro NO_UNROLLED_LOOPS.
+ * This results in shorter code at the expense of reduced performance.
+ */
+
+/* This file is NOT used in conjunction with zlib, or when only creation of
+ * the basic CRC_32_Table (for other purpose) is requested.
+ */
+#if !defined(USE_ZLIB) && !defined(CRC_TABLE_ONLY)
+
+/* Preprocess with -DNO_UNDERLINE if your C compiler does not prefix
+ * external symbols with an underline character '_'.
+ */
+#if defined(NO_UNDERLINE) || defined(__ELF__)
+#  define _crc32            crc32
+#  define _get_crc_table    get_crc_table
+#endif
+/* Use 16-byte alignment if your assembler supports it. Warning: gas
+ * uses a log(x) parameter (.align 4 means 16-byte alignment). On SVR4
+ * the parameter is a number of bytes.
+ */
+#ifndef ALIGNMENT
+#  define ALIGNMENT .align 4,0x90
+#endif
+
+#if defined(i386) || defined(_i386) || defined(_I386) || defined(__i386)
+
+/* This version is for 386 Unix, OS/2, MSDOS in 32 bit mode (gcc & gas).
+ * Warning: it uses the AT&T syntax: mov source,dest
+ * This file is only optional. If you want to use the C version,
+ * remove -DASM_CRC from CFLAGS in Makefile and set OBJA to an empty string.
+ */
+
+                .file   "crc_i386.S"
+
+#if !defined(PRE_686) && !defined(__686)
+   /* Optimize for Pentium Pro and compatible CPUs by default. */
+#  define __686
+#endif
+
+#if defined(NO_STD_STACKFRAME) && defined(USE_STD_STACKFRAME)
+#  undef USE_STACKFRAME
+#else
+   /* The default is to use standard stack frame entry, because it
+    * results in smaller code!
+    */
+#  ifndef USE_STD_STACKFRAME
+#    define USE_STD_STACKFRAME
+#  endif
+#endif
+
+#ifdef USE_STD_STACKFRAME
+#  define _STD_ENTRY    pushl   %ebp ; movl   %esp,%ebp
+#  define arg1  8(%ebp)
+#  define arg2  12(%ebp)
+#  define arg3  16(%ebp)
+#  define _STD_LEAVE    popl    %ebp
+#else /* !USE_STD_STACKFRAME */
+#  define _STD_ENTRY
+#  define arg1  24(%esp)
+#  define arg2  28(%esp)
+#  define arg3  32(%esp)
+#  define _STD_LEAVE
+#endif /* ?USE_STD_STACKFRAME */
+
+/*
+ * These two (three) macros make up the loop body of the CRC32 cruncher.
+ * registers modified:
+ *   eax  : crc value "c"
+ *   esi  : pointer to next data byte (or lword) "buf++"
+ * registers read:
+ *   edi  : pointer to base of crc_table array
+ * scratch registers:
+ *   ebx  : index into crc_table array
+ *          (requires upper three bytes = 0 when __686 is undefined)
+ */
+#ifndef __686   /* optimize for 386, 486, Pentium */
+#define Do_CRC          /* c = (c >> 8) ^ table[c & 0xFF] */\
+                movb    %al, %bl                ;/* tmp = c & 0xFF  */\
+                shrl    $8, %eax                ;/* c = (c >> 8)    */\
+                xorl    (%edi, %ebx, 4), %eax   ;/* c ^= table[tmp] */
+#else   /* __686 : optimize for Pentium Pro and compatible CPUs */
+#define Do_CRC          /* c = (c >> 8) ^ table[c & 0xFF] */\
+                movzbl  %al, %ebx               ;/* tmp = c & 0xFF  */\
+                shrl    $8, %eax                ;/* c = (c >> 8)    */\
+                xorl    (%edi, %ebx, 4), %eax   ;/* c ^=table[tmp]  */
+#endif  /* ?__686 */
+
+#define Do_CRC_byte             /* c = (c >> 8) ^ table[(c^*buf++)&0xFF] */\
+                xorb    (%esi), %al     ;/* c ^= *buf  */\
+                incl    %esi            ;/* buf++      */\
+                Do_CRC
+
+#define Do_CRC_byteof(ofs)      /* c = (c >> 8) ^ table[(c^*buf++)&0xFF] */\
+                xorb    ofs(%esi), %al  ;/* c ^= *buf  */\
+                incl    %esi            ;/* buf++      */\
+                Do_CRC
+
+#ifndef  NO_32_BIT_LOADS
+# ifdef IZ_CRCOPTIM_UNFOLDTBL
+   /* the edx register is needed in crc calculation */
+#  define SavLen arg3
+#  define UpdCRC_lword \
+                movzbl  %al, %ebx               ; \
+                movl    3072(%edi,%ebx,4), %edx ; \
+                movzbl  %ah, %ebx               ; \
+                shrl    $16, %eax               ; \
+                xor     2048(%edi,%ebx,4), %edx ; \
+                movzbl  %al, %ebx               ; \
+                shrl    $8,%eax                 ; \
+                xorl    1024(%edi,%ebx,4), %edx ; \
+                movl    (%edi,%eax,4), %eax     ; \
+                xorl    %edx,%eax               ;
+#  define UpdCRC_lword_sh(dwPtrIncr) \
+                movzbl  %al, %ebx               ; \
+                movl    3072(%edi,%ebx,4), %edx ; \
+                movzbl  %ah, %ebx               ; \
+                shrl    $16, %eax               ; \
+                xor     2048(%edi,%ebx,4), %edx ; \
+                movzbl  %al, %ebx               ; \
+                addl    $4*(dwPtrIncr), %esi    ;/* ((ulg *)buf)+=dwPtrIncr */\
+                shrl    $8,%eax                 ; \
+                xorl    1024(%edi,%ebx,4), %edx ; \
+                movl    (%edi,%eax,4),%eax      ; \
+                xorl    %edx,%eax               ;
+# else /* !IZ_CRCOPTIM_UNFOLDTBL */
+   /* the edx register is not needed anywhere else */
+#  define SavLen %edx
+#  define UpdCRC_lword \
+                Do_CRC \
+                Do_CRC \
+                Do_CRC \
+                Do_CRC
+#  define UpdCRC_lword_sh(dwPtrIncr) \
+                Do_CRC \
+                Do_CRC \
+                addl    $4*(dwPtrIncr), %esi    ;/* ((ulg *)buf)++   */\
+                Do_CRC \
+                Do_CRC
+# endif /* ?IZ_CRCOPTIM_UNFOLDTBL */
+#define Do_CRC_lword \
+                xorl    (%esi), %eax           ;/* c ^= *(ulg *)buf */\
+                UpdCRC_lword_sh(1)              /* ... ((ulg *)buf)++ */
+#define Do_CRC_4lword \
+                xorl    (%esi), %eax           ;/* c ^= *(ulg *)buf */\
+                UpdCRC_lword \
+                xorl    4(%esi), %eax          ;/* c ^= *((ulg *)buf+1) */\
+                UpdCRC_lword \
+                xorl    8(%esi), %eax          ;/* c ^= *((ulg *)buf+2) */\
+                UpdCRC_lword \
+                xorl    12(%esi), %eax         ;/* c ^= *((ulg *)buf]+3 */\
+                UpdCRC_lword_sh(4)              /* ... ((ulg *)buf)+=4 */
+#endif  /* !NO_32_BIT_LOADS */
+
+
+                .text
+
+                .globl  _crc32
+
+_crc32:                         /* ulg crc32(ulg crc, uch *buf, extent len) */
+                _STD_ENTRY
+                pushl   %edi
+                pushl   %esi
+                pushl   %ebx
+                pushl   %edx
+                pushl   %ecx
+
+                movl    arg2, %esi           /* 2nd arg: uch *buf            */
+                subl    %eax, %eax           /* > if (!buf)                  */
+                testl   %esi, %esi           /* >   return 0;                */
+                jz      .L_fine              /* > else {                     */
+                call    _get_crc_table
+                movl    %eax, %edi
+                movl    arg1, %eax           /* 1st arg: ulg crc             */
+#ifndef __686
+                subl    %ebx, %ebx           /* ebx=0; bl usable as dword    */
+#endif
+                movl    arg3, %ecx           /* 3rd arg: extent len          */
+                notl    %eax                 /* >   c = ~crc;                */
+
+                testl   %ecx, %ecx
+#ifndef  NO_UNROLLED_LOOPS
+                jz      .L_bail
+#  ifndef  NO_32_BIT_LOADS
+                /* Assert now have positive length */
+.L_align_loop:
+                testl   $3, %esi        /* Align buf on lword boundary */
+                jz      .L_aligned_now
+                Do_CRC_byte
+                decl    %ecx
+                jnz     .L_align_loop
+.L_aligned_now:
+#  endif  /* !NO_32_BIT_LOADS */
+                movl    %ecx, SavLen         /* save current value of len */
+                shrl    $4, %ecx             /* ecx = len / 16   */
+                jz      .L_No_Sixteens
+/*  align loop head at start of 486 internal cache line !! */
+                ALIGNMENT
+.L_Next_Sixteen:
+#  ifndef NO_32_BIT_LOADS
+                 Do_CRC_4lword
+#  else   /* NO_32_BIT_LOADS */
+                 Do_CRC_byteof(0)
+                 Do_CRC_byteof(1)
+                 Do_CRC_byteof(2)
+                 Do_CRC_byteof(3)
+                 Do_CRC_byteof(4)
+                 Do_CRC_byteof(5)
+                 Do_CRC_byteof(6)
+                 Do_CRC_byteof(7)
+                 Do_CRC_byteof(8)
+                 Do_CRC_byteof(9)
+                 Do_CRC_byteof(10)
+                 Do_CRC_byteof(11)
+                 Do_CRC_byteof(12)
+                 Do_CRC_byteof(13)
+                 Do_CRC_byteof(14)
+                 Do_CRC_byteof(15)
+                 addl    $16,%esi        ;/* buf += 16 */
+#  endif  /* ?NO_32_BIT_LOADS */
+                decl    %ecx
+                jnz     .L_Next_Sixteen
+
+.L_No_Sixteens:
+                movl    SavLen, %ecx
+                andl    $15, %ecx         /* ecx = len % 16   */
+# ifndef NO_32_BIT_LOADS
+                shrl    $2,%ecx           /* ecx = len / 4    */
+                jz      .L_No_Fours
+.L_Next_Four:
+                Do_CRC_lword
+                decl    %ecx
+                jnz     .L_Next_Four
+.L_No_Fours:
+                movl    SavLen,%ecx
+                andl    $3,%ecx          /* ecx = len % 4 */
+# endif /* !NO_32_BIT_LOADS */
+#endif /* !NO_UNROLLED_LOOPS */
+                jz      .L_bail          /* > if (len)                       */
+/* align loop head at start of 486 internal cache line !! */
+                ALIGNMENT
+.L_loupe:                                /* >   do {                         */
+                 Do_CRC_byte             /*       c = CRC32(c,*buf++,crctab);*/
+                decl    %ecx             /* >   } while (--len);             */
+                jnz     .L_loupe
+
+.L_bail:                                 /* > }                              */
+                notl    %eax             /* > return ~c;                     */
+.L_fine:
+                popl    %ecx
+                popl    %edx
+                popl    %ebx
+                popl    %esi
+                popl    %edi
+                _STD_LEAVE
+                ret
+
+#else
+ error: this asm version is for 386 only
+#endif /* i386 || _i386 || _I386 || __i386 */
+
+#endif /* !USE_ZLIB && !CRC_TABLE_ONLY */
diff --git a/crypt.c b/crypt.c
new file mode 100644 (file)
index 0000000..cc974ec
--- /dev/null
+++ b/crypt.c
@@ -0,0 +1,690 @@
+/*
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+  crypt.c (full version) by Info-ZIP.      Last revised:  [see crypt.h]
+
+  The main encryption/decryption source code for Info-Zip software was
+  originally written in Europe.  To the best of our knowledge, it can
+  be freely distributed in both source and object forms from any country,
+  including the USA under License Exception TSU of the U.S. Export
+  Administration Regulations (section 740.13(e)) of 6 June 2002.
+
+  NOTE on copyright history:
+  Previous versions of this source package (up to version 2.8) were
+  not copyrighted and put in the public domain.  If you cannot comply
+  with the Info-Zip LICENSE, you may want to look for one of those
+  public domain versions.
+ */
+
+/*
+  This encryption code is a direct transcription of the algorithm from
+  Roger Schlafly, described by Phil Katz in the file appnote.txt.  This
+  file (appnote.txt) is distributed with the PKZIP program (even in the
+  version without encryption capabilities).
+ */
+
+#define ZCRYPT_INTERNAL
+#include "zip.h"
+#include "crypt.h"
+#include "ttyio.h"
+
+#if CRYPT
+
+#ifndef FALSE
+#  define FALSE 0
+#endif
+
+#ifdef ZIP
+   /* For the encoding task used in Zip (and ZipCloak), we want to initialize
+      the crypt algorithm with some reasonably unpredictable bytes, see
+      the crypthead() function. The standard rand() library function is
+      used to supply these `random' bytes, which in turn is initialized by
+      a srand() call. The srand() function takes an "unsigned" (at least 16bit)
+      seed value as argument to determine the starting point of the rand()
+      pseudo-random number generator.
+      This seed number is constructed as "Seed = Seed1 .XOR. Seed2" with
+      Seed1 supplied by the current time (= "(unsigned)time()") and Seed2
+      as some (hopefully) nondeterministic bitmask. On many (most) systems,
+      we use some "process specific" number, as the PID or something similar,
+      but when nothing unpredictable is available, a fixed number may be
+      sufficient.
+      NOTE:
+      1.) This implementation requires the availability of the following
+          standard UNIX C runtime library functions: time(), rand(), srand().
+          On systems where some of them are missing, the environment that
+          incorporates the crypt routines must supply suitable replacement
+          functions.
+      2.) It is a very bad idea to use a second call to time() to set the
+          "Seed2" number! In this case, both "Seed1" and "Seed2" would be
+          (almost) identical, resulting in a (mostly) "zero" constant seed
+          number passed to srand().
+
+      The implementation environment defined in the "zip.h" header should
+      supply a reasonable definition for ZCR_SEED2 (an unsigned number; for
+      most implementations of rand() and srand(), only the lower 16 bits are
+      significant!). An example that works on many systems would be
+           "#define ZCR_SEED2  (unsigned)getpid()".
+      The default definition for ZCR_SEED2 supplied below should be regarded
+      as a fallback to allow successful compilation in "beta state"
+      environments.
+    */
+#  include <time.h>     /* time() function supplies first part of crypt seed */
+   /* "last resort" source for second part of crypt seed pattern */
+#  ifndef ZCR_SEED2
+#    define ZCR_SEED2 (unsigned)3141592654L     /* use PI as default pattern */
+#  endif
+#  ifdef GLOBAL         /* used in Amiga system headers, maybe others too */
+#    undef GLOBAL
+#  endif
+#  define GLOBAL(g) g
+#else /* !ZIP */
+#  define GLOBAL(g) G.g
+#endif /* ?ZIP */
+
+
+#ifdef UNZIP
+   /* char *key = (char *)NULL; moved to globals.h */
+#  ifndef FUNZIP
+     local int testp OF((__GPRO__ ZCONST uch *h));
+     local int testkey OF((__GPRO__ ZCONST uch *h, ZCONST char *key));
+#  endif
+#else /* def UNZIP */           /* moved to globals.h for UnZip */
+   local z_uint4 keys[3];       /* keys defining the pseudo-random sequence */
+#endif /* def UNZIP [else] */
+
+#ifndef Trace
+#  ifdef CRYPT_DEBUG
+#    define Trace(x) fprintf x
+#  else
+#    define Trace(x)
+#  endif
+#endif
+
+#include "crc32.h"
+
+#ifdef IZ_CRC_BE_OPTIMIZ
+   local z_uint4 near crycrctab[256];
+   local z_uint4 near *cry_crctb_p = NULL;
+   local z_uint4 near *crytab_init OF((__GPRO));
+#  define CRY_CRC_TAB  cry_crctb_p
+#  undef CRC32
+#  define CRC32(c, b, crctab) (crctab[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
+#else
+#  define CRY_CRC_TAB  CRC_32_TAB
+#endif /* ?IZ_CRC_BE_OPTIMIZ */
+
+/***********************************************************************
+ * Return the next byte in the pseudo-random sequence
+ */
+int decrypt_byte(__G)
+    __GDEF
+{
+    unsigned temp;  /* POTENTIAL BUG:  temp*(temp^1) may overflow in an
+                     * unpredictable manner on 16-bit systems; not a problem
+                     * with any known compiler so far, though */
+
+    temp = ((unsigned)GLOBAL(keys[2]) & 0xffff) | 2;
+    return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
+}
+
+/***********************************************************************
+ * Update the encryption keys with the next byte of plain text
+ */
+int update_keys(__G__ c)
+    __GDEF
+    int c;                      /* byte of plain text */
+{
+    GLOBAL(keys[0]) = CRC32(GLOBAL(keys[0]), c, CRY_CRC_TAB);
+    GLOBAL(keys[1]) = (GLOBAL(keys[1])
+                       + (GLOBAL(keys[0]) & 0xff))
+                      * 134775813L + 1;
+    {
+      register int keyshift = (int)(GLOBAL(keys[1]) >> 24);
+      GLOBAL(keys[2]) = CRC32(GLOBAL(keys[2]), keyshift, CRY_CRC_TAB);
+    }
+    return c;
+}
+
+
+/***********************************************************************
+ * Initialize the encryption keys and the random header according to
+ * the given password.
+ */
+void init_keys(__G__ passwd)
+    __GDEF
+    ZCONST char *passwd;        /* password string with which to modify keys */
+{
+#ifdef IZ_CRC_BE_OPTIMIZ
+    if (cry_crctb_p == NULL) {
+        cry_crctb_p = crytab_init(__G);
+    }
+#endif
+    GLOBAL(keys[0]) = 305419896L;
+    GLOBAL(keys[1]) = 591751049L;
+    GLOBAL(keys[2]) = 878082192L;
+    while (*passwd != '\0') {
+        update_keys(__G__ (int)*passwd);
+        passwd++;
+    }
+}
+
+
+/***********************************************************************
+ * Initialize the local copy of the table of precomputed crc32 values.
+ * Whereas the public crc32-table is optimized for crc32 calculations
+ * on arrays of bytes, the crypt code needs the crc32 values in an
+ * byte-order-independent form as 32-bit unsigned numbers. On systems
+ * with Big-Endian byte order using the optimized crc32 code, this
+ * requires inverting the byte-order of the values in the
+ * crypt-crc32-table.
+ */
+#ifdef IZ_CRC_BE_OPTIMIZ
+local z_uint4 near *crytab_init(__G)
+    __GDEF
+{
+    int i;
+
+    for (i = 0; i < 256; i++) {
+        crycrctab[i] = REV_BE(CRC_32_TAB[i]);
+    }
+    return crycrctab;
+}
+#endif
+
+
+#ifdef ZIP
+
+/***********************************************************************
+ * Write encryption header to file zfile using the password passwd
+ * and the cyclic redundancy check crc.
+ */
+void crypthead(passwd, crc)
+    ZCONST char *passwd;         /* password string */
+    ulg crc;                     /* crc of file being encrypted */
+{
+    int n;                       /* index in random header */
+    int t;                       /* temporary */
+    int c;                       /* random byte */
+    uch header[RAND_HEAD_LEN];   /* random header */
+    static unsigned calls = 0;   /* ensure different random header each time */
+
+    /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
+     * output of rand() to get less predictability, since rand() is
+     * often poorly implemented.
+     */
+    if (++calls == 1) {
+        srand((unsigned)time(NULL) ^ ZCR_SEED2);
+    }
+    init_keys(passwd);
+    for (n = 0; n < RAND_HEAD_LEN-2; n++) {
+        c = (rand() >> 7) & 0xff;
+        header[n] = (uch)zencode(c, t);
+    }
+    /* Encrypt random header (last two bytes is high word of crc) */
+    init_keys(passwd);
+    for (n = 0; n < RAND_HEAD_LEN-2; n++) {
+        header[n] = (uch)zencode(header[n], t);
+    }
+    header[RAND_HEAD_LEN-2] = (uch)zencode((int)(crc >> 16) & 0xff, t);
+    header[RAND_HEAD_LEN-1] = (uch)zencode((int)(crc >> 24) & 0xff, t);
+    bfwrite(header, 1, RAND_HEAD_LEN, BFWRITE_DATA);
+}
+
+
+#ifdef UTIL
+
+/***********************************************************************
+ * Encrypt the zip entry described by z from file in_file to file y
+ * using the password passwd.  Return an error code in the ZE_ class.
+ */
+int zipcloak(z, passwd)
+    struct zlist far *z;    /* zip entry to encrypt */
+    ZCONST char *passwd;    /* password string */
+{
+    int c;                  /* input byte */
+    int res;                /* result code */
+    zoff_t n;               /* holds offset and counts size */
+    int t;                  /* temporary */
+    struct zlist far *localz; /* local header */
+    uch buf[1024];          /* write buffer */
+    int b;                  /* bytes in buffer */
+
+    /* Set encrypted bit, clear extended local header bit and write local
+       header to output file */
+    if ((n = (zoff_t)zftello(y)) == (zoff_t)-1L) return ZE_TEMP;
+
+    /* assume this archive is one disk and the file is open */
+
+    /* read the local header */
+    res = readlocal(&localz, z);
+
+    /* update disk and offset */
+    z->dsk = 0;
+    z->off = n;
+
+    /* Set encryption and unset any extended local header */
+    z->flg |= 1,  z->flg &= ~8;
+    localz->lflg |= 1, localz->lflg &= ~8;
+
+    /* Add size of encryption header */
+    localz->siz += RAND_HEAD_LEN;
+    z->siz = localz->siz;
+
+    /* Put the local header */
+    if ((res = putlocal(localz, PUTLOCAL_WRITE)) != ZE_OK) return res;
+
+    /* Initialize keys with password and write random header */
+    crypthead(passwd, localz->crc);
+
+    /* Encrypt data */
+    b = 0;
+    for (n = z->siz - RAND_HEAD_LEN; n; n--) {
+      if ((c = getc(in_file)) == EOF) {
+          return ferror(in_file) ? ZE_READ : ZE_EOF;
+      }
+      buf[b] = (uch)zencode(c, t);
+      b++;
+      if (b >= 1024) {
+        /* write the buffer */
+        bfwrite(buf, 1, b, BFWRITE_DATA);
+        b = 0;
+      }
+    }
+    if (b) {
+      /* write the buffer */
+      bfwrite(buf, 1, b, BFWRITE_DATA);
+      b = 0;
+    }
+
+    /* Since we seek to the start of each local header can skip
+       reading any extended local header */
+    /*
+    if ((flag & 8) != 0 && zfseeko(in_file, 16L, SEEK_CUR)) {
+        return ferror(in_file) ? ZE_READ : ZE_EOF;
+    }
+    if (fflush(y) == EOF) return ZE_TEMP;
+    */
+
+    /* Update number of bytes written to output file */
+    tempzn += (4 + LOCHEAD) + localz->nam + localz->ext + localz->siz;
+
+    /* Free local header */
+    if (localz->ext) free(localz->extra);
+    if (localz->nam) free(localz->iname);
+    if (localz->nam) free(localz->name);
+#ifdef UNICODE_SUPPORT
+    if (localz->uname) free(localz->uname);
+#endif
+    free(localz);
+
+    return ZE_OK;
+}
+
+/***********************************************************************
+ * Decrypt the zip entry described by z from file in_file to file y
+ * using the password passwd.  Return an error code in the ZE_ class.
+ */
+int zipbare(z, passwd)
+    struct zlist far *z;  /* zip entry to encrypt */
+    ZCONST char *passwd;  /* password string */
+{
+#ifdef ZIP10
+    int c0                /* byte preceding the last input byte */
+#endif
+    int c1;               /* last input byte */
+    /* all file offset and size now zoff_t - 8/28/04 EG */
+    zoff_t size;          /* size of input data */
+    struct zlist far *localz; /* local header */
+    uch buf[1024];        /* write buffer */
+    int b;                /* bytes in buffer */
+    zoff_t n;
+    int r;                /* size of encryption header */
+    int res;              /* return code */
+
+    /* Save position */
+    if ((n = (zoff_t)zftello(y)) == (zoff_t)-1L) return ZE_TEMP;
+
+    /* Read local header */
+    res = readlocal(&localz, z);
+
+    /* Update disk and offset */
+    z->dsk = 0;
+    z->off = n;
+
+    /* Initialize keys with password */
+    init_keys(passwd);
+
+    /* Decrypt encryption header, save last two bytes */
+    c1 = 0;
+    for (r = RAND_HEAD_LEN; r; r--) {
+#ifdef ZIP10
+        c0 = c1;
+#endif
+        if ((c1 = getc(in_file)) == EOF) {
+            return ferror(in_file) ? ZE_READ : ZE_EOF;
+        }
+        Trace((stdout, " (%02x)", c1));
+        zdecode(c1);
+        Trace((stdout, " %02x", c1));
+    }
+    Trace((stdout, "\n"));
+
+    /* If last two bytes of header don't match crc (or file time in the
+     * case of an extended local header), back up and just copy. For
+     * pkzip 2.0, the check has been reduced to one byte only.
+     */
+#ifdef ZIP10
+    if ((ush)(c0 | (c1<<8)) !=
+        (z->flg & 8 ? (ush) z->tim & 0xffff : (ush)(z->crc >> 16))) {
+#else
+    if ((ush)c1 != (z->flg & 8 ? (ush) z->tim >> 8 : (ush)(z->crc >> 24))) {
+#endif
+        if (zfseeko(in_file, n, SEEK_SET)) {
+            return ferror(in_file) ? ZE_READ : ZE_EOF;
+        }
+        if ((res = zipcopy(z)) != ZE_OK) {
+            ziperr(res, "was copying an entry");
+        }
+        return ZE_MISS;
+    }
+
+    z->siz -= RAND_HEAD_LEN;
+    localz->siz = z->siz;
+
+    localz->flg = z->flg &= ~9;
+    z->lflg = localz->lflg &= ~9;
+
+    if ((res = putlocal(localz, PUTLOCAL_WRITE)) != ZE_OK) return res;
+
+    /* Decrypt data */
+    b = 0;
+    for (size = z->siz; size; size--) {
+        if ((c1 = getc(in_file)) == EOF) {
+            return ferror(in_file) ? ZE_READ : ZE_EOF;
+        }
+        zdecode(c1);
+        buf[b] = c1;
+        b++;
+        if (b >= 1024) {
+          /* write the buffer */
+          bfwrite(buf, 1, b, BFWRITE_DATA);
+          b = 0;
+        }
+    }
+    if (b) {
+      /* write the buffer */
+      bfwrite(buf, 1, b, BFWRITE_DATA);
+      b = 0;
+    }
+    /* Since we seek to the start of each local header can skip
+         reading any extended local header */
+
+    /* Update number of bytes written to output file */
+    tempzn += (4 + LOCHEAD) + localz->nam + localz->ext + localz->siz;
+
+    /* Free local header */
+    if (localz->ext) free(localz->extra);
+    if (localz->nam) free(localz->iname);
+    if (localz->nam) free(localz->name);
+#ifdef UNICODE_SUPPORT
+    if (localz->uname) free(localz->uname);
+#endif
+    free(localz);
+
+    return ZE_OK;
+}
+
+
+#else /* !UTIL */
+
+/***********************************************************************
+ * If requested, encrypt the data in buf, and in any case call fwrite()
+ * with the arguments to zfwrite().  Return what fwrite() returns.
+ *
+ * now write to global y
+ *
+ * A bug has been found when encrypting large files that don't
+ * compress.  See trees.c for the details and the fix.
+ */
+unsigned zfwrite(buf, item_size, nb)
+    zvoid *buf;                 /* data buffer */
+    extent item_size;           /* size of each item in bytes */
+    extent nb;                  /* number of items */
+#if 0
+    FILE *f;                    /* file to write to */
+#endif
+{
+    int t;                      /* temporary */
+
+    if (key != (char *)NULL) {  /* key is the global password pointer */
+        ulg size;               /* buffer size */
+        char *p = (char *)buf;  /* steps through buffer */
+
+        /* Encrypt data in buffer */
+        for (size = item_size*(ulg)nb; size != 0; p++, size--) {
+            *p = (char)zencode(*p, t);
+        }
+    }
+    /* Write the buffer out */
+    return bfwrite(buf, item_size, nb, BFWRITE_DATA);
+}
+
+#endif /* ?UTIL */
+#endif /* ZIP */
+
+
+#if (defined(UNZIP) && !defined(FUNZIP))
+
+/***********************************************************************
+ * Get the password and set up keys for current zipfile member.
+ * Return PK_ class error.
+ */
+int decrypt(__G__ passwrd)
+    __GDEF
+    ZCONST char *passwrd;
+{
+    ush b;
+    int n, r;
+    uch h[RAND_HEAD_LEN];
+
+    Trace((stdout, "\n[incnt = %d]: ", GLOBAL(incnt)));
+
+    /* get header once (turn off "encrypted" flag temporarily so we don't
+     * try to decrypt the same data twice) */
+    GLOBAL(pInfo->encrypted) = FALSE;
+    defer_leftover_input(__G);
+    for (n = 0; n < RAND_HEAD_LEN; n++) {
+        b = NEXTBYTE;
+        h[n] = (uch)b;
+        Trace((stdout, " (%02x)", h[n]));
+    }
+    undefer_input(__G);
+    GLOBAL(pInfo->encrypted) = TRUE;
+
+    if (GLOBAL(newzip)) { /* this is first encrypted member in this zipfile */
+        GLOBAL(newzip) = FALSE;
+        if (passwrd != (char *)NULL) { /* user gave password on command line */
+            if (!GLOBAL(key)) {
+                if ((GLOBAL(key) = (char *)malloc(strlen(passwrd)+1)) ==
+                    (char *)NULL)
+                    return PK_MEM2;
+                strcpy(GLOBAL(key), passwrd);
+                GLOBAL(nopwd) = TRUE;  /* inhibit password prompting! */
+            }
+        } else if (GLOBAL(key)) { /* get rid of previous zipfile's key */
+            free(GLOBAL(key));
+            GLOBAL(key) = (char *)NULL;
+        }
+    }
+
+    /* if have key already, test it; else allocate memory for it */
+    if (GLOBAL(key)) {
+        if (!testp(__G__ h))
+            return PK_COOL;   /* existing password OK (else prompt for new) */
+        else if (GLOBAL(nopwd))
+            return PK_WARN;   /* user indicated no more prompting */
+    } else if ((GLOBAL(key) = (char *)malloc(IZ_PWLEN+1)) == (char *)NULL)
+        return PK_MEM2;
+
+    /* try a few keys */
+    n = 0;
+    do {
+        r = (*G.decr_passwd)((zvoid *)&G, &n, GLOBAL(key), IZ_PWLEN+1,
+                             GLOBAL(zipfn), GLOBAL(filename));
+        if (r == IZ_PW_ERROR) {         /* internal error in fetch of PW */
+            free (GLOBAL(key));
+            GLOBAL(key) = NULL;
+            return PK_MEM2;
+        }
+        if (r != IZ_PW_ENTERED) {       /* user replied "skip" or "skip all" */
+            *GLOBAL(key) = '\0';        /*   We try the NIL password, ... */
+            n = 0;                      /*   and cancel fetch for this item. */
+        }
+        if (!testp(__G__ h))
+            return PK_COOL;
+        if (r == IZ_PW_CANCELALL)       /* User replied "Skip all" */
+            GLOBAL(nopwd) = TRUE;       /*   inhibit any further PW prompt! */
+    } while (n > 0);
+
+    return PK_WARN;
+
+} /* end function decrypt() */
+
+
+
+/***********************************************************************
+ * Test the password.  Return -1 if bad, 0 if OK.
+ */
+local int testp(__G__ h)
+    __GDEF
+    ZCONST uch *h;
+{
+    int r;
+    char *key_translated;
+
+    /* On systems with "obscure" native character coding (e.g., EBCDIC),
+     * the first test translates the password to the "main standard"
+     * character coding. */
+
+#ifdef STR_TO_CP1
+    /* allocate buffer for translated password */
+    if ((key_translated = malloc(strlen(GLOBAL(key)) + 1)) == (char *)NULL)
+        return -1;
+    /* first try, test password translated "standard" charset */
+    r = testkey(__G__ h, STR_TO_CP1(key_translated, GLOBAL(key)));
+#else /* !STR_TO_CP1 */
+    /* first try, test password as supplied on the extractor's host */
+    r = testkey(__G__ h, GLOBAL(key));
+#endif /* ?STR_TO_CP1 */
+
+#ifdef STR_TO_CP2
+    if (r != 0) {
+#ifndef STR_TO_CP1
+        /* now prepare for second (and maybe third) test with translated pwd */
+        if ((key_translated = malloc(strlen(GLOBAL(key)) + 1)) == (char *)NULL)
+            return -1;
+#endif
+        /* second try, password translated to alternate ("standard") charset */
+        r = testkey(__G__ h, STR_TO_CP2(key_translated, GLOBAL(key)));
+#ifdef STR_TO_CP3
+        if (r != 0)
+            /* third try, password translated to another "standard" charset */
+            r = testkey(__G__ h, STR_TO_CP3(key_translated, GLOBAL(key)));
+#endif
+#ifndef STR_TO_CP1
+        free(key_translated);
+#endif
+    }
+#endif /* STR_TO_CP2 */
+
+#ifdef STR_TO_CP1
+    free(key_translated);
+    if (r != 0) {
+        /* last resort, test password as supplied on the extractor's host */
+        r = testkey(__G__ h, GLOBAL(key));
+    }
+#endif /* STR_TO_CP1 */
+
+    return r;
+
+} /* end function testp() */
+
+
+local int testkey(__G__ h, key)
+    __GDEF
+    ZCONST uch *h;      /* decrypted header */
+    ZCONST char *key;   /* decryption password to test */
+{
+    ush b;
+#ifdef ZIP10
+    ush c;
+#endif
+    int n;
+    uch *p;
+    uch hh[RAND_HEAD_LEN]; /* decrypted header */
+
+    /* set keys and save the encrypted header */
+    init_keys(__G__ key);
+    memcpy(hh, h, RAND_HEAD_LEN);
+
+    /* check password */
+    for (n = 0; n < RAND_HEAD_LEN; n++) {
+        zdecode(hh[n]);
+        Trace((stdout, " %02x", hh[n]));
+    }
+
+    /* use fzofft to format zoff_t as strings - 10/19/04 from SMS */
+    Trace((stdout,
+      "\n  lrec.crc= %08lx  crec.crc= %08lx  pInfo->ExtLocHdr= %s\n",
+      GLOBAL(lrec.crc32), GLOBAL(pInfo->crc),
+      GLOBAL(pInfo->ExtLocHdr) ? "true":"false"));
+    Trace((stdout, "  incnt = %d  unzip offset into zipfile = %s\n",
+      GLOBAL(incnt),
+      fzofft(GLOBAL(cur_zipfile_bufstart)+(GLOBAL(inptr)-GLOBAL(inbuf)),
+             NULL, NULL)));
+
+    /* same test as in zipbare(): */
+
+#ifdef ZIP10 /* check two bytes */
+    c = hh[RAND_HEAD_LEN-2], b = hh[RAND_HEAD_LEN-1];
+    Trace((stdout,
+      "  (c | (b<<8)) = %04x  (crc >> 16) = %04x  lrec.time = %04x\n",
+      (ush)(c | (b<<8)), (ush)(GLOBAL(lrec.crc32) >> 16),
+      ((ush)GLOBAL(lrec.last_mod_dos_datetime) & 0xffff))));
+    if ((ush)(c | (b<<8)) != (GLOBAL(pInfo->ExtLocHdr) ?
+                           ((ush)GLOBAL(lrec.last_mod_dos_datetime) & 0xffff) :
+                           (ush)(GLOBAL(lrec.crc32) >> 16)))
+        return -1;  /* bad */
+#else
+    b = hh[RAND_HEAD_LEN-1];
+    Trace((stdout, "  b = %02x  (crc >> 24) = %02x  (lrec.time >> 8) = %02x\n",
+      b, (ush)(GLOBAL(lrec.crc32) >> 24),
+      ((ush)GLOBAL(lrec.last_mod_dos_datetime) >> 8) & 0xff));
+    if (b != (GLOBAL(pInfo->ExtLocHdr) ?
+        ((ush)GLOBAL(lrec.last_mod_dos_datetime) >> 8) & 0xff :
+        (ush)(GLOBAL(lrec.crc32) >> 24)))
+        return -1;  /* bad */
+#endif
+    /* password OK:  decrypt current buffer contents before leaving */
+    for (n = (zoff_t)GLOBAL(incnt) > GLOBAL(csize) ?
+             (int)GLOBAL(csize) : GLOBAL(incnt),
+         p = GLOBAL(inptr); n--; p++)
+        zdecode(*p);
+    return 0;       /* OK */
+
+} /* end function testkey() */
+
+#endif /* UNZIP && !FUNZIP */
+
+#else /* !CRYPT */
+
+/* something "externally visible" to shut up compiler/linker warnings */
+int zcr_dummy;
+
+#endif /* ?CRYPT */
diff --git a/crypt.h b/crypt.h
new file mode 100644 (file)
index 0000000..61f3234
--- /dev/null
+++ b/crypt.h
@@ -0,0 +1,169 @@
+/*
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+  crypt.h (full version) by Info-ZIP.   Last revised:  [see CR_VERSION_DATE]
+
+  The main encryption/decryption source code for Info-Zip software was
+  originally written in Europe.  To the best of our knowledge, it can
+  be freely distributed in both source and object forms from any country,
+  including the USA under License Exception TSU of the U.S. Export
+  Administration Regulations (section 740.13(e)) of 6 June 2002.
+
+  NOTE on copyright history:
+  Previous versions of this source package (up to version 2.8) were
+  not copyrighted and put in the public domain.  If you cannot comply
+  with the Info-Zip LICENSE, you may want to look for one of those
+  public domain versions.
+ */
+
+#ifndef __crypt_h   /* don't include more than once */
+#define __crypt_h
+
+#ifdef CRYPT
+#  undef CRYPT
+#endif
+/*
+   Logic of selecting "full crypt" code:
+   a) default behaviour:
+      - dummy crypt code when compiling UnZipSFX stub, to minimize size
+      - full crypt code when used to compile Zip, UnZip and fUnZip
+   b) USE_CRYPT defined:
+      - always full crypt code
+   c) NO_CRYPT defined:
+      - never full crypt code
+   NO_CRYPT takes precedence over USE_CRYPT
+ */
+#if defined(NO_CRYPT)
+#  define CRYPT  0  /* dummy version */
+#else
+#if defined(USE_CRYPT)
+#  define CRYPT  1  /* full version */
+#else
+#if !defined(SFX)
+#  define CRYPT  1  /* full version for zip and main unzip */
+#else
+#  define CRYPT  0  /* dummy version for unzip sfx */
+#endif
+#endif /* ?USE_CRYPT */
+#endif /* ?NO_CRYPT */
+
+#if CRYPT
+/* full version */
+
+#ifdef CR_BETA
+#  undef CR_BETA    /* this is not a beta release */
+#endif
+
+#define CR_MAJORVER        2
+#define CR_MINORVER        91
+#ifdef CR_BETA
+#  define CR_BETA_VER      "c BETA"
+#  define CR_VERSION_DATE  "05 Jan 2007"       /* last real code change */
+#else
+#  define CR_BETA_VER      ""
+#  define CR_VERSION_DATE  "05 Jan 2007"       /* last public release date */
+#  define CR_RELEASE
+#endif
+
+#ifndef __G         /* UnZip only, for now (DLL stuff) */
+#  define __G
+#  define __G__
+#  define __GDEF
+#  define __GPRO    void
+#  define __GPRO__
+#endif
+
+#if defined(MSDOS) || defined(OS2) || defined(WIN32)
+#  ifndef DOS_OS2_W32
+#    define DOS_OS2_W32
+#  endif
+#endif
+
+#if defined(DOS_OS2_W32) || defined(__human68k__)
+#  ifndef DOS_H68_OS2_W32
+#    define DOS_H68_OS2_W32
+#  endif
+#endif
+
+#if defined(VM_CMS) || defined(MVS)
+#  ifndef CMS_MVS
+#    define CMS_MVS
+#  endif
+#endif
+
+/* To allow combining of Zip and UnZip static libraries in a single binary,
+ * the Zip and UnZip versions of the crypt core functions have to be named
+ * differently.
+ */
+#ifdef ZIP
+#  ifdef REALLY_SHORT_SYMS
+#    define decrypt_byte   zdcrby
+#  else
+#    define decrypt_byte   zp_decrypt_byte
+#  endif
+#  define  update_keys     zp_update_keys
+#  define  init_keys       zp_init_keys
+#else /* !ZIP */
+#  ifdef REALLY_SHORT_SYMS
+#    define decrypt_byte   dcrbyt
+#  endif
+#endif /* ?ZIP */
+
+#define IZ_PWLEN  80    /* input buffer size for reading encryption key */
+#ifndef PWLEN           /* for compatibility with previous zcrypt release... */
+#  define PWLEN IZ_PWLEN
+#endif
+#define RAND_HEAD_LEN  12       /* length of encryption random header */
+
+/* the crc_32_tab array has to be provided externally for the crypt calculus */
+
+/* encode byte c, using temp t.  Warning: c must not have side effects. */
+#define zencode(c,t)  (t=decrypt_byte(__G), update_keys(c), t^(c))
+
+/* decode byte c in place */
+#define zdecode(c)   update_keys(__G__ c ^= decrypt_byte(__G))
+
+int  decrypt_byte OF((__GPRO));
+int  update_keys OF((__GPRO__ int c));
+void init_keys OF((__GPRO__ ZCONST char *passwd));
+
+#ifdef ZIP
+   void crypthead OF((ZCONST char *, ulg));
+#  ifdef UTIL
+     int zipcloak OF((struct zlist far *, ZCONST char *));
+     int zipbare OF((struct zlist far *, ZCONST char *));
+#  else
+     unsigned zfwrite OF((zvoid *, extent, extent));
+     extern char *key;
+#  endif
+#endif /* ZIP */
+
+#if (defined(UNZIP) && !defined(FUNZIP))
+   int  decrypt OF((__GPRO__ ZCONST char *passwrd));
+#endif
+
+#ifdef FUNZIP
+   extern int encrypted;
+#  ifdef NEXTBYTE
+#    undef NEXTBYTE
+#  endif
+#  define NEXTBYTE \
+   (encrypted? update_keys(__G__ getc(G.in)^decrypt_byte(__G)) : getc(G.in))
+#endif /* FUNZIP */
+
+#else /* !CRYPT */
+/* dummy version */
+
+#define zencode
+#define zdecode
+
+#define zfwrite(b,s,c) bfwrite(b,s,c,BFWRITE_DATA)
+
+#endif /* ?CRYPT */
+#endif /* !__crypt_h */
diff --git a/deflate.c b/deflate.c
new file mode 100644 (file)
index 0000000..c830854
--- /dev/null
+++ b/deflate.c
@@ -0,0 +1,929 @@
+/*
+  deflate.c - Zip 3
+
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2005-Feb-10 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  deflate.c by Jean-loup Gailly.
+ *
+ *  PURPOSE
+ *
+ *      Identify new text as repetitions of old text within a fixed-
+ *      length sliding window trailing behind the new text.
+ *
+ *  DISCUSSION
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many info-zippers for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      APPNOTE.TXT documentation file in PKZIP 1.93a distribution.
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ *  INTERFACE
+ *
+ *      void lm_init (int pack_level, ush *flags)
+ *          Initialize the "longest match" routines for a new file
+ *
+ *      ulg deflate (void)
+ *          Processes a new input file and return its compressed length. Sets
+ *          the compressed length, crc, deflate flags and internal file
+ *          attributes.
+ */
+
+#define __DEFLATE_C
+
+#include "zip.h"
+
+#ifndef USE_ZLIB
+
+/* ===========================================================================
+ * Configuration parameters
+ */
+
+/* Compile with MEDIUM_MEM to reduce the memory requirements or
+ * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
+ * entire input file can be held in memory (not possible on 16 bit systems).
+ * Warning: defining these symbols affects HASH_BITS (see below) and thus
+ * affects the compression ratio. The compressed output
+ * is still correct, and might even be smaller in some cases.
+ */
+
+#ifdef SMALL_MEM
+#   define HASH_BITS  13  /* Number of bits used to hash strings */
+#endif
+#ifdef MEDIUM_MEM
+#   define HASH_BITS  14
+#endif
+#ifndef HASH_BITS
+#   define HASH_BITS  15
+   /* For portability to 16 bit machines, do not use values above 15. */
+#endif
+
+#define HASH_SIZE (unsigned)(1<<HASH_BITS)
+#define HASH_MASK (HASH_SIZE-1)
+#define WMASK     (WSIZE-1)
+/* HASH_SIZE and WSIZE must be powers of two */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#define FAST 4
+#define SLOW 2
+/* speed options for the general purpose bit flag */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#if (defined(ASMV) && !defined(MSDOS16) && defined(DYN_ALLOC))
+   error: DYN_ALLOC not yet supported in match.S or match32.asm
+#endif
+
+#ifdef MEMORY16
+#  define MAXSEG_64K
+#endif
+
+/* ===========================================================================
+ * Local data used by the "longest match" routines.
+ */
+
+#if defined(MMAP) || defined(BIG_MEM)
+  typedef unsigned Pos; /* must be at least 32 bits */
+#else
+  typedef ush Pos;
+#endif
+typedef unsigned IPos;
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+#ifndef DYN_ALLOC
+  uch    window[2L*WSIZE];
+  /* Sliding window. Input bytes are read into the second half of the window,
+   * and move to the first half later to keep a dictionary of at least WSIZE
+   * bytes. With this organization, matches are limited to a distance of
+   * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
+   * performed with a length multiple of the block size. Also, it limits
+   * the window size to 64K, which is quite useful on MSDOS.
+   * To do: limit the window size to WSIZE+CBSZ if SMALL_MEM (the code would
+   * be less efficient since the data would have to be copied WSIZE/CBSZ times)
+   */
+  Pos    prev[WSIZE];
+  /* Link to older string with same hash index. To limit the size of this
+   * array to 64K, this link is maintained only for the last 32K strings.
+   * An index in this array is thus a window index modulo 32K.
+   */
+  Pos    head[HASH_SIZE];
+  /* Heads of the hash chains or NIL. If your compiler thinks that
+   * HASH_SIZE is a dynamic value, recompile with -DDYN_ALLOC.
+   */
+#else
+  uch far * near window = NULL;
+  Pos far * near prev   = NULL;
+  Pos far * near head;
+#endif
+ulg window_size;
+/* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
+ * input file length plus MIN_LOOKAHEAD.
+ */
+
+long block_start;
+/* window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+local int sliding;
+/* Set to false when the input file is already in memory */
+
+local unsigned ins_h;  /* hash index of string to be inserted */
+
+#define H_SHIFT  ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
+/* Number of bits by which ins_h and del_h must be shifted at each
+ * input step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ *   H_SHIFT * MIN_MATCH >= HASH_BITS
+ */
+
+unsigned int near prev_length;
+/* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+      unsigned near strstart;      /* start of string to insert */
+      unsigned near match_start;   /* start of matching string */
+local int           eofile;        /* flag set at end of input file */
+local unsigned      lookahead;     /* number of valid bytes ahead in window */
+
+unsigned near max_chain_length;
+/* To speed up deflation, hash chains are never searched beyond this length.
+ * A higher limit improves compression ratio but degrades the speed.
+ */
+
+local unsigned int max_lazy_match;
+/* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+#define max_insert_length  max_lazy_match
+/* Insert new strings in the hash table only if the match length
+ * is not greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+unsigned near good_match;
+/* Use a faster search when the previous match is longer than this */
+
+#ifdef  FULL_SEARCH
+# define nice_match MAX_MATCH
+#else
+  int near nice_match; /* Stop searching when current match exceeds this */
+#endif
+
+
+/* Values for max_lazy_match, good_match, nice_match and max_chain_length,
+ * depending on the desired pack level (0..9). The values given below have
+ * been tuned to exclude worst case performance for pathological files.
+ * Better values may be found for specific files.
+ */
+
+typedef struct config {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+} config;
+
+local config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0},  /* store only */
+/* 1 */ {4,    4,  8,    4},  /* maximum speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8},
+/* 3 */ {4,    6, 32,   32},
+
+/* 4 */ {4,    4, 16,   16},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32},
+/* 6 */ {8,   16, 128, 128},
+/* 7 */ {8,   32, 128, 256},
+/* 8 */ {32, 128, 258, 1024},
+/* 9 */ {32, 258, 258, 4096}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+/* ===========================================================================
+ *  Prototypes for local functions.
+ */
+
+local void fill_window   OF((void));
+
+local uzoff_t deflate_fast OF((void));    /* now use uzoff_t 7/24/04 EG */
+
+      int  longest_match OF((IPos cur_match));
+#if defined(ASMV) && !defined(RISCOS)
+      void match_init OF((void)); /* asm code initialization */
+#endif
+
+#ifdef DEBUG
+local  void check_match OF((IPos start, IPos match, int length));
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
+
+/* ===========================================================================
+ * Insert string s in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of s are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, match_head) \
+   (UPDATE_HASH(ins_h, window[(s) + (MIN_MATCH-1)]), \
+    prev[(s) & WMASK] = match_head = head[ins_h], \
+    head[ins_h] = (s))
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new file
+ *
+ * IN assertion: window_size is > 0 if the input file is already read or
+ *    mmap'ed in the window[] array, 0 otherwise. In the first case,
+ *    window_size is sufficient to contain the whole input file plus
+ *    MIN_LOOKAHEAD bytes (to avoid referencing memory beyond the end
+ *    of window[] when looking for matches towards the end).
+ */
+void lm_init (pack_level, flags)
+    int pack_level; /* 0: store, 1: best speed, 9: best compression */
+    ush *flags;     /* general purpose bit flag */
+{
+    register unsigned j;
+
+    if (pack_level < 1 || pack_level > 9) error("bad pack level");
+
+    /* Do not slide the window if the whole input is already in memory
+     * (window_size > 0)
+     */
+    sliding = 0;
+    if (window_size == 0L) {
+        sliding = 1;
+        window_size = (ulg)2L*WSIZE;
+    }
+
+    /* Use dynamic allocation if compiler does not like big static arrays: */
+#ifdef DYN_ALLOC
+    if (window == NULL) {
+        window = (uch far *) zcalloc(WSIZE,   2*sizeof(uch));
+        if (window == NULL) ziperr(ZE_MEM, "window allocation");
+    }
+    if (prev == NULL) {
+        prev   = (Pos far *) zcalloc(WSIZE,     sizeof(Pos));
+        head   = (Pos far *) zcalloc(HASH_SIZE, sizeof(Pos));
+        if (prev == NULL || head == NULL) {
+            ziperr(ZE_MEM, "hash table allocation");
+        }
+    }
+#endif /* DYN_ALLOC */
+
+    /* Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+     * prev[] will be initialized on the fly.
+     */
+    head[HASH_SIZE-1] = NIL;
+    memset((char*)head, NIL, (unsigned)(HASH_SIZE-1)*sizeof(*head));
+
+    /* Set the default configuration parameters:
+     */
+    max_lazy_match   = configuration_table[pack_level].max_lazy;
+    good_match       = configuration_table[pack_level].good_length;
+#ifndef FULL_SEARCH
+    nice_match       = configuration_table[pack_level].nice_length;
+#endif
+    max_chain_length = configuration_table[pack_level].max_chain;
+    if (pack_level <= 2) {
+       *flags |= FAST;
+    } else if (pack_level >= 8) {
+       *flags |= SLOW;
+    }
+    /* ??? reduce max_chain_length for binary files */
+
+    strstart = 0;
+    block_start = 0L;
+#if defined(ASMV) && !defined(RISCOS)
+    match_init(); /* initialize the asm code */
+#endif
+
+    j = WSIZE;
+#ifndef MAXSEG_64K
+    if (sizeof(int) > 2) j <<= 1; /* Can read 64K in one step */
+#endif
+    lookahead = (*read_buf)((char*)window, j);
+
+    if (lookahead == 0 || lookahead == (unsigned)EOF) {
+       eofile = 1, lookahead = 0;
+       return;
+    }
+    eofile = 0;
+    /* Make sure that we always have enough lookahead. This is important
+     * if input comes from a device such as a tty.
+     */
+    if (lookahead < MIN_LOOKAHEAD) fill_window();
+
+    ins_h = 0;
+    for (j=0; j<MIN_MATCH-1; j++) UPDATE_HASH(ins_h, window[j]);
+    /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
+     * not important since only literal bytes will be emitted.
+     */
+}
+
+/* ===========================================================================
+ * Free the window and hash table
+ */
+void lm_free()
+{
+#ifdef DYN_ALLOC
+    if (window != NULL) {
+        zcfree(window);
+        window = NULL;
+    }
+    if (prev != NULL) {
+        zcfree(prev);
+        zcfree(head);
+        prev = head = NULL;
+    }
+#endif /* DYN_ALLOC */
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0 and ARM, an optimized version is in match.asm or
+ * match.S. The code is functionally equivalent, so you can use the C version
+ * if desired.
+ */
+int longest_match(cur_match)
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = max_chain_length;   /* max hash chain length */
+    register uch far *scan = window + strstart; /* current string */
+    register uch far *match;                    /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = prev_length;                 /* best match length so far */
+    IPos limit = strstart > (IPos)MAX_DIST ? strstart - (IPos)MAX_DIST : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+
+/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+#if HASH_BITS < 8 || MAX_MATCH != 258
+   error: Code too clever
+#endif
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register uch far *strend = window + strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ush far *)scan;
+    register ush scan_end   = *(ush far *)(scan+best_len-1);
+#else
+    register uch far *strend = window + strstart + MAX_MATCH;
+    register uch scan_end1  = scan[best_len-1];
+    register uch scan_end   = scan[best_len];
+#endif
+
+    /* Do not waste too much time if we already have a good match: */
+    if (prev_length >= good_match) {
+        chain_length >>= 2;
+    }
+
+    Assert(strstart <= window_size-MIN_LOOKAHEAD, "insufficient lookahead");
+
+    do {
+        Assert(cur_match < strstart, "no future");
+        match = window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2:
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ush far *)(match+best_len-1) != scan_end ||
+            *(ush far *)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        scan++, match++;
+        do {
+        } while (*(ush far *)(scan+=2) == *(ush far *)(match+=2) &&
+                 *(ush far *)(scan+=2) == *(ush far *)(match+=2) &&
+                 *(ush far *)(scan+=2) == *(ush far *)(match+=2) &&
+                 *(ush far *)(scan+=2) == *(ush far *)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= window+(unsigned)(window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= window+(unsigned)(window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ush far *)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & WMASK]) > limit
+             && --chain_length != 0);
+
+    return best_len;
+}
+#endif /* ASMV */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(start, match, length)
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (memcmp((char*)window + match,
+                (char*)window + start, length) != EQUAL) {
+        fprintf(mesg,
+            " start %d, match %d, length %d\n",
+            start, match, length);
+        error("invalid match");
+    }
+    if (verbose > 1) {
+        fprintf(mesg,"\\[%d,%d]", start-match, length);
+#ifndef WINDLL
+        do { putc(window[start++], mesg); } while (--length != 0);
+#else
+        do { fprintf(stdout,"%c",window[start++]); } while (--length != 0);
+#endif
+    }
+}
+#else
+#  define check_match(start, match, length)
+#endif
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK(eof) \
+   flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
+                (char*)NULL, (ulg)strstart - (ulg)block_start, (eof))
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead, and sets eofile if end of input file.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or eofile is set; file reads are
+ *    performed for at least two bytes (required for the translate_eol option).
+ */
+local void fill_window()
+{
+    register unsigned n, m;
+    unsigned more;    /* Amount of free space at the end of the window. */
+
+    do {
+        more = (unsigned)(window_size - (ulg)lookahead - (ulg)strstart);
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        if (more == (unsigned)EOF) {
+            /* Very unlikely, but possible on 16 bit machine if strstart == 0
+             * and lookahead == 1 (input done one byte at time)
+             */
+            more--;
+
+        /* For MMAP or BIG_MEM, the whole input file is already in memory so
+         * we must not perform sliding. We must however call (*read_buf)() in
+         * order to compute the crc, update lookahead and possibly set eofile.
+         */
+        } else if (strstart >= WSIZE+MAX_DIST && sliding) {
+
+#ifdef FORCE_METHOD
+            /* When methods "stored" or "store_block" are requested, the
+             * current block must be flushed before sliding the window.
+             */
+            if (level <= 2) FLUSH_BLOCK(0), block_start = strstart;
+#endif
+            /* By the IN assertion, the window is not empty so we can't confuse
+             * more == 0 with more == 64K on a 16 bit machine.
+             */
+            memcpy((char*)window, (char*)window+WSIZE, (unsigned)WSIZE);
+            match_start -= WSIZE;
+            strstart    -= WSIZE; /* we now have strstart >= MAX_DIST: */
+
+            block_start -= (long) WSIZE;
+
+            for (n = 0; n < HASH_SIZE; n++) {
+                m = head[n];
+                head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
+            }
+            for (n = 0; n < WSIZE; n++) {
+                m = prev[n];
+                prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
+                /* If n is not on any hash chain, prev[n] is garbage but
+                 * its value will never be used.
+                 */
+            }
+            more += WSIZE;
+            if (dot_size > 0 && !display_globaldots) {
+              /* initial space */
+              if (noisy && dot_count == -1) {
+#ifndef WINDLL
+                putc(' ', mesg);
+                fflush(mesg);
+#else
+                fprintf(stdout,"%c",' ');
+#endif
+                dot_count++;
+              }
+              dot_count++;
+              if (dot_size <= (dot_count + 1) * WSIZE) dot_count = 0;
+            }
+            if ((verbose || noisy) && dot_size && !dot_count) {
+#ifndef WINDLL
+              putc('.', mesg);
+              fflush(mesg);
+#else
+              fprintf(stdout,"%c",'.');
+#endif
+              mesg_line_started = 1;
+            }
+        }
+        if (eofile) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the MMAP or BIG_MEM case (not yet supported in gzip),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = (*read_buf)((char*)window+strstart+lookahead, more);
+        if (n == 0 || n == (unsigned)EOF) {
+            eofile = 1;
+        } else {
+            lookahead += n;
+        }
+    } while (lookahead < MIN_LOOKAHEAD && !eofile);
+}
+
+/* ===========================================================================
+ * Processes a new input file and return its compressed length. This
+ * function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local uzoff_t deflate_fast()
+{
+    IPos hash_head = NIL;       /* head of the hash chain */
+    int flush;                  /* set if current block must be flushed */
+    unsigned match_length = 0;  /* length of best match */
+
+    prev_length = MIN_MATCH-1;
+    while (lookahead != 0) {
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+#ifndef DEFL_UNDETERM
+        if (lookahead >= MIN_MATCH)
+#endif
+        INSERT_STRING(strstart, hash_head);
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && strstart - hash_head <= MAX_DIST) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+#ifndef HUFFMAN_ONLY
+#  ifndef DEFL_UNDETERM
+            /* Do not look for matches beyond the end of the input.
+             * This is necessary to make deflate deterministic.
+             */
+            if ((unsigned)nice_match > lookahead) nice_match = (int)lookahead;
+#  endif
+            match_length = longest_match (hash_head);
+            /* longest_match() sets match_start */
+            if (match_length > lookahead) match_length = lookahead;
+#endif
+        }
+        if (match_length >= MIN_MATCH) {
+            check_match(strstart, match_start, match_length);
+
+            flush = ct_tally(strstart-match_start, match_length - MIN_MATCH);
+
+            lookahead -= match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+            if (match_length <= max_insert_length
+#ifndef DEFL_UNDETERM
+                && lookahead >= MIN_MATCH
+#endif
+                                                 ) {
+                match_length--; /* string at strstart already in hash table */
+                do {
+                    strstart++;
+                    INSERT_STRING(strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+#ifdef DEFL_UNDETERM
+                    /* If lookahead < MIN_MATCH these bytes are garbage,
+                     * but it does not matter since the next lookahead bytes
+                     * will be emitted as literals.
+                     */
+#endif
+                } while (--match_length != 0);
+                strstart++;
+            } else {
+                strstart += match_length;
+                match_length = 0;
+                ins_h = window[strstart];
+                UPDATE_HASH(ins_h, window[strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c",window[strstart]));
+            flush = ct_tally (0, window[strstart]);
+            lookahead--;
+            strstart++;
+        }
+        if (flush) FLUSH_BLOCK(0), block_start = strstart;
+
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (lookahead < MIN_LOOKAHEAD) fill_window();
+    }
+    return FLUSH_BLOCK(1); /* eof */
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+uzoff_t deflate()
+{
+    IPos hash_head = NIL;       /* head of hash chain */
+    IPos prev_match;            /* previous match */
+    int flush;                  /* set if current block must be flushed */
+    int match_available = 0;    /* set if previous match exists */
+    register unsigned match_length = MIN_MATCH-1; /* length of best match */
+#ifdef DEBUG
+    extern uzoff_t isize;       /* byte length of input file, for debug only */
+#endif
+
+    if (level <= 3) return deflate_fast(); /* optimized for speed */
+
+    /* Process the input block. */
+    while (lookahead != 0) {
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+#ifndef DEFL_UNDETERM
+        if (lookahead >= MIN_MATCH)
+#endif
+        INSERT_STRING(strstart, hash_head);
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        prev_length = match_length, prev_match = match_start;
+        match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && prev_length < max_lazy_match &&
+            strstart - hash_head <= MAX_DIST) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+#ifndef HUFFMAN_ONLY
+#  ifndef DEFL_UNDETERM
+            /* Do not look for matches beyond the end of the input.
+             * This is necessary to make deflate deterministic.
+             */
+            if ((unsigned)nice_match > lookahead) nice_match = (int)lookahead;
+#  endif
+            match_length = longest_match (hash_head);
+            /* longest_match() sets match_start */
+            if (match_length > lookahead) match_length = lookahead;
+#endif
+
+#ifdef FILTERED
+            /* Ignore matches of length <= 5 */
+            if (match_length <= 5) {
+#else
+            /* Ignore a length 3 match if it is too distant: */
+            if (match_length == MIN_MATCH && strstart-match_start > TOO_FAR){
+#endif
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (prev_length >= MIN_MATCH && match_length <= prev_length) {
+#ifndef DEFL_UNDETERM
+            unsigned max_insert = strstart + lookahead - MIN_MATCH;
+
+#endif
+            check_match(strstart-1, prev_match, prev_length);
+
+            flush = ct_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted.
+             */
+            lookahead -= prev_length-1;
+            prev_length -= 2;
+#ifndef DEFL_UNDETERM
+            do {
+                if (++strstart <= max_insert) {
+                    INSERT_STRING(strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                }
+            } while (--prev_length != 0);
+            strstart++;
+#else /* DEFL_UNDETERM */
+            do {
+                strstart++;
+                INSERT_STRING(strstart, hash_head);
+                /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                 * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+                 * these bytes are garbage, but it does not matter since the
+                 * next lookahead bytes will always be emitted as literals.
+                 */
+            } while (--prev_length != 0);
+            strstart++;
+#endif /* ?DEFL_UNDETERM */
+            match_available = 0;
+            match_length = MIN_MATCH-1;
+
+            if (flush) FLUSH_BLOCK(0), block_start = strstart;
+
+        } else if (match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c",window[strstart-1]));
+            if (ct_tally (0, window[strstart-1])) {
+                FLUSH_BLOCK(0), block_start = strstart;
+            }
+            strstart++;
+            lookahead--;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            match_available = 1;
+            strstart++;
+            lookahead--;
+        }
+        Assert(strstart <= isize && lookahead <= isize, "a bit too far");
+
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (lookahead < MIN_LOOKAHEAD) fill_window();
+    }
+    if (match_available) ct_tally (0, window[strstart-1]);
+
+    return FLUSH_BLOCK(1); /* eof */
+}
+#endif /* !USE_ZLIB */
diff --git a/ebcdic.h b/ebcdic.h
new file mode 100644 (file)
index 0000000..a52de1e
--- /dev/null
+++ b/ebcdic.h
@@ -0,0 +1,328 @@
+/*
+  ebcdic.h
+
+  Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2005-Feb-10 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/licen
+*/
+/*---------------------------------------------------------------------------
+
+  ebcdic.h
+
+  The CECP 1047 (Extended de-facto EBCDIC) <-> ISO 8859-1 conversion tables,
+  from ftp://aix1.segi.ulg.ac.be/pub/docs/iso8859/iso8859.networking
+
+  NOTES:
+  <Paul_von_Behren@stortek.com> (OS/390 port 12/97)
+   These table no longer represent the standard mappings (for example in the
+   OS/390 iconv utility).  In order to follow current standards I remapped
+     ebcdic x0a to ascii x15    and
+     ebcdic x85 to ascii x25    (and vice-versa)
+   Without these changes, newlines in auto-convert text files appeared
+   as literal \045.
+   I'm not sure what effect this remap would have on the MVS and CMS ports, so
+   I ifdef'd these changes.  Hopefully these ifdef's can be removed when the
+   MVS/CMS folks test the new mappings.
+
+  Christian Spieler <spieler@ikp.tu-darmstadt.de>, 27-Apr-1998
+   The problem mentioned by Paul von Behren was already observed previously
+   on VM/CMS, during the preparation of the CMS&MVS port of UnZip 5.20 in
+   1996. At that point, the ebcdic tables were not changed since they seemed
+   to be an adopted standard (to my knowledge, these tables are still used
+   as presented in mainfraime KERMIT). Instead, the "end-of-line" conversion
+   feature of Zip's and UnZip's "text-translation" mode was used to force
+   correct mappings between ASCII and EBCDIC newline markers.
+   Before interchanging the ASCII mappings of the EBCDIC control characters
+   "NL" 0x25 and "LF" 0x15 according to the OS/390 setting, we have to
+   make sure that EBCDIC 0x15 is never used as line termination.
+
+  ---------------------------------------------------------------------------*/
+
+#ifndef __ebcdic_h      /* prevent multiple inclusions */
+#define __ebcdic_h
+
+
+#ifndef ZCONST
+#  define ZCONST const
+#endif
+
+#ifdef EBCDIC
+#ifndef MTS             /* MTS uses a slightly "special" EBCDIC code page */
+
+ZCONST uch ebcdic[] = {
+    0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,  /* 00 - 07 */
+#ifdef OS390
+    0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,  /* 08 - 0F */
+#else
+    0x16, 0x05, 0x25, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,  /* 08 - 0F */
+#endif
+    0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,  /* 10 - 17 */
+    0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,  /* 18 - 1F */
+    0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,  /* 20 - 27 */
+    0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,  /* 28 - 2F */
+    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,  /* 30 - 37 */
+    0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,  /* 38 - 3F */
+    0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,  /* 40 - 47 */
+    0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,  /* 48 - 4F */
+    0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,  /* 50 - 57 */
+    0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,  /* 58 - 5F */
+    0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,  /* 60 - 67 */
+    0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,  /* 68 - 6F */
+    0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,  /* 70 - 77 */
+    0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,  /* 78 - 7F */
+#ifdef OS390
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x06, 0x17,  /* 80 - 87 */
+#else
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17,  /* 80 - 87 */
+#endif
+    0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x09, 0x0A, 0x1B,  /* 88 - 8F */
+    0x30, 0x31, 0x1A, 0x33, 0x34, 0x35, 0x36, 0x08,  /* 90 - 97 */
+    0x38, 0x39, 0x3A, 0x3B, 0x04, 0x14, 0x3E, 0xFF,  /* 98 - 9F */
+    0x41, 0xAA, 0x4A, 0xB1, 0x9F, 0xB2, 0x6A, 0xB5,  /* A0 - A7 */
+    0xBB, 0xB4, 0x9A, 0x8A, 0xB0, 0xCA, 0xAF, 0xBC,  /* A8 - AF */
+    0x90, 0x8F, 0xEA, 0xFA, 0xBE, 0xA0, 0xB6, 0xB3,  /* B0 - B7 */
+    0x9D, 0xDA, 0x9B, 0x8B, 0xB7, 0xB8, 0xB9, 0xAB,  /* B8 - BF */
+    0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9E, 0x68,  /* C0 - C7 */
+    0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77,  /* C8 - CF */
+    0xAC, 0x69, 0xED, 0xEE, 0xEB, 0xEF, 0xEC, 0xBF,  /* D0 - D7 */
+    0x80, 0xFD, 0xFE, 0xFB, 0xFC, 0xBA, 0xAE, 0x59,  /* D8 - DF */
+    0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9C, 0x48,  /* E0 - E7 */
+    0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57,  /* E8 - EF */
+    0x8C, 0x49, 0xCD, 0xCE, 0xCB, 0xCF, 0xCC, 0xE1,  /* F0 - F7 */
+    0x70, 0xDD, 0xDE, 0xDB, 0xDC, 0x8D, 0x8E, 0xDF   /* F8 - FF */
+};
+
+#if (defined(ZIP) || CRYPT)
+ZCONST uch ascii[] = {
+    0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,  /* 00 - 07 */
+    0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,  /* 08 - 0F */
+#ifdef OS390
+    0x10, 0x11, 0x12, 0x13, 0x9D, 0x0A, 0x08, 0x87,  /* 10 - 17 */
+#else
+    0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,  /* 10 - 17 */
+#endif
+    0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,  /* 18 - 1F */
+#ifdef OS390
+    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x17, 0x1B,  /* 20 - 27 */
+#else
+    0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,  /* 20 - 27 */
+#endif
+    0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,  /* 28 - 2F */
+    0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,  /* 30 - 37 */
+    0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,  /* 38 - 3F */
+    0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,  /* 40 - 47 */
+    0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,  /* 48 - 4F */
+    0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,  /* 50 - 57 */
+    0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,  /* 58 - 5F */
+    0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,  /* 60 - 67 */
+    0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,  /* 68 - 6F */
+    0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,  /* 70 - 77 */
+    0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,  /* 78 - 7F */
+    0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,  /* 80 - 87 */
+    0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,  /* 88 - 8F */
+    0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,  /* 90 - 97 */
+    0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,  /* 98 - 9F */
+    0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,  /* A0 - A7 */
+    0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0x5B, 0xDE, 0xAE,  /* A8 - AF */
+    0xAC, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,  /* B0 - B7 */
+    0xBD, 0xBE, 0xDD, 0xA8, 0xAF, 0x5D, 0xB4, 0xD7,  /* B8 - BF */
+    0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,  /* C0 - C7 */
+    0x48, 0x49, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,  /* C8 - CF */
+    0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,  /* D0 - D7 */
+    0x51, 0x52, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,  /* D8 - DF */
+    0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,  /* E0 - E7 */
+    0x59, 0x5A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,  /* E8 - EF */
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,  /* F0 - F7 */
+    0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F   /* F8 - FF */
+};
+#endif /* ZIP || CRYPT */
+
+#else /* MTS */
+
+/*
+ * This is the MTS ASCII->EBCDIC translation table. It provides a 1-1
+ * translation from ISO 8859/1 8-bit ASCII to IBM Code Page 37 EBCDIC.
+ */
+
+ZCONST uch ebcdic[] = {
+    0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,  /* 00 - 07 */
+    0x16, 0x05, 0x25, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,  /* 08 - 0F */
+    0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,  /* 10 - 17 */
+    0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,  /* 18 - 1F */
+    0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,  /* 20 - 27 */
+    0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,  /* 28 - 2F */
+    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,  /* 30 - 37 */
+    0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,  /* 38 - 3F */
+    0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,  /* 40 - 47 */
+    0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,  /* 48 - 4F */
+    0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,  /* 50 - 57 */
+    0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,  /* 58 - 5F */
+    0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,  /* 60 - 67 */
+    0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,  /* 68 - 6F */
+    0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,  /* 70 - 77 */
+    0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,  /* 78 - 7F */
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17,  /* 80 - 87 */
+    0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x09, 0x0A, 0x1B,  /* 88 - 8F */
+    0x30, 0x31, 0x1A, 0x33, 0x34, 0x35, 0x36, 0x08,  /* 90 - 97 */
+    0x38, 0x39, 0x3A, 0x3B, 0x04, 0x14, 0x3E, 0xFF,  /* 98 - 9F */
+    0x41, 0xAA, 0x4A, 0xB1, 0x9F, 0xB2, 0x6A, 0xB5,  /* A0 - A7 */
+    0xBD, 0xB4, 0x9A, 0x8A, 0x5F, 0xCA, 0xAF, 0xBC,  /* A8 - AF */
+    0x90, 0x8F, 0xEA, 0xFA, 0xBE, 0xA0, 0xB6, 0xB3,  /* B0 - B7 */
+    0x9D, 0xDA, 0x9B, 0x8B, 0xB7, 0xB8, 0xB9, 0xAB,  /* B8 - BF */
+    0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9E, 0x68,  /* C0 - C7 */
+    0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77,  /* C8 - CF */
+    0xAC, 0x69, 0xED, 0xEE, 0xEB, 0xEF, 0xEC, 0xBF,  /* D0 - D7 */
+    0x80, 0xFD, 0xFE, 0xFB, 0xFC, 0xAD, 0xAE, 0x59,  /* D8 - DF */
+    0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9C, 0x48,  /* E0 - E7 */
+    0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57,  /* E8 - EF */
+    0x8C, 0x49, 0xCD, 0xCE, 0xCB, 0xCF, 0xCC, 0xE1,  /* F0 - F7 */
+    0x70, 0xDD, 0xDE, 0xDB, 0xDC, 0x8D, 0x8E, 0xDF   /* F8 - FF */
+};
+
+#if (defined(ZIP) || CRYPT)
+ZCONST uch ascii[] = {
+    0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,  /* 00 - 07 */
+    0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,  /* 08 - 0F */
+    0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,  /* 10 - 17 */
+    0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,  /* 18 - 1F */
+    0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,  /* 20 - 27 */
+    0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,  /* 28 - 2F */
+    0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,  /* 30 - 37 */
+    0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,  /* 38 - 3F */
+    0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,  /* 40 - 47 */
+    0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,  /* 48 - 4F */
+    0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,  /* 50 - 57 */
+    0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,  /* 58 - 5F */
+    0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,  /* 60 - 67 */
+    0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,  /* 68 - 6F */
+    0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,  /* 70 - 77 */
+    0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,  /* 78 - 7F */
+    0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,  /* 80 - 87 */
+    0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,  /* 88 - 8F */
+    0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,  /* 90 - 97 */
+    0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,  /* 98 - 9F */
+    0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,  /* A0 - A7 */
+    0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE,  /* A8 - AF */
+    0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,  /* B0 - B7 */
+    0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7,  /* B8 - BF */
+    0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,  /* C0 - C7 */
+    0x48, 0x49, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,  /* C8 - CF */
+    0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,  /* D0 - D7 */
+    0x51, 0x52, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,  /* D8 - DF */
+    0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,  /* E0 - E7 */
+    0x59, 0x5A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,  /* E8 - EF */
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,  /* F0 - F7 */
+    0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F   /* F8 - FF */
+};
+#endif /* ZIP || CRYPT */
+
+#endif /* ?MTS */
+#endif /* EBCDIC */
+
+/*---------------------------------------------------------------------------
+
+  The following conversion tables translate between IBM PC CP 850
+  (OEM codepage) and the "Western Europe & America" Windows codepage 1252.
+  The Windows codepage 1252 contains the ISO 8859-1 "Latin 1" codepage,
+  with some additional printable characters in the range (0x80 - 0x9F),
+  that is reserved to control codes in the ISO 8859-1 character table.
+
+  The ISO <--> OEM conversion tables were constructed with the help
+  of the WIN32 (Win16?) API's OemToAnsi() and AnsiToOem() conversion
+  functions and have been checked against the CP850 and LATIN1 tables
+  provided in the MS-Kermit 3.14 distribution.
+
+  ---------------------------------------------------------------------------*/
+
+#ifdef IZ_ISO2OEM_ARRAY
+#ifdef OEM_RUSS
+ZCONST uch Far iso2oem[] = {
+    0x3F, 0x3F, 0x27, 0x9F, 0x22, 0x2E, 0xC5, 0xCE,  /* 80 - 87 */
+    0xFD, 0x25, 0x53, 0x3C, 0x4F, 0x3F, 0x3F, 0x3F,  /* 88 - 8F */
+    0x3F, 0x27, 0x27, 0x22, 0x22, 0xF9, 0x2D, 0x2D,  /* 90 - 97 */
+    0x7E, 0x54, 0x73, 0x3E, 0x6F, 0x3F, 0x3F, 0x59,  /* 98 - 9F */
+    0xFF, 0xF6, 0xF7, 0x9C, 0xCF, 0xBE, 0xFE, 0xF5,  /* A0 - A7 */
+    0xF0, 0xB8, 0xF2, 0xAE, 0xAA, 0xF0, 0xA9, 0xEE,  /* A8 - AF */
+    0xF8, 0xFB, 0xF4, 0xF5, 0xEF, 0xE6, 0xF4, 0xFA,  /* B0 - B7 */
+    0xF1, 0xFC, 0xF3, 0xAF, 0xAC, 0xAB, 0xF3, 0xA8,  /* B8 - BF */
+    0x80, 0x81, 0x82, 0x83, 0x84, 0x86, 0x86, 0x87,  /* C0 - C7 */
+    0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,  /* C8 - CF */
+    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,  /* D0 - D7 */
+    0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,  /* D8 - DF */
+    0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,  /* E0 - E7 */
+    0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,  /* E8 - EF */
+    0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,  /* F0 - F7 */
+    0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF   /* F8 - FF */
+};
+#else /* OEM_RUS */
+ZCONST uch Far iso2oem[] = {
+    0x3F, 0x3F, 0x27, 0x9F, 0x22, 0x2E, 0xC5, 0xCE,  /* 80 - 87 */
+    0x5E, 0x25, 0x53, 0x3C, 0x4F, 0x3F, 0x3F, 0x3F,  /* 88 - 8F */
+    0x3F, 0x27, 0x27, 0x22, 0x22, 0x07, 0x2D, 0x2D,  /* 90 - 97 */
+    0x7E, 0x54, 0x73, 0x3E, 0x6F, 0x3F, 0x3F, 0x59,  /* 98 - 9F */
+    0xFF, 0xAD, 0xBD, 0x9C, 0xCF, 0xBE, 0xDD, 0xF5,  /* A0 - A7 */
+    0xF9, 0xB8, 0xA6, 0xAE, 0xAA, 0xF0, 0xA9, 0xEE,  /* A8 - AF */
+    0xF8, 0xF1, 0xFD, 0xFC, 0xEF, 0xE6, 0xF4, 0xFA,  /* B0 - B7 */
+    0xF7, 0xFB, 0xA7, 0xAF, 0xAC, 0xAB, 0xF3, 0xA8,  /* B8 - BF */
+    0xB7, 0xB5, 0xB6, 0xC7, 0x8E, 0x8F, 0x92, 0x80,  /* C0 - C7 */
+    0xD4, 0x90, 0xD2, 0xD3, 0xDE, 0xD6, 0xD7, 0xD8,  /* C8 - CF */
+    0xD1, 0xA5, 0xE3, 0xE0, 0xE2, 0xE5, 0x99, 0x9E,  /* D0 - D7 */
+    0x9D, 0xEB, 0xE9, 0xEA, 0x9A, 0xED, 0xE8, 0xE1,  /* D8 - DF */
+    0x85, 0xA0, 0x83, 0xC6, 0x84, 0x86, 0x91, 0x87,  /* E0 - E7 */
+    0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B,  /* E8 - EF */
+    0xD0, 0xA4, 0x95, 0xA2, 0x93, 0xE4, 0x94, 0xF6,  /* F0 - F7 */
+    0x9B, 0x97, 0xA3, 0x96, 0x81, 0xEC, 0xE7, 0x98   /* F8 - FF */
+};
+#endif /* OEM_RUS */
+#endif /* IZ_ISO2OEM_ARRAY */
+
+#ifdef IZ_OEM2ISO_ARRAY
+#ifdef OEM_RUSS
+ZCONST uch Far oem2iso[] = {
+    0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,  /* 80 - 87 */
+    0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,  /* 88 - 8F */
+    0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,  /* 90 - 97 */
+    0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,  /* 98 - 9F */
+    0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,  /* A0 - A7 */
+    0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,  /* A8 - AF */
+    0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xC1, 0xC2, 0xC0,  /* B0 - B7 */
+    0xA9, 0xA6, 0xA6, 0x2B, 0x2B, 0xA2, 0xA5, 0x2B,  /* B8 - BF */
+    0x2B, 0x2D, 0x2D, 0x2B, 0x2D, 0x2B, 0xE3, 0xC3,  /* C0 - C7 */
+    0x2B, 0x2B, 0x2D, 0x2D, 0xA6, 0x2D, 0x2B, 0xA4,  /* C8 - CF */
+    0xF0, 0xD0, 0xCA, 0xCB, 0xC8, 0x69, 0xCD, 0xCE,  /* D0 - D7 */
+    0xCF, 0x2B, 0x2B, 0xA6, 0x5F, 0xA6, 0xCC, 0xAF,  /* D8 - DF */
+    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,  /* E0 - E7 */
+    0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,  /* E8 - EF */
+    0xA8, 0xB8, 0xAA, 0xBA, 0xB2, 0xB3, 0xA1, 0xA2,  /* F0 - F7 */
+    0xB0, 0x95, 0xB7, 0xB1, 0xB9, 0x88, 0xA6, 0xA0   /* F8 - FF */
+};
+#else /* OEM_RUS */
+ZCONST uch Far oem2iso[] = {
+    0xC7, 0xFC, 0xE9, 0xE2, 0xE4, 0xE0, 0xE5, 0xE7,  /* 80 - 87 */
+    0xEA, 0xEB, 0xE8, 0xEF, 0xEE, 0xEC, 0xC4, 0xC5,  /* 88 - 8F */
+    0xC9, 0xE6, 0xC6, 0xF4, 0xF6, 0xF2, 0xFB, 0xF9,  /* 90 - 97 */
+    0xFF, 0xD6, 0xDC, 0xF8, 0xA3, 0xD8, 0xD7, 0x83,  /* 98 - 9F */
+    0xE1, 0xED, 0xF3, 0xFA, 0xF1, 0xD1, 0xAA, 0xBA,  /* A0 - A7 */
+    0xBF, 0xAE, 0xAC, 0xBD, 0xBC, 0xA1, 0xAB, 0xBB,  /* A8 - AF */
+    0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xC1, 0xC2, 0xC0,  /* B0 - B7 */
+    0xA9, 0xA6, 0xA6, 0x2B, 0x2B, 0xA2, 0xA5, 0x2B,  /* B8 - BF */
+    0x2B, 0x2D, 0x2D, 0x2B, 0x2D, 0x2B, 0xE3, 0xC3,  /* C0 - C7 */
+    0x2B, 0x2B, 0x2D, 0x2D, 0xA6, 0x2D, 0x2B, 0xA4,  /* C8 - CF */
+    0xF0, 0xD0, 0xCA, 0xCB, 0xC8, 0x69, 0xCD, 0xCE,  /* D0 - D7 */
+    0xCF, 0x2B, 0x2B, 0xA6, 0x5F, 0xA6, 0xCC, 0xAF,  /* D8 - DF */
+    0xD3, 0xDF, 0xD4, 0xD2, 0xF5, 0xD5, 0xB5, 0xFE,  /* E0 - E7 */
+    0xDE, 0xDA, 0xDB, 0xD9, 0xFD, 0xDD, 0xAF, 0xB4,  /* E8 - EF */
+    0xAD, 0xB1, 0x3D, 0xBE, 0xB6, 0xA7, 0xF7, 0xB8,  /* F0 - F7 */
+    0xB0, 0xA8, 0xB7, 0xB9, 0xB3, 0xB2, 0xA6, 0xA0   /* F8 - FF */
+};
+#endif /* OEM_RUS */
+#endif /* IZ_OEM2ISO_ARRAY */
+
+#if defined(THEOS) || defined(THEOS_SUPPORT)
+#  include "theos/charconv.h"
+#endif
+
+#endif /* __ebcdic_h  */
diff --git a/file_id.diz b/file_id.diz
new file mode 100644 (file)
index 0000000..5e3f34e
--- /dev/null
@@ -0,0 +1,15 @@
+Info-ZIP's Zip 3.0: generic C sources.
+  Complete C source code for Info-ZIP's
+  PKZIP-compatible .zip archiver, for
+  all supported compilers and platforms
+  (Unix, OS/2, MS-DOS, NT, VMS, Amiga,
+  Atari, Mac, Acorn, VM/CMS, etc.), plus
+  lots of pretty decent documentation.
+  Includes Info-ZIP's ZCrypt 2.9 for
+  PKWARE-compatible standard encryption
+  and decryption support for Info-ZIP's
+  Zip 2.32, Zip 3.0, UnZip 5.52,
+  UnZip 6.0, and WiZ 5.02 (and later).
+This is FREE (but copyrighted) software.
+See LICENSE for details on distribution
+and reuse.
diff --git a/fileio.c b/fileio.c
new file mode 100644 (file)
index 0000000..1847e62
--- /dev/null
+++ b/fileio.c
@@ -0,0 +1,4903 @@
+/*
+  fileio.c - Zip 3
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  fileio.c by Mark Adler
+ */
+#define __FILEIO_C
+
+#include "zip.h"
+#include "crc32.h"
+
+#ifdef MACOS
+#  include "helpers.h"
+#endif
+
+#ifdef VMS
+#  include "vms/vms.h"
+#endif /* def VMS */
+
+#include <time.h>
+
+#ifdef NO_MKTIME
+time_t mktime OF((struct tm *));
+#endif
+
+#ifdef OSF
+#define EXDEV 18   /* avoid a bug in the DEC OSF/1 header files. */
+#else
+#include <errno.h>
+#endif
+
+#ifdef NO_ERRNO
+extern int errno;
+#endif
+
+/* -----------------------
+   For long option support
+   ----------------------- */
+#include <ctype.h>
+
+
+#if defined(VMS) || defined(TOPS20)
+#  define PAD 5
+#else
+#  define PAD 0
+#endif
+
+#ifdef NO_RENAME
+int rename OF((ZCONST char *, ZCONST char *));
+#endif
+
+
+/* Local functions */
+local int optionerr OF((char *, ZCONST char *, int, int));
+local unsigned long get_shortopt OF((char **, int, int *, int *, char **, int *, int));
+local unsigned long get_longopt OF((char **, int, int *, int *, char **, int *, int));
+
+#ifdef UNICODE_SUPPORT
+local int utf8_char_bytes OF((ZCONST char *utf8));
+local long ucs4_char_from_utf8 OF((ZCONST char **utf8 ));
+local int utf8_from_ucs4_char OF((char *utf8buf, ulg ch));
+local int utf8_to_ucs4_string OF((ZCONST char *utf8, ulg *usc4buf,
+                                  int buflen));
+local int ucs4_string_to_utf8 OF((ZCONST ulg *ucs4, char *utf8buf,
+                                  int buflen));
+#if 0
+  local int utf8_chars OF((ZCONST char *utf8));
+#endif
+#endif /* UNICODE_SUPPORT */
+
+#ifndef UTIL    /* the companion #endif is a bit of ways down ... */
+
+local int fqcmp  OF((ZCONST zvoid *, ZCONST zvoid *));
+local int fqcmpz OF((ZCONST zvoid *, ZCONST zvoid *));
+
+
+/* Local module level variables. */
+char *label = NULL;                /* global, but only used in `system'.c */
+local z_stat zipstatb;             /* now use z_stat globally - 7/24/04 EG */
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+ local zw_stat zipstatbw;
+#endif
+#if (!defined(MACOS) && !defined(WINDLL))
+local int zipstate = -1;
+#else
+int zipstate;
+#endif
+/* -1 unknown, 0 old zip file exists, 1 new zip file */
+
+#if 0
+char *getnam(n, fp)
+char *n;                /* where to put name (must have >=FNMAX+1 bytes) */
+#endif
+
+/* converted to return string pointer from malloc to avoid
+   size limitation - 11/8/04 EG */
+#define GETNAM_MAX 9000 /* hopefully big enough for now */
+char *getnam(fp)
+  FILE *fp;
+  /* Read a \n or \r delimited name from stdin into n, and return
+     n.  If EOF, then return NULL.  Also, if problem return NULL. */
+{
+  char name[GETNAM_MAX + 1];
+  int c;                /* last character read */
+  char *p;              /* pointer into name area */
+
+
+  p = name;
+  while ((c = getc(fp)) == '\n' || c == '\r')
+    ;
+  if (c == EOF)
+    return NULL;
+  do {
+    if (p - name >= GETNAM_MAX)
+      return NULL;
+    *p++ = (char) c;
+    c = getc(fp);
+  } while (c != EOF && (c != '\n' && c != '\r'));
+#ifdef WIN32
+/*
+ * WIN32 strips off trailing spaces and periods in filenames
+ * XXX what about a filename that only consists of spaces ?
+ *     Answer: on WIN32, a filename must contain at least one non-space char
+ */
+  while (p > name) {
+    if ((c = p[-1]) != ' ' && c != '.')
+      break;
+    --p;
+  }
+#endif
+  *p = 0;
+  /* malloc a copy */
+  if ((p = malloc(strlen(name) + 1)) == NULL) {
+    return NULL;
+  }
+  strcpy(p, name);
+  return p;
+}
+
+struct flist far *fexpel(f)
+struct flist far *f;    /* entry to delete */
+/* Delete the entry *f in the doubly-linked found list.  Return pointer to
+   next entry to allow stepping through list. */
+{
+  struct flist far *t;  /* temporary variable */
+
+  t = f->nxt;
+  *(f->lst) = t;                        /* point last to next, */
+  if (t != NULL)
+    t->lst = f->lst;                    /* and next to last */
+  if (f->name != NULL)                  /* free memory used */
+    free((zvoid *)(f->name));
+  if (f->zname != NULL)
+    free((zvoid *)(f->zname));
+  if (f->iname != NULL)
+    free((zvoid *)(f->iname));
+#ifdef UNICODE_SUPPORT
+  if (f->uname)
+    free((zvoid *)f->uname);
+# ifdef WIN32
+  if (f->namew)
+    free((zvoid *)f->namew);
+  if (f->inamew)
+    free((zvoid *)f->inamew);
+  if (f->znamew)
+    free((zvoid *)f->znamew);
+# endif
+#endif
+  farfree((zvoid far *)f);
+  fcount--;                             /* decrement count */
+  return t;                             /* return pointer to next */
+}
+
+local int fqcmp(a, b)
+  ZCONST zvoid *a, *b;          /* pointers to pointers to found entries */
+/* Used by qsort() to compare entries in the found list by name. */
+{
+  return strcmp((*(struct flist far **)a)->name,
+                (*(struct flist far **)b)->name);
+}
+
+local int fqcmpz(a, b)
+  ZCONST zvoid *a, *b;          /* pointers to pointers to found entries */
+/* Used by qsort() to compare entries in the found list by iname. */
+{
+  return strcmp((*(struct flist far **)a)->iname,
+                (*(struct flist far **)b)->iname);
+}
+
+char *last(p, c)
+  char *p;                /* sequence of path components */
+  int c;                  /* path components separator character */
+/* Return a pointer to the start of the last path component. For a directory
+ * name terminated by the character in c, the return value is an empty string.
+ */
+{
+  char *t;              /* temporary variable */
+
+  if ((t = strrchr(p, c)) != NULL)
+    return t + 1;
+  else
+#ifndef AOS_VS
+    return p;
+#else
+/* We want to allow finding of end of path in either AOS/VS-style pathnames
+ * or Unix-style pathnames.  This presents a few little problems ...
+ */
+  {
+    if (*p == '='  ||  *p == '^')      /* like ./ and ../ respectively */
+      return p + 1;
+    else
+      return p;
+  }
+#endif
+}
+
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+wchar_t *lastw(pw, c)
+  wchar_t *pw;            /* sequence of path components */
+  wchar_t c;              /* path components separator character */
+/* Return a pointer to the start of the last path component. For a directory
+ * name terminated by the character in c, the return value is an empty string.
+ */
+{
+  wchar_t *tw;            /* temporary variable */
+
+  if ((tw = wcsrchr(pw, c)) != NULL)
+    return tw + 1;
+  else
+# ifndef AOS_VS
+    return pw;
+# else
+/* We want to allow finding of end of path in either AOS/VS-style pathnames
+ * or Unix-style pathnames.  This presents a few little problems ...
+ */
+  {
+    if (*pw == (wchar_t)'='  ||  *pw == (wchar_t)'^')      /* like ./ and ../ respectively */
+      return pw + 1;
+    else
+      return pw;
+  }
+# endif
+}
+#endif
+
+
+char *msname(n)
+  char *n;
+/* Reduce all path components to MSDOS upper case 8.3 style names. */
+{
+  int c;                /* current character */
+  int f;                /* characters in current component */
+  char *p;              /* source pointer */
+  char *q;              /* destination pointer */
+
+  p = q = n;
+  f = 0;
+  while ((c = (unsigned char)*POSTINCSTR(p)) != 0)
+    if (c == ' ' || c == ':' || c == '"' || c == '*' || c == '+' ||
+        c == ',' || c == ';' || c == '<' || c == '=' || c == '>' ||
+        c == '?' || c == '[' || c == ']' || c == '|')
+      continue;                         /* char is discarded */
+    else if (c == '/')
+    {
+      *POSTINCSTR(q) = (char)c;
+      f = 0;                            /* new component */
+    }
+#ifdef __human68k__
+    else if (ismbblead(c) && *p)
+    {
+      if (f == 7 || f == 11)
+        f++;
+      else if (*p && f < 12 && f != 8)
+      {
+        *q++ = c;
+        *q++ = *p++;
+        f += 2;
+      }
+    }
+#endif /* __human68k__ */
+    else if (c == '.')
+    {
+      if (f == 0)
+        continue;                       /* leading dots are discarded */
+      else if (f < 9)
+      {
+        *POSTINCSTR(q) = (char)c;
+        f = 9;                          /* now in file type */
+      }
+      else
+        f = 12;                         /* now just excess characters */
+    }
+    else
+      if (f < 12 && f != 8)
+      {
+        f += CLEN(p);                   /* do until end of name or type */
+        *POSTINCSTR(q) = (char)(to_up(c));
+      }
+  *q = 0;
+  return n;
+}
+
+#ifdef UNICODE_SUPPORT
+wchar_t *msnamew(nw)
+  wchar_t *nw;
+/* Reduce all path components to MSDOS upper case 8.3 style names. */
+{
+  wchar_t c;            /* current character */
+  int f;                /* characters in current component */
+  wchar_t *pw;          /* source pointer */
+  wchar_t *qw;          /* destination pointer */
+
+  pw = qw = nw;
+  f = 0;
+  while ((c = (unsigned char)*pw++) != 0)
+    if (c == ' ' || c == ':' || c == '"' || c == '*' || c == '+' ||
+        c == ',' || c == ';' || c == '<' || c == '=' || c == '>' ||
+        c == '?' || c == '[' || c == ']' || c == '|')
+      continue;                         /* char is discarded */
+    else if (c == '/')
+    {
+      *qw++ = c;
+      f = 0;                            /* new component */
+    }
+#ifdef __human68k__
+    else if (ismbblead(c) && *pw)
+    {
+      if (f == 7 || f == 11)
+        f++;
+      else if (*pw && f < 12 && f != 8)
+      {
+        *qw++ = c;
+        *qw++ = *pw++;
+        f += 2;
+      }
+    }
+#endif /* __human68k__ */
+    else if (c == '.')
+    {
+      if (f == 0)
+        continue;                       /* leading dots are discarded */
+      else if (f < 9)
+      {
+        *qw++ = c;
+        f = 9;                          /* now in file type */
+      }
+      else
+        f = 12;                         /* now just excess characters */
+    }
+    else
+      if (f < 12 && f != 8)
+      {
+        f++;                            /* do until end of name or type */
+        *qw++ = towupper(c);
+      }
+  *qw = 0;
+  return nw;
+}
+#endif
+
+
+int proc_archive_name(n, caseflag)
+  char *n;             /* name to process */
+  int caseflag;         /* true to force case-sensitive match */
+/* Process a name or sh expression in existing archive to operate
+   on (or exclude).  Return an error code in the ZE_ class. */
+{
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (strcmp(n, "-") == 0) {   /* if compressing stdin */
+    zipwarn("Cannot select stdin when selecting archive entries", "");
+    return ZE_MISS;
+  }
+  else
+  {
+    /* Search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->oname);
+        m = 0;
+      }
+    }
+#ifdef UNICODE_SUPPORT
+    /* also check escaped Unicode names */
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (z->zuname) {
+#ifdef WIN32
+        /* It seems something is lost in going from a listed
+           name from zip -su in a console window to using that
+           name in a command line.  This kluge may fix it
+           and just takes zuname, converts to oem (i.e. ouname),
+           then converts it back which ends up not the same as
+           started with.
+         */
+        char *zuname = z->wuname;
+#else
+        char *zuname = z->zuname;
+#endif
+        if (MATCH(p, zuname, caseflag))
+        {
+          z->mark = pcount ? filter(zuname, caseflag) : 1;
+          if (verbose) {
+              fprintf(mesg, "zip diagnostic: %scluding %s\n",
+                 z->mark ? "in" : "ex", z->oname);
+              fprintf(mesg, "     Escaped Unicode:  %s\n",
+                 z->ouname);
+          }
+          m = 0;
+        }
+      }
+    }
+#endif
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+}
+
+
+int check_dup()
+/* Sort the found list and remove duplicates.
+   Return an error code in the ZE_ class. */
+{
+  struct flist far *f;          /* steps through found linked list */
+  extent j, k;                  /* indices for s */
+  struct flist far **s;         /* sorted table */
+  struct flist far **nodup;     /* sorted table without duplicates */
+
+  /* sort found list, remove duplicates */
+  if (fcount)
+  {
+    extent fl_size = fcount * sizeof(struct flist far *);
+    if ((fl_size / sizeof(struct flist far *)) != fcount ||
+        (s = (struct flist far **)malloc(fl_size)) == NULL)
+      return ZE_MEM;
+    for (j = 0, f = found; f != NULL; f = f->nxt)
+      s[j++] = f;
+    /* Check names as given (f->name) */
+    qsort((char *)s, fcount, sizeof(struct flist far *), fqcmp);
+    for (k = j = fcount - 1; j > 0; j--)
+      if (strcmp(s[j - 1]->name, s[j]->name) == 0)
+        /* remove duplicate entry from list */
+        fexpel(s[j]);           /* fexpel() changes fcount */
+      else
+        /* copy valid entry into destination position */
+        s[k--] = s[j];
+    s[k] = s[0];                /* First entry is always valid */
+    nodup = &s[k];              /* Valid entries are at end of array s */
+
+    /* sort only valid items and check for unique internal names (f->iname) */
+    qsort((char *)nodup, fcount, sizeof(struct flist far *), fqcmpz);
+    for (j = 1; j < fcount; j++)
+      if (strcmp(nodup[j - 1]->iname, nodup[j]->iname) == 0)
+      {
+        char tempbuf[FNMAX+4081];
+
+        sprintf(errbuf, "  first full name: %s\n", nodup[j - 1]->name);
+        sprintf(tempbuf, " second full name: %s\n", nodup[j]->name);
+        strcat(errbuf, "                     ");
+        strcat(errbuf, tempbuf);
+#ifdef EBCDIC
+        strtoebc(nodup[j]->iname, nodup[j]->iname);
+#endif
+        sprintf(tempbuf, "name in zip file repeated: %s", nodup[j]->iname);
+        strcat(errbuf, "                     ");
+        strcat(errbuf, tempbuf);
+        if (pathput == 0) {
+          strcat(errbuf, "\n                     this may be a result of using -j");
+        }
+#ifdef EBCDIC
+        strtoasc(nodup[j]->iname, nodup[j]->iname);
+#endif
+        zipwarn(errbuf, "");
+        return ZE_PARMS;
+      }
+    free((zvoid *)s);
+  }
+  return ZE_OK;
+}
+
+int filter(name, casesensitive)
+  char *name;
+  int casesensitive;
+  /* Scan the -R, -i and -x lists for matches to the given name.
+     Return TRUE if the name must be included, FALSE otherwise.
+     Give precedence to -x over -i and -R.
+     Note that if both R and i patterns are given then must
+     have a match for both.
+     This routine relies on the following global variables:
+       patterns                 array of match pattern structures
+       pcount                   total number of patterns
+       icount                   number of -i patterns
+       Rcount                   number of -R patterns
+     These data are set up by the command line parsing code.
+   */
+{
+   unsigned int n;
+   int slashes;
+   char *p, *q;
+   /* without -i patterns, every name matches the "-i select rules" */
+   int imatch = (icount == 0);
+   /* without -R patterns, every name matches the "-R select rules" */
+   int Rmatch = (Rcount == 0);
+
+   if (pcount == 0) return TRUE;
+
+   for (n = 0; n < pcount; n++) {
+      if (!patterns[n].zname[0])        /* it can happen... */
+         continue;
+      p = name;
+      switch (patterns[n].select) {
+       case 'R':
+         if (Rmatch)
+            /* one -R match is sufficient, skip this pattern */
+            continue;
+         /* With -R patterns, if the pattern has N path components (that is,
+            N-1 slashes), then we test only the last N components of name.
+          */
+         slashes = 0;
+         for (q = patterns[n].zname; (q = MBSCHR(q, '/')) != NULL; MB_NEXTCHAR(q))
+            slashes++;
+         /* The name may have M path components (M-1 slashes) */
+         for (q = p; (q = MBSCHR(q, '/')) != NULL; MB_NEXTCHAR(q))
+            slashes--;
+         /* Now, "slashes" contains the difference "N-M" between the number
+            of path components in the pattern (N) and in the name (M).
+          */
+         if (slashes < 0)
+            /* We found "M > N"
+                --> skip the first (M-N) path components of the name.
+             */
+            for (q = p; (q = MBSCHR(q, '/')) != NULL; MB_NEXTCHAR(q))
+               if (++slashes == 0) {
+                  p = q + 1;    /* q points at '/', mblen("/") is 1 */
+                  break;
+               }
+         break;
+       case 'i':
+         if (imatch)
+            /* one -i match is sufficient, skip this pattern */
+            continue;
+         break;
+      }
+      if (MATCH(patterns[n].zname, p, casesensitive)) {
+         switch (patterns[n].select) {
+            case 'x':
+               /* The -x match takes precedence over everything else */
+               return FALSE;
+            case 'R':
+               Rmatch = TRUE;
+               break;
+            default:
+               /* this must be a type -i match */
+               imatch = TRUE;
+               break;
+         }
+      }
+   }
+   return imatch && Rmatch;
+}
+
+
+#ifdef UNICODE_SUPPORT
+# ifdef WIN32
+
+int newnamew(namew, isdir, casesensitive)
+  wchar_t *namew;             /* name to add (or exclude) */
+  int  isdir;                 /* true for a directory */
+  int  casesensitive;         /* true for case-sensitive matching */
+/* Add (or exclude) the name of an existing disk file.  Return an error
+   code in the ZE_ class. */
+{
+  wchar_t *inamew = NULL;     /* internal name */
+  wchar_t *znamew = NULL;     /* external version of iname */
+  wchar_t *undosmw = NULL;    /* zname version with "-j" and "-k" options disabled */
+  char *oname = NULL;         /* iname converted for display */
+  char *name = NULL;
+  char *iname = NULL;
+  char *zname = NULL;
+  char *zuname = NULL;
+  char *undosm = NULL;
+  struct flist far *f;        /* where in found, or new found entry */
+  struct zlist far *z;        /* where in zfiles (if found) */
+  int dosflag;
+
+  /* Scanning files ...
+   *
+   * After 5 seconds output Scanning files...
+   * then a dot every 2 seconds
+   */
+  if (noisy) {
+    /* If find files then output message after delay */
+    if (scan_count == 0) {
+      time_t current = time(NULL);
+      scan_start = current;
+    }
+    scan_count++;
+    if (scan_count % 100 == 0) {
+      time_t current = time(NULL);
+
+      if (current - scan_start > scan_delay) {
+        if (scan_last == 0) {
+          zipmessage_nl("Scanning files ", 0);
+          scan_last = current;
+        }
+        if (current - scan_last > scan_dot_time) {
+          scan_last = current;
+          fprintf(mesg, ".");
+          fflush(mesg);
+        }
+      }
+    }
+  }
+
+  /* Search for name in zip file.  If there, mark it, else add to
+     list of new names to do (or remove from that list). */
+  if ((inamew = ex2inw(namew, isdir, &dosflag)) == NULL)
+    return ZE_MEM;
+
+  /* Discard directory names with zip -rj */
+  if (*inamew == (wchar_t)'\0') {
+
+ /* If extensions needs to be swapped, we will have empty directory names
+    instead of the original directory. For example, zipping 'c.', 'c.main'
+    should zip only 'main.c' while 'c.' will be converted to '\0' by ex2in. */
+
+    if (pathput && !recurse) error("empty name without -j or -r");
+    free((zvoid *)inamew);
+    return ZE_OK;
+  }
+
+  if (dosflag || !pathput) {
+    int save_dosify = dosify, save_pathput = pathput;
+    dosify = 0;
+    pathput = 1;
+    /* zname is temporarly mis-used as "undosmode" iname pointer */
+    if ((znamew = ex2inw(namew, isdir, NULL)) != NULL) {
+      undosmw = in2exw(znamew);
+      free(znamew);
+    }
+    dosify = save_dosify;
+    pathput = save_pathput;
+  }
+  if ((znamew = in2exw(inamew)) == NULL)
+    return ZE_MEM;
+
+  /* Convert names from wchar_t to char */
+
+  name = wchar_to_local_string(namew);
+  iname = wchar_to_local_string(inamew);
+  zname = wchar_to_local_string(znamew);
+
+  oname = local_to_display_string(zname);
+
+  zuname = wchar_to_local_string(znamew);
+
+  if (undosmw == NULL)
+    undosmw = znamew;
+  undosm = wchar_to_local_string(undosmw);
+
+  if ((z = zsearch(zuname)) != NULL) {
+    if (pcount && !filter(undosm, casesensitive)) {
+      /* Do not clear z->mark if "exclude", because, when "dosify || !pathput"
+       * is in effect, two files with different filter options may hit the
+       * same z entry.
+       */
+      if (verbose)
+        fprintf(mesg, "excluding %s\n", oname);
+    } else {
+      z->mark = 1;
+      if ((z->name = malloc(strlen(name) + 1 + PAD)) == NULL) {
+        if (undosmw != znamew)
+          free(undosmw);
+        if (undosm) free(undosm);
+        if (inamew) free(inamew);
+        if (znamew) free(znamew);
+        if (name) free(name);
+        if (iname) free(iname);
+        if (zname) free(zname);
+        if (oname) free(oname);
+        if (zuname) free(zuname);
+        return ZE_MEM;
+      }
+      strcpy(z->name, name);
+      z->oname = oname;
+      oname = NULL;
+      z->dosflag = dosflag;
+
+#ifdef FORCE_NEWNAME
+      free((zvoid *)(z->iname));
+      z->iname = iname;
+      iname = NULL;
+#else
+      /* Better keep the old name. Useful when updating on MSDOS a zip file
+       * made on Unix.
+       */
+#endif /* ? FORCE_NEWNAME */
+    }
+
+    if ((z->namew = (wchar_t *)malloc((wcslen(namew) + 1) * sizeof(wchar_t))) == NULL) {
+      if (undosmw != znamew)
+        free(undosmw);
+      if (undosm) free(undosm);
+      if (inamew) free(inamew);
+      if (znamew) free(znamew);
+      if (name) free(name);
+      if (iname) free(iname);
+      if (zname) free(zname);
+      if (oname) free(oname);
+      if (zuname) free(zuname);
+      return ZE_MEM;
+    }
+    wcscpy(z->namew, namew);
+    z->inamew = inamew;
+    inamew = NULL;
+    z->znamew = znamew;
+    znamew = NULL;
+    z->uname = wchar_to_utf8_string(z->inamew);
+    if (name == label) {
+       label = z->name;
+    }
+  } else if (pcount == 0 || filter(undosm, casesensitive)) {
+
+    /* Check that we are not adding the zip file to itself. This
+     * catches cases like "zip -m foo ../dir/foo.zip".
+     */
+/* Version of stat() for CMS/MVS isn't complete enough to see if       */
+/* files match.  Just let ZIP.C compare the filenames.  That's good    */
+/* enough for CMS anyway since there aren't paths to worry about.      */
+    zw_stat statbw;     /* need for wide stat */
+    wchar_t *zipfilew = local_to_wchar_string(zipfile);
+
+    if (zipstate == -1)
+       zipstate = strcmp(zipfile, "-") != 0 &&
+                   zwstat(zipfilew, &zipstatbw) == 0;
+    free(zipfilew);
+
+    if (zipstate == 1 && (statbw = zipstatbw, zwstat(namew, &statbw) == 0
+      && zipstatbw.st_mode  == statbw.st_mode
+      && zipstatbw.st_ino   == statbw.st_ino
+      && zipstatbw.st_dev   == statbw.st_dev
+      && zipstatbw.st_uid   == statbw.st_uid
+      && zipstatbw.st_gid   == statbw.st_gid
+      && zipstatbw.st_size  == statbw.st_size
+      && zipstatbw.st_mtime == statbw.st_mtime
+      && zipstatbw.st_ctime == statbw.st_ctime)) {
+      /* Don't compare a_time since we are reading the file */
+        if (verbose)
+          fprintf(mesg, "file matches zip file -- skipping\n");
+        if (undosmw != znamew)
+          free(undosmw);
+        if (undosm) free(undosm);
+        if (inamew) free(inamew);
+        if (znamew) free(znamew);
+        if (name) free(name);
+        if (iname) free(iname);
+        if (zname) free(zname);
+        if (oname) free(oname);
+        if (zuname) free(zuname);
+        return ZE_OK;
+    }
+
+    /* allocate space and add to list */
+    if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL ||
+        fcount + 1 < fcount ||
+        (f->name = malloc(strlen(name) + 1 + PAD)) == NULL)
+    {
+      if (f != NULL)
+        farfree((zvoid far *)f);
+      if (undosmw != znamew)
+        free(undosmw);
+      if (undosm) free(undosm);
+      if (inamew) free(inamew);
+      if (znamew) free(znamew);
+      if (name) free(name);
+      if (iname) free(iname);
+      if (zname) free(zname);
+      if (oname) free(oname);
+      if (zuname) free(zuname);
+      return ZE_MEM;
+    }
+    if (undosmw != znamew)
+      free((zvoid *)undosmw);
+    strcpy(f->name, name);
+    f->iname = iname;
+    iname = NULL;
+    f->zname = zname;
+    zname = NULL;
+    /* Unicode */
+    if ((f->namew = (wchar_t *)malloc((wcslen(namew) + 1) * sizeof(wchar_t))) == NULL) {
+      if (f != NULL)
+        farfree((zvoid far *)f);
+      if (undosmw != znamew)
+        free(undosmw);
+      if (undosm) free(undosm);
+      if (inamew) free(inamew);
+      if (znamew) free(znamew);
+      if (name) free(name);
+      if (iname) free(iname);
+      if (zname) free(zname);
+      if (oname) free(oname);
+      if (zuname) free(zuname);
+      return ZE_MEM;
+    }
+    wcscpy(f->namew, namew);
+    f->znamew = znamew;
+    znamew = NULL;
+    f->uname = wchar_to_utf8_string(inamew);
+    f->inamew = inamew;
+    inamew = NULL;
+    f->oname = oname;
+    oname = NULL;
+    f->dosflag = dosflag;
+    *fnxt = f;
+    f->lst = fnxt;
+    f->nxt = NULL;
+    fnxt = &f->nxt;
+    fcount++;
+    if (name == label) {
+      label = f->name;
+    }
+  }
+  if (undosm) free(undosm);
+  if (inamew) free(inamew);
+  if (znamew) free(znamew);
+  if (name) free(name);
+  if (iname) free(iname);
+  if (zname) free(zname);
+  if (oname) free(oname);
+  if (zuname) free(zuname);
+  return ZE_OK;
+}
+
+# endif
+#endif
+
+int newname(name, isdir, casesensitive)
+  char *name;           /* name to add (or exclude) */
+  int  isdir;           /* true for a directory */
+  int  casesensitive;   /* true for case-sensitive matching */
+/* Add (or exclude) the name of an existing disk file.  Return an error
+   code in the ZE_ class. */
+{
+  char *iname, *zname;  /* internal name, external version of iname */
+  char *undosm;         /* zname version with "-j" and "-k" options disabled */
+  char *oname;          /* iname converted for display */
+  struct flist far *f;  /* where in found, or new found entry */
+  struct zlist far *z;  /* where in zfiles (if found) */
+  int dosflag;
+
+  /* Scanning files ...
+   *
+   * After 5 seconds output Scanning files...
+   * then a dot every 2 seconds
+   */
+  if (noisy) {
+    /* If find files then output message after delay */
+    if (scan_count == 0) {
+      time_t current = time(NULL);
+      scan_start = current;
+    }
+    scan_count++;
+    if (scan_count % 100 == 0) {
+      time_t current = time(NULL);
+
+      if (current - scan_start > scan_delay) {
+        if (scan_last == 0) {
+          zipmessage_nl("Scanning files ", 0);
+          scan_last = current;
+        }
+        if (current - scan_last > scan_dot_time) {
+          scan_last = current;
+          fprintf(mesg, ".");
+          fflush(mesg);
+        }
+      }
+    }
+  }
+
+  /* Search for name in zip file.  If there, mark it, else add to
+     list of new names to do (or remove from that list). */
+  if ((iname = ex2in(name, isdir, &dosflag)) == NULL)
+    return ZE_MEM;
+
+  /* Discard directory names with zip -rj */
+  if (*iname == '\0') {
+#ifndef AMIGA
+/* A null string is a legitimate external directory name in AmigaDOS; also,
+ * a command like "zip -r zipfile FOO:" produces an empty internal name.
+ */
+# ifndef RISCOS
+ /* If extensions needs to be swapped, we will have empty directory names
+    instead of the original directory. For example, zipping 'c.', 'c.main'
+    should zip only 'main.c' while 'c.' will be converted to '\0' by ex2in. */
+
+    if (pathput && !recurse) error("empty name without -j or -r");
+
+# endif /* !RISCOS */
+#endif /* !AMIGA */
+    free((zvoid *)iname);
+    return ZE_OK;
+  }
+  undosm = NULL;
+  if (dosflag || !pathput) {
+    int save_dosify = dosify, save_pathput = pathput;
+    dosify = 0;
+    pathput = 1;
+    /* zname is temporarly mis-used as "undosmode" iname pointer */
+    if ((zname = ex2in(name, isdir, NULL)) != NULL) {
+      undosm = in2ex(zname);
+      free(zname);
+    }
+    dosify = save_dosify;
+    pathput = save_pathput;
+  }
+  if ((zname = in2ex(iname)) == NULL)
+    return ZE_MEM;
+#ifdef UNICODE_SUPPORT
+  /* Convert name to display or OEM name */
+  oname = local_to_display_string(iname);
+#else
+  if ((oname = malloc(strlen(zname) + 1)) == NULL)
+    return ZE_MEM;
+  strcpy(oname, zname);
+#endif
+  if (undosm == NULL)
+    undosm = zname;
+  if ((z = zsearch(zname)) != NULL) {
+    if (pcount && !filter(undosm, casesensitive)) {
+      /* Do not clear z->mark if "exclude", because, when "dosify || !pathput"
+       * is in effect, two files with different filter options may hit the
+       * same z entry.
+       */
+      if (verbose)
+        fprintf(mesg, "excluding %s\n", oname);
+      free((zvoid *)iname);
+      free((zvoid *)zname);
+    } else {
+      z->mark = 1;
+      if ((z->name = malloc(strlen(name) + 1 + PAD)) == NULL) {
+        if (undosm != zname)
+          free((zvoid *)undosm);
+        free((zvoid *)iname);
+        free((zvoid *)zname);
+        return ZE_MEM;
+      }
+      strcpy(z->name, name);
+      z->oname = oname;
+      z->dosflag = dosflag;
+
+#ifdef FORCE_NEWNAME
+      free((zvoid *)(z->iname));
+      z->iname = iname;
+#else
+      /* Better keep the old name. Useful when updating on MSDOS a zip file
+       * made on Unix.
+       */
+      free((zvoid *)iname);
+      free((zvoid *)zname);
+#endif /* ? FORCE_NEWNAME */
+    }
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+    z->namew = NULL;
+    z->inamew = NULL;
+    z->znamew = NULL;
+#endif
+    if (name == label) {
+       label = z->name;
+    }
+  } else if (pcount == 0 || filter(undosm, casesensitive)) {
+
+    /* Check that we are not adding the zip file to itself. This
+     * catches cases like "zip -m foo ../dir/foo.zip".
+     */
+#ifndef CMS_MVS
+/* Version of stat() for CMS/MVS isn't complete enough to see if       */
+/* files match.  Just let ZIP.C compare the filenames.  That's good    */
+/* enough for CMS anyway since there aren't paths to worry about.      */
+    z_stat statb;      /* now use structure z_stat and function zstat globally 7/24/04 EG */
+
+    if (zipstate == -1)
+       zipstate = strcmp(zipfile, "-") != 0 &&
+                   zstat(zipfile, &zipstatb) == 0;
+
+    if (zipstate == 1 && (statb = zipstatb, zstat(name, &statb) == 0
+      && zipstatb.st_mode  == statb.st_mode
+#ifdef VMS
+      && memcmp(zipstatb.st_ino, statb.st_ino, sizeof(statb.st_ino)) == 0
+      && strcmp(zipstatb.st_dev, statb.st_dev) == 0
+      && zipstatb.st_uid   == statb.st_uid
+#else /* !VMS */
+      && zipstatb.st_ino   == statb.st_ino
+      && zipstatb.st_dev   == statb.st_dev
+      && zipstatb.st_uid   == statb.st_uid
+      && zipstatb.st_gid   == statb.st_gid
+#endif /* ?VMS */
+      && zipstatb.st_size  == statb.st_size
+      && zipstatb.st_mtime == statb.st_mtime
+      && zipstatb.st_ctime == statb.st_ctime)) {
+      /* Don't compare a_time since we are reading the file */
+         if (verbose)
+           fprintf(mesg, "file matches zip file -- skipping\n");
+         if (undosm != zname)
+           free((zvoid *)zname);
+         if (undosm != iname)
+           free((zvoid *)undosm);
+         free((zvoid *)iname);
+         free(oname);
+         return ZE_OK;
+    }
+#endif  /* CMS_MVS */
+
+    /* allocate space and add to list */
+    if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL ||
+        fcount + 1 < fcount ||
+        (f->name = malloc(strlen(name) + 1 + PAD)) == NULL)
+    {
+      if (f != NULL)
+        farfree((zvoid far *)f);
+      if (undosm != zname)
+        free((zvoid *)undosm);
+      free((zvoid *)iname);
+      free((zvoid *)zname);
+      free(oname);
+      return ZE_MEM;
+    }
+    strcpy(f->name, name);
+    f->iname = iname;
+    f->zname = zname;
+#ifdef UNICODE_SUPPORT
+    /* Unicode */
+    f->uname = local_to_utf8_string(iname);
+#ifdef WIN32
+    f->namew = NULL;
+    f->inamew = NULL;
+    f->znamew = NULL;
+    if (strcmp(f->name, "-") == 0) {
+      f->namew = local_to_wchar_string(f->name);
+    }
+#endif
+
+#endif
+    f->oname = oname;
+    f->dosflag = dosflag;
+
+    *fnxt = f;
+    f->lst = fnxt;
+    f->nxt = NULL;
+    fnxt = &f->nxt;
+    fcount++;
+    if (name == label) {
+      label = f->name;
+    }
+  }
+  if (undosm != zname)
+    free((zvoid *)undosm);
+  return ZE_OK;
+}
+
+ulg dostime(y, n, d, h, m, s)
+int y;                  /* year */
+int n;                  /* month */
+int d;                  /* day */
+int h;                  /* hour */
+int m;                  /* minute */
+int s;                  /* second */
+/* Convert the date y/n/d and time h:m:s to a four byte DOS date and
+   time (date in high two bytes, time in low two bytes allowing magnitude
+   comparison). */
+{
+  return y < 1980 ? DOSTIME_MINIMUM /* dostime(1980, 1, 1, 0, 0, 0) */ :
+        (((ulg)y - 1980) << 25) | ((ulg)n << 21) | ((ulg)d << 16) |
+        ((ulg)h << 11) | ((ulg)m << 5) | ((ulg)s >> 1);
+}
+
+
+ulg unix2dostime(t)
+time_t *t;              /* unix time to convert */
+/* Return the Unix time t in DOS format, rounded up to the next two
+   second boundary. */
+{
+  time_t t_even;
+  struct tm *s;         /* result of localtime() */
+
+  t_even = (time_t)(((unsigned long)(*t) + 1) & (~1));
+                                /* Round up to even seconds. */
+  s = localtime(&t_even);       /* Use local time since MSDOS does. */
+  if (s == (struct tm *)NULL) {
+      /* time conversion error; use current time as emergency value
+         (assuming that localtime() does at least accept this value!) */
+      t_even = (time_t)(((unsigned long)time(NULL) + 1) & (~1));
+      s = localtime(&t_even);
+  }
+  return dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday,
+                 s->tm_hour, s->tm_min, s->tm_sec);
+}
+
+int issymlnk(a)
+ulg a;                  /* Attributes returned by filetime() */
+/* Return true if the attributes are those of a symbolic link */
+{
+#ifndef QDOS
+#ifdef S_IFLNK
+#ifdef __human68k__
+  int *_dos_importlnenv(void);
+
+  if (_dos_importlnenv() == NULL)
+    return 0;
+#endif
+  return ((a >> 16) & S_IFMT) == S_IFLNK;
+#else /* !S_IFLNK */
+  return (int)a & 0;    /* avoid warning on unused parameter */
+#endif /* ?S_IFLNK */
+#else
+  return 0;
+#endif
+}
+
+#endif /* !UTIL */
+
+
+#if (!defined(UTIL) && !defined(ZP_NEED_GEN_D2U_TIME))
+   /* There is no need for dos2unixtime() in the ZipUtils' code. */
+#  define ZP_NEED_GEN_D2U_TIME
+#endif
+#if ((defined(OS2) || defined(VMS)) && defined(ZP_NEED_GEN_D2U_TIME))
+   /* OS/2 and VMS use a special solution to handle time-stams of files. */
+#  undef ZP_NEED_GEN_D2U_TIME
+#endif
+#if (defined(W32_STATROOT_FIX) && !defined(ZP_NEED_GEN_D2U_TIME))
+   /* The Win32 stat()-bandaid to fix stat'ing root directories needs
+    * dos2unixtime() to calculate the time-stamps. */
+#  define ZP_NEED_GEN_D2U_TIME
+#endif
+
+#ifdef ZP_NEED_GEN_D2U_TIME
+
+time_t dos2unixtime(dostime)
+ulg dostime;            /* DOS time to convert */
+/* Return the Unix time_t value (GMT/UTC time) for the DOS format (local)
+ * time dostime, where dostime is a four byte value (date in most significant
+ * word, time in least significant word), see dostime() function.
+ */
+{
+  struct tm *t;         /* argument for mktime() */
+  ZCONST time_t clock = time(NULL);
+
+  t = localtime(&clock);
+  t->tm_isdst = -1;     /* let mktime() determine if DST is in effect */
+  /* Convert DOS time to UNIX time_t format */
+  t->tm_sec  = (((int)dostime) <<  1) & 0x3e;
+  t->tm_min  = (((int)dostime) >>  5) & 0x3f;
+  t->tm_hour = (((int)dostime) >> 11) & 0x1f;
+  t->tm_mday = (int)(dostime >> 16) & 0x1f;
+  t->tm_mon  = ((int)(dostime >> 21) & 0x0f) - 1;
+  t->tm_year = ((int)(dostime >> 25) & 0x7f) + 80;
+
+  return mktime(t);
+}
+
+#undef ZP_NEED_GEN_D2U_TIME
+#endif /* ZP_NEED_GEN_D2U_TIME */
+
+
+#ifndef MACOS
+int destroy(f)
+  char *f;             /* file to delete */
+/* Delete the file *f, returning non-zero on failure. */
+{
+  return unlink(f);
+}
+
+
+int replace(d, s)
+char *d, *s;            /* destination and source file names */
+/* Replace file *d by file *s, removing the old *s.  Return an error code
+   in the ZE_ class. This function need not preserve the file attributes,
+   this will be done by setfileattr() later.
+ */
+{
+  z_stat t;         /* results of stat() */
+#if defined(CMS_MVS)
+  /* cmsmvs.h defines FOPW_TEMP as memory(hiperspace).  Since memory is
+   * lost at end of run, always do copy instead of rename.
+   */
+  int copy = 1;
+#else
+  int copy = 0;
+#endif
+  int d_exists;
+
+#if defined(VMS) || defined(CMS_MVS)
+  /* stat() is broken on VMS remote files (accessed through Decnet).
+   * This patch allows creation of remote zip files, but is not sufficient
+   * to update them or compress remote files */
+  unlink(d);
+#else /* !(VMS || CMS_MVS) */
+  d_exists = (LSTAT(d, &t) == 0);
+  if (d_exists)
+  {
+    /*
+     * respect existing soft and hard links!
+     */
+    if (t.st_nlink > 1
+# ifdef S_IFLNK
+        || (t.st_mode & S_IFMT) == S_IFLNK
+# endif
+        )
+       copy = 1;
+    else if (unlink(d))
+       return ZE_CREAT;                 /* Can't erase zip file--give up */
+  }
+#endif /* ?(VMS || CMS_MVS) */
+#ifndef CMS_MVS
+  if (!copy) {
+      if (rename(s, d)) {               /* Just move s on top of d */
+          copy = 1;                     /* failed ? */
+#if !defined(VMS) && !defined(ATARI) && !defined(AZTEC_C)
+#if !defined(CMS_MVS) && !defined(RISCOS) && !defined(QDOS)
+    /* For VMS, ATARI, AMIGA Aztec, VM_CMS, MVS, RISCOS,
+       always assume that failure is EXDEV */
+          if (errno != EXDEV
+#  ifdef THEOS
+           && errno != EEXIST
+#  else
+#    ifdef ENOTSAM
+           && errno != ENOTSAM /* Used at least on Turbo C */
+#    endif
+#  endif
+              ) return ZE_CREAT;
+#endif /* !CMS_MVS && !RISCOS */
+#endif /* !VMS && !ATARI && !AZTEC_C */
+      }
+  }
+#endif /* !CMS_MVS */
+
+  if (copy) {
+    FILE *f, *g;        /* source and destination files */
+    int r;              /* temporary variable */
+
+#ifdef RISCOS
+    if (SWI_OS_FSControl_26(s,d,0xA1)!=NULL) {
+#endif
+
+    /* Use zfopen for almost all opens where fopen is used.  For
+       most OS that support large files we use the 64-bit file
+       environment and zfopen maps to fopen, but this allows
+       tweeking ports that don't do that.  7/24/04 */
+    if ((f = zfopen(s, FOPR)) == NULL) {
+      fprintf(mesg," replace: can't open %s\n", s);
+      return ZE_TEMP;
+    }
+    if ((g = zfopen(d, FOPW)) == NULL)
+    {
+      fclose(f);
+      return ZE_CREAT;
+    }
+
+    r = fcopy(f, g, (ulg)-1L);
+    fclose(f);
+    if (fclose(g) || r != ZE_OK)
+    {
+      unlink(d);
+      return r ? (r == ZE_TEMP ? ZE_WRITE : r) : ZE_WRITE;
+    }
+    unlink(s);
+#ifdef RISCOS
+    }
+#endif
+  }
+  return ZE_OK;
+}
+#endif /* !MACOS */
+
+
+int getfileattr(f)
+char *f;                /* file path */
+/* Return the file attributes for file f or 0 if failure */
+{
+#ifdef __human68k__
+  struct _filbuf buf;
+
+  return _dos_files(&buf, f, 0xff) < 0 ? 0x20 : buf.atr;
+#else
+  z_stat s;
+
+  return SSTAT(f, &s) == 0 ? (int) s.st_mode : 0;
+#endif
+}
+
+
+int setfileattr(f, a)
+char *f;                /* file path */
+int a;                  /* attributes returned by getfileattr() */
+/* Give the file f the attributes a, return non-zero on failure */
+{
+#if defined(TOPS20) || defined (CMS_MVS)
+  return 0;
+#else
+#ifdef __human68k__
+  return _dos_chmod(f, a) < 0 ? -1 : 0;
+#else
+  return chmod(f, a);
+#endif
+#endif
+}
+
+
+/* tempname */
+
+#ifndef VMS /* VMS-specific function is in VMS.C. */
+
+char *tempname(zip)
+  char *zip;              /* path name of zip file to generate temp name for */
+
+/* Return a temporary file name in its own malloc'ed space, using tempath. */
+{
+  char *t = zip;   /* malloc'ed space for name (use zip to avoid warning) */
+
+# ifdef CMS_MVS
+  if ((t = malloc(strlen(tempath) + L_tmpnam + 2)) == NULL)
+    return NULL;
+
+#  ifdef VM_CMS
+  tmpnam(t);
+  /* Remove filemode and replace with tempath, if any. */
+  /* Otherwise A-disk is used by default */
+  *(strrchr(t, ' ')+1) = '\0';
+  if (tempath!=NULL)
+     strcat(t, tempath);
+  return t;
+#  else   /* !VM_CMS */
+  /* For MVS */
+  tmpnam(t);
+  if (tempath != NULL)
+  {
+    int l1 = strlen(t);
+    char *dot;
+    if (*t == '\'' && *(t+l1-1) == '\'' && (dot = strchr(t, '.')))
+    {
+      /* MVS and not OE.  tmpnam() returns quoted string of 5 qualifiers.
+       * First is HLQ, rest are timestamps.  User can only replace HLQ.
+       */
+      int l2 = strlen(tempath);
+      if (strchr(tempath, '.') || l2 < 1 || l2 > 8)
+        ziperr(ZE_PARMS, "On MVS and not OE, tempath (-b) can only be HLQ");
+      memmove(t+1+l2, dot, l1+1-(dot-t));  /* shift dot ready for new hlq */
+      memcpy(t+1, tempath, l2);            /* insert new hlq */
+    }
+    else
+    {
+      /* MVS and probably OE.  tmpnam() returns filename based on TMPDIR,
+       * no point in even attempting to change it.  User should modify TMPDIR
+       * instead.
+       */
+      zipwarn("MVS, assumed to be OE, change TMPDIR instead of option -b: ",
+              tempath);
+    }
+  }
+  return t;
+#  endif  /* !VM_CMS */
+
+# else /* !CMS_MVS */
+
+#  ifdef TANDEM
+  char cur_subvol [FILENAME_MAX];
+  char temp_subvol [FILENAME_MAX];
+  char *zptr;
+  char *ptr;
+  char *cptr = &cur_subvol[0];
+  char *tptr = &temp_subvol[0];
+  short err;
+  FILE *tempf;
+  int attempts;
+
+  t = (char *)malloc(NAMELEN); /* malloc here as you cannot free */
+                               /* tmpnam allocated storage later */
+
+  zptr = strrchr(zip, TANDEM_DELIMITER);
+
+  if (zptr != NULL) {
+    /* ZIP file specifies a Subvol so make temp file there so it can just
+       be renamed at end */
+
+    *tptr = *cptr = '\0';
+    strcat(cptr, getenv("DEFAULTS"));
+
+    strncat(tptr, zip, _min(FILENAME_MAX, (zptr - zip)) ); /* temp subvol */
+    strncat(t, zip, _min(NAMELEN, ((zptr - zip) + 1)) );   /* temp stem   */
+
+    err = chvol(tptr);
+    ptr = t + strlen(t);  /* point to end of stem */
+  }
+  else
+    ptr = t;
+
+  /* If two zips are running in same subvol then we can get contention problems
+     with the temporary filename.  As a work around we attempt to create
+     the file here, and if it already exists we get a new temporary name */
+
+  attempts = 0;
+  do {
+    attempts++;
+    tmpnam(ptr);  /* Add filename */
+    tempf = zfopen(ptr, FOPW_TMP);    /* Attempt to create file */
+  } while (tempf == NULL && attempts < 100);
+
+  if (attempts >= 100) {
+    ziperr(ZE_TEMP, "Could not get unique temp file name");
+  }
+
+  fclose(tempf);
+
+  if (zptr != NULL) {
+    err = chvol(cptr);  /* Put ourself back to where we came in */
+  }
+
+  return t;
+
+#  else /* !CMS_MVS && !TANDEM */
+/*
+ * Do something with TMPDIR, TMP, TEMP ????
+ */
+  if (tempath != NULL)
+  {
+    if ((t = malloc(strlen(tempath) + 12)) == NULL)
+      return NULL;
+    strcpy(t, tempath);
+
+#   if (!defined(VMS) && !defined(TOPS20))
+#    ifdef MSDOS
+    {
+      char c = (char)lastchar(t);
+      if (c != '/' && c != ':' && c != '\\')
+        strcat(t, "/");
+    }
+#    else
+
+#     ifdef AMIGA
+    {
+      char c = (char)lastchar(t);
+      if (c != '/' && c != ':')
+        strcat(t, "/");
+    }
+#     else /* !AMIGA */
+#      ifdef RISCOS
+    if (lastchar(t) != '.')
+      strcat(t, ".");
+#      else /* !RISCOS */
+
+#       ifdef QDOS
+    if (lastchar(t) != '_')
+      strcat(t, "_");
+#       else
+    if (lastchar(t) != '/')
+      strcat(t, "/");
+#       endif /* ?QDOS */
+#      endif /* ?RISCOS */
+#     endif  /* ?AMIGA */
+#    endif /* ?MSDOS */
+#   endif /* !VMS && !TOPS20 */
+  }
+  else
+  {
+    if ((t = malloc(12)) == NULL)
+      return NULL;
+    *t = 0;
+  }
+#   ifdef NO_MKTEMP
+  {
+    char *p = t + strlen(t);
+    sprintf(p, "%08lx", (ulg)time(NULL));
+    return t;
+  }
+#   else
+  strcat(t, "ziXXXXXX"); /* must use lowercase for Linux dos file system */
+#     if defined(UNIX) && !defined(NO_MKSTEMP)
+  /* tempname should not be called */
+  return t;
+#     else
+  return mktemp(t);
+#     endif
+#   endif /* NO_MKTEMP */
+#  endif /* TANDEM */
+# endif /* CMS_MVS */
+}
+#endif /* !VMS */
+
+int fcopy(f, g, n)
+  FILE *f, *g;            /* source and destination files */
+  /* now use uzoff_t for all file sizes 5/14/05 CS */
+  uzoff_t n;               /* number of bytes to copy or -1 for all */
+/* Copy n bytes from file *f to file *g, or until EOF if (zoff_t)n == -1.
+   Return an error code in the ZE_ class. */
+{
+  char *b;              /* malloc'ed buffer for copying */
+  extent k;             /* result of fread() */
+  uzoff_t m;            /* bytes copied so far */
+
+  if ((b = malloc(CBSZ)) == NULL)
+    return ZE_MEM;
+  m = 0;
+  while (n == (uzoff_t)(-1L) || m < n)
+  {
+    if ((k = fread(b, 1, n == (uzoff_t)(-1) ?
+                   CBSZ : (n - m < CBSZ ? (extent)(n - m) : CBSZ), f)) == 0)
+    {
+      if (ferror(f))
+      {
+        free((zvoid *)b);
+        return ZE_READ;
+      }
+      else
+        break;
+    }
+    if (fwrite(b, 1, k, g) != k)
+    {
+      free((zvoid *)b);
+      fprintf(mesg," fcopy: write error\n");
+      return ZE_TEMP;
+    }
+    m += k;
+  }
+  free((zvoid *)b);
+  return ZE_OK;
+}
+
+
+/* from zipfile.c */
+
+#ifdef THEOS
+ /* Macros cause stack overflow in compiler */
+ ush SH(uch* p) { return ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)); }
+ ulg LG(uch* p) { return ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)); }
+#else /* !THEOS */
+ /* Macros for converting integers in little-endian to machine format */
+# define SH(a) ((ush)(((ush)(uch)(a)[0]) | (((ush)(uch)(a)[1]) << 8)))
+# define LG(a) ((ulg)SH(a) | ((ulg)SH((a)+2) << 16))
+# ifdef ZIP64_SUPPORT           /* zip64 support 08/31/2003 R.Nausedat */
+#  define LLG(a) ((zoff_t)LG(a) | ((zoff_t)LG((a)+4) << 32))
+# endif
+#endif /* ?THEOS */
+
+
+/* always copies from global in_file to global output file y */
+int bfcopy(n)
+  /* now use uzoff_t for all file sizes 5/14/05 CS */
+  uzoff_t n;               /* number of bytes to copy or -1 for all */
+/* Copy n bytes from in_file to out_file, or until EOF if (zoff_t)n == -1.
+
+   Normally we have the compressed size from either the central directory
+   entry or the local header.
+
+   If n != -1 and EOF, close current split and open next and continue
+   copying.
+
+   If n == -2, copy until find the extended header (data descriptor).  Only
+   used for -FF when no size available.
+
+   If fix == 1 calculate CRC of input entry and verify matches.
+
+   If fix == 2 and this entry using data descriptor keep a sliding
+   window in the buffer for looking for signature.
+
+   Return an error code in the ZE_ class. */
+{
+  char *b;              /* malloc'ed buffer for copying */
+  extent k;             /* result of fread() */
+  uzoff_t m;            /* bytes copied so far */
+  extent brd;           /* bytes to read */
+  zoff_t data_start = 0;
+  zoff_t des_start = 0;
+  char *split_path;
+  extent kk;
+  int i;
+  char sbuf[4];         /* buffer for sliding signature window for fix = 2 */
+  int des = 0;          /* this entry has data descriptor to find */
+
+  if ((b = malloc(CBSZ)) == NULL)
+    return ZE_MEM;
+
+  if (copy_only && !display_globaldots) {
+    /* initialize dot count */
+    dot_count = -1;
+  }
+
+  if (fix == 2 && n == (uzoff_t) -2) {
+    data_start = zftello(in_file);
+    for (kk = 0; kk < 4; kk++)
+      sbuf[kk] = 0;
+    des = 1;
+  }
+
+  des_good = 0;
+
+  m = 0;
+  while (des || n == (uzoff_t)(-1L) || m < n)
+  {
+    if (des || n == (uzoff_t)(-1))
+      brd = CBSZ;
+    else
+      brd = (n - m < CBSZ ? (extent)(n - m) : CBSZ);
+
+    des_start = zftello(in_file);
+
+    if ((k = fread(b, 1, brd, in_file)) == 0)
+    {
+      if (fix == 2 && k < brd) {
+        free((zvoid *)b);
+        return ZE_READ;
+      }
+      else if (ferror(in_file))
+      {
+        free((zvoid *)b);
+        return ZE_READ;
+      }
+      else {
+        break;
+      }
+    }
+
+
+    /* end at extended local header (data descriptor) signature */
+    if (des) {
+      des_crc = 0;
+      des_csize = 0;
+      des_usize = 0;
+
+      /* If first 4 bytes in buffer are data descriptor signature then
+         try to read the data descriptor.
+         If not, scan for signature and break if found, let bfwrite flush
+         the data and then next read should put the data descriptor at
+         the beginning of the buffer.
+       */
+
+      if (
+          (b[0] != 0x50 /*'P' except EBCDIC*/ ||
+           b[1] != 0x4b /*'K' except EBCDIC*/ ||
+           b[2] != '\07' ||
+           b[3] != '\010')) {
+        /* buffer is not start of data descriptor */
+
+        for (kk = 0; kk < k; kk++) {
+          /* add byte to end of sbuf */
+          for (i = 0; i < 3; i++)
+            sbuf[i] = sbuf[i + 1];
+          sbuf[3] = b[kk];
+
+          /* see if this is signature */
+          if (
+              (sbuf[0] == 0x50 /*'P' except EBCDIC*/ &&
+               sbuf[1] == 0x4b /*'K' except EBCDIC*/ &&
+               sbuf[2] == '\07' &&
+               sbuf[3] == '\010')) {
+            kk -= 3;
+            if (zfseeko(in_file, bytes_this_split + kk, SEEK_SET) != 0) {
+              /* seek error */
+              ZIPERR(ZE_READ, "seek failed reading descriptor");
+            }
+            des_start = zftello(in_file);
+            k = kk;
+            break;
+          }
+        }
+      }
+      else
+
+      /* signature at start of buffer */
+      {
+        des_good = 0;
+
+#ifdef ZIP64_SUPPORT
+        if (zip64_entry) {
+
+          /* read Zip64 data descriptor */
+          if (k < 24) {
+            /* not enough bytes, so can't be data descriptor
+               as data descriptors can't be split across splits
+             */
+          }
+          else
+          {
+            /* read the Zip64 descriptor */
+
+            des_crc = LG(b + 4);
+            des_csize = LLG(b + 8);
+            des_usize = LLG(b + 16);
+
+            /* if this is the right data descriptor then the sizes should match */
+            if ((uzoff_t)des_start - (uzoff_t)data_start != des_csize) {
+              /* apparently this signature does not go with this data so skip */
+
+              /* write out signature as data */
+              k = 4;
+              if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
+                /* seek error */
+                ZIPERR(ZE_READ, "seek failed reading descriptor");
+              }
+              if (bfwrite(b, 1, k, BFWRITE_DATA) != k)
+              {
+                free((zvoid *)b);
+                fprintf(mesg," fcopy: write error\n");
+                return ZE_TEMP;
+              }
+              m += k;
+              continue;
+            }
+            else
+            {
+              /* apparently this is the correct data descriptor */
+
+              /* we should check the CRC but would need to inflate
+                 the data */
+
+              /* skip descriptor as will write out later */
+              des_good = 1;
+              k = 24;
+              data_start = zftello(in_file);
+              if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
+                /* seek error */
+                ZIPERR(ZE_READ, "seek failed reading descriptor");
+              }
+              data_start = zftello(in_file);
+            }
+          }
+
+        }
+        else
+#endif
+        {
+          /* read standard data descriptor */
+
+          if (k < 16) {
+            /* not enough bytes, so can't be data descriptor
+               as data descriptors can't be split across splits
+             */
+          }
+          else
+          {
+            /* read the descriptor */
+
+            des_crc = LG(b + 4);
+            des_csize = LG(b + 8);
+            des_usize = LG(b + 12);
+
+            /* if this is the right data descriptor then the sizes should match */
+            if ((uzoff_t)des_start - (uzoff_t)data_start != des_csize) {
+              /* apparently this signature does not go with this data so skip */
+
+              /* write out signature as data */
+              k = 4;
+              if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
+                /* seek error */
+                ZIPERR(ZE_READ, "seek failed reading descriptor");
+              }
+              if (bfwrite(b, 1, k, BFWRITE_DATA) != k)
+              {
+                free((zvoid *)b);
+                fprintf(mesg," fcopy: write error\n");
+                return ZE_TEMP;
+              }
+              m += k;
+              continue;
+            }
+            else
+            {
+              /* apparently this is the correct data descriptor */
+
+              /* we should check the CRC but this does not work for
+                 encrypted data */
+
+              /* skip descriptor as will write out later */
+              des_good = 1;
+              data_start = zftello(in_file);
+              k = 16;
+              if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
+                /* seek error */
+                ZIPERR(ZE_READ, "seek failed reading descriptor");
+              }
+              data_start = zftello(in_file);
+            }
+          }
+
+
+        }
+      }
+    }
+
+
+    if (des_good) {
+      /* skip descriptor as will write out later */
+    } else {
+      /* write out apparently wrong descriptor as data */
+      if (bfwrite(b, 1, k, BFWRITE_DATA) != k)
+      {
+        free((zvoid *)b);
+        fprintf(mesg," fcopy: write error\n");
+        return ZE_TEMP;
+      }
+      m += k;
+    }
+
+    if (copy_only && !display_globaldots) {
+      if (dot_size > 0) {
+        /* initial space */
+        if (noisy && dot_count == -1) {
+#ifndef WINDLL
+          putc(' ', mesg);
+          fflush(mesg);
+#else
+          fprintf(stdout,"%c",' ');
+#endif
+          dot_count++;
+        }
+        dot_count += k;
+        if (dot_size <= dot_count) dot_count = 0;
+      }
+      if ((verbose || noisy) && dot_size && !dot_count) {
+#ifndef WINDLL
+        putc('.', mesg);
+        fflush(mesg);
+#else
+        fprintf(stdout,"%c",'.');
+#endif
+        mesg_line_started = 1;
+      }
+    }
+
+    if (des_good)
+      break;
+
+    if (des)
+      continue;
+
+    if ((des || n != (uzoff_t)(-1L)) && m < n && feof(in_file)) {
+      /* open next split */
+      current_in_disk++;
+
+      if (current_in_disk >= total_disks) {
+        /* done */
+        break;
+
+      } else if (current_in_disk == total_disks - 1) {
+        /* last disk is archive.zip */
+        if ((split_path = malloc(strlen(in_path) + 1)) == NULL) {
+          zipwarn("reading archive: ", in_path);
+          return ZE_MEM;
+        }
+        strcpy(split_path, in_path);
+      } else {
+        /* other disks are archive.z01, archive.z02, ... */
+        split_path = get_in_split_path(in_path, current_in_disk);
+      }
+
+      fclose(in_file);
+
+      /* open the split */
+      while ((in_file = zfopen(split_path, FOPR)) == NULL) {
+        int r = 0;
+
+        /* could not open split */
+
+        if (fix == 1 && skip_this_disk) {
+          free(split_path);
+          free((zvoid *)b);
+          return ZE_FORM;
+        }
+
+        /* Ask for directory with split.  Updates in_path */
+        r = ask_for_split_read_path(current_in_disk);
+        if (r == ZE_ABORT) {
+          zipwarn("could not find split: ", split_path);
+          free(split_path);
+          free((zvoid *)b);
+          return ZE_ABORT;
+        }
+        if (r == ZE_EOF) {
+          zipmessage_nl("", 1);
+          zipwarn("user ended reading - closing archive", "");
+          free(split_path);
+          free((zvoid *)b);
+          return ZE_EOF;
+        }
+        if (fix == 2 && skip_this_disk) {
+          /* user asked to skip this disk */
+          zipwarn("skipping split file: ", split_path);
+          current_in_disk++;
+        }
+
+        if (current_in_disk == total_disks - 1) {
+          /* last disk is archive.zip */
+          if ((split_path = malloc(strlen(in_path) + 1)) == NULL) {
+            zipwarn("reading archive: ", in_path);
+            return ZE_MEM;
+          }
+          strcpy(split_path, in_path);
+        } else {
+          /* other disks are archive.z01, archive.z02, ... */
+          split_path = get_in_split_path(zipfile, current_in_disk);
+        }
+      }
+      if (fix == 2 && skip_this_disk) {
+        /* user asked to skip this disk */
+        free(split_path);
+        free((zvoid *)b);
+        return ZE_FORM;
+      }
+      free(split_path);
+    }
+  }
+  free((zvoid *)b);
+  return ZE_OK;
+}
+
+
+
+#ifdef NO_RENAME
+int rename(from, to)
+ZCONST char *from;
+ZCONST char *to;
+{
+    unlink(to);
+    if (link(from, to) == -1)
+        return -1;
+    if (unlink(from) == -1)
+        return -1;
+    return 0;
+}
+
+#endif /* NO_RENAME */
+
+
+#ifdef ZMEM
+
+/************************/
+/*  Function memset()   */
+/************************/
+
+/*
+ * memset - for systems without it
+ *  bill davidsen - March 1990
+ */
+
+char *
+memset(buf, init, len)
+register char *buf;     /* buffer loc */
+register int init;      /* initializer */
+register unsigned int len;   /* length of the buffer */
+{
+    char *start;
+
+    start = buf;
+    while (len--) *(buf++) = init;
+    return(start);
+}
+
+
+/************************/
+/*  Function memcpy()   */
+/************************/
+
+char *
+memcpy(dst,src,len)             /* v2.0f */
+register char *dst, *src;
+register unsigned int len;
+{
+    char *start;
+
+    start = dst;
+    while (len--)
+        *dst++ = *src++;
+    return(start);
+}
+
+
+/************************/
+/*  Function memcmp()   */
+/************************/
+
+int
+memcmp(b1,b2,len)                     /* jpd@usl.edu -- 11/16/90 */
+register char *b1, *b2;
+register unsigned int len;
+{
+
+    if (len) do {       /* examine each byte (if any) */
+      if (*b1++ != *b2++)
+        return (*((uch *)b1-1) - *((uch *)b2-1));  /* exit when miscompare */
+    } while (--len);
+
+    return(0);          /* no miscompares, yield 0 result */
+}
+
+#endif  /* ZMEM */
+
+
+/*------------------------------------------------------------------
+ * Split archives
+ */
+
+
+/* ask_for_split_read_path
+ *
+ * If the next split file is not in the current directory, ask
+ * the user where it is.
+ *
+ * in_path is the base path for reading splits and is usually
+ * the same as zipfile.  The path in in_path must be the archive
+ * file ending in .zip as this is assumed by get_in_split_path().
+ *
+ * Updates in_path if changed.  Returns ZE_OK if OK or ZE_ABORT if
+ * user cancels reading archive.
+ *
+ * If fix = 1 then allow skipping disk (user may not have it).
+ */
+
+#define SPLIT_MAXPATH (FNMAX + 4010)
+
+int ask_for_split_read_path(current_disk)
+  ulg current_disk;
+{
+  FILE *f;
+  int is_readable = 0;
+  int i;
+  char *split_dir = NULL;
+  char *archive_name = NULL;
+  char *split_name = NULL;
+  char *split_path = NULL;
+  char buf[SPLIT_MAXPATH + 100];
+
+  /* get split path */
+  split_path = get_in_split_path(in_path, current_disk);
+
+  /* get the directory */
+  if ((split_dir = malloc(strlen(in_path) + 40)) == NULL) {
+    ZIPERR(ZE_MEM, "split path");
+  }
+  strcpy(split_dir, in_path);
+
+  /* remove any name at end */
+  for (i = strlen(split_dir) - 1; i >= 0; i--) {
+    if (split_dir[i] == '/' || split_dir[i] == '\\'
+          || split_dir[i] == ':') {
+      split_dir[i + 1] = '\0';
+      break;
+    }
+  }
+  if (i < 0)
+    split_dir[0] = '\0';
+
+  /* get the name of the archive */
+  if ((archive_name = malloc(strlen(in_path) + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "split path");
+  }
+  if (strlen(in_path) == strlen(split_dir)) {
+    archive_name[0] = '\0';
+  } else {
+    strcpy(archive_name, in_path + strlen(split_dir));
+  }
+
+  /* get the name of the split */
+  if ((split_name = malloc(strlen(split_path) + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "split path");
+  }
+  if (strlen(in_path) == strlen(split_dir)) {
+    split_name[0] = '\0';
+  } else {
+    strcpy(split_name, split_path + strlen(split_dir));
+  }
+  if (i < 0) {
+    strcpy(split_dir, "(current directory)");
+  }
+
+  fprintf(mesg, "\n\nCould not find:\n");
+  fprintf(mesg, "  %s\n", split_path);
+  /*
+  fprintf(mesg, "Please enter the path directory (. for cur dir) where\n");
+  fprintf(mesg, "  %s\n", split_name);
+  fprintf(mesg, "is located\n");
+  */
+  for (;;) {
+    if (is_readable) {
+      fprintf(mesg, "\nHit c      (change path to where this split file is)");
+      fprintf(mesg, "\n    q      (abort archive - quit)");
+      fprintf(mesg, "\n or ENTER  (continue with this split): ");
+    } else {
+      if (fix == 1) {
+        fprintf(mesg, "\nHit c      (change path to where this split file is)");
+        fprintf(mesg, "\n    s      (skip this split)");
+        fprintf(mesg, "\n    q      (abort archive - quit)");
+        fprintf(mesg, "\n or ENTER  (try reading this split again): ");
+      } else if (fix == 2) {
+        fprintf(mesg, "\nHit c      (change path to where this split file is)");
+        fprintf(mesg, "\n    s      (skip this split)");
+        fprintf(mesg, "\n    q      (abort archive - quit)");
+        fprintf(mesg, "\n    e      (end this archive - no more splits)");
+        fprintf(mesg, "\n    z      (look for .zip split - the last split)");
+        fprintf(mesg, "\n or ENTER  (try reading this split again): ");
+      } else {
+        fprintf(mesg, "\nHit c      (change path to where this split file is)");
+        fprintf(mesg, "\n    q      (abort archive - quit)");
+        fprintf(mesg, "\n or ENTER  (try reading this split again): ");
+      }
+    }
+    fflush(mesg);
+    fgets(buf, SPLIT_MAXPATH, stdin);
+    /* remove any newline */
+    for (i = 0; buf[i]; i++) {
+      if (buf[i] == '\n') {
+        buf[i] = '\0';
+        break;
+      }
+    }
+    if (toupper(buf[0]) == 'Q') {
+      return ZE_ABORT;
+    } else if ((fix == 1 || fix == 2) && toupper(buf[0]) == 'S') {
+    /*
+      fprintf(mesg, "\nSkip this split/disk?  (files in this split will not be recovered) [n/y] ");
+      fflush(mesg);
+      fgets(buf, SPLIT_MAXPATH, stdin);
+      if (buf[0] == 'y' || buf[0] == 'Y') {
+    */
+      skip_this_disk = current_in_disk + 1;
+      return ZE_FORM;
+    } else if (toupper(buf[0]) == 'C') {
+      fprintf(mesg, "\nEnter path where this split is (ENTER = same dir, . = current dir)");
+      fprintf(mesg, "\n: ");
+      fflush(mesg);
+      fgets(buf, SPLIT_MAXPATH, stdin);
+      is_readable = 0;
+      /* remove any newline */
+      for (i = 0; buf[i]; i++) {
+        if (buf[i] == '\n') {
+          buf[i] = '\0';
+          break;
+        }
+      }
+      if (buf[0] == '\0') {
+        /* Hit ENTER so try old path again - could be removable media was changed */
+        strcpy(buf, split_path);
+      }
+    } else if (fix == 2 && toupper(buf[0]) == 'E') {
+      /* no more splits to read */
+      return ZE_EOF;
+    } else if (fix == 2 && toupper(buf[0]) == 'Z') {
+      total_disks = current_disk + 1;
+      free(split_path);
+      split_path = get_in_split_path(in_path, current_disk);
+      buf[0] = '\0';
+      strncat(buf, split_path, SPLIT_MAXPATH);
+    }
+    if (strlen(buf) > 0) {
+      /* changing path */
+
+      /* check if user wants current directory */
+      if (buf[0] == '.' && buf[1] == '\0') {
+        buf[0] = '\0';
+      }
+      /* remove any name at end */
+      for (i = strlen(buf); i >= 0; i--) {
+        if (buf[i] == '/' || buf[i] == '\\'
+             || buf[i] == ':') {
+          buf[i + 1] = '\0';
+          break;
+        }
+      }
+      /* update base_path to newdir/split_name - in_path is the .zip file path */
+      free(in_path);
+      if (i < 0) {
+        /* just name so current directory */
+        strcpy(buf, "(current directory)");
+        if (archive_name == NULL) {
+          i = 0;
+        } else {
+          i = strlen(archive_name);
+        }
+        if ((in_path = malloc(strlen(archive_name) + 40)) == NULL) {
+          ZIPERR(ZE_MEM, "split path");
+        }
+        strcpy(in_path, archive_name);
+      } else {
+        /* not the current directory */
+        /* remove any name at end */
+        for (i = strlen(buf); i >= 0; i--) {
+          if (buf[i] == '/') {
+            buf[i + 1] = '\0';
+            break;
+          }
+        }
+        if (i < 0) {
+          buf[0] = '\0';
+        }
+        if ((in_path = malloc(strlen(buf) + strlen(archive_name) + 40)) == NULL) {
+          ZIPERR(ZE_MEM, "split path");
+        }
+        strcpy(in_path, buf);
+        strcat(in_path, archive_name);
+      }
+
+      free(split_path);
+
+      /* get split path */
+      split_path = get_in_split_path(in_path, current_disk);
+
+      free(split_dir);
+      if ((split_dir = malloc(strlen(in_path) + 40)) == NULL) {
+        ZIPERR(ZE_MEM, "split path");
+      }
+      strcpy(split_dir, in_path);
+      /* remove any name at end */
+      for (i = strlen(split_dir); i >= 0; i--) {
+        if (split_dir[i] == '/') {
+          split_dir[i + 1] = '\0';
+          break;
+        }
+      }
+
+      /* try to open it */
+      if ((f = fopen(split_path, "r")) == NULL) {
+        fprintf(mesg, "\nCould not find or open\n");
+        fprintf(mesg, "  %s\n", split_path);
+        /*
+        fprintf(mesg, "Please enter the path (. for cur dir) where\n");
+        fprintf(mesg, "  %s\n", split_name);
+        fprintf(mesg, "is located\n");
+        */
+        continue;
+      }
+      fclose(f);
+      is_readable = 1;
+      fprintf(mesg, "Found:  %s\n", split_path);
+    } else {
+      /* try to open it */
+      if ((f = fopen(split_path, "r")) == NULL) {
+        fprintf(mesg, "\nCould not find or open\n");
+        fprintf(mesg, "  %s\n", split_path);
+        /*
+        fprintf(mesg, "Please enter the path (. for cur dir) where\n");
+        fprintf(mesg, "  %s\n", split_name);
+        fprintf(mesg, "is located\n");
+        */
+        continue;
+      }
+      fclose(f);
+      is_readable = 1;
+      fprintf(mesg, "\nFound:  %s\n", split_path);
+      break;
+    }
+  }
+  free(archive_name);
+  free(split_dir);
+  free(split_name);
+
+  return ZE_OK;
+}
+
+
+/* ask_for_split_write_path
+ *
+ * Verify the directory for the next split.  Called
+ * when -sp is used to pause between writing splits.
+ *
+ * Updates out_path and return 1 if OK or 0 if cancel
+ */
+int ask_for_split_write_path(current_disk)
+  ulg current_disk;
+{
+  unsigned int num = (unsigned int)current_disk + 1;
+  int i;
+  char *split_dir = NULL;
+  char *split_name = NULL;
+  char buf[FNMAX + 40];
+
+  /* get the directory */
+  if ((split_dir = malloc(strlen(out_path) + 40)) == NULL) {
+    ZIPERR(ZE_MEM, "split path");
+  }
+  strcpy(split_dir, out_path);
+
+  /* remove any name at end */
+  for (i = strlen(split_dir); i >= 0; i--) {
+    if (split_dir[i] == '/' || split_dir[i] == '\\'
+          || split_dir[i] == ':') {
+      split_dir[i + 1] = '\0';
+      break;
+    }
+  }
+
+  /* get the name of the split */
+  if ((split_name = malloc(strlen(out_path) + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "split path");
+  }
+  if (strlen(out_path) == strlen(split_dir)) {
+    split_name[0] = '\0';
+  } else {
+    strcpy(split_name, out_path + strlen(split_dir));
+  }
+  if (i < 0) {
+    strcpy(split_dir, "(current directory)");
+  }
+  if (mesg_line_started)
+    fprintf(mesg, "\n");
+  fprintf(mesg, "\nOpening disk %d\n", num);
+  fprintf(mesg, "Hit ENTER to write to default path of\n");
+  fprintf(mesg, "  %s\n", split_dir);
+  fprintf(mesg, "or enter a new directory path (. for cur dir) and hit ENTER\n");
+  for (;;) {
+    fprintf(mesg, "\nPath (or hit ENTER to continue): ");
+    fflush(mesg);
+    fgets(buf, FNMAX, stdin);
+    /* remove any newline */
+    for (i = 0; buf[i]; i++) {
+      if (buf[i] == '\n') {
+        buf[i] = '\0';
+        break;
+      }
+    }
+    if (strlen(buf) > 0) {
+      /* changing path */
+
+      /* current directory */
+      if (buf[0] == '.' && buf[1] == '\0') {
+        buf[0] = '\0';
+      }
+      /* remove any name at end */
+      for (i = strlen(buf); i >= 0; i--) {
+        if (buf[i] == '/' || buf[i] == '\\'
+             || buf[i] == ':') {
+          buf[i + 1] = '\0';
+          break;
+        }
+      }
+      /* update out_path to newdir/split_name */
+      free(out_path);
+      if (i < 0) {
+        /* just name so current directory */
+        strcpy(buf, "(current directory)");
+        if (split_name == NULL) {
+          i = 0;
+        } else {
+          i = strlen(split_name);
+        }
+        if ((out_path = malloc(strlen(split_name) + 40)) == NULL) {
+          ZIPERR(ZE_MEM, "split path");
+        }
+        strcpy(out_path, split_name);
+      } else {
+        /* not the current directory */
+        /* remove any name at end */
+        for (i = strlen(buf); i >= 0; i--) {
+          if (buf[i] == '/') {
+            buf[i + 1] = '\0';
+            break;
+          }
+        }
+        if (i < 0) {
+          buf[0] = '\0';
+        }
+        if ((out_path = malloc(strlen(buf) + strlen(split_name) + 40)) == NULL) {
+          ZIPERR(ZE_MEM, "split path");
+        }
+        strcpy(out_path, buf);
+        strcat(out_path, split_name);
+      }
+      fprintf(mesg, "Writing to:\n  %s\n", buf);
+      free(split_name);
+      free(split_dir);
+      if ((split_dir = malloc(strlen(out_path) + 40)) == NULL) {
+        ZIPERR(ZE_MEM, "split path");
+      }
+      strcpy(split_dir, out_path);
+      /* remove any name at end */
+      for (i = strlen(split_dir); i >= 0; i--) {
+        if (split_dir[i] == '/') {
+          split_dir[i + 1] = '\0';
+          break;
+        }
+      }
+      if ((split_name = malloc(strlen(out_path) + 1)) == NULL) {
+        ZIPERR(ZE_MEM, "split path");
+      }
+      strcpy(split_name, out_path + strlen(split_dir));
+    } else {
+      break;
+    }
+  }
+  free(split_dir);
+  free(split_name);
+
+  /* for now no way out except Ctrl C */
+  return 1;
+}
+
+
+/* split_name
+ *
+ * get name of split being read
+ */
+char *get_in_split_path(base_path, disk_number)
+  char *base_path;
+  ulg disk_number;
+{
+  char *split_path = NULL;
+  int base_len = 0;
+  int path_len = 0;
+  ulg num = disk_number + 1;
+  char ext[6];
+#ifdef VMS
+  int vers_len;                         /* File version length. */
+  char *vers_ptr;                       /* File version string. */
+#endif /* def VMS */
+
+  /*
+   * A split has extension z01, z02, ..., z99, z100, z101, ... z999
+   * We currently support up to .z99999
+   * WinZip will also read .100, .101, ... but AppNote 6.2.2 uses above
+   * so use that.  Means on DOS can only have 100 splits.
+   */
+
+  if (num == total_disks) {
+    /* last disk is base path */
+    if ((split_path = malloc(strlen(base_path) + 1)) == NULL) {
+      ZIPERR(ZE_MEM, "base path");
+    }
+    strcpy(split_path, base_path);
+
+    return split_path;
+  } else {
+    if (num > 99999) {
+      ZIPERR(ZE_BIG, "More than 99999 splits needed");
+    }
+    sprintf(ext, "z%02lu", num);
+  }
+
+  /* create path for this split - zip.c checked for .zip extension */
+  base_len = strlen(base_path) - 3;
+  path_len = base_len + strlen(ext);
+
+#ifdef VMS
+  /* On VMS, locate the file version, and adjust base_len accordingly.
+     Note that path_len is correct, as-is.
+  */
+  vers_ptr = vms_file_version( base_path);
+  vers_len = strlen( vers_ptr);
+  base_len -= vers_len;
+#endif /* def VMS */
+
+  if ((split_path = malloc(path_len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "split path");
+  }
+  /* copy base_path except for end zip */
+  strcpy(split_path, base_path);
+  split_path[base_len] = '\0';
+  /* add extension */
+  strcat(split_path, ext);
+
+#ifdef VMS
+  /* On VMS, append (preserve) the file version. */
+  strcat(split_path, vers_ptr);
+#endif /* def VMS */
+
+  return split_path;
+}
+
+
+/* split_name
+ *
+ * get name of split being written
+ */
+char *get_out_split_path(base_path, disk_number)
+  char *base_path;
+  ulg disk_number;
+{
+  char *split_path = NULL;
+  int base_len = 0;
+  int path_len = 0;
+  ulg num = disk_number + 1;
+  char ext[6];
+#ifdef VMS
+  int vers_len;                         /* File version length. */
+  char *vers_ptr;                       /* File version string. */
+#endif /* def VMS */
+
+  /*
+   * A split has extension z01, z02, ..., z99, z100, z101, ... z999
+   * We currently support up to .z99999
+   * WinZip will also read .100, .101, ... but AppNote 6.2.2 uses above
+   * so use that.  Means on DOS can only have 100 splits.
+   */
+
+  if (num > 99999) {
+    ZIPERR(ZE_BIG, "More than 99999 splits needed");
+  }
+  sprintf(ext, "z%02lu", num);
+
+  /* create path for this split - zip.c checked for .zip extension */
+  base_len = strlen(base_path) - 3;
+  path_len = base_len + strlen(ext);
+
+#ifdef VMS
+  /* On VMS, locate the file version, and adjust base_len accordingly.
+     Note that path_len is correct, as-is.
+  */
+  vers_ptr = vms_file_version( base_path);
+  vers_len = strlen( vers_ptr);
+  base_len -= vers_len;
+#endif /* def VMS */
+
+  if ((split_path = malloc(path_len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "split path");
+  }
+  /* copy base_path except for end zip */
+  strcpy(split_path, base_path);
+  split_path[base_len] = '\0';
+  /* add extension */
+  strcat(split_path, ext);
+
+#ifdef VMS
+  /* On VMS, append (preserve) the file version. */
+  strcat(split_path, vers_ptr);
+#endif /* def VMS */
+
+  return split_path;
+}
+
+/* close_split
+ *
+ * close a split - assume that the paths needed for the splits are
+ * available.
+ */
+int close_split(disk_number, tempfile, temp_name)
+  ulg disk_number;
+  FILE *tempfile;
+  char *temp_name;
+{
+  char *split_path = NULL;
+
+  split_path = get_out_split_path(out_path, disk_number);
+
+  if (noisy_splits) {
+    zipmessage("\tClosing split ", split_path);
+  }
+
+  fclose(tempfile);
+
+  rename_split(temp_name, split_path);
+  set_filetype(split_path);
+
+  return ZE_OK;
+}
+
+/* bfwrite
+   Does the fwrite but also counts bytes and does splits */
+size_t bfwrite(buffer, size, count, mode)
+  ZCONST void *buffer;
+  size_t size;
+  size_t count;
+  int mode;
+{
+  size_t bytes_written = 0;
+  size_t r;
+  size_t b = size * count;
+  uzoff_t bytes_left_in_split = 0;
+  size_t bytes_to_write = b;
+
+
+  /* -------------------------------- */
+  /* local header */
+  if (mode == BFWRITE_LOCALHEADER) {
+    /* writing local header - reset entry data count */
+    bytes_this_entry = 0;
+    /* save start of local header so we can rewrite later */
+    current_local_file = y;
+    current_local_disk = current_disk;
+    current_local_offset = bytes_this_split;
+  }
+
+  if (split_size == 0)
+    bytes_left_in_split = bytes_to_write;
+  else
+    bytes_left_in_split = split_size - bytes_this_split;
+
+  if (bytes_to_write > bytes_left_in_split) {
+    if (mode == BFWRITE_HEADER ||
+        mode == BFWRITE_LOCALHEADER ||
+        mode == BFWRITE_CENTRALHEADER) {
+      /* if can't write entire header save for next split */
+      bytes_to_write = 0;
+    } else {
+      /* normal data so fill the split */
+      bytes_to_write = (size_t)bytes_left_in_split;
+    }
+  }
+
+  /* -------------------------------- */
+  /* central header */
+  if (mode == BFWRITE_CENTRALHEADER) {
+    /* set start disk for CD */
+    if (cd_start_disk == (ulg)-1) {
+      cd_start_disk = current_disk;
+      cd_start_offset = bytes_this_split;
+    }
+    cd_entries_this_disk++;
+    total_cd_entries++;
+  }
+
+  /* -------------------------------- */
+  if (bytes_to_write > 0) {
+    /* write out the bytes for this split */
+    r = fwrite(buffer, size, bytes_to_write, y);
+    bytes_written += r;
+    bytes_to_write = b - r;
+    bytes_this_split += r;
+    if (mode == BFWRITE_DATA)
+      /* if data descriptor do not include in count */
+      bytes_this_entry += r;
+  } else {
+    bytes_to_write = b;
+  }
+
+  if (bytes_to_write > 0) {
+    if (split_method) {
+      /* still bytes to write so close split and open next split */
+      bytes_prev_splits += bytes_this_split;
+
+      if (split_method == 1 && ferror(y)) {
+        /* if writing all splits to same place and have problem then bad */
+        ZIPERR(ZE_WRITE, "Could not write split");
+      }
+
+      if (split_method == 2 && ferror(y)) {
+        /* A split must be at least 64K except last .zip split */
+        if (bytes_this_split < 64 * (uzoff_t)0x400) {
+          ZIPERR(ZE_WRITE, "Not enough space to write split");
+        }
+      }
+
+      /* close this split */
+      if (split_method == 1 && current_local_disk == current_disk) {
+        /* keep split open so can update it */
+        current_local_tempname = tempzip;
+      } else {
+        /* close split */
+        close_split(current_disk, y, tempzip);
+        y = NULL;
+        free(tempzip);
+        tempzip = NULL;
+      }
+      cd_entries_this_disk = 0;
+      bytes_this_split = 0;
+
+      /* increment disk - disks are numbered 0, 1, 2, ... and
+         splits are 01, 02, ... */
+      current_disk++;
+
+      if (split_method == 2 && split_bell) {
+        /* bell when pause to ask for next split */
+        putc('\007', mesg);
+        fflush(mesg);
+      }
+
+      for (;;) {
+        /* if method 2 pause and allow changing path */
+        if (split_method == 2) {
+          if (ask_for_split_write_path(current_disk) == 0) {
+            ZIPERR(ZE_ABORT, "could not write split");
+          }
+        }
+
+        /* open next split */
+#if defined(UNIX) && !defined(NO_MKSTEMP)
+        {
+          int yd;
+          int i;
+
+          /* use mkstemp to avoid race condition and compiler warning */
+
+          if (tempath != NULL)
+          {
+            /* if -b used to set temp file dir use that for split temp */
+            if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
+              ZIPERR(ZE_MEM, "allocating temp filename");
+            }
+            strcpy(tempzip, tempath);
+            if (lastchar(tempzip) != '/')
+              strcat(tempzip, "/");
+          }
+          else
+          {
+            /* create path by stripping name and appending template */
+            if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
+            ZIPERR(ZE_MEM, "allocating temp filename");
+            }
+            strcpy(tempzip, zipfile);
+            for(i = strlen(tempzip); i > 0; i--) {
+              if (tempzip[i - 1] == '/')
+                break;
+            }
+            tempzip[i] = '\0';
+          }
+          strcat(tempzip, "ziXXXXXX");
+
+          if ((yd = mkstemp(tempzip)) == EOF) {
+            ZIPERR(ZE_TEMP, tempzip);
+          }
+          if ((y = fdopen(yd, FOPW_TMP)) == NULL) {
+            ZIPERR(ZE_TEMP, tempzip);
+          }
+        }
+#else
+        if ((tempzip = tempname(zipfile)) == NULL) {
+          ZIPERR(ZE_MEM, "allocating temp filename");
+        }
+        if ((y = zfopen(tempzip, FOPW_TMP)) == NULL) {
+          ZIPERR(ZE_TEMP, tempzip);
+        }
+#endif
+
+        r = fwrite((char *)buffer + bytes_written, 1, bytes_to_write, y);
+        bytes_written += r;
+        bytes_this_split += r;
+        if (!(mode == BFWRITE_HEADER ||
+              mode == BFWRITE_LOCALHEADER ||
+              mode == BFWRITE_CENTRALHEADER)) {
+          bytes_this_entry += r;
+        }
+        if (bytes_to_write > r) {
+          /* buffer bigger than split */
+          if (split_method == 2) {
+            /* let user choose another disk */
+            zipwarn("Not enough room on disk", "");
+            continue;
+          } else {
+            ZIPERR(ZE_WRITE, "Not enough room on disk");
+          }
+        }
+        if (mode == BFWRITE_LOCALHEADER ||
+            mode == BFWRITE_HEADER ||
+            mode == BFWRITE_CENTRALHEADER) {
+          if (split_method == 1 && current_local_file &&
+              current_local_disk != current_disk) {
+            /* We're opening a new split because the next header
+               did not fit on the last split.  We need to now close
+               the last split and update the pointers for
+               the current split. */
+            close_split(current_local_disk, current_local_file,
+                        current_local_tempname);
+            free(current_local_tempname);
+          }
+          current_local_tempname = tempzip;
+          current_local_file = y;
+          current_local_offset = 0;
+          current_local_disk = current_disk;
+        }
+        break;
+      }
+    }
+    else
+    {
+      /* likely have more than fits but no splits */
+
+      /* probably already have error "no space left on device" */
+      /* could let flush_outbuf() handle error but bfwrite() is called for
+         headers also */
+      if (ferror(y))
+        ziperr(ZE_WRITE, "write error on zip file");
+    }
+  }
+
+
+  /* display dots for archive instead of for each file */
+  if (display_globaldots) {
+    if (dot_size > 0) {
+      /* initial space */
+      if (dot_count == -1) {
+#ifndef WINDLL
+        putc(' ', mesg);
+        fflush(mesg);
+#else
+        fprintf(stdout,"%c",' ');
+#endif
+        /* assume a header will be written first, so avoid 0 */
+        dot_count = 1;
+      }
+      /* skip incrementing dot count for small buffers like for headers */
+      if (size * count > 1000) {
+        dot_count++;
+        if (dot_size <= dot_count * (zoff_t)size * (zoff_t)count) dot_count = 0;
+      }
+    }
+    if (dot_size && !dot_count) {
+      dot_count++;
+#ifndef WINDLL
+      putc('.', mesg);
+      fflush(mesg);
+#else
+      fprintf(stdout,"%c",'.');
+#endif
+      mesg_line_started = 1;
+    }
+  }
+
+
+  return bytes_written;
+}
+
+
+#ifdef UNICODE_SUPPORT
+
+/*---------------------------------------------
+ * Unicode conversion functions
+ *
+ * Provided by Paul Kienitz
+ *
+ * Some modifications to work with Zip
+ *
+ *---------------------------------------------
+ */
+
+/*
+   NOTES APPLICABLE TO ALL STRING FUNCTIONS:
+
+   All of the x_to_y functions take parameters for an output buffer and
+   its available length, and return an int.  The value returned is the
+   length of the string that the input produces, which may be larger than
+   the provided buffer length.  If the returned value is less than the
+   buffer length, then the contents of the buffer will be null-terminated;
+   otherwise, it will not be terminated and may be invalid, possibly
+   stopping in the middle of a multibyte sequence.
+
+   In all cases you may pass NULL as the buffer and/or 0 as the length, if
+   you just want to learn how much space the string is going to require.
+
+   The functions will return -1 if the input is invalid UTF-8 or cannot be
+   encoded as UTF-8.
+*/
+
+/* utility functions for managing UTF-8 and UCS-4 strings */
+
+
+/* utf8_char_bytes
+ *
+ * Returns the number of bytes used by the first character in a UTF-8
+ * string, or -1 if the UTF-8 is invalid or null.
+ */
+local int utf8_char_bytes(utf8)
+  ZCONST char *utf8;
+{
+  int      t, r;
+  unsigned lead;
+
+  if (!utf8)
+    return -1;          /* no input */
+  lead = (unsigned char) *utf8;
+  if (lead < 0x80)
+    r = 1;              /* an ascii-7 character */
+  else if (lead < 0xC0)
+    return -1;          /* error: trailing byte without lead byte */
+  else if (lead < 0xE0)
+    r = 2;              /* an 11 bit character */
+  else if (lead < 0xF0)
+    r = 3;              /* a 16 bit character */
+  else if (lead < 0xF8)
+    r = 4;              /* a 21 bit character (the most currently used) */
+  else if (lead < 0xFC)
+    r = 5;              /* a 26 bit character (shouldn't happen) */
+  else if (lead < 0xFE)
+    r = 6;              /* a 31 bit character (shouldn't happen) */
+  else
+    return -1;          /* error: invalid lead byte */
+  for (t = 1; t < r; t++)
+    if ((unsigned char) utf8[t] < 0x80 || (unsigned char) utf8[t] >= 0xC0)
+      return -1;        /* error: not enough valid trailing bytes */
+  return r;
+}
+
+
+/* ucs4_char_from_utf8
+ *
+ * Given a reference to a pointer into a UTF-8 string, returns the next
+ * UCS-4 character and advances the pointer to the next character sequence.
+ * Returns ~0 and does not advance the pointer when input is ill-formed.
+ *
+ * Since the Unicode standard says 32-bit values won't be used (just
+ * up to the current 21-bit mappings) changed this to signed to allow -1 to
+ * be returned.
+ */
+long ucs4_char_from_utf8(utf8)
+  ZCONST char **utf8;
+{
+  ulg  ret;
+  int  t, bytes;
+
+  if (!utf8)
+    return -1;                          /* no input */
+  bytes = utf8_char_bytes(*utf8);
+  if (bytes <= 0)
+    return -1;                          /* invalid input */
+  if (bytes == 1)
+    ret = **utf8;                       /* ascii-7 */
+  else
+    ret = **utf8 & (0x7F >> bytes);     /* lead byte of a multibyte sequence */
+  (*utf8)++;
+  for (t = 1; t < bytes; t++)           /* consume trailing bytes */
+    ret = (ret << 6) | (*((*utf8)++) & 0x3F);
+  return (long) ret;
+}
+
+
+/* utf8_from_ucs4_char - Convert UCS char to UTF-8
+ *
+ * Returns the number of bytes put into utf8buf to represent ch, from 1 to 6,
+ * or -1 if ch is too large to represent.  utf8buf must have room for 6 bytes.
+ */
+local int utf8_from_ucs4_char(utf8buf, ch)
+  char *utf8buf;
+  ulg ch;
+{
+  int trailing = 0;
+  int leadmask = 0x80;
+  int leadbits = 0x3F;
+  ulg tch = ch;
+  int ret;
+
+  if (ch > 0x7FFFFFFF)
+    return -1;                /* UTF-8 can represent 31 bits */
+  if (ch < 0x7F)
+  {
+    *utf8buf++ = (char) ch;   /* ascii-7 */
+    return 1;
+  }
+  do {
+    trailing++;
+    leadmask = (leadmask >> 1) | 0x80;
+    leadbits >>= 1;
+    tch >>= 6;
+  } while (tch & ~leadbits);
+  ret = trailing + 1;
+  /* produce lead byte */
+  *utf8buf++ = (char) (leadmask | (ch >> (6 * trailing)));
+  /* produce trailing bytes */
+  while (--trailing >= 0)
+    *utf8buf++ = (char) (0x80 | ((ch >> (6 * trailing)) & 0x3F));
+  return ret;
+}
+
+
+/*===================================================================*/
+
+/* utf8_to_ucs4_string - convert UTF-8 string to UCS string
+ *
+ * Return UCS count.  Now returns int so can return -1.
+ */
+local int utf8_to_ucs4_string(utf8, ucs4buf, buflen)
+  ZCONST char *utf8;
+  ulg *ucs4buf;
+  int buflen;
+{
+  int count = 0;
+
+  for (;;)
+  {
+    long ch = ucs4_char_from_utf8(&utf8);
+    if (ch == -1)
+      return -1;
+    else
+    {
+      if (ucs4buf && count < buflen)
+        ucs4buf[count] = ch;
+      if (ch == 0)
+        return count;
+      count++;
+    }
+  }
+}
+
+
+/* ucs4_string_to_utf8
+ *
+ *
+ */
+local int ucs4_string_to_utf8(ucs4, utf8buf, buflen)
+  ZCONST ulg *ucs4;
+  char *utf8buf;
+  int buflen;
+{
+  char mb[6];
+  int  count = 0;
+
+  if (!ucs4)
+    return -1;
+  for (;;)
+  {
+    int mbl = utf8_from_ucs4_char(mb, *ucs4++);
+    int c;
+    if (mbl <= 0)
+      return -1;
+    /* We could optimize this a bit by passing utf8buf + count */
+    /* directly to utf8_from_ucs4_char when buflen >= count + 6... */
+    c = buflen - count;
+    if (mbl < c)
+      c = mbl;
+    if (utf8buf && count < buflen)
+      strncpy(utf8buf + count, mb, c);
+    if (mbl == 1 && !mb[0])
+      return count;           /* terminating nul */
+    count += mbl;
+  }
+}
+
+
+#if 0  /* currently unused */
+/* utf8_chars
+ *
+ * Wrapper: counts the actual unicode characters in a UTF-8 string.
+ */
+local int utf8_chars(utf8)
+  ZCONST char *utf8;
+{
+  return utf8_to_ucs4_string(utf8, NULL, 0);
+}
+#endif
+
+
+/* --------------------------------------------------- */
+/* Unicode Support
+ *
+ * These functions common for all Unicode ports.
+ *
+ * These functions should allocate and return strings that can be
+ * freed with free().
+ *
+ * 8/27/05 EG
+ *
+ * Use zwchar for wide char which is unsigned long
+ * in zip.h and 32 bits.  This avoids problems with
+ * different sizes of wchar_t.
+ */
+
+#ifdef WIN32
+
+zwchar *wchar_to_wide_string(wchar_string)
+  wchar_t *wchar_string;
+{
+  int i;
+  int wchar_len;
+  zwchar *wide_string;
+
+  wchar_len = wcslen(wchar_string);
+
+  if ((wide_string = malloc((wchar_len + 1) * sizeof(zwchar))) == NULL) {
+    ZIPERR(ZE_MEM, "wchar to wide conversion");
+  }
+  for (i = 0; i <= wchar_len; i++) {
+    wide_string[i] = wchar_string[i];
+  }
+
+  return wide_string;
+}
+
+/* is_ascii_stringw
+ * Checks if a wide string is all ascii
+ */
+int is_ascii_stringw(wstring)
+  wchar_t *wstring;
+{
+  wchar_t *pw;
+  wchar_t cw;
+
+  if (wstring == NULL)
+    return 0;
+
+  for (pw = wstring; (cw = *pw) != '\0'; pw++) {
+    if (cw > 0x7F) {
+      return 0;
+    }
+  }
+  return 1;
+}
+
+#endif
+
+/* is_ascii_string
+ * Checks if a string is all ascii
+ */
+int is_ascii_string(mbstring)
+  char *mbstring;
+{
+  char *p;
+  uch c;
+
+  if (mbstring == NULL)
+    return 0;
+
+  for (p = mbstring; (c = (uch)*p) != '\0'; p++) {
+    if (c > 0x7F) {
+      return 0;
+    }
+  }
+  return 1;
+}
+
+/* local to UTF-8 */
+char *local_to_utf8_string(local_string)
+  char *local_string;
+{
+  zwchar *wide_string = local_to_wide_string(local_string);
+  char *utf8_string = wide_to_utf8_string(wide_string);
+
+  free(wide_string);
+  return utf8_string;
+}
+
+/* wide_char_to_escape_string
+   provides a string that represents a wide char not in local char set
+
+   An initial try at an algorithm.  Suggestions welcome.
+
+   If not an ASCII char, probably need 2 bytes at least.  So if
+   a 2-byte wide encode it as 4 hex digits with a leading #U.
+   Since the Unicode standard has been frozen, it looks like 3 bytes
+   should be enough for any large Unicode character.  In these cases
+   prefix the string with #L.
+   So
+   #U1234
+   is a 2-byte wide character with bytes 0x12 and 0x34 while
+   #L123456
+   is a 3-byte wide with bytes 0x12, 0x34, and 0x56.
+   On Windows, wide that need two wide characters as a surrogate pair
+   to represent them need to be converted to a single number.
+  */
+
+ /* set this to the max bytes an escape can be */
+#define MAX_ESCAPE_BYTES 8
+
+char *wide_char_to_escape_string(wide_char)
+  zwchar wide_char;
+{
+  int i;
+  zwchar w = wide_char;
+  uch b[9];
+  char e[7];
+  int len;
+  char *r;
+
+  /* fill byte array with zeros */
+  for (len = 0; len < sizeof(zwchar); len++) {
+    b[len] = 0;
+  }
+  /* get bytes in right to left order */
+  for (len = 0; w; len++) {
+    b[len] = (char)(w % 0x100);
+    w /= 0x100;
+  }
+
+  if ((r = malloc(MAX_ESCAPE_BYTES + 8)) == NULL) {
+    ZIPERR(ZE_MEM, "wide_char_to_escape_string");
+  }
+  strcpy(r, "#");
+  /* either 2 bytes or 4 bytes */
+  if (len < 3) {
+    len = 2;
+    strcat(r, "U");
+  } else {
+    len = 3;
+    strcat(r, "L");
+  }
+  for (i = len - 1; i >= 0; i--) {
+    sprintf(e, "%02x", b[i]);
+    strcat(r, e);
+  }
+  return r;
+}
+
+#if 0
+/* returns the wide character represented by the escape string */
+zwchar escape_string_to_wide(escape_string)
+  char *escape_string;
+{
+  int i;
+  zwchar w;
+  char c;
+  char u;
+  int len;
+  char *e = escape_string;
+
+  if (e == NULL) {
+    return 0;
+  }
+  if (e[0] != '#') {
+    /* no leading # */
+    return 0;
+  }
+  len = strlen(e);
+  /* either #U1234 or #L123456 format */
+  if (len != 6 && len != 8) {
+    return 0;
+  }
+  w = 0;
+  if (e[1] == 'L') {
+    if (len != 8) {
+      return 0;
+    }
+    /* 3 bytes */
+    for (i = 2; i < 8; i++) {
+      c = e[i];
+      u = toupper(c);
+      if (u >= 'A' && u <= 'F') {
+        w = w * 0x10 + (zwchar)(u + 10 - 'A');
+      } else if (c >= '0' && c <= '9') {
+        w = w * 0x10 + (zwchar)(c - '0');
+      } else {
+        return 0;
+      }
+    }
+  } else if (e[1] == 'U') {
+    /* 2 bytes */
+    for (i = 2; i < 6; i++) {
+      c = e[i];
+      u = toupper(c);
+      if (u >= 'A' && u <= 'F') {
+        w = w * 0x10 + (zwchar)(u + 10 - 'A');
+      } else if (c >= '0' && c <= '9') {
+        w = w * 0x10 + (zwchar)(c - '0');
+      } else {
+        return 0;
+      }
+    }
+  }
+  return w;
+}
+#endif
+
+
+char *local_to_escape_string(local_string)
+  char *local_string;
+{
+  zwchar *wide_string = local_to_wide_string(local_string);
+  char *escape_string = wide_to_escape_string(wide_string);
+
+  free(wide_string);
+  return escape_string;
+}
+
+#ifdef WIN32
+char *wchar_to_local_string(wstring)
+  wchar_t *wstring;
+{
+  zwchar *wide_string = wchar_to_wide_string(wstring);
+  char *local_string = wide_to_local_string(wide_string);
+
+  free(wide_string);
+
+  return local_string;
+}
+#endif
+
+
+#ifndef WIN32   /* The Win32 port uses a system-specific variant. */
+/* convert wide character string to multi-byte character string */
+char *wide_to_local_string(wide_string)
+  zwchar *wide_string;
+{
+  int i;
+  wchar_t wc;
+  int b;
+  int state_dependent;
+  int wsize = 0;
+  int max_bytes = MB_CUR_MAX;
+  char buf[9];
+  char *buffer = NULL;
+  char *local_string = NULL;
+
+  for (wsize = 0; wide_string[wsize]; wsize++) ;
+
+  if (MAX_ESCAPE_BYTES > max_bytes)
+    max_bytes = MAX_ESCAPE_BYTES;
+
+  if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "wide_to_local_string");
+  }
+
+  /* convert it */
+  buffer[0] = '\0';
+  /* set initial state if state-dependent encoding */
+  wc = (wchar_t)'a';
+  b = wctomb(NULL, wc);
+  if (b == 0)
+    state_dependent = 0;
+  else
+    state_dependent = 1;
+  for (i = 0; i < wsize; i++) {
+    if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) {
+      /* wchar_t probably 2 bytes */
+      /* could do surrogates if state_dependent and wctomb can do */
+      wc = zwchar_to_wchar_t_default_char;
+    } else {
+      wc = (wchar_t)wide_string[i];
+    }
+    b = wctomb(buf, wc);
+    if (unicode_escape_all) {
+      if (b == 1 && (uch)buf[0] <= 0x7f) {
+        /* ASCII */
+        strncat(buffer, buf, b);
+      } else {
+        /* use escape for wide character */
+        char *e = wide_char_to_escape_string(wide_string[i]);
+        strcat(buffer, e);
+        free(e);
+      }
+    } else if (b > 0) {
+      /* multi-byte char */
+      strncat(buffer, buf, b);
+    } else {
+      /* no MB for this wide */
+      if (use_wide_to_mb_default) {
+        /* default character */
+        strcat(buffer, wide_to_mb_default_string);
+      } else {
+        /* use escape for wide character */
+        char *e = wide_char_to_escape_string(wide_string[i]);
+        strcat(buffer, e);
+        free(e);
+      }
+    }
+  }
+  if ((local_string = (char *)malloc(strlen(buffer) + 1)) == NULL) {
+    free(buffer);
+    ZIPERR(ZE_MEM, "wide_to_local_string");
+  }
+  strcpy(local_string, buffer);
+  free(buffer);
+
+  return local_string;
+}
+#endif /* !WIN32 */
+
+
+/* convert wide character string to escaped string */
+char *wide_to_escape_string(wide_string)
+  zwchar *wide_string;
+{
+  int i;
+  int wsize = 0;
+  char buf[9];
+  char *buffer = NULL;
+  char *escape_string = NULL;
+
+  for (wsize = 0; wide_string[wsize]; wsize++) ;
+
+  if ((buffer = (char *)malloc(wsize * MAX_ESCAPE_BYTES + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "wide_to_escape_string");
+  }
+
+  /* convert it */
+  buffer[0] = '\0';
+  for (i = 0; i < wsize; i++) {
+    if (wide_string[i] <= 0x7f && isprint((char)wide_string[i])) {
+      /* ASCII */
+      buf[0] = (char)wide_string[i];
+      buf[1] = '\0';
+      strcat(buffer, buf);
+    } else {
+      /* use escape for wide character */
+      char *e = wide_char_to_escape_string(wide_string[i]);
+      strcat(buffer, e);
+      free(e);
+    }
+  }
+  if ((escape_string = (char *)malloc(strlen(buffer) + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "wide_to_escape_string");
+  }
+  strcpy(escape_string, buffer);
+  free(buffer);
+
+  return escape_string;
+}
+
+
+/* convert local string to display character set string */
+char *local_to_display_string(local_string)
+  char *local_string;
+{
+  char *temp_string;
+  char *display_string;
+
+  /* For Windows, OEM string should never be bigger than ANSI string, says
+     CharToOem description.
+     On UNIX, non-printable characters (0x00 - 0xFF) will be replaced by
+     "^x", so more space may be needed.  Note that "^" itself is a valid
+     name character, so this leaves an ambiguity, but UnZip displays
+     names this way, too.  (0x00 is not possible, I hope.)
+     For all other ports, just make a copy of local_string.
+  */
+
+#ifdef UNIX
+  char *cp_dst;                 /* Character pointers used in the */
+  char *cp_src;                 /*  copying/changing procedure.   */
+#endif
+
+  if ((temp_string = (char *)malloc(2 * strlen(local_string) + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "local_to_display_string");
+  }
+
+#ifdef WIN32
+  /* convert to OEM display character set */
+  local_to_oem_string(temp_string, local_string);
+#else
+# ifdef UNIX
+  /* Copy source string, expanding non-printable characters to "^x". */
+  cp_dst = temp_string;
+  cp_src = local_string;
+  while (*cp_src != '\0') {
+    if ((unsigned char)*cp_src < ' ') {
+      *cp_dst++ = '^';
+      *cp_dst++ = '@'+ *cp_src++;
+    }
+    else {
+      *cp_dst++ = *cp_src++;
+    }
+  }
+  *cp_dst = '\0';
+# else /* not UNIX */
+  strcpy(temp_string, local_string);
+# endif /* UNIX */
+#endif
+
+#ifdef EBCDIC
+  {
+    char *ebc;
+
+    if ((ebc = malloc(strlen(display_string) + 1)) ==  NULL) {
+      ZIPERR(ZE_MEM, "local_to_display_string");
+    }
+    strtoebc(ebc, display_string);
+    free(display_string);
+    display_string = ebc;
+  }
+#endif
+
+  if ((display_string = (char *)malloc(strlen(temp_string) + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "local_to_display_string");
+  }
+  strcpy(display_string, temp_string);
+  free(temp_string);
+
+  return display_string;
+}
+
+/* UTF-8 to local */
+char *utf8_to_local_string(utf8_string)
+  char *utf8_string;
+{
+  zwchar *wide_string = utf8_to_wide_string(utf8_string);
+  char *loc = wide_to_local_string(wide_string);
+  if (wide_string)
+    free(wide_string);
+  return loc;
+}
+
+/* UTF-8 to local */
+char *utf8_to_escape_string(utf8_string)
+  char *utf8_string;
+{
+  zwchar *wide_string = utf8_to_wide_string(utf8_string);
+  char *escape_string = wide_to_escape_string(wide_string);
+  free(wide_string);
+  return escape_string;
+}
+
+#ifndef WIN32   /* The Win32 port uses a system-specific variant. */
+/* convert multi-byte character string to wide character string */
+zwchar *local_to_wide_string(local_string)
+  char *local_string;
+{
+  int wsize;
+  wchar_t *wc_string;
+  zwchar *wide_string;
+
+  /* for now try to convert as string - fails if a bad char in string */
+  wsize = mbstowcs(NULL, local_string, MB_CUR_MAX );
+  if (wsize == (size_t)-1) {
+    /* could not convert */
+    return NULL;
+  }
+
+  /* convert it */
+  if ((wc_string = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t))) == NULL) {
+    ZIPERR(ZE_MEM, "local_to_wide_string");
+  }
+  wsize = mbstowcs(wc_string, local_string, strlen(local_string) + 1);
+  wc_string[wsize] = (wchar_t) 0;
+
+  /* in case wchar_t is not zwchar */
+  if ((wide_string = (zwchar *)malloc((wsize + 1) * sizeof(zwchar))) == NULL) {
+    ZIPERR(ZE_MEM, "local_to_wide_string");
+  }
+  for (wsize = 0; (wide_string[wsize] = (zwchar)wc_string[wsize]); wsize++) ;
+  wide_string[wsize] = (zwchar)0;
+  free(wc_string);
+
+  return wide_string;
+}
+#endif /* !WIN32 */
+
+
+#if 0
+/* All wchar functions are only used by Windows and are
+   now in win32zip.c so that the Windows functions can
+   be used and multiple character wide characters can
+   be handled easily. */
+# ifndef WIN32
+char *wchar_to_utf8_string(wstring)
+  wchar_t *wstring;
+{
+  zwchar *wide_string = wchar_to_wide_string(wstring);
+  char *local_string = wide_to_utf8_string(wide_string);
+
+  free(wide_string);
+
+  return local_string;
+}
+# endif
+#endif
+
+
+/* convert wide string to UTF-8 */
+char *wide_to_utf8_string(wide_string)
+  zwchar *wide_string;
+{
+  int mbcount;
+  char *utf8_string;
+
+  /* get size of utf8 string */
+  mbcount = ucs4_string_to_utf8(wide_string, NULL, 0);
+  if (mbcount == -1)
+    return NULL;
+  if ((utf8_string = (char *) malloc(mbcount + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "wide_to_utf8_string");
+  }
+  mbcount = ucs4_string_to_utf8(wide_string, utf8_string, mbcount + 1);
+  if (mbcount == -1)
+    return NULL;
+
+  return utf8_string;
+}
+
+/* convert UTF-8 string to wide string */
+zwchar *utf8_to_wide_string(utf8_string)
+  char *utf8_string;
+{
+  int wcount;
+  zwchar *wide_string;
+
+  wcount = utf8_to_ucs4_string(utf8_string, NULL, 0);
+  if (wcount == -1)
+    return NULL;
+  if ((wide_string = (zwchar *) malloc((wcount + 2) * sizeof(zwchar))) == NULL) {
+    ZIPERR(ZE_MEM, "utf8_to_wide_string");
+  }
+  wcount = utf8_to_ucs4_string(utf8_string, wide_string, wcount + 1);
+
+  return wide_string;
+}
+
+
+#endif /* UNICODE_SUPPORT */
+
+
+/*---------------------------------------------------------------
+ *  Long option support
+ *  8/23/2003
+ *
+ *  Defines function get_option() to get and process the command
+ *  line options and arguments from argv[].  The caller calls
+ *  get_option() in a loop to get either one option and possible
+ *  value or a non-option argument each loop.
+ *
+ *  This version does not include argument file support and can
+ *  work directly on argv.  The argument file code complicates things and
+ *  it seemed best to leave it out for now.  If argument file support (reading
+ *  in command line arguments stored in a file and inserting into
+ *  command line where @filename is found) is added later the arguments
+ *  can change and a freeable copy of argv will be needed and can be
+ *  created using copy_args in the left out code.
+ *
+ *  Supports short and long options as defined in the array options[]
+ *  in zip.c, multiple short options in an argument (like -jlv), long
+ *  option abbreviation (like --te for --temp-file if --te unique),
+ *  short and long option values (like -b filename or --temp-file filename
+ *  or --temp-file=filename), optional and required values, option negation
+ *  by trailing - (like -S- to not include hidden and system files in MSDOS),
+ *  value lists (like -x a b c), argument permuting (returning all options
+ *  and values before any non-option arguments), and argument files (where any
+ *  non-option non-value argument in form @path gets substituted with the
+ *  white space separated arguments in the text file at path).  In this
+ *  version argument file support has been removed to simplify development but
+ *  may be added later.
+ *
+ *  E. Gordon
+ */
+
+
+/* message output - char casts are needed to handle constants */
+#define oWARN(message) zipwarn((char *) message, "")
+#define oERR(err,message) ZIPERR(err, (char *) message)
+
+
+/* Although the below provides some support for multibyte characters
+   the proper thing to do may be to use wide characters and support
+   Unicode.  May get to it soon.  EG
+ */
+
+/* For now stay with muti-byte characters.  May support wide characters
+   in Zip 3.1.
+ */
+
+/* multibyte character set support
+   Multibyte characters use typically two or more sequential bytes
+   to represent additional characters than can fit in a single byte
+   character set.  The code used here is based on the ANSI mblen function. */
+#ifdef MULTIBYTE_GETOPTNS
+  int mb_clen(ptr)
+    ZCONST char *ptr;
+  {
+    /* return the number of bytes that the char pointed to is.  Return 1 if
+       null character or error like not start of valid multibyte character. */
+    int cl;
+
+    cl = mblen(ptr, MB_CUR_MAX);
+    return (cl > 0) ? cl : 1;
+  }
+#endif
+
+
+  /* moved to zip.h */
+#if 0
+#ifdef UNICODE_SUPPORT
+# define MB_CLEN(ptr) (1)
+# define MB_NEXTCHAR(ptr) ((ptr)++)
+# ifdef MULTIBYTE_GETOPTNS
+#    undef MULTIBYTE_GETOPTNS
+# endif
+#else
+# ifdef _MBCS
+#  ifndef MULTIBYTE_GETOPTNS
+#    define MULTIBYTE_GETOPTNS
+#  endif
+# endif
+/* multibyte character set support
+   Multibyte characters use typically two or more sequential bytes
+   to represent additional characters than can fit in a single byte
+   character set.  The code used here is based on the ANSI mblen function. */
+#  ifdef MULTIBYTE_GETOPTNS
+  local int mb_clen OF((ZCONST char *));  /* declare proto first */
+  local int mb_clen(ptr)
+    ZCONST char *ptr;
+  {
+    /* return the number of bytes that the char pointed to is.  Return 1 if
+       null character or error like not start of valid multibyte character. */
+    int cl;
+
+    cl = mblen(ptr, MB_CUR_MAX);
+    return (cl > 0) ? cl : 1;
+  }
+#  define MB_CLEN(ptr) mb_clen(ptr)
+#  define MB_NEXTCHAR(ptr) ((ptr) += MB_CLEN(ptr))
+# else
+#  define MB_CLEN(ptr) (1)
+#  define MB_NEXTCHAR(ptr) ((ptr)++)
+# endif
+#endif
+#endif
+
+
+/* constants */
+
+/* function get_args_from_arg_file() can return this in depth parameter */
+#define ARG_FILE_ERR -1
+
+/* internal settings for optchar */
+#define SKIP_VALUE_ARG   -1
+#define THIS_ARG_DONE    -2
+#define START_VALUE_LIST -3
+#define IN_VALUE_LIST    -4
+#define NON_OPTION_ARG   -5
+#define STOP_VALUE_LIST  -6
+/* 7/25/04 EG */
+#define READ_REST_ARGS_VERBATIM -7
+
+
+/* global veriables */
+
+int enable_permute = 1;                     /* yes - return options first */
+/* 7/25/04 EG */
+int doubledash_ends_options = 1;            /* when -- what follows are not options */
+
+/* buffer for error messages (this sizing is a guess but must hold 2 paths) */
+#define OPTIONERR_BUF_SIZE (FNMAX * 2 + 4000)
+local char Far optionerrbuf[OPTIONERR_BUF_SIZE + 1];
+
+/* error messages */
+static ZCONST char Far op_not_neg_err[] = "option %s not negatable";
+static ZCONST char Far op_req_val_err[] = "option %s requires a value";
+static ZCONST char Far op_no_allow_val_err[] = "option %s does not allow a value";
+static ZCONST char Far sh_op_not_sup_err[] = "short option '%c' not supported";
+static ZCONST char Far oco_req_val_err[] = "option %s requires one character value";
+static ZCONST char Far oco_no_mbc_err[] = "option %s does not support multibyte values";
+static ZCONST char Far num_req_val_err[] = "option %s requires number value";
+static ZCONST char Far long_op_ambig_err[] = "long option '%s' ambiguous";
+static ZCONST char Far long_op_not_sup_err[] = "long option '%s' not supported";
+
+static ZCONST char Far no_arg_files_err[] = "argument files not enabled\n";
+
+
+/* below removed as only used for processing argument files */
+
+/* get_nextarg */
+/* get_args_from_string */
+/* insert_args */
+/* get_args_from_arg_file */
+
+
+/* copy error, option name, and option description if any to buf */
+local int optionerr(buf, err, optind, islong)
+  char *buf;
+  ZCONST char *err;
+  int optind;
+  int islong;
+{
+  char optname[50];
+
+  if (options[optind].name && options[optind].name[0] != '\0') {
+    if (islong)
+      sprintf(optname, "'%s' (%s)", options[optind].longopt, options[optind].name);
+    else
+      sprintf(optname, "'%s' (%s)", options[optind].shortopt, options[optind].name);
+  } else {
+    if (islong)
+      sprintf(optname, "'%s'", options[optind].longopt);
+    else
+      sprintf(optname, "'%s'", options[optind].shortopt);
+  }
+  sprintf(buf, err, optname);
+  return 0;
+}
+
+
+/* copy_args
+ *
+ * Copy arguments in args, allocating storage with malloc.
+ * Copies until a NULL argument is found or until max_args args
+ * including args[0] are copied.  Set max_args to 0 to copy
+ * until NULL.  Always terminates returned args[] with NULL arg.
+ *
+ * Any argument in the returned args can be freed with free().  Any
+ * freed argument should be replaced with either another string
+ * allocated with malloc or by NULL if last argument so that free_args
+ * will properly work.
+ */
+char **copy_args(args, max_args)
+  char **args;
+  int max_args;
+{
+  int j;
+  char **new_args;
+
+  if (args == NULL) {
+    return NULL;
+  }
+
+  /* count args */
+  for (j = 0; args[j] && (max_args == 0 || j < max_args); j++) ;
+
+  if ((new_args = (char **) malloc((j + 1) * sizeof(char *))) == NULL) {
+    oERR(ZE_MEM, "ca");
+  }
+
+  for (j = 0; args[j] && (max_args == 0 || j < max_args); j++) {
+    if (args[j] == NULL) {
+      /* null argument is end of args */
+      new_args[j] = NULL;
+      break;
+    }
+    if ((new_args[j] = malloc(strlen(args[j]) + 1)) == NULL) {
+      free_args(new_args);
+      oERR(ZE_MEM, "ca");
+    }
+    strcpy(new_args[j], args[j]);
+  }
+  new_args[j] = NULL;
+
+  return new_args;
+}
+
+
+/* free args - free args created with one of these functions */
+int free_args(args)
+  char **args;
+{
+  int i;
+
+  if (args == NULL) {
+    return 0;
+  }
+
+  for (i = 0; args[i]; i++) {
+    free(args[i]);
+  }
+  free(args);
+  return i;
+}
+
+
+/* insert_arg
+ *
+ * Insert the argument arg into the array args before argument at_arg.
+ * Return the new count of arguments (argc).
+ *
+ * If free_args is true, this function frees the old args array
+ * (but not the component strings).  DO NOT set free_args on original
+ * argv but only on args allocated with malloc.
+ */
+
+int insert_arg(pargs, arg, at_arg, free_args)
+   char ***pargs;
+   ZCONST char *arg;
+   int at_arg;
+   int free_args;
+{
+   char *newarg = NULL;
+   char **args;
+   char **newargs = NULL;
+   int argnum;
+   int newargnum;
+   int argcnt;
+   int newargcnt;
+
+   if (pargs == NULL) {
+     return 0;
+   }
+   args = *pargs;
+
+   /* count args */
+   if (args == NULL) {
+     argcnt = 0;
+   } else {
+     for (argcnt = 0; args[argcnt]; argcnt++) ;
+   }
+   if (arg == NULL) {
+     /* done */
+     return argcnt;
+   }
+   newargcnt = argcnt + 1;
+
+   /* get storage for new args */
+   if ((newargs = (char **) malloc((newargcnt + 1) * sizeof(char *))) == NULL) {
+     oERR(ZE_MEM, "ia");
+   }
+
+   /* copy argument pointers from args to position at_arg, copy arg, then rest args */
+   argnum = 0;
+   newargnum = 0;
+   if (args) {
+     for (; args[argnum] && argnum < at_arg; argnum++) {
+       newargs[newargnum++] = args[argnum];
+     }
+   }
+   /* copy new arg */
+   if ((newarg = (char *) malloc(strlen(arg) + 1)) == NULL) {
+     oERR(ZE_MEM, "ia");
+   }
+   strcpy(newarg, arg);
+
+   newargs[newargnum++] = newarg;
+   if (args) {
+     for ( ; args[argnum]; argnum++) {
+       newargs[newargnum++] = args[argnum];
+     }
+   }
+   newargs[newargnum] = NULL;
+
+   /* free old args array but not component strings - this assumes that
+      args was allocated with malloc as copy_args does.  DO NOT DO THIS
+      on the original argv.
+    */
+   if (free_args)
+     free(args);
+
+   *pargs = newargs;
+
+   return newargnum;
+}
+
+/* ------------------------------------- */
+
+
+
+
+/* get_shortopt
+ *
+ * Get next short option from arg.  The state is stored in argnum, optchar, and
+ * option_num so no static storage is used.  Returns the option_ID.
+ *
+ * parameters:
+ *    args        - argv array of arguments
+ *    argnum      - index of current arg in args
+ *    optchar     - pointer to index of next char to process.  Can be 0 or
+ *                  const defined at top of this file like THIS_ARG_DONE
+ *    negated     - on return pointer to int set to 1 if option negated or 0 otherwise
+ *    value       - on return pointer to string set to value of option if any or NULL
+ *                  if none.  If value is returned then the caller should free()
+ *                  it when not needed anymore.
+ *    option_num  - pointer to index in options[] of returned option or
+ *                  o_NO_OPTION_MATCH if none.  Do not change as used by
+ *                  value lists.
+ *    depth       - recursion depth (0 at top level, 1 or more in arg files)
+ */
+local unsigned long get_shortopt(args, argnum, optchar, negated, value,
+                                 option_num, depth)
+  char **args;
+  int argnum;
+  int *optchar;
+  int *negated;
+  char **value;
+  int *option_num;
+  int depth;
+{
+  char *shortopt;
+  int clen;
+  char *nextchar;
+  char *s;
+  char *start;
+  int op;
+  char *arg;
+  int match = -1;
+
+
+  /* get arg */
+  arg = args[argnum];
+  /* current char in arg */
+  nextchar = arg + (*optchar);
+  clen = MB_CLEN(nextchar);
+  /* next char in arg */
+  (*optchar) +=  clen;
+  /* get first char of short option */
+  shortopt = arg + (*optchar);
+  /* no value */
+  *value = NULL;
+
+  if (*shortopt == '\0') {
+    /* no more options in arg */
+    *optchar = 0;
+    *option_num = o_NO_OPTION_MATCH;
+    return 0;
+  }
+
+  /* look for match in options */
+  clen = MB_CLEN(shortopt);
+  for (op = 0; options[op].option_ID; op++) {
+    s = options[op].shortopt;
+    if (s && s[0] == shortopt[0]) {
+      if (s[1] == '\0' && clen == 1) {
+        /* single char match */
+        match = op;
+      } else {
+        /* 2 wide short opt.  Could support more chars but should use long opts instead */
+        if (s[1] == shortopt[1]) {
+          /* match 2 char short opt or 2 byte char */
+          match = op;
+          if (clen == 1) (*optchar)++;
+          break;
+        }
+      }
+    }
+  }
+
+  if (match > -1) {
+    /* match */
+    clen = MB_CLEN(shortopt);
+    nextchar = arg + (*optchar) + clen;
+    /* check for trailing dash negating option */
+    if (*nextchar == '-') {
+      /* negated */
+      if (options[match].negatable == o_NOT_NEGATABLE) {
+        if (options[match].value_type == o_NO_VALUE) {
+          optionerr(optionerrbuf, op_not_neg_err, match, 0);
+          if (depth > 0) {
+            /* unwind */
+            oWARN(optionerrbuf);
+            return o_ARG_FILE_ERR;
+          } else {
+            oERR(ZE_PARMS, optionerrbuf);
+          }
+        }
+      } else {
+        *negated = 1;
+        /* set up to skip negating dash */
+        (*optchar) += clen;
+        clen = 1;
+      }
+    }
+
+    /* value */
+    clen = MB_CLEN(arg + (*optchar));
+    /* optional value, one char value, and number value must follow option */
+    if (options[match].value_type == o_ONE_CHAR_VALUE) {
+      /* one char value */
+      if (arg[(*optchar) + clen]) {
+        /* has value */
+        if (MB_CLEN(arg + (*optchar) + clen) > 1) {
+          /* multibyte value not allowed for now */
+          optionerr(optionerrbuf, oco_no_mbc_err, match, 0);
+          if (depth > 0) {
+            /* unwind */
+            oWARN(optionerrbuf);
+            return o_ARG_FILE_ERR;
+          } else {
+            oERR(ZE_PARMS, optionerrbuf);
+          }
+        }
+        if ((*value = (char *) malloc(2)) == NULL) {
+          oERR(ZE_MEM, "gso");
+        }
+        (*value)[0] = *(arg + (*optchar) + clen);
+        (*value)[1] = '\0';
+        *optchar += clen;
+        clen = 1;
+      } else {
+        /* one char values require a value */
+        optionerr(optionerrbuf, oco_req_val_err, match, 0);
+        if (depth > 0) {
+          oWARN(optionerrbuf);
+          return o_ARG_FILE_ERR;
+        } else {
+          oERR(ZE_PARMS, optionerrbuf);
+        }
+      }
+    } else if (options[match].value_type == o_NUMBER_VALUE) {
+      /* read chars until end of number */
+      start = arg + (*optchar) + clen;
+      if (*start == '+' || *start == '-') {
+        start++;
+      }
+      s = start;
+      for (; isdigit(*s); MB_NEXTCHAR(s)) ;
+      if (s == start) {
+        /* no digits */
+        optionerr(optionerrbuf, num_req_val_err, match, 0);
+        if (depth > 0) {
+          oWARN(optionerrbuf);
+          return o_ARG_FILE_ERR;
+        } else {
+          oERR(ZE_PARMS, optionerrbuf);
+        }
+      }
+      start = arg + (*optchar) + clen;
+      if ((*value = (char *) malloc((int)(s - start) + 1)) == NULL) {
+        oERR(ZE_MEM, "gso");
+      }
+      *optchar += (int)(s - start);
+      strncpy(*value, start, (int)(s - start));
+      (*value)[(int)(s - start)] = '\0';
+      clen = MB_CLEN(s);
+    } else if (options[match].value_type == o_OPTIONAL_VALUE) {
+      /* optional value */
+      /* This seemed inconsistent so now if no value attached to argument look
+         to the next argument if that argument is not an option for option
+         value - 11/12/04 EG */
+      if (arg[(*optchar) + clen]) {
+        /* has value */
+        /* add support for optional = - 2/6/05 EG */
+        if (arg[(*optchar) + clen] == '=') {
+          /* skip = */
+          clen++;
+        }
+        if (arg[(*optchar) + clen]) {
+          if ((*value = (char *)malloc(strlen(arg + (*optchar) + clen) + 1))
+              == NULL) {
+            oERR(ZE_MEM, "gso");
+          }
+          strcpy(*value, arg + (*optchar) + clen);
+        }
+        *optchar = THIS_ARG_DONE;
+      } else if (args[argnum + 1] && args[argnum + 1][0] != '-') {
+        /* use next arg for value */
+        if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
+          oERR(ZE_MEM, "gso");
+        }
+        /* using next arg as value */
+        strcpy(*value, args[argnum + 1]);
+        *optchar = SKIP_VALUE_ARG;
+      }
+    } else if (options[match].value_type == o_REQUIRED_VALUE ||
+               options[match].value_type == o_VALUE_LIST) {
+      /* see if follows option */
+      if (arg[(*optchar) + clen]) {
+        /* has value following option as -ovalue */
+        /* add support for optional = - 6/5/05 EG */
+        if (arg[(*optchar) + clen] == '=') {
+          /* skip = */
+          clen++;
+        }
+          if ((*value = (char *)malloc(strlen(arg + (*optchar) + clen) + 1))
+              == NULL) {
+          oERR(ZE_MEM, "gso");
+        }
+        strcpy(*value, arg + (*optchar) + clen);
+        *optchar = THIS_ARG_DONE;
+      } else {
+        /* use next arg for value */
+        if (args[argnum + 1]) {
+          if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
+            oERR(ZE_MEM, "gso");
+          }
+          strcpy(*value, args[argnum + 1]);
+          if (options[match].value_type == o_VALUE_LIST) {
+            *optchar = START_VALUE_LIST;
+          } else {
+            *optchar = SKIP_VALUE_ARG;
+          }
+        } else {
+          /* no value found */
+          optionerr(optionerrbuf, op_req_val_err, match, 0);
+          if (depth > 0) {
+            oWARN(optionerrbuf);
+            return o_ARG_FILE_ERR;
+          } else {
+            oERR(ZE_PARMS, optionerrbuf);
+          }
+        }
+      }
+    }
+
+    *option_num = match;
+    return options[match].option_ID;
+  }
+  sprintf(optionerrbuf, sh_op_not_sup_err, *shortopt);
+  if (depth > 0) {
+    /* unwind */
+    oWARN(optionerrbuf);
+    return o_ARG_FILE_ERR;
+  } else {
+    oERR(ZE_PARMS, optionerrbuf);
+  }
+  return 0;
+}
+
+
+/* get_longopt
+ *
+ * Get the long option in args array at argnum.
+ * Parameters same as for get_shortopt.
+ */
+
+local unsigned long get_longopt(args, argnum, optchar, negated, value,
+                                option_num, depth)
+  char **args;
+  int argnum;
+  int *optchar;
+  int *negated;
+  char **value;
+  int *option_num;
+  int depth;
+{
+  char *longopt;
+  char *lastchr;
+  char *valuestart;
+  int op;
+  char *arg;
+  int match = -1;
+  *value = NULL;
+
+  if (args == NULL) {
+    *option_num = o_NO_OPTION_MATCH;
+    return 0;
+  }
+  if (args[argnum] == NULL) {
+    *option_num = o_NO_OPTION_MATCH;
+    return 0;
+  }
+  /* copy arg so can chop end if value */
+  if ((arg = (char *)malloc(strlen(args[argnum]) + 1)) == NULL) {
+    oERR(ZE_MEM, "glo");
+  }
+  strcpy(arg, args[argnum]);
+
+  /* get option */
+  longopt = arg + 2;
+  /* no value */
+  *value = NULL;
+
+  /* find = */
+  for (lastchr = longopt, valuestart = longopt;
+       *valuestart && *valuestart != '=';
+       lastchr = valuestart, MB_NEXTCHAR(valuestart)) ;
+  if (*valuestart) {
+    /* found =value */
+    *valuestart = '\0';
+    valuestart++;
+  } else {
+    valuestart = NULL;
+  }
+
+  if (*lastchr == '-') {
+    /* option negated */
+    *negated = 1;
+    *lastchr = '\0';
+  } else {
+    *negated = 0;
+  }
+
+  /* look for long option match */
+  for (op = 0; options[op].option_ID; op++) {
+    if (options[op].longopt && strcmp(options[op].longopt, longopt) == 0) {
+      /* exact match */
+      match = op;
+      break;
+    }
+    if (options[op].longopt && strncmp(options[op].longopt, longopt, strlen(longopt)) == 0) {
+      if (match > -1) {
+        sprintf(optionerrbuf, long_op_ambig_err, longopt);
+        free(arg);
+        if (depth > 0) {
+          /* unwind */
+          oWARN(optionerrbuf);
+          return o_ARG_FILE_ERR;
+        } else {
+          oERR(ZE_PARMS, optionerrbuf);
+        }
+      }
+      match = op;
+    }
+  }
+
+  if (match == -1) {
+    sprintf(optionerrbuf, long_op_not_sup_err, longopt);
+    free(arg);
+    if (depth > 0) {
+      oWARN(optionerrbuf);
+      return o_ARG_FILE_ERR;
+    } else {
+      oERR(ZE_PARMS, optionerrbuf);
+    }
+  }
+
+  /* one long option an arg */
+  *optchar = THIS_ARG_DONE;
+
+  /* if negated then see if allowed */
+  if (*negated && options[match].negatable == o_NOT_NEGATABLE) {
+    optionerr(optionerrbuf, op_not_neg_err, match, 1);
+    free(arg);
+    if (depth > 0) {
+      /* unwind */
+      oWARN(optionerrbuf);
+      return o_ARG_FILE_ERR;
+    } else {
+      oERR(ZE_PARMS, optionerrbuf);
+    }
+  }
+  /* get value */
+  if (options[match].value_type == o_OPTIONAL_VALUE) {
+    /* optional value in form option=value */
+    if (valuestart) {
+      /* option=value */
+      if ((*value = (char *)malloc(strlen(valuestart) + 1)) == NULL) {
+        free(arg);
+        oERR(ZE_MEM, "glo");
+      }
+      strcpy(*value, valuestart);
+    }
+  } else if (options[match].value_type == o_REQUIRED_VALUE ||
+             options[match].value_type == o_NUMBER_VALUE ||
+             options[match].value_type == o_ONE_CHAR_VALUE ||
+             options[match].value_type == o_VALUE_LIST) {
+    /* handle long option one char and number value as required value */
+    if (valuestart) {
+      /* option=value */
+      if ((*value = (char *)malloc(strlen(valuestart) + 1)) == NULL) {
+        free(arg);
+        oERR(ZE_MEM, "glo");
+      }
+      strcpy(*value, valuestart);
+    } else {
+      /* use next arg */
+      if (args[argnum + 1]) {
+        if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
+          free(arg);
+          oERR(ZE_MEM, "glo");
+        }
+        /* using next arg as value */
+        strcpy(*value, args[argnum + 1]);
+        if (options[match].value_type == o_VALUE_LIST) {
+          *optchar = START_VALUE_LIST;
+        } else {
+          *optchar = SKIP_VALUE_ARG;
+        }
+      } else {
+        /* no value found */
+        optionerr(optionerrbuf, op_req_val_err, match, 1);
+        free(arg);
+        if (depth > 0) {
+          /* unwind */
+          oWARN(optionerrbuf);
+          return o_ARG_FILE_ERR;
+        } else {
+          oERR(ZE_PARMS, optionerrbuf);
+        }
+      }
+    }
+  } else if (options[match].value_type == o_NO_VALUE) {
+    /* this option does not accept a value */
+    if (valuestart) {
+      /* --option=value */
+      optionerr(optionerrbuf, op_no_allow_val_err, match, 1);
+      free(arg);
+      if (depth > 0) {
+        oWARN(optionerrbuf);
+        return o_ARG_FILE_ERR;
+      } else {
+        oERR(ZE_PARMS, optionerrbuf);
+      }
+    }
+  }
+  free(arg);
+
+  *option_num = match;
+  return options[match].option_ID;
+}
+
+
+
+/* get_option
+ *
+ * Main interface for user.  Use this function to get options, values and
+ * non-option arguments from a command line provided in argv form.
+ *
+ * To use get_option() first define valid options by setting
+ * the global variable options[] to an array of option_struct.  Also
+ * either change defaults below or make variables global and set elsewhere.
+ * Zip uses below defaults.
+ *
+ * Call get_option() to get an option (like -b or --temp-file) and any
+ * value for that option (like filename for -b) or a non-option argument
+ * (like archive name) each call.  If *value* is not NULL after calling
+ * get_option() it is a returned value and the caller should either store
+ * the char pointer or free() it before calling get_option() again to avoid
+ * leaking memory.  If a non-option non-value argument is returned get_option()
+ * returns o_NON_OPTION_ARG and value is set to the entire argument.
+ * When there are no more arguments get_option() returns 0.
+ *
+ * The parameters argnum (after set to 0 on initial call),
+ * optchar, first_nonopt_arg, option_num, and depth (after initial
+ * call) are set and maintained by get_option() and should not be
+ * changed.  The parameters argc, negated, and value are outputs and
+ * can be used by the calling program.  get_option() returns either the
+ * option_ID for the current option, a special value defined in
+ * zip.h, or 0 when no more arguments.
+ *
+ * The value returned by get_option() is the ID value in the options
+ * table.  This value can be duplicated in the table if different
+ * options are really the same option.  The index into the options[]
+ * table is given by option_num, though the ID should be used as
+ * option numbers change when the table is changed.  The ID must
+ * not be 0 for any option as this ends the table.  If get_option()
+ * finds an option not in the table it calls oERR to post an
+ * error and exit.  Errors also result if the option requires a
+ * value that is missing, a value is present but the option does
+ * not take one, and an option is negated but is not
+ * negatable.  Non-option arguments return o_NON_OPTION_ARG
+ * with the entire argument in value.
+ *
+ * For Zip, permuting is on and all options and their values are
+ * returned before any non-option arguments like archive name.
+ *
+ * The arguments "-" alone and "--" alone return as non-option arguments.
+ * Note that "-" should not be used as part of a short option
+ * entry in the table but can be used in the middle of long
+ * options such as in the long option "a-long-option".  Now "--" alone
+ * stops option processing, returning any arguments following "--" as
+ * non-option arguments instead of options.
+ *
+ * Argument file support is removed from this version. It may be added later.
+ *
+ * After each call:
+ *   argc       is set to the current size of args[] but should not change
+ *                with argument file support removed,
+ *   argnum     is the index of the current arg,
+ *   value      is either the value of the returned option or non-option
+ *                argument or NULL if option with no value,
+ *   negated    is set if the option was negated by a trailing dash (-)
+ *   option_num is set to either the index in options[] for the option or
+ *                o_NO_OPTION_MATCH if no match.
+ * Negation is checked before the value is read if the option is negatable so
+ * that the - is not included in the value.  If the option is not negatable
+ * but takes a value then the - will start the value.  If permuting then
+ * argnum and first_nonopt_arg are unreliable and should not be used.
+ *
+ * Command line is read from left to right.  As get_option() finds non-option
+ * arguments (arguments not starting with - and that are not values to options)
+ * it moves later options and values in front of the non-option arguments.
+ * This permuting is turned off by setting enable_permute to 0.  Then
+ * get_option() will return options and non-option arguments in the order
+ * found.  Currently permuting is only done after an argument is completely
+ * processed so that any value can be moved with options they go with.  All
+ * state information is stored in the parameters argnum, optchar,
+ * first_nonopt_arg and option_num.  You should not change these after the
+ * first call to get_option().  If you need to back up to a previous arg then
+ * set argnum to that arg (remembering that args may have been permuted) and
+ * set optchar = 0 and first_nonopt_arg to the first non-option argument if
+ * permuting.  After all arguments are returned the next call to get_option()
+ * returns 0.  The caller can then call free_args(args) if appropriate.
+ *
+ * get_option() accepts arguments in the following forms:
+ *  short options
+ *       of 1 and 2 characters, e.g. a, b, cc, d, and ba, after a single
+ *       leading -, as in -abccdba.  In this example if 'b' is followed by 'a'
+ *       it matches short option 'ba' else it is interpreted as short option
+ *       b followed by another option.  The character - is not legal as a
+ *       short option or as part of a 2 character short option.
+ *
+ *       If a short option has a value it immediately follows the option or
+ *       if that option is the end of the arg then the next arg is used as
+ *       the value.  So if short option e has a value, it can be given as
+ *             -evalue
+ *       or
+ *             -e value
+ *       and now
+ *             -e=value
+ *       but now that = is optional a leading = is stripped for the first.
+ *       This change allows optional short option values to be defaulted as
+ *             -e=
+ *       Either optional or required values can be specified.  Optional values
+ *       now use both forms as ignoring the later got confusing.  Any
+ *       non-value short options can preceed a valued short option as in
+ *             -abevalue
+ *       Some value types (one_char and number) allow options after the value
+ *       so if oc is an option that takes a character and n takes a number
+ *       then
+ *             -abocVccn42evalue
+ *       returns value V for oc and value 42 for n.  All values are strings
+ *       so programs may have to convert the "42" to a number.  See long
+ *       options below for how value lists are handled.
+ *
+ *       Any short option can be negated by following it with -.  Any - is
+ *       handled and skipped over before any value is read unless the option
+ *       is not negatable but takes a value and then - starts the value.
+ *
+ *       If the value for an optional value is just =, then treated as no
+ *       value.
+ *
+ *  long options
+ *       of arbitrary length are assumed if an arg starts with -- but is not
+ *       exactly --.  Long options are given one per arg and can be abbreviated
+ *       if the abbreviation uniquely matches one of the long options.
+ *       Exact matches always match before partial matches.  If ambiguous an
+ *       error is generated.
+ *
+ *       Values are specified either in the form
+ *             --longoption=value
+ *       or can be the following arg if the value is required as in
+ *             --longoption value
+ *       Optional values to long options must be in the first form.
+ *
+ *       Value lists are specified by o_VALUE_LIST and consist of an option
+ *       that takes a value followed by one or more value arguments.
+ *       The two forms are
+ *             --option=value
+ *       or
+ *             -ovalue
+ *       for a single value or
+ *             --option value1 value2 value3 ... --option2
+ *       or
+ *             -o value1 value2 value3 ...
+ *       for a list of values.  The list ends at the next option, the
+ *       end of the command line, or at a single "@" argument.
+ *       Each value is treated as if it was preceeded by the option, so
+ *             --option1 val1 val2
+ *       with option1 value_type set to o_VALUE_LIST is the same as
+ *             --option1=val1 --option1=val2
+ *
+ *       Long options can be negated by following the option with - as in
+ *             --longoption-
+ *       Long options with values can also be negated if this makes sense for
+ *       the caller as:
+ *             --longoption-=value
+ *       If = is not followed by anything it is treated as no value.
+ *
+ *  @path
+ *       When an argument in the form @path is encountered, the file at path
+ *       is opened and white space separated arguments read from the file
+ *       and inserted into the command line at that point as if the contents
+ *       of the file were directly typed at that location.  The file can
+ *       have options, files to zip, or anything appropriate at that location
+ *       in the command line.  Since Zip has permuting enabled, options and
+ *       files will propagate to the appropriate locations in the command
+ *       line.
+ *
+ *       Argument files support has been removed from this version.  It may
+ *       be added back later.
+ *
+ *  non-option argument
+ *       is any argument not given above.  If enable_permute is 1 then
+ *       these are returned after all options, otherwise all options and
+ *       args are returned in order.  Returns option ID o_NON_OPTION_ARG
+ *       and sets value to the argument.
+ *
+ *
+ * Arguments to get_option:
+ *  char ***pargs          - pointer to arg array in the argv form
+ *  int *argc              - returns the current argc for args incl. args[0]
+ *  int *argnum            - the index of the current argument (caller
+ *                            should set = 0 on first call and not change
+ *                            after that)
+ *  int *optchar           - index of next short opt in arg or special
+ *  int *first_nonopt_arg  - used by get_option to permute args
+ *  int *negated           - option was negated (had trailing -)
+ *  char *value            - value of option if any (free when done with it) or NULL
+ *  int *option_num        - the index in options of the last option returned
+ *                            (can be o_NO_OPTION_MATCH)
+ *  int recursion_depth    - current depth of recursion
+ *                            (always set to 0 by caller)
+ *                            (always 0 with argument files support removed)
+ *
+ *  Caller should only read the returned option ID and the value, negated,
+ *  and option_num (if required) parameters after each call.
+ *
+ *  Ed Gordon
+ *  24 August 2003 (last updated 2 April 2008 EG)
+ *
+ */
+
+unsigned long get_option(pargs, argc, argnum, optchar, value,
+                         negated, first_nonopt_arg, option_num, recursion_depth)
+  char ***pargs;
+  int *argc;
+  int *argnum;
+  int *optchar;
+  char **value;
+  int *negated;
+  int *first_nonopt_arg;
+  int *option_num;
+  int recursion_depth;
+{
+  char **args;
+  unsigned long option_ID;
+
+  int argcnt;
+  int first_nonoption_arg;
+  char *arg = NULL;
+  int h;
+  int optc;
+  int argn;
+  int j;
+  int v;
+  int read_rest_args_verbatim = 0;  /* 7/25/04 - ignore options and arg files for rest args */
+
+  /* value is outdated.  The caller should free value before
+     calling get_option again. */
+  *value = NULL;
+
+  /* if args is NULL then done */
+  if (pargs == NULL) {
+    *argc = 0;
+    return 0;
+  }
+  args = *pargs;
+  if (args == NULL) {
+    *argc = 0;
+    return 0;
+  }
+
+  /* count args */
+  for (argcnt = 0; args[argcnt]; argcnt++) ;
+
+  /* if no provided args then nothing to do */
+  if (argcnt < 1 || (recursion_depth == 0 && argcnt < 2)) {
+    *argc = argcnt;
+    /* return 0 to note that no args are left */
+    return 0;
+  }
+
+  *negated = 0;
+  first_nonoption_arg = *first_nonopt_arg;
+  argn = *argnum;
+  optc = *optchar;
+
+  if (optc == READ_REST_ARGS_VERBATIM) {
+    read_rest_args_verbatim = 1;
+  }
+
+  if (argn == -1 || (recursion_depth == 0 && argn == 0)) {
+    /* first call */
+    /* if depth = 0 then args[0] is argv[0] so skip */
+    *option_num = o_NO_OPTION_MATCH;
+    optc = THIS_ARG_DONE;
+    first_nonoption_arg = -1;
+  }
+
+  /* if option_num is set then restore last option_ID in case continuing value list */
+  option_ID = 0;
+  if (*option_num != o_NO_OPTION_MATCH) {
+    option_ID = options[*option_num].option_ID;
+  }
+
+  /* get next option if any */
+  for (;;)  {
+    if (read_rest_args_verbatim) {
+      /* rest of args after "--" are non-option args if doubledash_ends_options set */
+      argn++;
+      if (argn > argcnt || args[argn] == NULL) {
+        /* done */
+        option_ID = 0;
+        break;
+      }
+      arg = args[argn];
+      if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
+        oERR(ZE_MEM, "go");
+      }
+      strcpy(*value, arg);
+      *option_num = o_NO_OPTION_MATCH;
+      option_ID = o_NON_OPTION_ARG;
+      break;
+
+    /* permute non-option args after option args so options are returned first */
+    } else if (enable_permute) {
+      if (optc == SKIP_VALUE_ARG || optc == THIS_ARG_DONE ||
+          optc == START_VALUE_LIST || optc == IN_VALUE_LIST ||
+          optc == STOP_VALUE_LIST) {
+        /* moved to new arg */
+        if (first_nonoption_arg > -1 && args[first_nonoption_arg]) {
+          /* do the permuting - move non-options after this option */
+          /* if option and value separate args or starting list skip option */
+          if (optc == SKIP_VALUE_ARG || optc == START_VALUE_LIST) {
+            v = 1;
+          } else {
+            v = 0;
+          }
+          for (h = first_nonoption_arg; h < argn; h++) {
+            arg = args[first_nonoption_arg];
+            for (j = first_nonoption_arg; j < argn + v; j++) {
+              args[j] = args[j + 1];
+            }
+            args[j] = arg;
+          }
+          first_nonoption_arg += 1 + v;
+        }
+      }
+    } else if (optc == NON_OPTION_ARG) {
+      /* if not permuting then already returned arg */
+      optc = THIS_ARG_DONE;
+    }
+
+    /* value lists */
+    if (optc == STOP_VALUE_LIST) {
+      optc = THIS_ARG_DONE;
+    }
+
+    if (optc == START_VALUE_LIST || optc == IN_VALUE_LIST) {
+      if (optc == START_VALUE_LIST) {
+        /* already returned first value */
+        argn++;
+        optc = IN_VALUE_LIST;
+      }
+      argn++;
+      arg = args[argn];
+      /* if end of args and still in list and there are non-option args then
+         terminate list */
+      if (arg == NULL && (optc == START_VALUE_LIST || optc == IN_VALUE_LIST)
+          && first_nonoption_arg > -1) {
+        /* terminate value list with @ */
+        /* this is only needed for argument files */
+        /* but is also good for show command line so command lines with lists
+           can always be read back in */
+        argcnt = insert_arg(&args, "@", first_nonoption_arg, 1);
+        argn++;
+        if (first_nonoption_arg > -1) {
+          first_nonoption_arg++;
+        }
+      }
+
+      arg = args[argn];
+      if (arg && arg[0] == '@' && arg[1] == '\0') {
+          /* inserted arguments terminator */
+          optc = STOP_VALUE_LIST;
+          continue;
+      } else if (arg && arg[0] != '-') {  /* not option */
+        /* - and -- are not allowed in value lists unless escaped */
+        /* another value in value list */
+        if ((*value = (char *)malloc(strlen(args[argn]) + 1)) == NULL) {
+          oERR(ZE_MEM, "go");
+        }
+        strcpy(*value, args[argn]);
+        break;
+
+      } else {
+        argn--;
+        optc = THIS_ARG_DONE;
+      }
+    }
+
+    /* move to next arg */
+    if (optc == SKIP_VALUE_ARG) {
+      argn += 2;
+      optc = 0;
+    } else if (optc == THIS_ARG_DONE) {
+      argn++;
+      optc = 0;
+    }
+    if (argn > argcnt) {
+      break;
+    }
+    if (args[argn] == NULL) {
+      /* done unless permuting and non-option args */
+      if (first_nonoption_arg > -1 && args[first_nonoption_arg]) {
+        /* return non-option arguments at end */
+        if (optc == NON_OPTION_ARG) {
+          first_nonoption_arg++;
+        }
+        /* after first pass args are permuted but skipped over non-option args */
+        /* swap so argn points to first non-option arg */
+        j = argn;
+        argn = first_nonoption_arg;
+        first_nonoption_arg = j;
+      }
+      if (argn > argcnt || args[argn] == NULL) {
+        /* done */
+        option_ID = 0;
+        break;
+      }
+    }
+
+    /* after swap first_nonoption_arg points to end which is NULL */
+    if (first_nonoption_arg > -1 && (args[first_nonoption_arg] == NULL)) {
+      /* only non-option args left */
+      if (optc == NON_OPTION_ARG) {
+        argn++;
+      }
+      if (argn > argcnt || args[argn] == NULL) {
+        /* done */
+        option_ID = 0;
+        break;
+      }
+      if ((*value = (char *)malloc(strlen(args[argn]) + 1)) == NULL) {
+        oERR(ZE_MEM, "go");
+      }
+      strcpy(*value, args[argn]);
+      optc = NON_OPTION_ARG;
+      option_ID = o_NON_OPTION_ARG;
+      break;
+    }
+
+    arg = args[argn];
+
+    /* is it an option */
+    if (arg[0] == '-') {
+      /* option */
+      if (arg[1] == '\0') {
+        /* arg = - */
+        /* treat like non-option arg */
+        *option_num = o_NO_OPTION_MATCH;
+        if (enable_permute) {
+          /* permute args to move all non-option args to end */
+          if (first_nonoption_arg < 0) {
+            first_nonoption_arg = argn;
+          }
+          argn++;
+        } else {
+          /* not permute args so return non-option args when found */
+          if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
+            oERR(ZE_MEM, "go");
+          }
+          strcpy(*value, arg);
+          optc = NON_OPTION_ARG;
+          option_ID = o_NON_OPTION_ARG;
+          break;
+        }
+
+      } else if (arg[1] == '-') {
+        /* long option */
+        if (arg[2] == '\0') {
+          /* arg = -- */
+          if (doubledash_ends_options) {
+            /* Now -- stops permuting and forces the rest of
+               the command line to be read verbatim - 7/25/04 EG */
+
+            /* never permute args after -- and return as non-option args */
+            if (first_nonoption_arg < 1) {
+              /* -- is first non-option argument - 8/7/04 EG */
+              argn--;
+            } else {
+              /* go back to start of non-option args - 8/7/04 EG */
+              argn = first_nonoption_arg - 1;
+            }
+
+            /* disable permuting and treat remaining arguments as not
+               options */
+            read_rest_args_verbatim = 1;
+            optc = READ_REST_ARGS_VERBATIM;
+
+          } else {
+            /* treat like non-option arg */
+            *option_num = o_NO_OPTION_MATCH;
+            if (enable_permute) {
+              /* permute args to move all non-option args to end */
+              if (first_nonoption_arg < 0) {
+                first_nonoption_arg = argn;
+              }
+              argn++;
+            } else {
+              /* not permute args so return non-option args when found */
+              if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
+                oERR(ZE_MEM, "go");
+              }
+              strcpy(*value, arg);
+              optc = NON_OPTION_ARG;
+              option_ID = o_NON_OPTION_ARG;
+              break;
+            }
+          }
+
+        } else {
+          option_ID = get_longopt(args, argn, &optc, negated, value, option_num, recursion_depth);
+          if (option_ID == o_ARG_FILE_ERR) {
+            /* unwind as only get this if recursion_depth > 0 */
+            return option_ID;
+          }
+          break;
+        }
+
+      } else {
+        /* short option */
+        option_ID = get_shortopt(args, argn, &optc, negated, value, option_num, recursion_depth);
+
+        if (option_ID == o_ARG_FILE_ERR) {
+          /* unwind as only get this if recursion_depth > 0 */
+          return option_ID;
+        }
+
+        if (optc == 0) {
+          /* if optc = 0 then ran out of short opts this arg */
+          optc = THIS_ARG_DONE;
+        } else {
+          break;
+        }
+      }
+
+#if 0
+    /* argument file code left out
+       so for now let filenames start with @
+    */
+
+    } else if (allow_arg_files && arg[0] == '@') {
+      /* arg file */
+      oERR(ZE_PARMS, no_arg_files_err);
+#endif
+
+    } else {
+      /* non-option */
+      if (enable_permute) {
+        /* permute args to move all non-option args to end */
+        if (first_nonoption_arg < 0) {
+          first_nonoption_arg = argn;
+        }
+        argn++;
+      } else {
+        /* no permute args so return non-option args when found */
+        if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
+          oERR(ZE_MEM, "go");
+        }
+        strcpy(*value, arg);
+        *option_num = o_NO_OPTION_MATCH;
+        optc = NON_OPTION_ARG;
+        option_ID = o_NON_OPTION_ARG;
+        break;
+      }
+
+    }
+  }
+
+  *pargs = args;
+  *argc = argcnt;
+  *first_nonopt_arg = first_nonoption_arg;
+  *argnum = argn;
+  *optchar = optc;
+
+  return option_ID;
+}
diff --git a/globals.c b/globals.c
new file mode 100644 (file)
index 0000000..e73392a
--- /dev/null
+++ b/globals.c
@@ -0,0 +1,253 @@
+/*
+  globals.c - Zip 3
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  globals.c by Mark Adler
+ */
+#define __GLOBALS_C
+
+#define GLOBALS         /* include definition of errors[] in zip.h */
+#ifndef UTIL
+#define UTIL            /* do not declare the read_buf variable */
+#endif
+
+#include "zip.h"
+
+
+/* Handy place to build error messages */
+char errbuf[FNMAX+4081];
+
+/* Argument processing globals */
+int recurse = 0;        /* 1=recurse into directories encountered */
+int dispose = 0;        /* 1=remove files after put in zip file */
+int pathput = 1;        /* 1=store path with name */
+#ifdef RISCOS
+int scanimage = 1;      /* 1=scan through image files */
+#endif
+int method = BEST;      /* one of BEST, DEFLATE (only), or STORE (only) */
+int dosify = 0;         /* 1=make new entries look like MSDOS */
+int verbose = 0;        /* 1=report oddities in zip file structure */
+int fix = 0;            /* 1=fix the zip file, 2=FF, 3=ZipNote */
+int filesync = 0;       /* 1=file sync, delete entries not on file system */
+int adjust = 0;         /* 1=adjust offsets for sfx'd file (keep preamble) */
+int level = 6;          /* 0=fastest compression, 9=best compression */
+int translate_eol = 0;  /* Translate end-of-line LF -> CR LF */
+#ifdef VMS
+   int vmsver = 0;      /* 1=append VMS version number to file names */
+   int vms_native = 0;  /* 1=store in VMS format */
+   int vms_case_2 = 0;  /* ODS2 file name case in VMS.  -1: down. */
+   int vms_case_5 = 0;  /* ODS5 file name case in VMS.  +1: preserve. */
+#endif /* VMS */
+#if defined(OS2) || defined(WIN32)
+   int use_longname_ea = 0;  /* 1=use the .LONGNAME EA as the file's name */
+#endif
+/* 9/26/04 */
+int no_wild = 0;             /* 1 = wildcards are disabled */
+int allow_regex = 0;         /* 1 = allow [list] matching */
+#ifdef WILD_STOP_AT_DIR
+   int wild_stop_at_dir = 1; /* default wildcards do not include / in matches */
+#else
+   int wild_stop_at_dir = 0; /* default wildcards do include / in matches */
+#endif
+
+#ifdef UNICODE_SUPPORT
+   int using_utf8 = 0;       /* 1 if current character set UTF-8 */
+# ifdef WIN32
+   int no_win32_wide = -1; /* 1 = no wide functions, like GetFileAttributesW() */
+# endif
+#endif
+
+ulg skip_this_disk = 0;
+int des_good = 0;       /* Good data descriptor found */
+ulg des_crc = 0;        /* Data descriptor CRC */
+uzoff_t des_csize = 0;  /* Data descriptor csize */
+uzoff_t des_usize = 0;  /* Data descriptor usize */
+
+/* dots 10/20/04 */
+zoff_t dot_size = 0;          /* bytes processed in deflate per dot, 0 = no dots */
+zoff_t dot_count = 0;         /* buffers seen, recyles at dot_size */
+/* status 10/30/04 */
+int display_counts = 0;       /* display running file count */
+int display_bytes = 0;        /* display running bytes remaining */
+int display_globaldots = 0;   /* display dots for archive instead of each file */
+int display_volume = 0;       /* display current input and output volume (disk) numbers */
+int display_usize = 0;        /* display uncompressed bytes */
+ulg files_so_far = 0;         /* files processed so far */
+ulg bad_files_so_far = 0;     /* bad files skipped so far */
+ulg files_total = 0;          /* files total to process */
+uzoff_t bytes_so_far = 0;     /* bytes processed so far (from initial scan) */
+uzoff_t good_bytes_so_far = 0;/* good bytes read so far */
+uzoff_t bad_bytes_so_far = 0; /* bad bytes skipped so far */
+uzoff_t bytes_total = 0;      /* total bytes to process (from initial scan) */
+
+/* logfile 6/5/05 */
+int logall = 0;               /* 0 = warnings/errors, 1 = all */
+FILE *logfile = NULL;         /* pointer to open logfile or NULL */
+int logfile_append = 0;       /* append to existing logfile */
+char *logfile_path = NULL;    /* pointer to path of logfile */
+
+int hidden_files = 0;         /* process hidden and system files */
+int volume_label = 0;         /* add volume label */
+int dirnames = 1;             /* include directory entries by default */
+int filter_match_case = 1;    /* 1=match case when filter() */
+int diff_mode = 0;            /* 1=require --out and only store changed and add */
+#if defined(WIN32)
+int only_archive_set = 0;     /* include only files with DOS archive bit set */
+int clear_archive_bits = 0;   /* clear DOS archive bit of included files */
+#endif
+int linkput = 0;              /* 1=store symbolic links as such */
+int noisy = 1;                /* 0=quiet operation */
+int extra_fields = 1;         /* 0=create minimum, 1=don't copy old, 2=keep old */
+int use_descriptors = 0;      /* 1=use data descriptors 12/29/04 */
+int zip_to_stdout = 0;        /* output zipfile to stdout 12/30/04 */
+int allow_empty_archive = 0;  /* if no files, create empty archive anyway 12/28/05 */
+int copy_only = 0;            /* 1=copying archive entries only */
+int allow_fifo = 0;           /* 1=allow reading Unix FIFOs, waiting if pipe open */
+int show_files = 0;           /* show files to operate on and exit (=2 log only) */
+
+int output_seekable = 1;      /* 1 = output seekable 3/13/05 EG */
+
+#ifdef ZIP64_SUPPORT          /* zip64 support 10/4/03 */
+  int force_zip64 = -1;       /* if 1 force entries to be zip64, 0 force not zip64 */
+                              /* mainly for streaming from stdin */
+  int zip64_entry = 0;        /* current entry needs Zip64 */
+  int zip64_archive = 0;      /* if 1 then at least 1 entry needs zip64 */
+#endif
+
+#ifdef NTSD_EAS
+  int use_privileges = 0;     /* 1=use security privilege overrides */
+#endif
+#ifndef RISCOS
+#ifndef QDOS
+#ifndef TANDEM
+char *special = ".Z:.zip:.zoo:.arc:.lzh:.arj"; /* List of special suffixes */
+#else /* TANDEM */
+char *special = " Z: zip: zoo: arc: lzh: arj"; /* List of special suffixes */
+#endif
+#else /* QDOS */
+char *special = "_Z:_zip:_zoo:_arc:_lzh:_arj"; /* List of special suffixes */
+#endif
+#else /* RISCOS */
+char *special = "DDC:D96:68E";
+#endif /* ?RISCOS */
+char *key = NULL;       /* Scramble password if scrambling */
+char *tempath = NULL;   /* Path for temporary files */
+FILE *mesg;             /* stdout by default, stderr for piping */
+
+#ifdef UNICODE_SUPPORT
+ int utf8_force = 0;    /* 1=force storing UTF-8 as standard per AppNote bit 11 */
+#endif
+int unicode_escape_all = 0; /* 1=escape all non-ASCII characters in paths */
+int unicode_mismatch = 1; /* unicode mismatch is 0=error, 1=warn, 2=ignore, 3=no */
+
+time_t scan_delay = 5;  /* seconds before display Scanning files message */
+time_t scan_dot_time = 2; /* time in seconds between Scanning files dots */
+time_t scan_start = 0;  /* start of scan */
+time_t scan_last = 0;   /* time of last message */
+int scan_started = 0;   /* scan has started */
+uzoff_t scan_count = 0; /* Used for Scanning files ... message */
+
+ulg before = 0;         /* 0=ignore, else exclude files before this time */
+ulg after = 0;          /* 0=ignore, else exclude files newer than this time */
+
+/* Zip file globals */
+char *zipfile;          /* New or existing zip archive (zip file) */
+
+/* zip64 support 08/31/2003 R.Nausedat */
+/* all are across splits - subtract bytes_prev_splits to get offsets for current disk */
+uzoff_t zipbeg;               /* Starting offset of zip structures */
+uzoff_t cenbeg;               /* Starting offset of central dir */
+uzoff_t tempzn;               /* Count of bytes written to output zip files */
+
+/* 10/28/05 */
+char *tempzip = NULL;         /* name of temp file */
+FILE *y = NULL;               /* output file now global so can change in splits */
+FILE *in_file = NULL;         /* current input file for splits */
+char *in_path = NULL;         /* base name of input archive file */
+char *in_split_path = NULL;   /* in split path */
+char *out_path = NULL;        /* base name of output file, usually same as zipfile */
+int zip_attributes = 0;
+
+/* in split globals */
+
+ulg     total_disks = 0;        /* total disks in archive */
+ulg     current_in_disk = 0;    /* current read split disk */
+uzoff_t current_in_offset = 0;  /* current offset in current read disk */
+ulg     skip_current_disk = 0;  /* if != 0 and fix then skip entries on this disk */
+
+
+/* out split globals */
+
+ulg     current_local_disk = 0;   /* disk with current local header */
+
+ulg     current_disk = 0;         /* current disk number */
+ulg     cd_start_disk = (ulg)-1;  /* central directory start disk */
+uzoff_t cd_start_offset = 0;      /* offset of start of cd on cd start disk */
+uzoff_t cd_entries_this_disk = 0; /* cd entries this disk */
+uzoff_t total_cd_entries = 0;     /* total cd entries in new/updated archive */
+ulg     zip64_eocd_disk = 0;      /* disk with Zip64 End Of Central Directory Record */
+uzoff_t zip64_eocd_offset = 0;    /* offset for Zip64 EOCD Record */
+
+/* for split method 1 (keep split with local header open and update) */
+char *current_local_tempname = NULL; /* name of temp file */
+FILE  *current_local_file = NULL; /* file pointer for current local header */
+uzoff_t current_local_offset = 0; /* offset to start of current local header */
+
+/* global */
+uzoff_t bytes_this_split = 0;     /* bytes written to the current split */
+int read_split_archive = 0;       /* 1=scanzipf_reg detected spanning signature */
+int split_method = 0;             /* 0=no splits, 1=seekable, 2=data desc, -1=no */
+uzoff_t split_size = 0;           /* how big each split should be */
+int split_bell = 0;               /* when pause for next split ring bell */
+uzoff_t bytes_prev_splits = 0;    /* total bytes written to all splits before this */
+uzoff_t bytes_this_entry = 0;     /* bytes written for this entry across all splits */
+int noisy_splits = 0;             /* note when splits are being created */
+int mesg_line_started = 0;        /* 1=started writing a line to mesg */
+int logfile_line_started = 0;     /* 1=started writing a line to logfile */
+
+#ifdef WIN32
+  int nonlocal_name = 0;          /* Name has non-local characters */
+  int nonlocal_path = 0;          /* Path has non-local characters */
+#endif
+#ifdef UNICODE_SUPPORT
+  int use_wide_to_mb_default = 0;
+#endif
+
+struct zlist far *zfiles = NULL;  /* Pointer to list of files in zip file */
+/* The limit for number of files using the Zip64 format is 2^64 - 1 (8 bytes)
+   but extent is used for many internal sorts and other tasks and is generally
+   long on 32-bit systems.  Because of that, but more because of various memory
+   utilization issues limiting the practical number of central directory entries
+   that can be sorted, the number of actual entries that can be stored probably
+   can't exceed roughly 2^30 on 32-bit systems so extent is probably sufficient. */
+extent zcount;                    /* Number of files in zip file */
+int zipfile_exists = 0;           /* 1 if zipfile exists */
+ush zcomlen;                      /* Length of zip file comment */
+char *zcomment = NULL;            /* Zip file comment (not zero-terminated) */
+struct zlist far **zsort;         /* List of files sorted by name */
+#ifdef UNICODE_SUPPORT
+  struct zlist far **zusort;      /* List of files sorted by zuname */
+#endif
+
+/* Files to operate on that are not in zip file */
+struct flist far *found = NULL;   /* List of names found */
+struct flist far * far *fnxt = &found;
+                                  /* Where to put next name in found list */
+extent fcount;                    /* Count of files in list */
+
+/* Patterns to be matched */
+struct plist *patterns = NULL;  /* List of patterns to be matched */
+unsigned pcount = 0;            /* number of patterns */
+unsigned icount = 0;            /* number of include only patterns */
+unsigned Rcount = 0;            /* number of -R include patterns */
+
+#ifdef IZ_CHECK_TZ
+int zp_tz_is_valid;     /* signals "timezone info is available" */
+#endif
diff --git a/human68k/Makefile b/human68k/Makefile
new file mode 100644 (file)
index 0000000..be1a8b7
--- /dev/null
@@ -0,0 +1,95 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for human68k
+# Written by NIIMI Satoshi <a01309@cfi.waseda.ac.jp>
+#
+# 1999/09/23: Modified by Shimazaki Ryo.
+
+ifeq "$(TARGET)" "X68030"
+COPT = -m68020-40
+AOPT = -m68020 -sCPU020
+LDFLAGS = -L/usr/local/lib/lib060
+endif
+
+VPATH = human68k
+
+CC = gcc2
+CFLAGS = $(COPT) -I. -Wall -O2 -fomit-frame-pointer -fstrength-reduce \
+        -DASM_CRC -D__DOS_INLINE__
+#LDFLAGS = -Wl,-x
+LIBS = -lhmem -lttyi -lsignal
+
+AS = g2as
+ASFLAGS = $(AOPT) -1 -c4 -y -w2
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crypt.o ttyio.o \
+       crc32.o human68k.o crc_68.o
+OBJI = deflate.o trees.o
+OBJA =
+OBJU = zipfile_.o fileio_.o util_.o globals.o human68k_.o
+OBJN = zipnote.o  $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h human68k/osdep.h
+
+all: zips
+
+.SUFFIXES: _.o .o .c
+.c_.o:
+       $(CC) $(CFLAGS) -DUTIL -c $< -o $@
+.c.o:
+       $(CC) $(CFLAGS) -c $< -o $@
+
+ZIPS = zip.x zipnote.x zipsplit.x zipcloak.x
+
+zips: $(ZIPS)
+
+zip.x: $(OBJZ) $(OBJI) $(OBJA)
+       $(CC) $(LDFLAGS) -o $@ $(OBJZ) $(OBJI) $(OBJA) $(LIBS)
+zipnote.x: $(OBJN)
+       $(CC) $(LDFLAGS) -o $@ $(OBJN) $(LIBS)
+zipcloak.x: $(OBJC)
+       $(CC) $(LDFLAGS) -o $@ $(OBJC) $(LIBS)
+zipsplit.x: $(OBJS)
+       $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
+
+
+human68k.o: human68k/human68k.c
+       $(CC) $(CFLAGS) -c -o $@ $<
+
+human68k_.o: human68k/human68k.c
+       $(CC) $(CFLAGS) -c -o $@ $< -DUTIL
+
+#match.o: human68k/match.s
+#      $(AS) $(ASFLAGS) -o $@ $<
+
+deflate.o: human68k/deflate.s
+       $(AS) $(ASFLAGS) -o $@ $<
+
+crc_68.o: human68k/crc_68.s
+       $(AS) $(ASFLAGS) -o $@ $<
+
+
+clean:
+       rm -f *.o $(ZIPS)
+
+zip.bfd: $(ZIPS)
+       rm -f $@
+       for file in $(ZIPS); do \
+               bdif -A -R uploaded/$$file $$file $@; \
+       done
+
+# rules for zip, zipnote, zipcloak, zipsplit.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o crc32.o crypt.o fileio.o zipfile.o zipup.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: human68k/zipup.h
+
+# EOF
diff --git a/human68k/Makefile.gcc b/human68k/Makefile.gcc
new file mode 100644 (file)
index 0000000..edf2989
--- /dev/null
@@ -0,0 +1,78 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for human68k
+# Written by NIIMI Satoshi <a01309@cfi.waseda.ac.jp>
+
+VPATH = human68k
+
+CC = gcc
+AS = as
+
+# if you are using mc68030 (or higher) based X68000,
+# uncomment following defines
+#CC = gcc -DUNALIGNED_OK
+#AS = as -s UNALIGNED_OK
+
+CFLAGS = -Wall -O -fomit-frame-pointer -fstrength-reduce -DASMV
+LDFLAGS = -s
+LIBS = -lsignal -lmb -ldos
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o crc32.o globals.o \
+       crypt.o ttyio.o
+
+OBJI = deflate.o trees.o
+OBJA = match.o human68k.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o human68_.o
+OBJN = zipnote.o  $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h human68k/osdep.h
+
+all: zips
+
+.SUFFIXES: _.o .o .c
+.c_.o:
+       $(CC) $(CFLAGS) -DUTIL -c $< -o $@
+.c.o:
+       $(CC) $(CFLAGS) -c $< -o $@
+
+ZIPS = zip.x zipnote.x zipsplit.x zipcloak.x
+
+zips: $(ZIPS)
+
+zip.x: $(OBJZ) $(OBJI) $(OBJA)
+       $(CC) -o zip.x $(LDFLAGS) $(OBJZ) $(OBJI) $(OBJA) $(LIBS)
+zipnote.x: $(OBJN)
+       $(CC) -o zipnote.x $(LDFLAGS) $(OBJN) $(LIBS)
+zipcloak.x: $(OBJC)
+       $(CC) -o zipcloak.x $(LDFLAGS) $(OBJC) $(LIBS)
+zipsplit.x: $(OBJS)
+       $(CC) -o zipsplit.x $(LDFLAGS) $(OBJS) $(LIBS)
+
+match.o: human68k/match.s
+       $(AS) -o $@ $<
+
+human68_.o: human68k/human68k.c
+       $(CC) $(CFLAGS) -DUTIL -c -o $@ $<
+
+clean:
+       rm -f *.o $(ZIPS)
+
+zip.bfd: $(ZIPS)
+       rm -f $@
+       for file in $(ZIPS); do \
+               bdif -A -R uploaded/$$file $$file $@; \
+       done
+
+# rules for zip, zipnote, zipcloak, zipsplit.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o crc32.o crypt.o fileio.o zipfile.o zipup.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: human68k/zipup.h
diff --git a/human68k/crc_68.s b/human68k/crc_68.s
new file mode 100644 (file)
index 0000000..9ce78d8
--- /dev/null
@@ -0,0 +1,144 @@
+;===========================================================================
+; Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 2000-Apr-09 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+; crc_68 created by Paul Kienitz, last modified 04 Jan 96.
+;
+; Return an updated 32 bit CRC value, given the old value and a block of data.
+; The CRC table used to compute the value is gotten by calling get_crc_table().
+; This replaces the older updcrc() function used in Zip and fUnZip.  The
+; prototype of the function is:
+;
+;    ulg crc32(ulg crcval, uch *text, extent textlen);
+;
+; On the Amiga, type extent is always unsigned long, not unsigned int, because
+; int can be short or long at whim, but size_t is long.
+;
+; If using this source on a non-Amiga 680x0 system, note that we treat
+; a0/a1/d0/d1 as scratch registers not preserved across function calls.
+; We do not bother to support registerized arguments for crc32() -- the
+; textlen parm is usually large enough so that savings outside the loop
+; are pointless.
+;
+; Define NO_UNROLLED_LOOPS to use a simple short loop which might be more
+; efficient on certain machines with dinky instruction caches ('020?), or for
+; processing short strings.  If loops are unrolled, the textlen parm must be
+; less than 512K; if not unrolled, it must be less than 64K.
+;
+; 1999/09/23: for Human68k: Modified by Shimazaki Ryo.
+
+        xdef    _crc32          ; (ulg val, uch *buf, extent bufsize)
+
+DO_CRC0 MACRO
+        moveq  #0,ltemp
+        move.b (textbuf)+,ltemp
+        eor.b  crcval,ltemp
+        lsl.w  #2,ltemp
+        move.l (crc_table,ltemp.w),ltemp
+        lsr.l  #8,crcval
+        eor.l  ltemp,crcval
+        ENDM
+
+
+DO_CRC2 MACRO
+        move.b (textbuf)+,btemp
+        eor.b  crcval,btemp
+        lsr.l  #8,crcval
+        move.l (crc_table,btemp.w*4),ltemp
+        eor.l  ltemp,crcval
+        ENDM
+
+crc_table       reg     a0      array of unsigned long
+crcval          reg     d0      unsigned long initial value
+textbuf         reg     a1      array of unsigned char
+textbufsize     reg     d1      unsigned long (count of bytes in textbuf)
+btemp           reg     d2
+ltemp           reg     d3
+
+
+        xref    _get_crc_table  ; ulg *get_crc_table(void)
+
+
+
+        quad
+_crc32:
+        move.l  8(sp),d0
+        bne.s   valid
+;;;;;   moveq  #0,d0
+         rts
+valid:  movem.l btemp/ltemp,-(sp)
+        jsr     _get_crc_table
+        movea.l d0,crc_table
+        move.l  12(sp),crcval
+        move.l  16(sp),textbuf
+        move.l  20(sp),textbufsize
+        not.l   crcval
+
+    ifdef   NO_UNROLLED_LOOPS
+
+    if CPU==68000
+        bra.s   decr
+loop:    DO_CRC0
+decr:    dbra   textbufsize,loop
+        bra.s   done
+
+    else
+twenty: moveq   #0,btemp
+        bra.s   decr2
+loop2:   DO_CRC2
+decr2:   dbra   textbufsize,loop2
+    endif
+
+    ELSE    ; !NO_UNROLLED_LOOPS
+
+    if CPU==68000
+        moveq   #7,btemp
+        and     textbufsize,btemp
+        lsr.l   #3,textbufsize
+        bra     decr8
+loop8:   DO_CRC0
+         DO_CRC0
+         DO_CRC0
+         DO_CRC0
+         DO_CRC0
+         DO_CRC0
+         DO_CRC0
+         DO_CRC0
+decr8:   dbra   textbufsize,loop8
+        bra.s   decr1
+loop1:   DO_CRC0
+decr1:   dbra   btemp,loop1
+        bra     done
+
+    else
+twenty: moveq   #0,btemp
+        move.l  textbufsize,-(sp)
+        lsr.l   #3,textbufsize
+        bra     decr82
+         quad
+loop82:  DO_CRC2
+         DO_CRC2
+         DO_CRC2
+         DO_CRC2
+         DO_CRC2
+         DO_CRC2
+         DO_CRC2
+         DO_CRC2
+decr82:  dbra   textbufsize,loop82
+        moveq   #7,textbufsize
+        and.l   (sp)+,textbufsize
+        bra.s   decr12
+loop12:  DO_CRC2
+decr12:  dbra   textbufsize,loop12
+    endif
+
+    ENDC    ; ?NO_UNROLLED_LOOPS
+
+done:   movem.l (sp)+,btemp/ltemp
+        not.l   crcval
+;;;;;   move.l  crcval,d0               ; crcval already is d0
+        rts
diff --git a/human68k/deflate.s b/human68k/deflate.s
new file mode 100644 (file)
index 0000000..246962c
--- /dev/null
@@ -0,0 +1,1076 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; This is a 680x0 assembly language translation of the Info-ZIP source file
+; deflate.c, by Paul Kienitz.  No rights reserved.  The function longest_match
+; is based in part on match.a by Carsten Steger, which in turn is partly based
+; on match.s for 386 by Jean-loup Gailly and Kai Uwe Rommel.  Mostly, however,
+; this material is based on deflate.c, by Gailly, Rommel, and Igor Mandrichenko.
+; This code is not commented very much; see deflate.c for comments that explain
+; what the functions are doing.
+;
+; The symbols that can be used to select different versions are as follows:
+;
+;   CPU020     if defined, use 68020 instructions always.
+;
+;   CPUTEST    if defined, check at runtime for CPU type.  Another symbol
+;               specifying the platform-specific test must be used with this.
+;               If neither of these is defined, use 68000 instructions only.
+;               Runtime test is nonportable; it is different for each OS.
+;
+;   AMIGA      use Amiga-specific test for 68020, if CPUTEST defined.  Also
+;               tells it that registers d0/a0/d1/a1 are not preserved by
+;               function calls.  At present, if AMIGA is not defined, it
+;               causes functions to preserve all registers.  ALL OF THIS CODE
+;               CURRENTLY ASSUMES THAT REGISTERS D2-D7/A2-A6 WILL BE PRESERVED
+;               BY ANY FUNCTIONS THAT IT CALLS.
+;
+;   DYN_ALLOC  should be defined here if it is defined for C source; tells us
+;               that big arrays are allocated instead of static.
+;
+;   WSIZE      must be defined as the same number used for WSIZE in the C
+;               source, and must be a power of two <= 32768.  As elsewhere,
+;               the default value is 32768.
+;
+;   INT16      define this if ints are 16 bits; otherwise 32 bit ints assumed.
+;
+;   SMALL_MEM  define this if it is defined in the C source; otherwise it uses
+;               the MEDIUM_MEM model.  BIG_MEM and MMAP are *not* supported.
+;               The FULL_SEARCH option in deflate.c is also not supported.
+;
+;   DEBUG      activates some tracing output, as in the C source.
+;
+;   QUADLONG   this selects a different version of the innermost longest_match
+;               loop code for 68020 operations, comparing bytes four at a time
+;               instead of two at a time.  It seems to be a tiny bit faster on
+;               average, but it's slower often enough that one can't generalize.
+;
+; This code currently assumes that function results are returned in D0 for
+; all platforms.  It assumes that args to functions are pushed onto the stack,
+; last arg first.  It also currently assumes that all C symbols have an
+; underscore prepended when referenced from assembly.
+;
+; 1999/09/23: for Human68k: Modified by Shimazaki Ryo.
+
+    IFNDEF  CPU020
+     IFNDEF CPUTEST
+CPU000  equ     1
+     ENDC
+    ENDC
+
+; Use these macros for accessing variables of type int:
+    IFDEF   INT16
+MOVINT  MACRO   _1,_2
+        move.w  _1,_2
+        ENDM
+CLRINT  MACRO   _1
+        clr.w   _1
+        ENDM
+INTSIZE equ     2
+    ELSE    ; !INT16
+MOVINT  MACRO   _1,_2
+        move.l  _1,_2
+        ENDM
+CLRINT  MACRO   _1
+        clr.l   _1
+        ENDM
+INTSIZE equ     4
+    ENDC
+
+    IFDEF   DYN_ALLOC
+BASEPTR MACRO   _1,_2
+        move.l  _1,_2
+        ENDM
+    ELSE
+BASEPTR MACRO   _1,_2
+        lea     _1,_2
+        ENDM
+    ENDC
+
+; constants we use, many of them adjustable:
+
+MAX_MATCH       equ     258
+MIN_MATCH       equ     3
+TOO_FAR         equ     4096
+    IFNDEF  WSIZE
+WSIZE           equ     32768
+    ENDC
+WMASK           equ     WSIZE-1
+MAX_DIST        equ     WSIZE-MAX_MATCH-MIN_MATCH-1
+MIN_LOOKAHEAD   equ     MAX_MATCH+MIN_MATCH+1
+;    IFD     BIG_MEM      ; NOT supported -- type Pos needs to be 32 bits
+;HASH_BITS      equ     15
+;    ELSE
+    IFDEF  SMALL_MEM
+HASH_BITS       equ     13
+    ELSE
+HASH_BITS       equ     14      ; default -- MEDIUM_MEM
+    ENDC
+;    ENDC    ; BIG_MEM
+HASH_SIZE       equ     1<<HASH_BITS
+HASH_MASK       equ     HASH_SIZE-1
+H_SHIFT         equ     (HASH_BITS+MIN_MATCH-1)/MIN_MATCH
+B_SLOW          equ     1
+B_FAST          equ     2
+ZE_MEM          equ     4
+EOF             equ     -1
+
+; struct config is defined by these offsets:
+Good_length     equ     0
+Max_lazy        equ     2
+Nice_length     equ     4
+Max_chain       equ     6
+Sizeof_config   equ     8
+
+
+; external functions we call:
+        xref    _ct_tally       ; int ct_tally(int, int)
+        xref    _flush_block    ; unsigned long F(char *, unsigned long, int)
+        xref    _ziperr         ; void ziperr(int, char *)
+        xref    _error          ; void error(char *)
+        xref    _calloc         ; stdlib function: void *calloc(size_t, size_t)
+        xref    _free           ; stdlib function: void free(void *)
+    IFDEF   DEBUG
+        xref    _fputc          ; stdio function: int fputc(int, FILE *)
+        xref    _stderr         ; pointer to FILE, which we pass to fputc
+    ENDC
+
+; our entry points:
+        xdef    _lm_init        ; void lm_init(int level, unsigned short *flags)
+        xdef    _lm_free        ; void lm_free(void)
+        xdef    _deflate        ; void deflate(void)  ...the big one
+        xdef    _fill_window    ; this line is just for debugging
+
+
+; ============================================================================
+; Here is where we have our global variables.
+
+;;;     section deflatevars,data
+
+; external global variables we reference:
+        xref    _verbose        ; signed int
+        xref    _level          ; signed int
+        xref    _read_buf       ; int (*read_buf)(char *, unsigned int)
+
+; global variables we make available:
+
+        xdef    _window
+        xdef    _prev
+        xdef    _head
+        xdef    _window_size
+        xdef    _block_start
+        xdef    _strstart
+
+        bss
+        quad
+
+    IFDEF   DYN_ALLOC
+_prev:          ds.l    1       ; pointer to calloc()'d unsigned short array
+_head:          ds.l    1       ; pointer to calloc()'d unsigned short array
+_window:        ds.l    1       ; pointer to calloc()'d unsigned char array
+    ELSE    ; !DYN_ALLOC
+_prev:          ds.w    WSIZE           ; array of unsigned short
+_head:          ds.w    HASH_SIZE       ; array of unsigned short
+_window:        ds.b    2*WSIZE         ; array of unsigned char
+    ENDC    ; ?DYN_ALLOC
+
+        text
+        quad
+_window_size:   ds.l    1               ; unsigned long
+_block_start:   ds.l    1               ; unsigned long
+_strstart:      ds.w    INTSIZE/2       ; unsigned int
+
+; Now here are our private variables:
+
+    IFDEF   CPUTEST
+is020:          ds.w    1       ; bool: CPU type is '020 or higher
+    ENDC
+ins_h:          ds.w    1       ; unsigned short
+sliding:        ds.w    1       ; bool: the file is read a piece at a time
+eofile:         ds.w    1       ; bool: we have read in the end of the file
+max_lazy_match: ds.w    1       ; unsigned short
+lookahead:      ds.w    1       ; unsigned short
+
+; These are NOT DECLARED AS STATIC in deflate.c, but currently could be:
+max_chain_len:  ds.w    1       ; unsigned short (unsigned int in deflate.c)
+prev_length:    ds.w    1       ; unsigned short (unsigned int in deflate.c)
+good_match:     ds.w    1       ; unsigned short (unsigned int in deflate.c)
+nice_match:     ds.w    1       ; unsigned short (signed int in deflate.c)
+match_start:    ds.w    1       ; unsigned short (unsigned int in deflate.c)
+
+; This array of struct config is a constant and could be in the code section:
+config_table:   dc.w    0,0,0,0         ; level 0: store uncompressed
+                dc.w    4,4,8,4         ; level 1: fastest, loosest compression
+                dc.w    4,5,16,8        ; level 2
+                dc.w    4,6,32,32       ; level 3: highest to use deflate_fast
+                dc.w    4,4,16,16       ; level 4: lowest to use lazy matches
+                dc.w    8,16,32,32      ; level 5
+                dc.w    8,16,128,128    ; level 6: the default level
+                dc.w    8,32,128,256    ; level 7
+                dc.w    32,128,258,1024 ; level 8
+                dc.w    32,258,258,4096 ; level 9: maximum compression, slow
+
+
+;;CAL_SH  MACRO                   ; macro for calling zcalloc()
+;;     IFD    INT16
+;;        move.w  #2,-(sp)
+;;        move.w  #\1,-(sp)
+;;        jsr     _zcalloc
+;;        addq    #4,sp
+;;     ELSE
+;;        pea     2
+;;        pea     \1
+;;        jsr     _zcalloc
+;;        addq    #8,sp
+;;     ENDC
+;;        ENDM
+
+CAL_SH  MACRO   _1              ; Okay, we're back to using regular calloc()...
+        movem.l d2/a2,-(sp)
+        pea     2
+        pea     _1
+        jsr     _calloc
+        addq    #8,sp
+        movem.l (sp)+,d2/a2
+        ENDM
+
+; ============================================================================
+; And here we begin our functions.  match_init is for internal use only:
+
+;;      section deflate,code
+
+match_init:
+    IFDEF   CPUTEST             ; now check for platform type
+     IFDEF  AMIGA               ; Amiga specific test for '020 CPU:
+        xref    _SysBase
+        NOLIST
+        INCLUDE       'exec/execbase.i'
+        LIST
+
+        clr.w   is020                   ; default value is 68000
+        move.l  _SysBase,a0
+        btst    #AFB_68020,AttnFlags+1(a0)
+        beq.s   cheap
+        move.w  #1,is020
+cheap:
+     ELSE   ; !AMIGA
+
+        FAIL    Write an '020-detector for your system here!
+; On the Macintosh, I believe GetEnvironment() provides the information.
+
+     ENDC   ; AMIGA
+    ENDC    ; CPUTEST
+        rts     ; match_init consists only of rts if CPUTEST unset
+
+
+; ============================================================================
+; Here is longest_match(), the function that the rest of this was built up
+; from, the hottest hot spot in the program and therefore the most heavily
+; optimized.  It has two different versions, one for '020 and higher CPUs, and
+; one for 68000/68010.  It can test at runtime which version to use if you
+; create a test function in match_init for your platform.  Currently such a
+; test is implemented for the Amiga.  It can also be assembled to use '000 or
+; '020 code only.
+
+Cur_Match       reg     d0              ; unsigned int, kept valid as long
+Best_Len        reg     d1              ; unsigned int, kept valid as long
+Scan_Start      reg     d3              ; pair of bytes
+Scan_End        reg     d4              ; pair of bytes
+Limit           reg     d5              ; unsigned int
+Chain_Length    reg     d6              ; unsigned int
+Scan_Test       reg     d7              ; counter, pair of bytes sometimes
+Scan            reg     a0              ; pointer to unsigned char
+Match           reg     a1              ; pointer to unsigned char
+Prev_Address    reg     a2              ; pointer to unsigned short
+Scan_Ini        reg     a3              ; pointer to unsigned char
+Match_Ini       reg     a5              ; pointer to unsigned char
+; Note: "pair of bytes" means the two low order bytes of the register in
+; 68020 code, but means the lowest and third lowest bytes on the 68000.
+SAVEREGS        reg     d3-d7/a2/a3/a5      ; don't protect d0/d1/a0/a1
+; d2, a4, a6 not used... on Amiga, a4 is used by small-data memory model
+
+
+longest_match:
+        movem.l SAVEREGS,-(sp)
+
+; setup steps common to byte and word versions:
+    IFDEF   INT16
+        and.l   #$0000FFFF,Cur_Match    ; upper half must be zero!
+; we use an and.l down here for the sake of ATSIGN/REGARGS.
+        moveq   #0,Limit                ; so adding to Scan_Ini works
+    ENDC
+        move.w  (max_chain_len,pc),Chain_Length
+        move.w  (prev_length,pc),Best_Len
+        MOVINT  (_strstart,pc),Limit
+        BASEPTR _prev,Prev_Address
+        BASEPTR _window,Match_Ini
+        move.l  Match_Ini,Scan_Ini
+        addq    #MIN_MATCH,Match_Ini    ; optimizes inner loop
+        add.l   Limit,Scan_Ini
+        sub.w   #MAX_DIST,Limit
+        bhi.s   limit_ok
+        moveq   #0,Limit
+limit_ok:
+        cmp.w   (good_match,pc),Best_Len
+        blo.s   length_ok
+        lsr.w   #2,Chain_Length
+length_ok:
+        subq.w  #1,Chain_Length
+
+    IFDEF   CPUTEST
+        tst.w   is020                   ; can we use '020 stuff today?
+        bne     WORD_match
+    ENDC
+
+    IFNDEF  CPU020
+
+; for 68000 or 68010, use byte operations:
+        moveq   #0,Scan_Start           ; clear 2nd & 4th bytes, use 1st & 3rd
+        moveq   #0,Scan_End             ; likewise
+        moveq   #0,Scan_Test            ; likewise
+        move.b  (Scan_Ini),Scan_Start
+        swap    Scan_Start              ; swap is faster than 8 bit shift
+        move.b  1(Scan_Ini),Scan_Start
+        move.b  -1(Scan_Ini,Best_Len.w),Scan_End
+        swap    Scan_End
+        move.b  0(Scan_Ini,Best_Len.w),Scan_End
+        bra.s   bdo_scan
+
+blong_loop:
+        move.b  -1(Scan_Ini,Best_Len.w),Scan_End
+        swap    Scan_End
+        move.b  0(Scan_Ini,Best_Len.w),Scan_End
+
+bshort_loop:
+        add.w   Cur_Match,Cur_Match     ; assert value before doubling < 32K
+     IFNE   32768-WSIZE
+        and.w   #(WMASK*2),Cur_Match
+     ENDC
+        move.w  (Prev_Address,Cur_Match.l),Cur_Match
+        cmp.w   Limit,Cur_Match
+        dbls    Chain_Length,bdo_scan
+        bra     return
+
+bdo_scan:
+        move.l  Match_Ini,Match
+        add.l   Cur_Match,Match
+        move.b  -MIN_MATCH-1(Match,Best_Len.w),Scan_Test
+        swap    Scan_Test
+        move.b  -MIN_MATCH(Match,Best_Len.w),Scan_Test
+        cmp.l   Scan_Test,Scan_End
+        bne.s   bshort_loop
+        move.b  -MIN_MATCH(Match),Scan_Test
+        swap    Scan_Test
+        move.b  -MIN_MATCH+1(Match),Scan_Test
+        cmp.l   Scan_Test,Scan_Start
+        bne.s   bshort_loop
+        move.w  #(MAX_MATCH-3),Scan_Test
+        lea     MIN_MATCH(Scan_Ini),Scan        ; offset optimizes inner loop
+
+bscan_loop:
+        cmp.b   (Match)+,(Scan)+
+        dbne    Scan_Test,bscan_loop
+        subq    #1,Scan
+
+        sub.l   Scan_Ini,Scan           ; assert difference is 16 bits
+        cmp.w   Best_Len,Scan
+        bls.s   bshort_loop
+        MOVINT  Scan,Best_Len
+        move.w  Cur_Match,match_start
+        cmp.w   (nice_match,pc),Best_Len
+        blo.s   blong_loop
+     IFDEF  CPUTEST
+        bra     return
+     ENDC
+
+    ENDC    ; !CPU020
+
+    IFNDEF  CPU000
+;;;     MACHINE MC68020
+
+; for 68020 or higher, use word operations even on odd addresses:
+WORD_match:
+        move.w  (Scan_Ini),Scan_Start
+        move.w  -1(Scan_Ini,Best_Len.w),Scan_End
+        bra.s   wdo_scan
+
+wlong_loop:
+        move.w  -1(Scan_Ini,Best_Len.w),Scan_End
+
+wshort_loop:
+        and.w   #WMASK,Cur_Match
+        move.w  (Prev_Address,Cur_Match.w*2),Cur_Match  ; '020 addressing mode
+        cmp.w   Limit,Cur_Match
+        dbls    Chain_Length,wdo_scan
+        bra.s   return
+
+wdo_scan:
+        move.l  Match_Ini,Match
+        add.l   Cur_Match,Match
+        cmp.w   -MIN_MATCH-1(Match,Best_Len.w),Scan_End
+        bne.s   wshort_loop
+        cmp.w   -MIN_MATCH(Match),Scan_Start
+        bne.s   wshort_loop
+     IFDEF  QUADLONG
+; By some measurements, this version of the code is a little tiny bit faster.
+; But on some files it's slower.  It probably pays off only when there are
+; long match strings, and costs in the most common case of three-byte matches.
+        moveq   #((MAX_MATCH-MIN_MATCH)/16),Scan_Test     ; value = 15
+        lea     MIN_MATCH(Scan_Ini),Scan        ; offset optimizes inner loop
+
+wscan_loop:
+        cmp.l   (Match)+,(Scan)+                ; test four bytes at a time
+        bne.s   odd
+        cmp.l   (Match)+,(Scan)+
+        bne.s   odd
+        cmp.l   (Match)+,(Scan)+
+        bne.s   odd
+        cmp.l   (Match)+,(Scan)+
+        dbne    Scan_Test,wscan_loop            ; '020 can cache a bigger loop
+odd:
+        subq    #4,Scan
+        subq    #4,Match
+        cmp.b   (Match)+,(Scan)+        ; find good bytes in bad longword
+        bne.s   even
+        cmp.b   (Match)+,(Scan)+
+        bne.s   even
+        cmp.b   (Match)+,(Scan)+
+        beq.s   steven
+even:   subq    #1,Scan
+     ELSE   ; !QUADLONG
+        moveq   #((MAX_MATCH-MIN_MATCH)/2),Scan_Test    ; value = 127
+        lea     MIN_MATCH(Scan_Ini),Scan        ; offset optimizes inner loop
+
+wscan_loop:
+        cmp.w   (Match)+,(Scan)+
+        dbne    Scan_Test,wscan_loop
+        subq    #2,Scan
+        move.b  -2(Match),Scan_Test
+        cmp.b   (Scan),Scan_Test
+        bne.s   steven
+        addq    #1,Scan
+     ENDC   ; ?QUADLONG
+steven:
+        sub.l   Scan_Ini,Scan           ; assert: difference is 16 bits
+        cmp.w   Best_Len,Scan
+        bls.s   wshort_loop
+        MOVINT  Scan,Best_Len
+        move.w  Cur_Match,match_start
+        cmp.w   (nice_match,pc),Best_Len
+        blo.s   wlong_loop
+
+;;;     MACHINE MC68000
+    ENDC    ; !CPU000
+
+return:
+        MOVINT  Best_Len,d0         ; return value (upper half should be clear)
+        movem.l (sp)+,SAVEREGS
+        rts
+
+
+; =============================================================================
+; This is the deflate() function itself, our main entry point.  It calls
+; longest_match, above, and some outside functions.  It is a hot spot, but not
+; as hot as longest_match.  It uses no special '020 code.
+
+; ================== Several macros used in deflate() and later functions:
+
+; Arg 1 is D-reg that new ins_h value is to be left in,
+; arg 2 is the byte value to be hashed into it, which must not be the same reg
+UP_HASH MACRO   _1,_2
+        move.w  (ins_h,pc),_1
+        asl.w   #H_SHIFT,_1
+        eor.b   _2,_1
+        and.w   #HASH_MASK,_1           ; ((ins_h << H_SHIFT) ^ c) & HASH_MASK
+        move.w  _1,ins_h                ; ins_h = that
+        ENDM
+
+; Arg 1 is scratch A, arg 2 is scratch D
+IN_STR  MACRO   _1,_2
+        move.l  Strst,_2
+        addq.w  #MIN_MATCH-1,_2
+        move.b  (Window,_2.l),_2        ; window[strstart + MIN_MATCH - 1]
+        UP_HASH Head,_2
+        add.l   Head,Head               ; assert upper word is zero before add
+        BASEPTR _head,_1
+        add.l   Head,_1
+        move.w  (_1),Head               ; hash_head = head[ins_h]
+        move.w  Strst,(_1)              ; head[ins_h] = strstart
+        move.l  Strst,_2
+    IFNE    WSIZE-32768
+        and.w   #WMASK,_2
+    ENDC
+        add.w   _2,_2                   ; masks implicitly when WSIZE == 32768
+        move.w  Head,(Prev,_2.l)        ; prev[str_start & WMASK] = hash_head
+        ENDM
+
+; Arg 1 is bool (int) EOF flag, flush_block result is in d0, trashes d1/a0/a1
+FLUSH_B MACRO   _1
+        local   nenu,nun
+        movem.l d2/a2,-(sp)
+    IF      _1==0
+        CLRINT  -(sp)
+    ELSEIF (INTSIZE==4).and.(_1<$8000)
+        pea     (_1).w
+    ELSE
+        MOVINT  #_1,-(sp)
+    ENDC
+        move.l  (_block_start,pc),d0
+        blt.s   nenu
+        move.l  Window,a0
+        add.l   d0,a0
+        bra.s   nun
+nenu:   sub.l   a0,a0           ; if block_start < 0, push NULL
+nun:    sub.l   Strst,d0
+        neg.l   d0
+        move.l  d0,-(sp)
+        move.l  a0,-(sp)
+        jsr     _flush_block
+        lea     8+INTSIZE(sp),sp
+        movem.l (sp)+,d2/a2
+        ENDM
+
+; This expands to nothing unless DEBUG is defined.
+; Arg 1 is a byte to be trace-outputted -- if it is d0 it must be a valid int
+TRACE_C MACRO  _1
+        local  qui
+    IFDEF  DEBUG
+        cmp.w  #1,_verbose+INTSIZE-2    ; test lower word only
+        ble.s   qui
+        moveq   #0,d0
+        move.b  ea,d0
+        movem.l d2/a2,-(sp)
+        move.l  _stderr,-(sp)
+        MOVINT  d0,-(sp)
+        jsr     _fputc
+        addq.l  #4+INTSIZE,sp
+        movem.l (sp)+,d2/a2
+qui:
+    ENDC    ; DEBUG
+        ENDM
+
+; ================== Here are the register vars we use, and deflate() itself:
+
+Window  reg     a2              ; cached address of window[]
+Prev    reg     a3              ; cached address of prev[]
+Strst   reg     d7              ; strstart cached as a longword
+Look    reg     d6              ; lookahead cached as short
+Head    reg     d5              ; local variable hash_head, short
+PrevL   reg     d4              ; prev_length cached as short
+MatchL  reg     d3              ; local variable match_length, unsigned short
+Avail   reg     d2              ; local variable available_match, bool
+PrevM   reg     a5              ; local variable prev_match, int in an A-reg
+
+DEFREGS reg     d3-d7/a3/a5
+
+
+_deflate:           ; first, setup steps common to deflate and deflate_fast:
+        movem.l DEFREGS,-(sp)
+    IFDEF   INT16
+        moveq   #0,Strst                ; make sure strstart is valid as a long
+    ENDC
+        moveq   #0,Head                 ; ditto for hash_head
+        MOVINT  (_strstart,pc),Strst
+        move.w  (lookahead,pc),Look
+        move.w  (prev_length,pc),PrevL
+        BASEPTR _window,Window
+        BASEPTR _prev,Prev
+        MOVINT  _level,d0
+        cmp.w   #3,d0
+        ble     deflate_fast
+        moveq   #MIN_MATCH-1,MatchL
+        moveq   #0,Avail
+
+look_loop:
+        tst.w   Look
+        beq     last_tally
+        IN_STR  a0,d0
+        move.w  MatchL,PrevL
+        move.w  (match_start,pc),PrevM
+        move.w  #MIN_MATCH-1,MatchL
+
+        tst.w   Head
+        beq.s   no_new_match
+        cmp.w   (max_lazy_match,pc),PrevL
+        bhs.s   no_new_match
+        move.w  Strst,d0
+        sub.w   Head,d0
+        cmp.w   #MAX_DIST,d0
+        bhi.s   no_new_match
+        move.w  PrevL,prev_length       ; longest_match reads these variables
+        MOVINT  Strst,_strstart
+        MOVINT  Head,d0                 ; parm for longest_match
+        bsr     longest_match           ; sets match_start
+        cmp.w   Look,d0                 ; does length exceed valid data?
+        bls.s   stml
+        move.w  Look,d0
+stml:   move.w  d0,MatchL               ; valid length of match
+        cmp.w   #MIN_MATCH,MatchL       ; is the match only three bytes?
+        bne.s   no_new_match
+        move.w  (match_start,pc),d0
+        sub.w   Strst,d0
+        cmp.w   #-TOO_FAR,d0
+        bge.s   no_new_match
+        moveq   #MIN_MATCH-1,MatchL     ; mark the current match as no good
+
+no_new_match:
+        cmp.w   #MIN_MATCH,PrevL
+        blo     literal
+        cmp.w   MatchL,PrevL
+        blo     literal
+        ; CHECK_MATCH   Strst-1,PrevM,PrevL
+        MOVINT  Strst,_strstart         ; ct_tally reads this variable
+        move.l  PrevL,d0
+        subq.w  #MIN_MATCH,d0
+        movem.l d2/a2,-(sp)
+        MOVINT  d0,-(sp)
+        move.l  Strst,d0
+        sub.w   PrevM,d0
+        subq.w  #1,d0
+        MOVINT  d0,-(sp)
+        jsr     _ct_tally               ; sets d0 true if we have to flush
+        addq    #2*INTSIZE,sp
+        movem.l (sp)+,d2/a2
+        subq.w  #3,PrevL                ; convert for dbra (prev_length - 2)
+        sub.w   PrevL,Look
+        subq.w  #2,Look
+insertmatch:
+        addq.w  #1,Strst
+        IN_STR  a0,d1                   ; don't clobber d0
+        dbra    PrevL,insertmatch
+        moveq   #0,Avail
+        moveq   #0,PrevL                ; not needed?
+        moveq   #MIN_MATCH-1,MatchL
+        addq.w  #1,Strst
+        tst.w   d0
+        beq     refill
+        FLUSH_B 0
+        move.l  Strst,_block_start
+        bra.s   refill
+
+literal:
+        tst.w   Avail
+        bne.s   yeslit
+        moveq   #1,Avail
+        bra.s   skipliteral
+yeslit: TRACE_C <-1(Window,Strst.l)>
+        MOVINT  Strst,_strstart         ; ct_tally reads this variable
+        moveq   #0,d0
+        move.b  -1(Window,Strst.l),d0
+        movem.l d2/a2,-(sp)
+        MOVINT  d0,-(sp)
+        CLRINT  -(sp)
+        jsr     _ct_tally
+        addq    #2*INTSIZE,sp
+        movem.l (sp)+,d2/a2
+        tst.w   d0
+        beq.s   skipliteral
+        FLUSH_B 0
+        move.l  Strst,_block_start
+skipliteral:
+        addq.w  #1,Strst
+        subq.w  #1,Look
+
+refill:
+        cmp.w   #MIN_LOOKAHEAD,Look
+        bhs     look_loop
+        bsr     fill_window
+        bra     look_loop
+
+last_tally:
+        tst.w   Avail
+        beq     last_flush
+        MOVINT  Strst,_strstart         ; ct_tally reads this variable
+        moveq   #0,d0
+        move.b  -1(Window,Strst.l),d0
+        movem.l d2/a2,-(sp)
+        MOVINT  d0,-(sp)
+        CLRINT  -(sp)
+        jsr     _ct_tally
+        addq    #2*INTSIZE,sp
+        movem.l (sp)+,d2/a2
+last_flush:
+        FLUSH_B 1
+        bra     deflate_exit
+
+; ================== This is another version used for low compression levels:
+
+deflate_fast:
+        moveq   #0,MatchL
+        moveq   #MIN_MATCH-1,PrevL
+flook_loop:
+        tst.w   Look
+        beq     flast_flush
+
+        IN_STR  a0,d0
+        tst.w   Head
+        beq.s   fno_new_match
+        move.w  Strst,d0
+        sub.w   Head,d0
+        cmp.w   #MAX_DIST,d0
+        bhi.s   fno_new_match
+        move.w  PrevL,prev_length       ; longest_match reads these variables
+        MOVINT  Strst,_strstart
+        MOVINT  Head,d0                 ; parm for longest_match
+        bsr     longest_match           ; sets match_start
+        cmp.w   Look,d0                 ; does length exceed valid data?
+        bls.s   fstml
+        move.w  Look,d0
+fstml:  move.w  d0,MatchL               ; valid length of match
+
+fno_new_match:
+        cmp.w   #MIN_MATCH,MatchL
+        blo     fliteral
+        ; CHECK_MATCH   Strst,match_start,MatchL
+        MOVINT  Strst,_strstart         ; ct_tally reads this variable
+        move.l  MatchL,d0
+        subq.w  #MIN_MATCH,d0
+        movem.l d2/a2,-(sp)
+        MOVINT  d0,-(sp)
+        move.l  Strst,d0
+        sub.w   (match_start,pc),d0
+        MOVINT  d0,-(sp)
+        jsr     _ct_tally               ; sets d0 true if we have to flush
+        addq    #2*INTSIZE,sp
+        movem.l (sp)+,d2/a2
+        sub.w   MatchL,Look
+        cmp.w   (max_lazy_match,pc),MatchL
+        bhi     ftoolong
+        subq.w  #2,MatchL
+finsertmatch:
+        addq.w  #1,Strst
+        IN_STR  a0,d1                   ; preserve d0
+        dbra    MatchL,finsertmatch
+        moveq   #0,MatchL               ; not needed?
+        addq.w  #1,Strst
+        bra.s   flushfill
+
+ftoolong:
+        add.w   MatchL,Strst
+        moveq   #0,MatchL
+        moveq   #0,d1                   ; preserve d0
+        move.b  (Window,Strst.l),d1
+        move.w  d1,ins_h
+; My assembler objects to passing <1(Window,Strst.l)> directly to UP_HASH...
+        move.b  1(Window,Strst.l),Avail ; Avail is not used in deflate_fast
+        UP_HASH d1,Avail                ; preserve d0
+    IFNE    MIN_MATCH-3
+        FAIL  needs to UP_HASH another MIN_MATCH-3 times, but with what arg?
+    ENDC
+        bra.s   flushfill
+
+fliteral:
+        TRACE_C <(Window,Strst.l)>
+        MOVINT  Strst,_strstart         ; ct_tally reads this variable
+        moveq   #0,d0
+        move.b  (Window,Strst.l),d0
+        movem.l d2/a2,-(sp)
+        MOVINT  d0,-(sp)
+        CLRINT  -(sp)
+        jsr     _ct_tally               ; d0 set if we need to flush
+        addq    #2*INTSIZE,sp
+        movem.l (sp)+,d2/a2
+        addq.w  #1,Strst
+        subq.w  #1,Look
+
+flushfill:
+        tst.w   d0
+        beq.s   frefill
+        FLUSH_B 0
+        move.l  Strst,_block_start
+frefill:
+        cmp.w   #MIN_LOOKAHEAD,Look
+        bhs     flook_loop
+        bsr     fill_window
+        bra     flook_loop
+
+flast_flush:
+        FLUSH_B 1                       ; sets our return value
+
+deflate_exit:
+        MOVINT  Strst,_strstart         ; save back cached values
+        move.w  PrevL,prev_length
+        move.w  Look,lookahead
+        movem.l (sp)+,DEFREGS
+        rts
+
+
+; =========================================================================
+; void fill_window(void) calls the input function to refill the sliding
+; window that we use to find substring matches in.
+
+More    reg     Head                    ; local variable in fill_window
+WindTop reg     Prev                    ; local variable used for sliding
+SlidIx  reg     PrevL                   ; local variable used for sliding
+
+FWREGS  reg     d2-d5/a2-a6             ; does NOT include Look and Strst
+; all registers available to be clobbered by the sliding operation:
+; we exclude More, WindTop, SlidIx, Look, Strst, Window, a4 and a7.
+SPAREGS reg     d0-d3/a0-a1/a5-a6
+SPCOUNT equ     8                       ; number of registers in SPAREGS
+
+
+_fill_window:                           ; C-callable entry point
+        movem.l Look/Strst,-(sp)
+    IFDEF   INT16
+        moveq   #0,Strst                ; Strst must be valid as a long
+    ENDC
+        MOVINT  (_strstart,pc),Strst
+        move.w  (lookahead,pc),Look
+        BASEPTR _window,Window
+        bsr.s   fill_window
+        MOVINT  Strst,_strstart
+        move.w  Look,lookahead
+        movem.l (sp)+,Look/Strst
+        rts
+
+; strstart, lookahead, and window must be cached in Strst, Look, and Window:
+fill_window:                            ; asm-callable entry point
+        movem.l FWREGS,-(sp)
+        move.w  (eofile,pc),d0          ; we put this up here for speed
+        bne     fwdone
+        and.l   #$FFFF,Look             ; make sure Look is valid as long
+fw_refill:
+        move.l  (_window_size,pc),More  ; <= 64K
+        sub.l   Look,More
+        sub.l   Strst,More              ; Strst is already valid as long
+        cmp.w   #EOF,More
+        bne.s   notboundary
+        subq.w  #1,More
+        bra     checkend
+
+notboundary:
+        move.w  (sliding,pc),d0
+        beq     checkend
+        cmp.w   #WSIZE+MAX_DIST,Strst
+        blo     checkend
+    IF      (32768-WSIZE)>0
+        lea     WSIZE(Window),WindTop   ; WindTop is aligned when Window is
+    ELSE
+        move.l  Window,WindTop
+        add.l   #WSIZE,WindTop
+    ENDC
+        move.l  Window,d0
+        and.w   #3,d0
+        beq.s   isaligned
+        subq.w  #1,d0
+align:  move.b  (WindTop)+,(Window)+    ; copy up to a longword boundary
+        dbra    d0,align
+isaligned:
+; This is faster than a simple move.l (WindTop)+,(Window)+ / dbra loop:
+        move.w  #(WSIZE-1)/(4*SPCOUNT),SlidIx
+slide:  movem.l (WindTop)+,SPAREGS      ; copy, 32 bytes at a time!
+        movem.l SPAREGS,(Window)        ; a slight overshoot doesn't matter.
+        lea     4*SPCOUNT(Window),Window        ; can't use (aN)+ as movem.l dest
+        dbra    SlidIx,slide
+        BASEPTR _window,Window                  ; restore cached value
+        sub.w   #WSIZE,match_start
+        sub.w   #WSIZE,Strst
+        sub.l   #WSIZE,_block_start
+        add.w   #WSIZE,More
+        BASEPTR _head,a0
+        move.w  #HASH_SIZE-1,d0
+fixhead:
+        move.w  (a0),d1
+        sub.w   #WSIZE,d1
+        bpl.s   headok
+        moveq   #0,d1
+headok: move.w  d1,(a0)+
+        dbra    d0,fixhead
+        BASEPTR _prev,a0
+        move.w  #WSIZE-1,d0
+fixprev:
+        move.w  (a0),d1
+        sub.w   #WSIZE,d1
+        bpl.s   prevok
+        moveq   #0,d1
+prevok: move.w  d1,(a0)+
+        dbra    d0,fixprev
+        TRACE_C #'.'
+
+        move    _verbose+INTSIZE-2,d0
+        beq     checkend
+        movem.l d2/a2,-(sp)
+        xref    _print_period
+        jsr     _print_period
+        movem.l (sp)+,d2/a2
+
+checkend:                               ; assert eofile is false
+        movem.l d2/a2,-(sp)
+        MOVINT  More,-(sp)              ; assert More's upper word is zero
+        move.l  Strst,d0
+        add.w   Look,d0
+        add.l   Window,d0
+        move.l  d0,-(sp)
+        move.l  _read_buf,a0
+        jsr     (a0)                    ; refill the upper part of the window
+        addq    #4+INTSIZE,sp
+        movem.l (sp)+,d2/a2
+        tst.w   d0
+        beq.s   iseof
+        cmp.w   #EOF,d0
+        beq.s   iseof
+        add.w   d0,Look
+        cmp.w   #MIN_LOOKAHEAD,Look
+        blo     fw_refill               ; eofile is still false
+
+        bra.s   fwdone
+iseof:  move.w  #1,eofile
+fwdone: movem.l (sp)+,FWREGS
+        rts
+
+
+; =========================================================================
+; void lm_free(void) frees dynamic arrays in the DYN_ALLOC version.
+
+;;;     xdef    _lm_free                ; the entry point
+
+_lm_free:
+    IFDEF   DYN_ALLOC
+        move.l  _window,d0
+        beq.s   lf_no_window
+        movem.l d2/a2,-(sp)
+        move.l  d0,-(sp)
+        jsr     _free
+        addq    #4,sp
+        movem.l (sp)+,d2/a2
+        clr.l   _window
+lf_no_window:
+        move.l  _prev,d0
+        beq.s   lf_no_prev
+        movem.l d2/a2,-(sp)
+        move.l  d0,-(sp)
+        jsr     _free
+        move.l  _head,(sp)              ; reuse the same stack arg slot
+        jsr     _free
+        addq    #4,sp
+        movem.l (sp)+,d2/a2
+        clr.l   _prev
+        clr.l   _head
+lf_no_prev:
+    ENDC
+        rts
+
+; ============================================================================
+; void lm_init(int pack_level, unsigned short *flags) allocates dynamic arrays
+; if any, and initializes all variables so that deflate() is ready to go.
+
+;;;     xdef    _lm_init                ; the entry point
+
+Level   reg     d2
+;Window reg     a2      ; as in deflate()
+
+_lm_init:
+        MOVINT  4(sp),d0
+        move.l  4+INTSIZE(sp),a0
+        move.w  d0,Level
+        cmp.w   #1,Level
+        blt.s   levelerr
+        bgt.s   try9
+        bset.b  #B_FAST,1(a0)
+try9:   cmp.w   #9,Level
+        bgt.s   levelerr
+        blt.s   levelok
+        bset.b  #B_SLOW,1(a0)
+        bra.s   levelok
+levelerr:
+        pea     (level_message,pc)
+        jsr     _error                  ; never returns
+levelok:
+        clr.w   sliding
+        move.l  (_window_size,pc),d0
+        bne.s   gotawindowsize
+        move.w  #1,sliding
+        move.l  #2*WSIZE,_window_size
+gotawindowsize:
+
+        BASEPTR _window,Window
+    IFDEF   DYN_ALLOC
+        move.l  Window,d0               ; fake tst.l
+        bne.s   gotsomewind
+        CAL_SH  WSIZE
+        move.l  d0,Window
+        move.l  d0,_window
+        bne.s   gotsomewind
+        pea     (window_message,pc)
+        bra     error
+gotsomewind:
+        tst.l   _prev
+        bne.s   gotsomehead
+        CAL_SH  WSIZE
+        move.l  d0,_prev
+        beq.s   nohead
+        CAL_SH  HASH_SIZE
+        move.l  d0,_head
+        bne.s   gotfreshhead            ; newly calloc'd memory is zeroed
+nohead: pea     (hash_message,pc)
+error:  MOVINT  #ZE_MEM,-(sp)
+        jsr     _ziperr                 ; never returns
+gotsomehead:
+    ENDC    ; DYN_ALLOC
+
+        move.w  #(HASH_SIZE/2)-1,d0     ; two shortwords per loop
+        BASEPTR _head,a0
+wipeh:  clr.l   (a0)+
+        dbra    d0,wipeh
+gotfreshhead:
+        move.l  Level,d0
+    IFEQ    Sizeof_config-8
+        asl.l   #3,d0
+    ELSE
+        mulu    #Sizeof_config,d0
+    ENDC
+        lea     (config_table,pc),a0
+        add.l   d0,a0
+        move.w  Max_lazy(a0),max_lazy_match
+        move.w  Good_length(a0),good_match
+        move.w  Nice_length(a0),nice_match
+        move.w  Max_chain(a0),max_chain_len
+        CLRINT  _strstart
+        clr.l   _block_start
+        bsr     match_init
+
+        clr.w   eofile
+        movem.l d2/a2,-(sp)
+        MOVINT  #WSIZE,-(sp)    ; We read only 32K because lookahead is short
+        move.l  Window,-(sp)    ; even when int size is long, as if deflate.c
+        move.l  _read_buf,a0    ; were compiled with MAXSEG_64K defined.
+        jsr     (a0)
+        addq    #4+INTSIZE,sp
+        movem.l (sp)+,d2/a2
+        move.w  d0,lookahead
+        beq.s   noread
+        cmp.w   #EOF,d0
+        bne.s   irefill
+noread: move.w  #1,eofile
+        clr.w   lookahead
+        bra.s   init_done
+
+irefill:
+        move.w  (lookahead,pc),d0
+        cmp.w   #MIN_LOOKAHEAD,d0
+        bhs.s   hashify
+        bsr     _fill_window            ; use the C-callable version
+hashify:
+        clr.w   ins_h
+        moveq   #MIN_MATCH-2,d0
+hash1:  move.b  (Window)+,d1
+        UP_HASH Level,d1
+        dbra    d0,hash1
+
+init_done:
+        rts
+
+; strings for error messages:
+    IFDEF   DYN_ALLOC
+hash_message    dc.b    'hash table allocation',0
+window_message  dc.b    'window allocation',0
+    ENDC
+level_message   dc.b    'bad pack level',0
+
+        end
diff --git a/human68k/human68k.c b/human68k/human68k.c
new file mode 100644 (file)
index 0000000..be47b57
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#include <time.h>
+#include <stdio.h>
+#include <dirent.h>
+#ifndef UTIL
+#include <sys/dos.h>
+#endif
+
+#define MATCH shmatch
+
+#define PAD 0
+
+
+#ifndef UTIL
+
+/* Library functions not in (most) header files */
+
+int utime OF((char *, ztimbuf *));
+
+/* Local functions */
+local char *readd OF((DIR *));
+
+local char *readd(DIR* d)
+{
+   struct dirent* e = readdir(d);
+
+   return e == NULL ? NULL : e->d_name;
+}
+
+int wild(char* w)
+{
+  struct _filbuf inf;
+  /* convert FNAMX to malloc - 11/08/04 EG */
+  char *name;
+  char *p;
+
+  if (strcmp(w, "-") == 0)   /* if compressing stdin */
+    return newname(w, 0, 0);
+  if ((name = malloc(strlen(w) + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "wild");
+  }
+  strcpy(name, w);
+  _toslash(name);
+
+  if ((p = strrchr(name, '/')) == NULL && (p = strrchr(name, ':')) == NULL)
+    p = name;
+  else
+    p++;
+  if (_dos_lfiles (&inf, w, 0xff) < 0) {
+    free(name);
+    return ZE_MISS;
+  }
+  do {
+    int r;
+
+    strcpy(p, inf.name);
+    r = procname(name, 0);
+    if (r != ZE_OK) {
+      free(name);
+      return r;
+    }
+  } while (_dos_nfiles(&inf) >= 0);
+  free(name);
+
+  return ZE_OK;
+}
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  DIR *d;               /* directory stream from opendir() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (LSSTAT(n, &s))
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  _toslash(n);
+  if ((s.st_mode & S_IFDIR) == 0)
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0, caseflag)) != ZE_OK)
+      return m;
+  } else {
+    /* Add trailing / to the directory name */
+    if ((p = malloc(strlen(n)+2)) == NULL)
+      return ZE_MEM;
+    if (strcmp(n, ".") == 0) {
+      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      strcpy(p, n);
+      a = p + strlen(p);
+      if (a[-1] != '/')
+        strcpy(a, "/");
+      if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+        free((zvoid *)p);
+        return m;
+      }
+    }
+    /* recurse into directory */
+    if (recurse && (d = opendir(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if (strcmp(e, ".") && strcmp(e, ".."))
+        {
+          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+          {
+            closedir(d);
+            free((zvoid *)p);
+            return ZE_MEM;
+          }
+          strcat(strcpy(a, p), e);
+          if ((m = procname(a, caseflag)) != ZE_OK)   /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", a);
+            else
+              ziperr(m, a);
+          }
+          free((zvoid *)a);
+        }
+      }
+      closedir(d);
+    }
+    free((zvoid *)p);
+  } /* (s.st_mode & S_IFDIR) == 0) */
+  return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t;              /* shortened name */
+
+  /* Find starting point in name before doing malloc */
+  t = (x[0] && x[1] == (char)':') ? x + 2 : x;
+  while (*t == (char)'/')
+    t++;
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+  _toslash(t);
+
+  if (!pathput)
+    t = last(t, '/');
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL)
+    return NULL;
+  strcpy(n, t);
+
+  if (dosify)
+    msname(n);
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosify;
+  return n;
+}
+
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+      return NULL;
+  return strcpy(x, n);
+}
+
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+  ztimbuf u;            /* argument for utime() */
+
+  /* Convert DOS time to time_t format in u */
+  u.actime = u.modtime = dos2unixtime(d);
+
+  /* Set updated and accessed times of f */
+  utime(f, &u);
+}
+
+ulg filetime(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  /* convert FNMAX to malloc - 11/8/04 EG */
+  char *name;
+  int len = strlen(f);
+  isstdin = !strcmp(f, "-");
+
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+
+  if (isstdin) {
+    if (fstat(fileno(stdin), &s) != 0) {
+      free(name);
+      error("fstat(stdin)");
+    }
+  } else if (LSSTAT(name, &s) != 0) {
+             /* Accept about any file kind including directories
+              * (stored with trailing / with -r option)
+              */
+    free(name);
+    return 0;
+  }
+
+  if (a != NULL) {
+    int atr = _dos_chmod(name, -1);
+
+    if (atr < 0)
+      atr = 0x20;
+    *a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)atr);
+  }
+  free(name);
+  if (n != NULL)
+    *n = S_ISVOL(s.st_mode) ? -2L : S_ISREG(s.st_mode) ? s.st_size : -1L;
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = s.st_ctime;
+  }
+
+  return unix2dostime(&s.st_mtime);
+}
+
+int set_extra_field(z, z_utim)
+  struct zlist far *z;
+  iztimes *z_utim;
+  /* create extra field and change z->att if desired */
+{
+#ifdef USE_EF_UT_TIME
+  if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
+    return ZE_MEM;
+
+  z->extra[0]  = 'U';
+  z->extra[1]  = 'T';
+  z->extra[2]  = EB_UT_LEN(1);          /* length of data part of e.f. */
+  z->extra[3]  = 0;
+  z->extra[4]  = EB_UT_FL_MTIME;
+  z->extra[5]  = (char)(z_utim->mtime);
+  z->extra[6]  = (char)(z_utim->mtime >> 8);
+  z->extra[7]  = (char)(z_utim->mtime >> 16);
+  z->extra[8]  = (char)(z_utim->mtime >> 24);
+
+  z->cext = z->ext = (EB_HEADSIZE+EB_UT_LEN(1));
+  z->cextra = z->extra;
+
+  return ZE_OK;
+#else /* !USE_EF_UT_TIME */
+  return (int)(z-z);
+#endif /* ?USE_EF_UT_TIME */
+}
+
+int deletedir(d)
+char *d;                /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+   Return the result of rmdir(), delete(), or system().
+   For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
+ */
+{
+    return rmdir(d);
+}
+
+void print_period(void)
+{
+  fputc('.', stderr);
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+void version_local()
+{
+    static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+#if 0
+    char buf[40];
+#endif
+
+    printf(CompiledWith,
+
+#ifdef __GNUC__
+      "gcc ", __VERSION__,
+#else
+#  if 0
+      "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
+#  else
+      "unknown compiler", "",
+#  endif
+#endif
+
+      "Human68k",
+#ifdef __MC68020__
+      " (X68030)",
+#else
+      " (X680x0)",
+#endif
+
+#ifdef __DATE__
+      " on ", __DATE__
+#else
+      "", ""
+#endif
+      );
+
+} /* end function version_local() */
diff --git a/human68k/match.s b/human68k/match.s
new file mode 100644 (file)
index 0000000..4e6bc1c
--- /dev/null
@@ -0,0 +1,163 @@
+*===========================================================================
+* Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+*
+* See the accompanying file LICENSE, version 1999-Oct-05 or later
+* (the contents of which are also included in zip.h) for terms of use.
+* If, for some reason, both of these files are missing, the Info-ZIP license
+* also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*===========================================================================
+*
+* match.s -- optional optimized asm version of longest match in deflate.c
+* Written by Jean-loup Gailly
+*
+* Adapted for X68000 by NIIMI Satoshi <a01309@cfi.waseda.ac.jp>
+* Adapted for the Amiga by Carsten Steger <stegerc@informatik.tu-muenchen.de>
+* using the code in match.S.
+* The major change in this code consists of removing all unaligned
+* word accesses, because they cause 68000-based machines to crash.
+* For maximum speed, UNALIGNED_OK can be defined.
+* The program will then only run on 68020-based machines, though.
+
+
+Cur_Match       reg     d0      ; Must be in d0!
+Best_Len        reg     d1
+Loop_Counter    reg     d2
+Scan_Start      reg     d3
+Scan_End        reg     d4
+Limit           reg     d5
+Chain_Length    reg     d6
+Scan_Test       reg     d7
+Scan            reg     a0
+Match           reg     a1
+Prev_Address    reg     a2
+Scan_Ini        reg     a3
+Match_Ini       reg     a4
+
+MAX_MATCH       equ     258
+MIN_MATCH       equ     3
+WSIZE           equ     32768
+MAX_DIST        equ     WSIZE-MAX_MATCH-MIN_MATCH-1
+
+
+        .xref   _max_chain_length
+        .xref   _prev_length
+        .xref   _prev
+        .xref   _window
+        .xref   _strstart
+        .xref   _good_match
+        .xref   _match_start
+        .xref   _nice_match
+
+
+        .xdef   _match_init
+        .xdef   _longest_match
+
+        .text
+        .even
+
+
+_match_init:
+        rts
+
+
+_longest_match:
+        move.l  4(sp),Cur_Match
+.ifdef  UNALIGNED_OK
+        movem.l d2-d6/a2-a4,-(sp)
+.else
+        movem.l d2-d7/a2-a4,-(sp)
+.endif
+        move.l  _max_chain_length,Chain_Length
+        move.l  _prev_length,Best_Len
+        lea     _prev,Prev_Address
+        lea     _window+MIN_MATCH,Match_Ini
+        move.l  _strstart,Limit
+        move.l  Match_Ini,Scan_Ini
+        add.l   Limit,Scan_Ini
+        subi.w  #MAX_DIST,Limit
+        bhi.b   limit_ok
+        moveq   #0,Limit
+limit_ok:
+        cmp.l   _good_match,Best_Len
+        bcs.b   length_ok
+        lsr.l   #2,Chain_Length
+length_ok:
+        subq.l  #1,Chain_Length
+
+.ifdef  UNALIGNED_OK
+        move.w  -MIN_MATCH(Scan_Ini),Scan_Start
+        move.w  -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
+.else
+        move.b  -MIN_MATCH(Scan_Ini),Scan_Start
+        lsl.w   #8,Scan_Start
+        move.b  -MIN_MATCH+1(Scan_Ini),Scan_Start
+        move.b  -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
+        lsl.w   #8,Scan_End
+        move.b  -MIN_MATCH(Scan_Ini,Best_Len.w),Scan_End
+.endif
+
+        bra.b   do_scan
+
+long_loop:
+
+.ifdef  UNALIGNED_OK
+        move.w  -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
+.else
+        move.b  -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
+        lsl.w   #8,Scan_End
+        move.b  -MIN_MATCH(Scan_Ini,Best_Len.w),Scan_End
+.endif
+
+short_loop:
+        lsl.w   #1,Cur_Match
+        move.w  0(Prev_Address,Cur_Match.l),Cur_Match
+        cmp.w   Limit,Cur_Match
+        dbls    Chain_Length,do_scan
+        bra.b   return
+
+do_scan:
+        move.l  Match_Ini,Match
+        add.l   Cur_Match,Match
+
+.ifdef  UNALIGNED_OK
+        cmp.w   -MIN_MATCH-1(Match,Best_Len.w),Scan_End
+        bne.b   short_loop
+        cmp.w   -MIN_MATCH(Match),Scan_Start
+        bne.b   short_loop
+.else
+        move.b  -MIN_MATCH-1(Match,Best_Len.w),Scan_Test
+        lsl.w   #8,Scan_Test
+        move.b  -MIN_MATCH(Match,Best_Len.w),Scan_Test
+        cmp.w   Scan_Test,Scan_End
+        bne.b   short_loop
+        move.b  -MIN_MATCH(Match),Scan_Test
+        lsl.w   #8,Scan_Test
+        move.b  -MIN_MATCH+1(Match),Scan_Test
+        cmp.w   Scan_Test,Scan_Start
+        bne.b   short_loop
+.endif
+
+        move.w  #(MAX_MATCH-MIN_MATCH),Loop_Counter
+        move.l  Scan_Ini,Scan
+scan_loop:
+        cmpm.b  (Match)+,(Scan)+
+        dbne    Loop_Counter,scan_loop
+
+        sub.l   Scan_Ini,Scan
+        addq.l  #(MIN_MATCH-1),Scan
+        cmp.l   Best_Len,Scan
+        bls.b   short_loop
+        move.l  Scan,Best_Len
+        move.l  Cur_Match,_match_start
+        cmp.l   _nice_match,Best_Len
+        bcs.b   long_loop
+return:
+        move.l  Best_Len,d0
+.ifdef  UNALIGNED_OK
+        movem.l (sp)+,d2-d6/a2-a4
+.else
+        movem.l (sp)+,d2-d7/a2-a4
+.endif
+        rts
+
+        end
diff --git a/human68k/osdep.h b/human68k/osdep.h
new file mode 100644 (file)
index 0000000..088a9ac
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include <io.h>
+#include <sys/stat.h>
+#include <sys/xglob.h>
+
+#ifdef ZCRYPT_INTERNAL
+#  include <process.h>          /* getpid() declaration for srand seed */
+#endif
+
+#define USE_CASE_MAP
+
+#define ROUNDED_TIME(time)  (((time) + 1) & (~1))
+
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+                     procname(n, 1))
+
+#ifdef HAVE_MBCTYPE_H
+#  include <mbctype.h>
+#else
+#  define ismbblead(c) (0x80 <= (c) && ((c) < 0xa0 || 0xe0 <= (c)))
+#endif
diff --git a/human68k/zipup.h b/human68k/zipup.h
new file mode 100644 (file)
index 0000000..592cff8
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define fhow (O_RDONLY|O_BINARY)
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/macos/Contents b/macos/Contents
new file mode 100644 (file)
index 0000000..3aec069
--- /dev/null
@@ -0,0 +1,63 @@
+Contents of the "macos" sub-archive for Zip 2.3 and later:
+
+
+MacOS:
+
+  Contents          this file
+  readme.1st        Instruction to unpack mac specific files
+  README.TXT        Dirk Haase's infos on updated MacIntosh ports of Zip/UnZip
+  HISTORY.TXT       Dirk Haase's MacOS specific ChangeLog
+
+  zipup.h           MacOS
+  osdep.h           MacOS specific configuration and declarations
+
+  ZipLib.h          used to build a static library, global to the project
+  ZipSx.h           used to build a standalone App with MW Sioux, global
+                    to the project
+  ZpPrj.hqx         Metrowerks CodeWarrior pro3 project file (BinHex)
+
+
+  source/        subdirectory containing all sources:
+                  a) Zip specific code
+    extrafld.c      contains all code related to the mac extra field
+    extrafld.h
+    macglob.h
+    macopen.c       replaces fopen() and open()
+    macopen.h
+    macos.c         Macintosh-specific routines for use with Info-ZIP's Zip
+    MatWild.c       Pattern matching function
+    recurse.c       Functions to go through the directories
+    recurse.h
+    unixlike.c      This file provides a unix like file-stat routine
+    unixlike.h
+    VolWarn.h       contains the warning message, about volumes with the
+                    same name
+    zip_rc.hqx      resource file for Macintosh unzip (BinHex)
+
+
+                  b) general utilities shared between Zip and UnZip
+    charmap.h       character mapping tables ISO 8859-1 <--> MacRoman
+    helpers.c       some helper functions
+    helpers.h
+    macstuff.c      Mac filemanager routines copied from MoreFiles 1.4.8
+    macstuff.h
+    mactime.c       replacement for broken Metrowerks RTL time functions
+    pathname.c      functions for handling MacOS HFS path- /filenames
+    pathname.h
+
+The new ZpPrj.hqx project file should be "un-BinHex'ed" into ZpPrj,
+which builds the following targets:
+        - Zip Lib (68K)   -> static library 68k
+        - Zip Lib (PPC)   -> static library PPC
+        - Zip Sioux (68K) -> MW Sioux standalone App, good for debugging
+        - Zip Sioux (PPC) -> MW Sioux standalone App, good for debugging
+
+
+The resource files and the compiler project files are in BinHex form because
+they contain Macintosh resource forks.  The resource info cannot be
+maintained when handling (e.g. repacking) the master source collection on
+non-Macintosh systems.  The BinHex form is the traditional way for
+transferring such files via non-Macintosh systems.
+It's also the safest since it uses only printable characters.  The ".hqx"
+files must be converted with StuffitExpander or BinHex 4.0 (or equivalent)
+on a Macintosh system before using them.
diff --git a/macos/HISTORY.TXT b/macos/HISTORY.TXT
new file mode 100644 (file)
index 0000000..3a14a02
--- /dev/null
@@ -0,0 +1,600 @@
+A free Macintosh Port of Info-ZIP's
+Zip and UnZip
+By Dirk Haase, d_haase@sitec.net
+Home page: www.sitec.net/maczip
+Mirror page:
+www.haase-online.de/dirk/maczip
+================================
+
+
+
+
+
+Release MacZip ver1.07 beta 1
+22. Februray 2001
+-----------------
+
+1) CHG: {unzip} switch to latest final release
+         unzip 5.42
+
+2) CHG: {zip} switch to latest beta release
+         zip 2.40a
+
+
+
+
+
+Release MacZip ver1.06 final
+22. Februray 2001
+-----------------
+
+1) CHG: {unzip} switch to latest final release
+         unzip 5.42
+
+2) CHG: switch to latest release of Apples
+        Universal Interfaces 3.3.2
+
+3) CHG: switch to latest release of
+        Morefiles 1.5
+
+
+
+
+Release MacZip ver1.06 beta 2
+02. August 2000
+---------------
+
+1) CHG: {unzip} switch to latest beta release
+         unzip 5.42d
+
+
+
+
+
+Release MacZip ver1.06 beta 1
+27. July 2000
+-------------
+
+1) CHG: {zip} switch to latest beta release
+         unzip 2.30
+
+2) CHG: {unzip} switch to latest beta release
+         unzip 5.42c
+
+
+
+
+
+Release MacZip ver1.05 final
+27. July 2000
+-------------
+
+1) CHG: {unzip} switch to latest final release
+         unzip 5.41
+
+2) FIX: {unzip} Fixed "unique unzip folder" foldername handling
+
+3) FIX: {unzip} added prototype crc32() in macbin3.c
+
+4) CHG: {unzip/zip} added exported Codewarrior project-file in xml-format
+
+5) ADD: {unzip} added extra-field recognition for Mac SmartZip in
+         zipinfo.c and unzpriv.h.
+
+
+
+
+
+Release MacZip ver1.04 final
+25. January 2000
+----------------
+
+
+Final release of MacZip. All parts now
+in final release state !!
+
+1) Switch to MW Codewarrior pro 5.3
+
+2) CHG: {zip} switch (back) to latest final release
+         unzip 2.30
+
+3) CHG: {unzip} switch (back) to latest final release
+         unzip 5.40
+
+
+
+
+Release MacZip ver1.04 beta 3
+05. October 1999
+----------------
+
+1) CHG: {zip} switch to latest source level
+         unzip 2.30o beta release
+
+2) CHG: {unzip} switch to latest source level
+         unzip 5.41c beta release
+
+3) ADD: {console} added menu to print the license
+
+
+
+
+Release MacZip ver1.04 beta 2
+02. June 1999
+--------------
+
+1) FIX: {unzip} added one more criteria to make the recognition
+         of macbinary more save.
+
+2) FIX: {unzip} sometimes, archive entries without any extra field
+         caused problems; the default setting of the extra field
+         was not set back to 'unknown' properly.
+
+3) FIX: {zip} Archive filename with invalid characters like '/' gets
+         renamed. However, I do not check the complete path - needs
+         some more work here.
+
+4) FIX: {zip} Filename match was case sensitive.
+
+6) CHG: {zip} switch to latest source level
+         unzip 2.30m beta release
+
+7) CHG: {unzip} switch to latest source level
+         unzip 5.41b beta release
+
+8) FIX: {zip/unzip 68k only) I have found a wrong compiler setting
+         for the 68k version. Because of this wrong setting the 68k
+         version crashed.
+
+
+
+
+Release MacZip ver1.04 beta 1
+30. March 1999
+--------------
+
+1) CHG: {unzip) switch to latest source level
+         unzip 5.41a beta release
+
+2) ADD: {all} Added message logging support for Syslogd
+        by Brian Bergstrand. Syslogd can be found at
+        http://www.classicalguitar.net/brian/apps/syslogd/
+        This feature is 'under construction'.
+
+3) FIX: {all} many small fixes and code cleanups
+
+
+
+
+Release MacZip ver1.03
+27. March 1999
+--------------
+
+1) CHG: {console} Like Stuffit Expander MacZip quits automatically when
+         used with drag'n drop or as Helper App (Web-Browser).
+
+2) CHG: {console} Since Macintosh users are used to be guided by their
+        software in order not to do something stupid, I added a check
+        to post an extra warning if the options -m and data fork only
+        are both checked.
+        This behavior can be disabled: See Applescript example and
+        "maczip.env".
+
+3) CHG: {zip} switch from immediate deletion to moving to the
+        trash. Immediate deletion is now an option in "maczip.env".
+
+4) CHG: {zip} enhanced progress display.
+
+5) CHG: {zip) switch to latest source level
+         zip 2.3l beta release
+
+6) CHG: {unzip} The zip archive contains file names greater than
+        31 characters. When MacZip tries to unzip the file, the
+        FSpCreate command fails because the filename length is to
+        long. MacZip correct this problem by trying to truncate
+        the file names to the 31 character limit.
+
+7) FIX: {zip/console} A couple of minor fixes
+
+8) CHG: {zip} Switched file-globbing to the Info-ZIP version.
+
+
+
+
+Release MacZip ver1.02
+14. February 1999
+-----------------
+
+1) CHG: {zip} Changed the rule of file inclusion if switch '-X'
+        is set. Following conditions are checked:
+        a) if length of resource-fork is equal zero *and* the
+              length of     data-fork is equal zero include the file.
+        b) if length of resource-fork  greater zero *and* the
+              length of     data-fork is equal zero don't include the file.
+        c) if length of     data-fork  greater zero include the file.
+
+2) CHG: {Console} Some users are very confused by the buttons "START PATH"
+        and "ZIP ARCHIVE". Somehow, it wasn't clear what the intended
+        meaning was. I changed the buttons to more clear labels on
+        them like: "file or folder to compress" and "location of
+        compressed file"
+
+3) CHG: {Console} I changed the menu structure to be more intuitive.
+
+4) FIX: {Console} Found a nasty bug which sometimes caused crashes
+        when the Zip / Unzip Dialogbox was used.
+
+5) CHG: {Console} Handling of file dialog is now a bit more restricted:
+        e.g: it's not possible to select a file if you have to select
+        a folder.
+
+
+
+
+Release MacZip ver1.01
+30. January 1999
+----------------------
+
+1) CHG: {console} The use of the "Current App" mechanism was clumsy
+        and forces the user into the Zip or Unzip modes. This kind
+        of modality is not so good for the command line. It's now
+        neccessary to enter zip or unzip to choose the action.
+
+2) FIX: {console} When Applescript sends quit to MacZip the script
+        that is running shows a spinning cursor and MacZip
+        does not quit.
+
+3) FIX: {console} MacZip gots accidentally the wrong creator code
+        (from BBedit)
+
+
+
+
+Final Release MacZip ver1.0
+---------------------------
+
+Released 21. January 1999
+
+
+
+
+9. Beta release 06.December.1998
+---------------------------------
+
+1) CHG: {console} The checkbox of Filedialog (for extract path and file path)
+        "Show all files" is now selected by default.
+
+2) CHG: {unzip/standalone} changed prototypes of mac[f]printf() to return
+        an int number (better ANSI conformance);
+
+3) FIX: {unzip} repaired "stdout/stderr" mode of macwrite(). So func
+        MacMessagePrnt() is now obsolete and removed.
+
+4) ADD: {zip/unzip} Compressed Mac3 extra-fields are now supported
+        (Thanks to Christian Spieler)
+
+5) ADD: {unzip} Extraction of ZipIt archive are now supported. This support
+        is not complete: Filenames are correct but folder names are only
+        restored with the public directory names.
+
+6) ADD: {zip/unzip} Improved documentation.
+
+7) FIX: {unzip} Function isZipfile() is completely rewritten.
+
+8) CHG: {zip/unzip) switch to latest source level
+        zip 2.3i beta and unzip 5.4 final release
+
+9) ADD: Applescript event "do_cmd".
+
+Unless there are big bugs found, this release will be the last
+beta release. The final release will come out in January 1999.
+
+
+
+
+8. Beta release 20.November.1998
+---------------------------------
+
+1) CHG: {zip/unzip) switch to latest source level
+        zip 2.3h beta and unzip 5.4 final release
+
+2) ADD: {zip} Zip finds "namelocked" files also, if switch "-S"
+        is set.
+
+3) FIX: {unzip} Function isZipfile() fails if the zip archive
+        has a comment.
+
+4) CHG: {zip} added some small speed improvements to pattern matching and
+        isZipFile() function.
+
+5) FIX: {unzip} Display of comments is fixed.
+        UzpMessagePrnt() is replaced by MacMessagePrnt(). I do not care
+        about ansi-bombs. I'm not sure, so this fix may be changed later.
+
+6) RMV: {unzip} Buildin More capability is removed since it's already built
+        into the GUI-App.
+
+
+
+7. Beta release 09.November.1998
+---------------------------------
+
+1) CHG: {all} switched to Metrowerks Codewarrior Pro 4
+
+2) FIX: {unzip} Display of comments stored in the zip-file is
+        now fixed
+
+3) FIX: {zip} Fixed display of the zip help-screen.
+
+4) CHG: {zip/unzip} Changed special dir 'Re$0urce.Fk' to 'XtraStuf.mac'
+        (see entry at 13.June.1998 item 3). I found it more descriptive for
+        users outside the mac-community.
+
+5) CHG: {all} switched to MoreFiles 1.4.9.
+
+6) CHG: {console} changed behaivor of the file open dialog: The select
+        button is now always enabled.
+
+7) ADD: {all} Environment variables are now supported.
+         Basically, it is possible to add timezone (= TZ environment variable)
+         support here, but it's not yet implemented.
+         See "MacZip.Env" for further info.
+
+8) RMV: {console} Targets "zip only" and "unzip only" are removed.
+
+
+
+6. Beta release 09.September.1998
+---------------------------------
+
+
+1) CHG: {Zip/Unzip} Metrowerks Standardlibrary time funktions are
+        rather broken and incomplete so I was forced to rewrite the
+        funktions: mktime(), localtime(), gmtime() and time().
+
+2) ADD: {Console} Added Pause Funktion for screen output.
+        The Pause-Function is selfadjusting: Count of lines is depending
+        on the window size.
+
+3) CHG: Extra-Field layout is changed: All datas are now in little-endian
+        format (see appnote)
+
+4) ADD: {Console} Added an option to test the archive automatically
+        after zipping. This option is only via Zip-Dialogbox available
+        because it needs the unzip-module also.
+
+5) CHG: {Zip} code is now up to date with the latest beta 2.3f.
+
+6) ADD: {Console} Added (drag'n) drop support. Drop on the MacZip icon.
+        The following situations are supported:
+                    1. drop of one or more zipfiles (action = unzip)
+                       each archive will be extracted in a separate folder
+                    2. drop of a folder (action = zip -r )
+                       The complete folder (inclusive sub-folders)
+                       will be zipped
+        Not (yet) supported is currently: dropping more than one file
+        to compress. Workaround: Put all your files in one folder and
+        drop that folder on MacZip.
+        MacZip recognize zip-archives automatically.
+
+
+5. Beta release 21.Aug.1998
+----------------------------
+
+
+1) ADD: {Console} Userinterface has now a Statusbar to show the
+        Progress.
+
+2) ADD: {Console} It's now possible to stop the run of Zip/Unzip
+        with the well known shortcut [Command] + [.]
+
+3) CHG: {Console} Improved user-entry routine.
+
+4) ADD: {Zip/Unzip} Crypt-code added. It's now possible to
+        encrypt/decrypt archives.
+
+5) RMV: {Unzip} Removed the warning of PKZip/Mac archive.
+        Unzip gets confused with the extra field of PKZip/Mac. So I assume
+        the extra field isn't compatible with Info-ZIP's definition.
+
+6) CHG: switched to Metrowerks Codewarrior Pro 3
+        this includes:
+        - new Universal Interfaces 3.1 Headers
+        - improved codegeneration
+
+7) CHG: {Zip} code is now up to date with the latest beta 2.3e.
+
+8) CHG: {Unzip} changed function names wprintf, wgets .. to macprintf, macgets ..
+        to avoid naming conflict standart library.
+
+9) ADD: {Zip/Unzip} FXinfo, Mac-Pathname, file-dates and Finder-Comments
+        are now stored in the extra-field. Extra-field layout is
+        changed accordingly. Unzip uses now the filename stored in the
+        extra-field when unzipping.
+
+10) CHG: {Unzip} code is now up to date with the latest beta 5.33g.
+
+11) CHG: {Unzip} code is (again) up to date with the latest beta 5.33h.
+
+12) ADD: {Unzip} following switches were added:
+       -J     [MacOS  only] ignore mac extra info. All macintosh
+              info are not restored. Datafork and resource-fork
+              are restored separatly.
+
+       -i     [MacOS  only] ignore filenames stored in mac extra
+              field. Use the most compatible filename stored in
+              the public field.
+
+       -E     [MacOS  only] show mac extra field during restoring
+
+13) ADD: {Zip/Unzip} Charset MacRoman to ISO8859 Latin and vice versa
+
+14) RMV: {Zip} -N option removed. This MacZip crashes using this option.
+         I will fix it later.
+
+
+I think I'm very close for a final release of "MacZip 1.0" :-)
+
+
+
+4. Beta release 27.June.1998
+----------------------------
+
+26.June.1998
+------------
+
+1) FIX: {Zip} extra field size value was wrong.
+
+
+
+25.June.1998
+------------
+
+1) CHG: {Zip} code is now up to date with the latest beta 2.3d.
+        So both modules, zip & unzip, uses now latest beta.
+
+2) ADD: {Zip} added a UT extra-field for better compatibility.
+
+3) CHG: {Unzip} changed the code to find the mac extra-field.
+        Unzip has to look for a mac extra-field because
+        mac-archives has now two extra-fields (UT + M3).
+
+4) CHG: {Unzip} changed the method to move extra-field data to
+        the internal extra-structure.
+        Old method was just BlockMove of the ef_structptr to ef_memptr.
+        This method was dangerous because not all members of the
+        structure seamless aligned. There are may be some fill
+        bytes in the structure depending on the compiler setting.
+
+5) ADD: {Unzip} added a warning if unzipping a ZipIt/PKZip archive.
+        ZipIt/PKZip archives are usually additionally coded somehow.
+        InfoZip's Unzip will *not* decode the files. So extracted
+        files are may be not decoded. (see also 6. and 7.)
+
+6) ADD: ZipIt (the Shareware Tool) has now a new extra-field signature:
+        0x2705. Found in "ZipIt 1.3.8". I added a new macro: EF_ZIPIT2
+
+7) ADD: Added PKWare's extra-field signature: 0xCF77.
+        Found in "PKZIP v2.03". I added a new macro: EF_PKMAC
+
+8) ADD: {console} It's now possible to save all screen outputs
+        to the disk.
+
+9) RMV: {console} this is the first beta without expire-date.
+
+
+16.June.1998
+------------
+
+1) FIX: {Unzip/console} Extract path now defaults to current-dir if
+        no path is given.
+
+2> CHG: {Unzip} creates now a extract-folder by default. This behavior
+        differs to the commandline tool of Unzip on other platforms.
+        However, for a mac-user is this behavior more convenient.
+
+
+3. Beta release 15.June.1998
+----------------------------
+
+15.June.1998
+------------
+
+1) CHG: {unzip/zip} I changed the layout of the extra field
+        to support more data.
+
+
+14.June.1998
+------------
+
+1) FIX: {Unzip} adjusted time_t value with an correct offset value.
+
+2) FIX: {Unzip} removed all unused code based on unfinished ideas by
+        former porter(s).
+
+3) CHG: use of shared code izshr 032.
+
+13.June.1998
+------------
+
+1) FIX: {Unzip} Filenames are only converted when needed. When zipping
+        with the switch 'datafork only' the filenames are shorted which
+        was wrong.
+
+2) CHG: {Unzip} code is now up to date with the latest beta 5.33f.
+
+3) CHG: {Zip} Changed the naming rule of filenames from old Johnny Lee's
+        to my implementation. Johnny Lee's idea is based on change of the
+        filenames which cases several problems when unziping on a non mac
+        plattform. My idea is to add a special directory: 'Re$0urce.Fk'.
+        For the future: Zip will create archives according the new nameing
+        rule. However unzip will be compatible with old nameing rule.
+        See also 4.
+
+4} ADD: {Unzip} Added a new nameing rule for resource forks filename.
+        Resource forks are now stored in a special directory: 'Re$0urce.Fk'.
+        This naming rule make it easier to for other platforms to use
+        mac zip-files.
+
+
+
+11.June.1998
+------------
+1) FIX: {Zip} Internal file attribute is set to BINARY by default
+        when zipping resource forks otherwise Unzip will create
+        sometimes wrong resource-forks.
+
+2) CHG: {Unzip} code is now up to date with the latest beta 5.33e.
+
+
+
+
+2. Beta release 10.June.1998
+--------------------------
+
+1) FIX: {Unzip} Long pathname fix solved. Unzip is now able to extract
+        archives with path longer than 256 chars.
+
+2) CHG: {Unzip} removed all conversion from c-style string to
+        pascal-string (see fix 1)
+
+3) ADD: {Unzip} Finderinfo of folders are also restored.
+
+4) ADD: {Console} Added info about current path in the command-line box.
+
+5) FIX: {Console} Construction of the command-line of the unzip-dialog
+        box fixed.
+
+
+
+First beta release 06.June.1998
+-----------------------------
+
+no history.
+Just to many code was neccessary to build the first mac-port.
+
+
+Start of the port MacZip
+February 1998
+
+
+--------------------------------------------------------------------------------
+Legende:
+
+FIX: fixes a bug
+CHG: inform about changed items.
+ADD: added feature
+RMV: removed Item
+
+{Unzip}   -> only related to the Unzip-module
+{Zip}     -> only related to the Zip-module
+             These are just libraries and are linked into the console-app.
+
+{Console} -> only related to the Userinterface (not SIOUX)
+             MacOS has no tool like a command-line. So it's neccessary
+             to write wrapper around the command-line tools.
+
+
+
+
+Dirk Haase
diff --git a/macos/README.TXT b/macos/README.TXT
new file mode 100644 (file)
index 0000000..839658d
--- /dev/null
@@ -0,0 +1,569 @@
+A free Macintosh Port of Info-ZIP's
+Zip and UnZip
+By Dirk Haase, d_haase@sitec.net
+Home page: www.sitec.net/maczip
+Mirror page:
+www.haase-online.de/dirk/maczip
+================================
+
+
+
+Abstract:
+---------
+MacZip is a cross-platform compatible tool that includes
+both Zip (for compression) and UnZip (for extraction).
+
+Zip is a compression and file packaging utility for Unix,
+VMS, MSDOS, OS/2, Windows 9x, Windows NT, Atari, Macintosh,
+Amiga, Acorn RISC OS, and other systems.
+
+UnZip unpacks zip archives. The Zip and UnZip programs can
+process archives produced by PKZIP, and PKZIP and PKUNZIP
+can work with archives produced by zip. Zip version 2.2 is
+compatible with PKZIP 2.04.
+
+If you are new to MacZip please read first the file
+"ReadMe.1st".
+
+
+
+License:
+--------
+  Copyright (c) 1990-2001 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in unzip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+
+
+
+Requirements
+------------
+MacZip requires at least System 7 and a Macintosh with a
+minimum of a Motorola 68020 or PowerPC 601 processor. Other
+configurations may work but it is not tested at all.
+
+The application is distributed as a fat binary with both
+regular 68K and native PowerPC versions included.
+
+
+
+Installation
+------------
+Move the executable(s) somewhere--for example, drag it (or
+them) to your Applications folder.  For easy access, make an
+alias in the Launcher Control Panel or directly on your
+desktop. The GUI is very simple. It was not my intention to
+make a full-blown GUI, however I think it is comfortable
+enough to use it as regular tool.
+
+This port supports also Apple-event. So you can install it
+in your WWW-Browser as a helper app.
+
+For more Info about the contents of this package, take a
+look into the "macos/Contents" (or :macos:Contents) file.
+Some notes on how to rebuild the Macintosh applications can
+be found in INSTALL.
+
+
+
+Usage:
+------
+
+Basically there are four ways to start MacZip:
+
+a) Drag'n Drop
+b) using the Dialog box (Menu: File -> Zip/Unzip):
+
+Please read the file "ReadMe.1st"
+for the description of the items a and b.
+
+c) Using the Command line (Menu: File->Command Line):
+   The Zip & UnZip tools are command line tools. So the
+   behavior is exactly the same like the Zip & UnZip tools on
+   Unix or Windows/DOS. This means, if you want to zip some
+   files, you have to write a command line like this: "zip
+   [switches] path_to_zip_archive path_to_files_folders"
+
+   - Go to "File", select "Command Line" and the
+     "MacZip Entry box" Dialog Box appears.
+
+   An example:
+
+   a: your zip may be created at
+           Macintosh HD:applications:archive.zip
+
+   b: your files may be found at
+           Macintosh HD:somewhere:my_folder_to_archive:*
+
+   Note: At the end of the path there must be a filename or
+         a wild card !
+   (see Footnotes: 1 wild card, 2 Mac path names)
+
+   So the command line should look like (one line!):
+
+   zip "Macintosh HD:applications:archive.zip" "Macintosh HD:somewhere:my_folder_to_archive:*"
+
+   - Click on "Enter" to start the task.
+
+   Since you can not set a default folder you have to enter
+   always a full qualified path names. Full-qualified path
+   names are path names including the Volume name ! (see
+   Footnote: 2 Mac path names)
+
+
+
+d) Using Applescript:
+
+There is only one additional event defined: "do_cmd". You
+can enter every valid command line. The first word must be
+"zip" or "unzip" to select the action (compress or
+extraction).
+
+See sample Applescript:
+
+    tell application "MacZip (PPC)"
+        activate
+        with timeout of 90000 seconds
+            do_cmd "zip -rjjN Volume:archive \"My Volume:*\" "
+        end timeout
+    end tell
+
+This script opens MacZip, brings it to the foreground on the
+Mac, starts the zip action with the command line: zip -rjjN
+Volume:archive "My Volume:*" .
+
+
+A short introduction is also available online:
+http://www.sitec.net/maczip/How-To-Do/
+
+It's possible to stop the run of Zip/Unzip with the well
+known shortcut [Command] + [.].
+
+
+---------------------------------------------------------------------------
+
+There are some Mac-specific switches available.
+Zip Module:
+       -df    [MacOS] Include only data-fork of files zipped into
+              the  archive.   Good for exporting files to foreign
+              operating-systems.  Resource-forks will be  ignored
+              at all.
+
+       -jj    [MacOS] record Fullpath (+ Volname).  The  complete
+              path  including  volume  will be stored. By default
+              the relative path will be stored.
+
+       -S     [MSDOS, OS/2, WIN32 and ATARI] Include  system  and
+              hidden files.
+              [MacOS]  Includes finder invisible files, which are
+              ignored otherwise.
+
+Unzip Module:
+       -E     [MacOS only] display contents of MacOS extra  field
+              during restore operation.
+
+       -i     [MacOS only] ignore filenames stored in MacOS extra
+              fields.  Instead,  the  most  compatible   filename
+              stored in the generic part of the entry's header is
+              used.
+
+       -J     [MacOS only] ignore MacOS extra fields.  All Macin-
+              tosh  specific  info  is  skipped.  Data-fork   and
+              resource-fork are restored as separate files.
+
+
+Select [File]->[Get Help on Zip/Unzip] for a complete list
+of switches.
+
+
+
+Limitations / Problems:
+-----------------------
+
+    - Aliases are not supported. I tried, but I got broken
+      aliases. This port will silently ignore all aliases.
+      It's on my to-do list for future releases.
+
+    - Zip needs much memory to compress many files: You may need
+      to increase the 'Preferred Size' in 'Get Info'. Values of 12
+      Megabytes or more are possible
+
+    - Unzip needs about 500 Kbytes of memory to unzip no matter
+      how many files were compressed and expanded.
+
+    - and finally one big macintosh-related problem:
+      This port has one weak point: It's based on path names.
+      As you may be already know: Path names are not unique on a Mac !
+      The main reason is that an attempt to implement support exact
+      saving of the MacOS specific internal file structures would
+      require a throughout rewrite of major parts of shared code,
+      probably sacrifying compatibility with other systems. I have
+      no solution at the moment. The port will just warn you if you
+      try zip from / to a volume which has a duplicate name.
+      MacZip has problems to find the archive or the files. My
+      (Big) recommendation: Name all your volumes with a unique
+      name and MacZip will run without any problem.
+
+
+Known Bugs:
+
+    - crypted files in a zip archive are sometimes corrupt:
+      I get an error message: invalid compressed data to inflate.
+      Appearance of this error is purely be chance: I did a small
+      test: Unzipping an archive containing 3589 files 56 files
+      fails to unzip, so about 1.5%. Root cause is completely
+      unclear to me :(
+
+I strongly recommend to test your archive (e.g. unzip -t archive).
+
+
+
+
+
+Zip Programs / Macintosh Extra-Data:
+-----------------------------------------
+A brief overview:
+Currently, as far as I know, there are 6 Zip programs
+available for the Macintosh platform. These programs build
+(of course) different variants of Zip files:
+
+    - Info-ZIP's first Port of Zip. Ported by Johnny Lee
+      This port is rather outdated and no longer supported (since 1992).
+      68K only. Only minimal Mac-info is stored
+      (Creator/Type, Finder attributes). Creator/Type: '????' / '????'
+      Until year 1998, only UnZip 5.32 survived.
+
+    - ZipIt by Tom Brown. This is Shareware and still supported I think.
+      ZipIt has a nice GUI, but I found it can't handle large Zip files
+      quite well. ZipIt compresses Macintosh files using the Mac Binary
+      format. So, transferring files to other platforms is not so easy.
+      Only minimal Mac-info is stored (Creator/Type, Finder attributes).
+      Mac filenames are changed to a most compatible filename.
+      Creator/Type: 'ZIP ' / 'ZIP '
+
+    - PKZIP/mac v2.03/210d. This is Shareware.
+      This Zip implementation for the Mac can be found on ASI's web site
+      (http://www.asizip.com/products/products.htm).  The name of this
+      program is misleading, it is NOT a product from PKWARE.  ASI's last
+      release version is v2.03, and they also offer a newer beta version
+      PKZIP/mac 210d. But even the Beta version is rather outdated (1995).
+      Only minimal Mac-info is stored (Creator/Type, Finder attributes).
+      The Zipfile format looks like incompatible to other platforms.
+      (More details about the compatibility issue can be found in
+      proginfo/3rdparty.bug!). Type: 'PKz1'
+      Mac filenames are restored without any change.
+
+    - Aladdin DropZip 1999, This is Shareware. Aladdin chose
+      the format of ZipIt. Therefore, it has the some drawbacks
+      like ZipIt.
+      Creator/Type: 'SITx' / 'ZIP '
+
+    - SmartZip 1.0 1999 - by Marco Bambini Vampire Software.
+      This is Shareware. SmartZip compresses Macintosh files using the
+      Mac Binary. Therefore, it has the same drawbacks like ZipIt.
+      Creator/Type: 'dZIP' / 'ZIP '
+
+and finally:
+    - Info-ZIP's latest Port of Zip. MacZip 1.0. Ported by me :-)
+      It is supported (of course) and up to date. Full set of macintosh
+      info is stored: Creator/Type, Finder attributes, Finder comments,
+      MacOS 8.0 Folder settings, Icon/Folder Positions ...
+      Mac filenames are restored without any change.
+      Creator/Type: 'IZip' / 'ZIP '
+
+
+Compatibility of my port; Extraction:
+   - Archives from Info-ZIP's first port (by Johnny Lee) are
+     still compatible.
+   - Extraction of ZipIt archives is supported. This support
+     is not complete: Filenames are correct but Directory names
+     are sometimes mangled to a DOS compatible form. Segmented
+     archives are not supported.
+   - PKZiP/mac archive files are extracted without resource-forks
+     and without any Finder info. I have no information about
+     that zip format.
+
+Compatibility of my port; Compression:
+   - My port supports only the new Info-ZIP format (introduced
+     with this port). Therefore archives created by MacZip 1.0
+     (March 1999) must be extracted with this version or later
+     releases of Info-ZIP's UnZip to restore the complete set of
+     Macintosh attributes.
+
+Note: This port is complete unrelated to the shareware ZipIt.
+Even more, handling of special Macintosh attributes is
+incompatible with ZipIt. This port (MacZip) may be used to
+extract archives created by ZipIt, but make sure that you
+get the result as you expected.
+
+
+
+Macintosh Files; File Forks:
+----------------------------
+
+All Macintosh files comprise two forks, known as the data
+fork and the resource fork.  Unlike the bytes stored in the
+resource fork, the bytes in the data fork do not have to
+exhibit any particular internal structure. The application
+is responsible for interpreting the bytes in the data fork
+in whatever manner is appropriate. The bytes in the resource
+fork usually have a defined internal structure and contain
+data object like menus, dialog boxes, icons and pictures.
+Although all Macintosh files contain both a data fork and a
+resource fork, one or both of these forks may be empty.
+
+MacZip stores data-forks and resource-forks separately. The
+Zipfile format does not allow to store two archive entries
+using exactly the same name. My solution is to modify the
+Path name of the resource-fork. All resource-fork names are
+prepended with a leading special directory named
+"XtraStuf.mac". So, when extracting on a Mac, you should
+never see this directory "XtraStuf.mac" on your *disk*.
+
+On all foreign systems that support directories in filenames
+(e.g.: OS/2, Unix, DOS/Windows, VMS) you will get a
+directory "XtraStuf.mac" when extracting MacZip archives.
+You can delete the complete directory "XtraStuf.mac" since
+Mac resources do not make much sense outside the MacOS
+world.
+
+
+
+Text encoding; Charsets of the Filenames:
+-----------------------------------------
+
+The following information is only important if you plan to
+transfer archives across different platforms/language systems:
+
+A typical Zip archive does not support different charsets.
+All filenames stored in the public area (= accessible by
+foreign systems other than MacOS) must be coded in the
+charset ISO-8859-1 (CP1252 in the Microsoft Windows world)
+or CP850 (DOSLatin1). The latter should only be used by Zip
+programs that mark the archive entries as "created under
+DOS". Apart from Macs, the commonly used platforms either
+support ISO-8859-1 directly, or are compatible with it. To
+achieve maximum compatibility, MacZip convert filenames from
+the Mac OS Roman character set to ISO-8859-1 and vice versa.
+But not every char of the charset MacRoman has their
+equivalent in ISO-8859-1. To make the mapping in most cases
+possible, I chose most similar chars or at least the MIDDLE
+DOT.
+
+Mac OS Roman character set is used for at least the
+following Mac OS localizations: U.S., British, Canadian
+French, French, Swiss French, German, Swiss German, Italian,
+Swiss Italian, Dutch, Swedish, Norwegian, Danish, Finnish,
+Spanish, Catalan, Portuguese, Brazilian, and the default
+International system.
+
+In all Mac OS encodings, character codes 0x00-0x7F are
+identical to ASCII, except that
+  - in Mac OS Japanese, yen sign replaces reverse solidus
+  - in Mac OS Arabic, Farsi, and Hebrew, some of the
+    punctuation in this range is treated as having strong
+    left-right directionality, although the corresponding
+    Unicode characters have neutral directionality
+So, for best compatibility, confine filenames to the standard
+7-bit ASCII character set.
+
+If you generate a filename list of your archive (unzip -l),
+you will see the converted filenames. Your can also extract
+the archive with the switch '-i' (= ignore mac filenames),
+and test your result.
+
+This MacZip port uses its own filename stored in the
+archive. At the moment, the filename will be not converted.
+However, I'm planning to add support for Unicode.
+
+Currently, the following Mac OS encodings are NOT supported:
+Japanese, ChineseTrad, Korean, Arabic, Hebrew, Greek,
+Cyrillic, Devanagari, Gurmukhi, Gujarati, Oriya, Bengali,
+Tamil, Telugu Kannada, Malayalam, Sinhalese, Burmese, Khmer,
+Thai, Laotian, Georgian, Armenian, ChineseSimp, Tibetan,
+Mongolian, Ethiopic, Vietnamese, ExtArabic and finally:
+Symbol - this is the encoding for the font named "Symbol".
+Dingbats - this is the encoding for the font named "Zapf Dingbats".
+If you extract an archive coded with one of these
+charsets you will probably get filenames with funny
+characters.
+
+These problems apply only to filenames and NOT to the file
+content.
+of course: The content of the files will NEVER be converted !!
+
+
+
+File-/Creator Type:
+-------------
+
+This port uses the creator type 'IZip' and it is registered
+at Apple (since 08. March 1998). File types can not be
+registered any more. This port uses 'ZIP ' for Zip archive
+files. The creator 'IZip' type should be used for all future
+versions of MacZip.
+
+
+
+Hints for proper restoration of file-time stamps:
+-------------------------------------------------
+
+UnZip requires the host computer to have proper time zone
+information in order to handle certain tasks correctly (see
+unzip.txt).  To set the time zone on the Macintosh, go to
+the Map Control Panel and enter the correct number of hours
+(and, in a few locales, minutes) offset from Universal
+Time/Greenwich Mean Time.  For example, the US Pacific time
+zone is -8 hours from UTC/GMT during standard (winter) time
+and -7 hours from UTC/GMT during Daylight Savings Time.  The
+US Eastern time zone is -5 hours during the winter and -4
+hours during the summer.
+
+Discussion of Daylight Savings Time
+-----------------------------------
+The setting in the Date & Time control panel for Daylight
+Savings time is a universal setting. That is, it assumes
+everybody in the world is observing Daylight Savings time
+when its check box is selected.
+
+If other areas of the world are not observing Daylight
+Savings time when the check box is selected in the Date &
+Time control panel, then the Map control panel will be off
+by an hour for all areas that are not recognizing Daylight
+Savings time.
+
+Conversely, if you set the Map control panel to an area that
+does not observe Daylight Savings time and deselect/uncheck
+the check box for Daylight Savings time in the Date & Time
+control panel, then time in all areas celebrating Daylight
+Savings time will be off by an hour in the Map control
+panel.
+
+Example:
+     In the case of Hawaiians, sometimes they are three hours
+     behind Pacific Standard Time (PST) and sometimes two hours
+     behind Pacific Daylight Time (PDT). The Map control panel
+     can only calculate differences between time zones relative
+     to Greenwich Mean Time (GMT). Hawaii will always show up as
+     three hours past the Pacific time zone and five hours past
+     the Central time zone.
+
+     When Hawaiians are not observing Daylight Savings time, but
+     the rest of the country is, there is no combination of
+     settings in Map and Date & Time control panels which will
+     enable you to display Hawaiian local time correctly AND
+     concurrently display the correct time in other places that
+     do observe Daylight Savings time.
+
+     The knowledge about which countries observe Daylight Savings
+     time and which do not is not built into the Map control
+     panel, so it does not allow for such a complex calculation.
+
+     This same situation also occurs in other parts of the world
+     besides Hawaii. Phoenix, Arizona is an example of an area of
+     the U.S. which also does not observe Daylight Savings time.
+
+Conclusion:
+MacZip only knows the GMT and DST offsets of the
+current time, not for the time in question.
+
+
+Projects & Packages:
+--------------------
+
+A Note to version numbers: Version of MacZip is currently
+1.06 and is based on the zip code version 2.3 and unzip code
+version 5.42. See About Box for current version and compiler
+build date.
+
+Because of the amount of sources I splitted this port into
+several projects. See http://www.sitec.net/maczip for
+updates.
+
+- core source parts:
+    unzxxx.zip
+    zipxxx.zip
+      These archives contains the main parts of the port. You can
+      build libraries and a standalone App with Metrowerks
+      standard console SIOUX. They contain only sources, no
+      executables. These archives are exact copies of the standard
+      Info-ZIP source distributions; they were only repackaged
+      under MacOS using MacZip, with one minor addition: For those
+      files that are stored in BinHex'ed format in the Info-ZIP
+      reference source archives, unpacked version that are ready
+      for use have been added.
+
+- additional source part:
+    MacZipxxx.zip: contains all the GUI stuff and the project
+      files to build the main-app.  Only sources of the GUI, no
+      zip or unzip code. To build MacZip successfully you will
+      need to also download the zip and unzip packages.
+
+- executables:
+    MacZipxxxnc.hqx: contains only executables and 'README.TXT',
+                     This version is without en-/decryption support !
+    MacZipxxxc.hqx:  contains only executables and 'README.TXT',
+                     This version supports en-/decryption !
+
+- encryption sources:
+    zcryptxx.zip: To build crypt versions of MacZip.
+    download from ftp://ftp.icce.rug.nl/infozip/ (and subdirectories)
+
+- documentation:
+    MacZipDocu.zip: contains some further docus about the algorithm,
+                    limits, Info-ZIP's appnote and a How-to-do Webpage.
+
+
+Credits:
+--------
+
+Macstuff.c and recurse.c: All the functions are from More Files.
+More Files fixes many of the broken or underfunctional parts of
+the file system. Thanks to Jim Luther. (see morefiles.doc)
+
+
+
+
+---------------------------------------------------------------------------
+Footnotes:
+
+1. wild card:
+    The '*' is a wild card and means 'all files'
+    Just in case you don't know wild cards:
+    '*' is a place holder for any character.
+    e.g.:
+    "this*" matches with "this_file" or  "this_textfile" but it
+    doesn't match with "only_this_file" or  "first_this_textfile"
+    "*this*" matches with "this_file" or  "this_textfile" AND
+    matches with "only_this_file" or  "first_this_textfile"
+
+
+2. Mac pathnames:
+The following characteristics of Macintosh pathnames should
+be noted:
+
+    A full pathname never begins with a colon, but must contain
+    at least one colon.
+    A partial pathname always begins with a colon separator except
+    in the case where the file partial pathname is a simple file or
+    directory name.
+    Single trailing separator colons in full or partial pathnames
+    are ignored except in the case of full pathnames to volumes.
+    In full pathnames to volumes, the trailing separator colon is
+    required.
+    Consecutive separator colons can be used to ascend a level
+    from a directory to its parent directory. Two consecutive
+    separator colons will ascend one level, three consecutive
+    separator colons will ascend two levels, and so on. Ascending
+    can only occur from a directory; not a file.
+
+
+
+
+
+---------------------------------------------------------------------------
+
+Dirk Haase
+==========
diff --git a/macos/ZipLib.h b/macos/ZipLib.h
new file mode 100644 (file)
index 0000000..e3dacf3
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+  ZipLib.h
+
+  This header-files is global to the project ZipLib.
+
+  ---------------------------------------------------------------------------*/
+
+
+
+/*****************************************************************************/
+/*  Macros, typedefs                                                         */
+/*****************************************************************************/
+
+#define MACOS
+#define MACZIP
+
+#define OLDROUTINENAMES     0           /* use new function names only */
+#define OLDROUTINELOCATIONS 0           /* use new headerlocations only */
+#define SystemSevenOrLater  1           /* Runs only on System 7.0 or later */
+
+/* These functions are defined as a macro instead of a function.
+so we have to undefine them for replacing (see printf.c)  */
+#undef getc
+#undef getchar
+#undef putchar
+#undef putc
+
+#ifndef ZCONST
+#  define ZCONST const
+#endif
+
+#define NAME_MAX    1024
+
+
+/*****************************************************************************/
+/*  Includes standard headers                                                */
+/*****************************************************************************/
+#include <ansi_prefix.mac.h>
+#include <stdio.h>
+#include <TextUtils.h>
+#include <Folders.h>
+#include <Aliases.h>
+#include <Resources.h>
+#include <Gestalt.h>
+#include <Traps.h>
+#include <Processes.h>
+#include <MacWindows.h>
+
+
+/* Many things are different for mac-users, so we need
+   special mac functions :-)  */
+int Zmacstat (const char *path, struct stat *buf);
+#define stat(path, bufPtr) Zmacstat(path, bufPtr)
+#define lstat(path, bufPtr) Zmacstat(path, bufPtr)
+
+int fprintf(FILE *file, const char *format, ...);
+int printf(const char *format, ...);
+void perror(const char *parm1);
+
+
+
+/*
+#define MAC_DEBUG  1
+#define DEBUG 1
+   */
+
+
+#ifdef MAC_DEBUG
+#define LOG_DEBUG   7   /* debug-level messages */
+int Print2Syslog(UInt8 priority, const char *format, ...);
+#include <ctype.h>
+
+
+#define Notify(msg)                                                 \
+        {                                                           \
+        (void)Print2Syslog(LOG_DEBUG, "%s (file: %s line: %d)",     \
+                     msg, __FILE__, __LINE__);        \
+        }
+
+
+
+
+#define Assert_it(cond,msg,kind)                                        \
+        {                                                               \
+        if (!(cond))                                                    \
+            {                                                           \
+            (void)Print2Syslog(LOG_DEBUG,"%s failed: [%s] cond: [%s] (file: %s line: %d)", \
+                          kind, msg, #cond, __FILE__, __LINE__);        \
+            }                                                           \
+        }
+
+
+
+
+
+#define AssertBool(b,msg) Assert_it (((b) == TRUE) || ((b) == FALSE),(msg),("AssertBool "))
+
+
+
+#define AssertStr(s,msg)                                            \
+    {                                                               \
+        int s_i = 0;                                                \
+        Assert_it ((s),(msg),("1. AssertStr "));                    \
+        while ((s)[s_i]) {                                          \
+            Assert_it ((!iscntrl((s)[s_i]) || ((s)[s_i] == 0x0A) ||  \
+                       ((s)[s_i] == 0x0D)),(s),("2. AssertStr "));  \
+            s_i++;                                                  \
+        }                                                           \
+    }
+
+
+
+#define AssertTime(t,msg)   Assert_it (((t).tm_sec  >=  0) && ((t).tm_sec  < 62) &&   \
+                ((t).tm_min  >=  0) && ((t).tm_min  < 60) &&   \
+                ((t).tm_hour >=  0) && ((t).tm_hour < 24) &&   \
+                ((t).tm_mday >=  1) && ((t).tm_mday < 32) &&   \
+                ((t).tm_mon  >=  0) && ((t).tm_mon  < 12) &&   \
+                ((t).tm_wday >=  0) && ((t).tm_wday < 7)  &&   \
+                ((t).tm_yday >=  0) && ((t).tm_yday < 366),(msg),("AssertStr "))
+
+
+
+#define AssertIntRange(myvalue,minimum,maximum, msg)  Assert_it ( \
+        ((myvalue) >= (minimum)) && ((myvalue) <= (maximum)), msg,("AssertIntRange "))
+
+
+
+
+#define AssertStrNoOverlap(str1,str2,msg)                           \
+    {                                                               \
+        long s_i = 0;                                               \
+        AssertStr((str1),(msg))                                     \
+        AssertStr((str2),(msg))                                     \
+        if ((str1) < (str2))                                        \
+            {                                                       \
+            s_i = strlen((str2));                                   \
+            Assert_it ( (((str1) + s_i) < (str2)),(msg),("AssertStrNoOverlap "));   \
+            }                                                       \
+        else                                                        \
+            {                                                       \
+            s_i = strlen((str1));                                   \
+            Assert_it ( (((str2) + s_i) < (str1)),(msg),("AssertStrNoOverlap "));   \
+            }                                                       \
+    }                                                               \
+
+
+
+
+#else
+#define Assert_it(cond,msg,kind)
+#define AssertBool(b,msg)
+#define AssertStr(s,msg)
+#define AssertTime(t,msg)
+#define AssertIntRange(myvalue,minimum,maximum,msg)
+#define AssertStrNoOverlap(str1,str2,msg)
+#endif
+
diff --git a/macos/ZipSx.h b/macos/ZipSx.h
new file mode 100644 (file)
index 0000000..d2b9ae8
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+  ZipSx.h
+
+  This header-files is global to the project ZipSioux.
+
+  ---------------------------------------------------------------------------*/
+
+
+/*****************************************************************************/
+/*  Macros, typedefs                                                         */
+/*****************************************************************************/
+
+#define MACOS
+#define USE_SIOUX
+#define MACZIP
+
+#define OLDROUTINENAMES     0           /* use new function names only */
+#define OLDROUTINELOCATIONS 0           /* use new headerlocations only */
+#define SystemSevenOrLater  1           /* Runs only on System 7.0 or later */
+
+/* These functions are defined as a macro instead of a function.
+so we have to undefine them for replacing (see printf.c)  */
+#undef getc
+#undef getchar
+#undef putchar
+
+#ifndef ZCONST
+#  define ZCONST const
+#endif
+
+#define NAME_MAX    1024
+
+
+/*****************************************************************************/
+/*  Includes standard headers                                                */
+/*****************************************************************************/
+#include <ansi_prefix.mac.h>
+#include <stdio.h>
+#include <TextUtils.h>
+#include <Folders.h>
+#include <Aliases.h>
+#include <Resources.h>
+#include <Gestalt.h>
+#include <Traps.h>
+#include <Processes.h>
+#include <MacWindows.h>
+
+
+/* Many things are different for mac-users, so we need
+   special mac functions :-)  */
+int Zmacstat (const char *path, struct stat *buf);
+#define stat(path, bufPtr) Zmacstat(path, bufPtr)
+#define lstat(path, bufPtr) Zmacstat(path, bufPtr)
+
+int fprintf(FILE *file, const char *format, ...);
+int printf(const char *format, ...);
+void perror(const char *parm1);
+
+
+
+/*
+#define MAC_DEBUG  1
+  */
+
+
+
+
+
+
+#ifdef MAC_DEBUG
+#define LOG_DEBUG   7   /* debug-level messages */
+int Print2Syslog(UInt8 priority, const char *format, ...);
+#include <ctype.h>
+
+
+#define Notify(msg)                                                 \
+        {                                                           \
+        (void)Print2Syslog(LOG_DEBUG, "%s (file: %s line: %d)",     \
+                     msg, __FILE__, __LINE__);        \
+        }
+
+
+
+
+#define Assert_it(cond,msg,kind)                                        \
+        {                                                               \
+        if (!(cond))                                                    \
+            {                                                           \
+            (void)Print2Syslog(LOG_DEBUG,"%s failed: [%s] cond: [%s] (file: %s line: %d)", \
+                          kind, msg, #cond, __FILE__, __LINE__);        \
+            }                                                           \
+        }
+
+
+
+
+#define AssertBool(b,msg) Assert_it (((b) == TRUE) || ((b) == FALSE),(msg),("AssertBool "))
+
+
+
+#define AssertStr(s,msg)                                            \
+    {                                                               \
+        int s_i = 0;                                                \
+        Assert_it ((s),(msg),("1. AssertStr "));                    \
+        while ((s)[s_i]) {                                          \
+            Assert_it ((!iscntrl((s)[s_i]) || ((s)[s_i] == 0x0A) ||  \
+                       ((s)[s_i] == 0x0D)),(s),("2. AssertStr "));  \
+            s_i++;                                                  \
+        }                                                           \
+    }
+
+
+
+#define AssertTime(t,msg)   Assert_it (((t).tm_sec  >=  0) && ((t).tm_sec  < 62) &&   \
+                ((t).tm_min  >=  0) && ((t).tm_min  < 60) &&   \
+                ((t).tm_hour >=  0) && ((t).tm_hour < 24) &&   \
+                ((t).tm_mday >=  1) && ((t).tm_mday < 32) &&   \
+                ((t).tm_mon  >=  0) && ((t).tm_mon  < 12) &&   \
+                ((t).tm_wday >=  0) && ((t).tm_wday < 7)  &&   \
+                ((t).tm_yday >=  0) && ((t).tm_yday < 366),(msg),("AssertStr "))
+
+
+
+#define AssertIntRange(myvalue,minimum,maximum, msg)  Assert_it ( \
+        ((myvalue) >= (minimum)) && ((myvalue) <= (maximum)), msg,("AssertIntRange "))
+
+
+
+
+#define AssertStrNoOverlap(str1,str2,msg)                           \
+    {                                                               \
+        long s_i = 0;                                               \
+        AssertStr((str1),(msg))                                     \
+        AssertStr((str2),(msg))                                     \
+        if ((str1) < (str2))                                        \
+            {                                                       \
+            s_i = strlen((str2));                                   \
+            Assert_it ( (((str1) + s_i) < (str2)),(msg),("AssertStrNoOverlap "));   \
+            }                                                       \
+        else                                                        \
+            {                                                       \
+            s_i = strlen((str1));                                   \
+            Assert_it ( (((str2) + s_i) < (str1)),(msg),("AssertStrNoOverlap "));   \
+            }                                                       \
+    }                                                               \
+
+
+
+
+#else
+#define Assert_it(cond,msg,kind)
+#define AssertBool(b,msg)
+#define AssertStr(s,msg)
+#define AssertTime(t,msg)
+#define AssertIntRange(myvalue,minimum,maximum,msg)
+#define AssertStrNoOverlap(str1,str2,msg)
+#endif
+
diff --git a/macos/ZpPrj.hqx b/macos/ZpPrj.hqx
new file mode 100644 (file)
index 0000000..5bb3da0
--- /dev/null
@@ -0,0 +1,455 @@
+(This file must be converted with BinHex 4.0)
+:#9T`8(*U,R0TG!"6594%8dP8)3#3"&66!*!%Ip96593K!!%!!&66FNaKG3)!N!3
+@!*!$$39DF&"bDJ#3!aEf1!,VX93!6&MU!*!$J!#3"!,cIF3NA3#3'[q3"%e08(*
+$9dP&!3b[H&ZZXklEb3#3"3,E[3#3"P40!!$hQ!#3"L8D"RMDS*NlIS6ISVG-[(8
+R+hBY21RaEd$i`XJbN!"bQK8YHRN,mmTE("$HbP6f+lXeRq'lH*3I@AbbH%Ef3E+
+Yif3KHp54hE%@hq8Fj,%GAml1RLpN-E,i(GQARdH@0q0,K(GffT%p5)X[RVFF@D4
+BKrHBaXd@6VD,AXpZB5d!C#'6K@abQi`@mJ[Cj$MPC!8iDT2X[EaXE0rjRCHM[$`
+Ej#4Rp[RPjG6VcFj"ITHAR9DQepPe(-SAiAji1arZ(-5ApPP[lbMciLAdmP)if0m
+4Z#m[-q'q["cNPGI1p`,!!JLip@eQPi2X'farqH4p"**I)T!!,ckH3A`!+i#AjfI
+6V9BMbl,P@GDh0P[fhKZcCArkf5`lka2F0rFYkb28qpDfD[R@DP(8@d9PSQMYcUH
+l#l&K+CqqV@b6b'8EXQaE[)pm16Za$2kVE&Ajrhr50p-icq)mQh-k-9rKr#ThirR
+rPjaIiecK!m`jJh-@jcQFFcJAF-lMl1)dliLFcVQ"F`IR*Xk0R"GcEZCFalQ0mbl
+1fcR[i$c+q@,1jh$HcAQBm`MR4C`2FElF9MERGNj6amLPR&XjIj*c$@F2jmXiAm$
+j*XlAFlk"mi@FrjhcMcNrbIN*cSpcISVc6cMr,HHpR$r0q3#eRXTrcYrLI$mR'2-
+,R+rKI"hRIH3Bb9R2#IC-iM3GT%lK(-,CcQPUVdlJ(-lCbMQ1Xi(6p)BkME10Xj%
+c+PDCdr561TN6d2S-jjpa'Lb,I*!!mcpbrKVR@cNIiIaPcSFjIjhc9cKrNI2GR'r
+Mr#$RKcMIc[R[1Aq9mbfFlq6m*Fi,1*Ga,Z@mKI0IFGl*#5!Dh)bmK[09R,GaAX,
+j"jarb2RI1(q(FaIR4cJrb[Nqc[Gb(Z#mQA-Ijhl1Jp4a$2rr-qGri@idr`pa2Tr
+c#j`c1@GcRXXjPh-Kjha1dcX4X#IbK!KDTSmLi&#%2SXmRI-QcLq9Z!9QHAK&RJp
+`lZ(FbhNGjrfFi0ZA1@rJr$6RRh*qP[1jR(r"H68Rb4GarLERAh1H6mK%r[mHjqp
+bAXYTHM*b(ZI2F2iXj`61[`QF)`)'4&l"HCccMCcrM[2R16r(qAR1Rq!dI4jj2HF
+pR$r&qmEbrbAmTmDmG5@R`BL)@2XZiLEchf"#j+Fj$@j%`)h)-cJ0YN6%B*!!fZ"
+0"!b*Q-YJ5Z6l13f@4"l,H6RRrq,m"ZHMR,r0#FVclQpbISXh8X0[Fcl'q6MRDNj
+kp$ZFEqEm1FlAFVk)df"Bj'l1*Cc,1EXjRmhj4Fi(1@rN[*lcMcMr0HFV1DrKT2p
+IcEQEmcpaIScc2h$Zj2`0c[G`AX&j+HFl*#EQK*KF5AfSiiFjrbYhe2BUcZFYQ8#
+8`"SqHK"mJ1I3kr3C28Brd%[d&(J&2Y#Ep#9p$1pa'!D(S)I"!2UBIUI2k&ekQ$k
+NTkNhA)PD1m`$$m!AqJL1"DHLhq&FB#FB#Zm#3m%Rq0Hr%%46EGlDqbRHVF#K%H!
+jCH(Hi#JG!5E6*4lH8SZ90Sij`3pl6lJjll@6MSXbZAq0&J$qBllBSmf01Ffr4[l
+C`lkV[XcL4ASG'Uq6pdGP+lLTLlHfZ[CGhY-)T@1p"c3qUpkHR1ZA["4,,hRFkea
+YBX@*hcX-dG"#+9Im%9i"mj8`IdC`pR"ZifcRl1$Xj"c&1CTc$1GBcR'FNcQl1'G
+`VZ*FcEQ@Fb2R*XiYR$GclZHmKI0@cJ1F"cN2F4lQ[)hc+1IYR(G`2Src(Xjl19r
+!q41F@f-(QGk,(-FjM(-iCbXRM$VH@aj#JTLJCcJ!8S+3!+!HU!JLJMDJ)qJ*@MT
+N"$e"8C!!&83&)8&+Kk"K"%KC3E!i)0$PJemF2ha%-$h8ZV&k4A@S8HedmNlrlUV
+k4r+lI'5L-VEe@@SUj"`H)5q"0Af[ML&D&MAMJ*Q(BUqXb8H5K0BVJkB$kF&FTK+
+E1,G`MZBF`cQ@Fa,R+-j1cKXiEq5mQA-NjdE1rCbhF0l+HC!!Xiec'fF2Cc[R#-j
+9R$GacZ$FblQDFbhR2Xl*R)FjEq-mbRNAjpfFcq0m2ZFpR&XjQcLE1BG`YR!1j4`
+QQE%pEq+fM@mD("[Z(pkQ6*ArB1m@(2NMrbrTZlE[a'9UA)NZ-1G*h2#q2MlNie#
+FlAKr`'(q0ph`MVp(96SX3dYqJ(B)h'F3ShNX,hEQPI(CraA+,q4E26%a@U*4G2h
+S*GZQpp4VDZqA6Ni-IBGlai[LEVbSIX8L6)&*mGBRF[Cp'P`'R8-#ZKG'%!T3Na#
+3!-m)-8N-L68ZIi`Zd6(CV9@'cMfh-Y4UGPU0[2,dLj`Tq,X[KR+QI5p6KIl4ahY
+LPcQ1D'%LG1"lQRGkkX`5C4jc2[L!DZG,#8B,5U,`Fq[1G#3r8(Mci'9Ud,jSF#T
+ciQZmAjrirRI0jCeZYIacC+Q'iD#62CM9E%`2YX+JZLEVVGQjbYU*LD&c+[cadf`
+LhS-SY$AS24*%1!"B$AaU%FbHEZBiI&Le*&2dm*m[h!(MBQeX&DQ`Q-m4dY!$bD8
+kHP%6%rda"hqX)Y,(1*GLV%NarU3BRe1-mLR'G"6MGiV4*m@3!)"LY%a"B48MHSS
+40SAJU"bI-b0DLV%IaELIFKb+X6Xc5U8Bhe115CP42-9iN@)m66&kT4ME8S`!+ND
+`&'1!bP%MmhBlHQAHENIq6!ilBQEHEJF8c*[YH+'TL4e&-HqfSf(QcBaJ-HTRalI
+-QaR0XZ0rjXefp0#0fM&5apJFihD-d6&kamJGih@-",S41aQYXQ09M1SaQXGB%f0
+hCUc,MZFamX5i(102M-iaYZG'X%`IfUkLVScJ-8E&'"jMCi`p-N,'Q#)M9BcX-BV
+'Q"BMLBaU-CE)q"NMMibJ-IE)5"TMN!#-G$%qb@JJif#-"c++a@JM)f+-p6(ZaTJ
+KSh#-26)#akJG)cf-J$+'b"JAii#-CXPS(b0DGM63M36#+mfiD'a8e)cUfE&(4Kd
+CKh5MMSa1-LV*b#0MNk!-Sj!!M&'kN8P'*"Q9G118M&bD)4$'`aJTC265MR%bcZP
+'1aP9C066MABbqXIS'D10M!$+f+!Gph0MPS`&-QVTa[BB(@4-N4%h4J8CE@2Ncih
+9-3l(i)SE-Q%iaBfmqX-Q$+-`f-)J#i-SE[L%N8I'C"PjC'5@m8FcHQK(%4PcC%5
+6F6X'BaM6C151N8h'laK*C-54N6Y'(XfiR"fhBr5488I'm4LVBlb4F8Q898Bc'FY
+Nh*049XBecBLQ(FQ%Kc2UL6M+q#hFJh%l0j,,+#lMSCR"(KP@53lhm0'6rT!!Ma[
+UBD#(34i'HKMHBCL(34i'HK"a'44#hN"HmSGk'1Y&cf"FQ2N+aL@4LKMrCE5BN@,
+'N4QbB-5Bd@)h&X`i-#2'M!XMmM*kc2JK)kb-*6,HbYJK+J9ML)`I-YTS4LJ91+[
+!9`@q+["9JFF+r&AJV!*R&6LV`'N&,L[`9S(h#Xa9B+i#Fa@iVm"G"8G3F!F&eLZ
+iJS*$+,L&JPXSZ)@#@bK`AX%V&,a#`5Z8I)+4BS-IGPcBi!!MbBb1-Tl+q'Cb60[
+d$q2CGJcCi*%Ge6-iT-!K"3iTm%H"2`Vm8H#2!Rm8q+2!(`Aq+2$(MLFcrQS`5)&
+"#Ja5i)S#Ea4iSm!E4@mSX%%jSQQ`4i%j#Xa4p)d#Fa5BSm!I"HiSF%H"1`VF8H#
+1!RF8Z+-F$6DiSm!G"HiSF%H"1mUH-pLM`"d&lLK`4p'AM"`UqPf"!`SX925k!JF
+9Q+$!"!8Q+,"5JBm+E&$JJJ)A&,LJ`!-&(LM`3)%(#Ma3i)%#$a4iS-!$"4iSm%#
+"X3T-8'##!K-8H+$J&!T1SH!5#LkKY"8`A%2"+44F3X%I&0a!`8%82%,")a3m3X%
+M&$a#`5-82%,")a3m3X'R&(a+`DH8)r@')bNiNS+[+(Q5i5E+N@E$663pT1NK63p
+THNM6EjVHd[55TTFd[D6T58hrDAT+de1DRY,dP+DR0$fPk5G02fRk5G02'KcAm'%
+06dC@e["L63pVkUDTQkCZQVTTq,1'2f[iS)C$DlLcKQYV1,D'3fXiY)C$DlLfT[i
+D,00`F!fHDALeKMYUZ,@'-fViYBCIDrLeKPpVq,@'[fTiVBD6DMLPKXYUH+@'9fT
+iTBE[DRL`"PmeZ+[Kq"UFe'#N"L-eA&1$NaUFe25LTKFe[DMT3Dd8ErTF`fXe[Dl
+TG3d@D$"!dr1DRYId[!BM0&a4Jp%DM0$JY!B(0"aCJ`-DRUc"!Jd@D,"!Jh%Dr02
+JP!EV0"LSiG%D204`D3f(eR"S$3CUF&1$QaVFe'#3!!Er0IL[`Am09pC`!#d(-"U
+!JQmVH,L#0bXd!S8fS1$IL[STDU%F#6HDJD)HL[FUhUTiUq+YL[j8p*ULca4pT1J
+K43mTHNJjGXriY(Q[3RG3p)b#RbZiX,,Z"XXdZ+2",JfQDEL!KJYSY!X0(p"`!3e
+Id2!%$5I3F!)0*p$`#-dl0*a&`b-dr%H$[aVqSm&RMHDK`9)0(QY`@S2A'Pc@B,N
+'bc9BVZ&''McAe&C6Fdep0(LZ`A-0RQX`A-060(a,`m-d2%a66`dAdh!a$5jVF&Q
+$baTFe[")$Br8p)Q'#fPiNSCVDMLQKYGSZ*''-fNiU+Eq'JkRiD!D(UIK8jUHdh!
+R66pU1*H'FfNiPiCcDAL@KQGTH*D'@fRk9F1[0$fVk9P0VfUiPSCVDEL@KQYT1+k
+'(fTiSBB6D[T3``Ze[*!!mAZM%5Pd(iAZSp!8&0U43[qaNaMS)%CV8'J-QJ!0RpE
+`E!hre["[$Ir@m'm0lpE`EJh[e["Y$Gr@m'd0hpEU*ZJ8B3GIH-fNB'1B3JRj'%8
+aRe@'`bJ'fdl93qCGKdIr(k0G&iF0[#%M-bGm-JqU9h[+JqSeiaYjr%&'P,'fP!I
+eE&M+JlTf@5p2X8P-&!VFXe-H9,V,8aj8[#Y6(T5qUe)He-#V8ai8`fY5(P6&De-
+H9-IV8Ki8h4Y6(Y6JQe)HP12l8Kl8cGHP2#LMVdTj8&6IP2+JVViQj8&jI8A+Jc,
+l`T3(pIDG[6c*-6!Ipe"iVdM[339qIXU$8[lbP!FerD'8"mApH-U$+[r6+3r+rBG
+5(Y6p$kBm6!$X6AQB%VJKj@'5i2U8KdQ$25N28`L[6hQB9(K$bX-Nd'G5(UDD4U8
+m6$f05hQBL*U8mM#jp2k8KmNUjfrAPiGTUkRIb12M+00CAFIbK"Kqp3Y@*5%[Rr2
+%D'*LHfYpqd1Q'%8rU[TPTCU9!ZrB&'H)J%d0cjQiHAcFqDRB&leNmjEJSQ'UecM
+CQLfQFbPHr@*FabPMeHRc*Y[jG(e(hFQek)D4d@'j&[q0Q2c#a@3MMkmhTaZc05I
+D'Q*m6rbr,IjI&Iq[MIpAarm[@Ra(jh'GXKM83X+ha2rhaIpharmEirp0LqRE9p+
++ebL#f'+Ck)liId6m2b2qEer-fV*LI2YZEIKFj6VMre(arqMiIdcm2cEq(lIiL+%
+q!PP&aq$*mArABT+aChCf9BZm9TR'hl5,@R8pUE+P'BEVKm9m,ieYpS,irfL-Zcr
+H(iVr$mIr0mIrpmErqq2r@q,r@q2r!r(r`F9kk-F-ETSFU3"H4kT&[B5!ZXA`qZA
+"AU-ZTQk0riI(rif,Z4U@"am$Q`X(*[RI&2rEmX+B%cR9+L!QqAUp'"dpr(VhhhD
+Tq6pX-9IMiGF2MIq(a2mYLlQ'R,!jAd!C&4qcGAjq[ZpAGXmfpecHfH(mT08%'lH
+MKZq)!"i#`hK'VKNDAcqmTV*QrH$8)(phM!a0+BL'U(aQTLGV3*0flr!0CV`6RKD
+ki0la6eC+49ZBd)TjNY!!CKar%am6&-kZK6RZZZ9Mch%qRrR`k,*p'r84B-kl2PX
+jV[V,2,2PlqCM2YNce[6Q[CXDkY+HUZXC0R[cfUi,m$j`mpI-q60rcBFRJ*P)DG)
+I!4m#TNliQ1e[rGV0jF`imqpYfhGlCEd)4Q3ri%JrmrTf@S3lTLJk-KL00dmF1D0
+9*Q3fedk!N!#$'@ZQ2,KM*Ye-FYKm+19MXTHeR"p'(4lE,LHDm)H`8aIFiA(!c$G
+hq"G-D&3P8ma'-`1q`RPL2"-Q26Bl9DN)$i2*`IQ,qGY)KBHD'M&V5kpCc`J6BQI
+[D82QckGP0kiQMPR!b1Vjq6ZG'fAqRKPqFY"rdaR5CDD1qINC38KKKYEdE11ERB2
+%0i,CIZBBm@%i9e6dCP-Mj`C2'qC1lD`rZI%LB1DI1fScKrFaPiL2`0b!&(91$-d
+,MKpeeSZDF-Im2pi!h$(PJ%F!GbJRH!9`"kpF&0K"R6i@LhAm-(Gi3P`3H%5G1,0
+Nf6lEUNlI"r`%$"1Ydb-"A`(Lm(GBPYei0VQLBYCbqX2d@p4T('EVJ5`m$&C52p0
+,8AR"KF("*5T@@A`dG`K@6+"`"c)bZmmGRKV#DU*k5c$,cahH$!+j8AZ#(J35`8&
+QqlPMAKm"KMY`%NQ%1l`pQ2AR$Qm-XHfUelH$k4(Z!$*kKcZm+*J#!@EaD3#[Z+-
+(K-Nhk!H#4`"hH(2`GZl`bU$1h1&p)GTAJpL$K`"hH%hJ*F!GrK(i#A$(Zr%9i)i
+DibrJi"f0L$X`(FcKMNNZm*-lqJm["ZlJ%(JkF!F'iIR!(4J"4q#1hXBEJM[k$Bm
+)lZJ0F)-lkQM"hYcaCN3,lSM"1i)lH!EH%G`a@5&#C+2H+Ki6L4b[M`VBcKfq+8b
+kF)GR#Ah+(6iN6+a`KhF+lq)1la3Q6lM$"d@mS"VY-cJ#GhL,#-YXe,X$0BFlq)V
+-4$EU6m+%#(IiH9!Vl["6`EF#kX58UUHr4%k3!*2K"m-GrK,iaA#(PiF`Z5Ca6Ub
+QQm4FDXiGrK[icA!(IZ%l`adi!VrLMMk(Lh&(2m&aZ+2ZBTMEC)h!,ZjiJaK`0ZN
+PJcm0Gr3(rF8GILc`$ZlS$haVZ-0r"EcL$Jm8m*ml2%c`Xq%1(aCmEEM$Xi3q09q
+c&"C-jJjZK*m-Gr!aZ"Khm#+i*(IiPH!h`aeiL4m0Gr3"IMAFd3IieR!(VZ&I`af
+B!LC`4fq$eGc49rMCF%HYi92Fm@CmEEMM2A!ClZ$1q0a`"jE!EER$CiGBlP"&)$V
+F`A("(ql`Im%2KcY`'PmFl["h`4q(1caKm-RK$Zj)2jT[L2L"p`phm'&i!AId"pi
+rh)'le)3lZ!FFK$Y`'3mKlX![[)5iSmrKM0c4*h!dlRJRhN,Fi4-%$R"(Vq-*`Kf
+H0IJ,FBFR$I8hAiXF!VmKlZKMq$jhm!EmKlL$@q*$a"eiKKm4Gr!LhXXGh!1Zc4f
+B$Mjc"fk#4Gb"4hJ(F3F@L"V9BKhKGp`4!aIQ$Tk(pa"hq1R!hlQMcq#NjKZUPJ'
+qFBH4-jj%h+%hi%h%(AS*(NAF`62TFHlJBrJ6F3F[`UH)1hS1[b,Z`'@i'hIJ(6h
+&(4J%eq!1,)!cFNFIiQ[%(If![a&h["1I)ql`(!*EZ--R#El2(9J,0c6I-2%$rX)
+G@![[jJj0"GcQMKVMBF3G(MqmLc[k%NmMlUJVRNEF`CI!-HlJ'23AGr3L(NIFJBP
+J"AGJ%lb*1rS5[b2ZU#1q4pca(VJ$GhJNiB0N[Z&b"IJXGfJpk"MFJArJ*hG`82U
+D1cJr[)`lH$9p`4dm&Tf"1cJKh)3lF!@[+1lJ-r"PlZ!9V(R!(CK16EJ$Bm"UlX!
+JH"phB!Gib"hp$0IQM[i4,i6KeS,Hj!kY#mmZml@+2AKhFBH'KBFAGiM4j1'1'X-
+VZB-$@IFdFiIIM(F9q6jpC15bPAVMFfA[m,U4dHe@*rGNR,99rb"C0k"9Mb$4reV
+eqa$pVe92$h&DD0@$4[5r9[eM42r$q"SI,AZ(4jESIfek"(Q,A841eGG(p,mfrA'
+B,1F1hae`L6[mHG!IZ'1b8I5r0MhAi-lFi@&KhQM[m$J5rDp0,a,4rpVd(8'li!j
+[($(TEG-M"pcM$KmFdIrDp-!3r@m%pEAV+A#(Ra%H80cK833[i!lr(bDaZF26KfP
+Vl[!KNY8K4ZJj*2VI#,hMd(bi`fF1[XmG[NkLrih3I`N[,qlS[j!!P8'%N!#!ch5
+Zld9UKQh3UIlaLhZ90LfCB+HE04Mpm4GQjPMU'f(#A*C+bmcjdR*"KRLhZmQ08,H
+[Ch*Nq,54CMF[QRQh-McAEV5+r0pRT[Ur6AP)1bHILaTp'0X(QAcISH&iEi$ZScF
+mlc8)0G[Md%K)frGH9Emd,R`-A'LIRcm3"c&#fVlId9NjM3XIZD(i+B6ERML)&Y,
+frD(ZffPFq+-ELX(2N!0r1!irK,&p''UB[j[90TPU,PNEQM`-RQb*HFS@L#B23bP
+EBakcfP!j$`-V25N2`bcE8Ki'AEDRqM$XXMrQDAM31X[NB4$QPT5()CPE8ak'CJk
+Q2!c8(%Tj',BjR2)`L(0EbX13!-k4P)F"RU-T$m-kGkBm$2,FPI)`N!"cImT$ql2
+pLMH9AXQ$UAKGbS24H%[+Jq&i8mU$+IQ3!*3(dr,QP!GMmk'p2%@V4*1(3IJ$k6d
+-(Gk6mQ!!-5cP`FKKH-U$FAaVbS-C4&[+J`(pL*3(NrVfP)GKpcX5rM!dqjb8Kb(
+jBbN2`q1hTc`-'ADN1Q+k2c,P`C5r)H9KkBXa+3p,B)a2H9JJBh,+``$j"hTmVj`
+(+mI1p"i'(UI&2%1qPBGP0kBFHdq)i4H'X#E+2fr"9&SEjIYlr)6!I@'"`h2@5$@
+XVIAp,b53!%`d$*`dZh&N+M[`fHJ8C,BRr2`AhD$'h(AM3,CdGYQ"6pqFII`(Vqi
+krM+"V@0DaSBhE8%[[(kU@ZLPGYrNe1BRF[r3a)4HL*&hEklAp)TkY*Th4C82%iq
+2bFIE4DjReZFf0+VQrIV8Q(iBNDpGN4FG&*8KkiZ@8Zr8dQe2[QLp((qaRR$4hHA
+)KqGhG@rTUfMpEp565cp'kX-@1$-VjIicGLXF['%mMl&l5cA9mjfk9hqpPZKCC6h
+[6NY#rZjHS44HRrA9rYB4iH`*Vmmc#!5CUV+8f6pZ!a"Ep$)@PCJ$HhV$[hmbHml
+YhaU[c1RhKTR3a&4,B%(QHX@DbarGGB)p"0dhPY!2ZK)B9TMe*`h@Y!r&JV*KSYl
+8KKClZmEU4%[l9@chQXC'P!fX09ac&`0kX5`E-TBhAD%+Qpb@,UELh[T9N91i-[9
+NrEE)UPBRjrfXU49j6,h4m!j,aYE*A5hAVX)HX1fCGCF[X$E+)mCD9h$('N4Qci%
+EZZ4MIDE)k9bCfV#H915-Ur)K9j!!`TkdXe'h0U`&&APXc)GYiZMZd"6eBmfSb&R
+GaQ9BeGCTIcHfhKbL0R9DXBdEkMDB$+l6&RKmBcCRkVK1'@4#im4*hP5RGHE%UEa
+M2Q`m*kd[P%RUY*HF2&98XEQYdj+aka3#c4f@J&K#QqQZU"1i8jZeR0k+ZQVCY,V
+2L+a3fMKVfEihB+-B&H[%%XlD&SXPA&3l5,'%LfSTLBdhGr3L0QG'ZUNAJE"bT)A
+j2f[C[YFbE9b[*H,Xl,JDr91[*DKB3YFl`5Dlb0CVIcShi%'ppTlc!Kl8Db-j2q"
+"[6,1JS!($8lK,Jaid1$+D1F(2'M3i@&4`)-'LlXii%'$0V!A"$aSd,Cd5F#$"Ud
+eP`BmD,![Z`-H0'T&Z#cJ3D1iY6cJ3D0fDLX#(M4U&ESbp,He"Vi`i%'MY9`9m+"
+4kd`QE8hr0@TaZ5EQ`iCaEF#$*LHCe`8mD0,fqU+!"dhfjIU!"deDafi)H0#N4Hh
+'J!G0pZ@QJ!G0@S0Z$RM3T(hPPS!(eZjfDm#$CLd"QB3e&U$0@U!bl@TUhDbe-KD
+fc&GKb`XZQhkfYV2)C)DR0@Z&#KBE'd9V)iZ9XTN5EpBpJ9SCI"NLaQ!*E55i)GU
+YBJR08$a[`a,D@"X1dIlbXN[c+qR4)IDPXB51JK0$l-[,4fEDp-d3mIk+LDd9F(b
+)eTeAATTG62eDV199MEBeE,'@9iHG&PVN%pFd@&r6h#%[AVZK-X)l@qJl,+(T[aD
+YG+m2q0HLGHDHJ(mYpZAH)&1fL$&Q1I)ZV(f(1K&qif6H*FP3qr+Q#TIQMYlBPdp
+@i5e$R8k&NaJq0&3,BV'%(UT0VPK#$p8'9LbKKfSh+TE3`m5BJjplRQX3$"0E$l(
+&P*%kKr(f52YMChH`A"dQ0lTYjlS+9Uc@k[3)2U1Q"iD*-8GG0X,FB@plM0+Ep`l
+6J[9fHX[JeM"Y3ZmBBE-#dl,djA2fV"X%$iEEPhIZkSK,`m@#Zpbl`0a4ZqHLjCL
+q(QjIhKhH0e`Hmlc`2QXYq[afZdlGKfY9HSpl'aMUK&[!mBYRkp5j94jhEdCbF`F
+ZL#9dUpa#,+&Ea6#aK'l9fPFXS9[P,Q)*MF@RXi4Zdkj6,+(EY(mA5qJf-88XSGZ
+dXaC,k$CYPX85ZNhF%N[S0RYG,+(Ej%CL#6e#e`'aK"iK0a*,k"&LQ9K#Mp"'@bb
+K4fMT,*E3f'8k5qJ4@YH+*I3)E96&LDKG'9SXSG[P%')*hDiYV&K#YfZl,CE3l9S
+pLb9dZdD3!')*hDjPVPK#Yf[I+TE3(ES)L#9dKha,,+%lP0A%%VV$(K0,k!kYPX8
+5ZN1X&8[S$Zeca4,DZTb+*I4)TAQaK"iTpaG,k*(DUSXPp%Ml@5bK4jTA,+&(DQ8
+XPY!Mj59L#GdTrSQmhLPI&%[S6ZhZa4+k8qiVPY#GpVPB3RIk0V'%lY4#@5bK1m9
+AXB3H*4m95qK4FNkaK"iPISXPp#KYf-85HT6p,*E3Shbc@%+2dNjC,+&(DI-VPY#
+MGI!35qM4fUD,*I4ShbIQRD2&2,'%(QhrLbAdD0mTPY#Ma3baK"kYhDjB3Sq4GiS
+Pp"MjM9K#Me%E%8[S-H+J@%+2XFI%%RU-m@)*28D1,TE3Bm9TXB3H+fm@5qLa1UQ
+**I4BF8J'2FD+&f)*2GEDL5Ad@2QI@%*E&eZaK"iR*a0,k((b','%(LG(%N[SFH+
+b@%+2Xmr&%RUFla&,k((D'SXPp(MjX9K#MpFH@LbKamZra4*k[2aE,+((LhGL#6h
+HAK*,k2(q&d[S#GUML#Ad",&(,+%Rb&2&%RU#j&!XS5H)k@)*28&F%%[S#GC),+%
+Rb"h&%RULqS4B3Nq8CiXPp%6aALbK*fUR,jE3%m9VXB5H+,k)*I4%DbD@d1`$l5b
+K*pPRBJNp5@`35qK*BS0B3Nq51iNPp#5aALbK*iNMBJNpb6U+*I4NY65aK*kXTL1
+Z5*2&Bl'%RU`++jE3Nm9lXB5H,'F35qM*B*Q6r#E6Efk5QT@pR59dPfXDLN90&qp
+cFQfA&XaL#GhP'K0L#GhP@SJbG0)&6MK,k#jUjbbKTp"ccK*kLZX-LLAd&0Fb&%[
+S+DlP+CE38l3r&N[S+DkI*jE38qKcC`NpPEc1%RUUkb++*I48ebB85qLTV[JTPY"
+6A@94,+'RZK+M@%*2"3HG*I48HXpC3Npcl85aK*lQqSCL#6h0e42&%RSDIHBXSDI
+4Cmi5HTUVm)NPp$4`bPP#RdAr1%[SXeb285bKch)94,'%2N[A$l'%2X[e3m85qLc
+AmK2plbcAk"2plba`c9P#RdeIX9kM[@1e4V%j2PXR&Y(rcYCp"%l%(DZ-bNSBCp[
+(S[qGE8q)rRFf1-9DMRc6U6[V1GSlqPK@`TMZ@SUb%XCd9f58P6#QZjUNV)3ahA8
+"iHrFXDSL()FlJf@Xp-Jh`jj$cq'1pl'q!(IJK+b%-81A#h#E1pDDK(G`a`U#XK,
+'$([1p#cI6(#+G4hY(6dR+f(-G$e(@3PMTUY!bNSB-qdj@3PMTUY4bNSB-eeM8&E
+#Q+R&ZDb%F3kiaPU2pSkHNj8`cY%P4eE#1-F9)f8PM(0F+e9@`MM(05YP*BacA)G
+39X)iajk6P6$1"DIX#L2FQEUc(U5p`ajG9X)iejk6P6$1eETG9X)i9aYd@3RMA&H
+%P*8`cVARC#@-@IDdV)3abji6*ljC[Np@`TLP8iQXK$(,062&hA1@Db$+5KLcA#p
+59X+BEFr*5KLcj41b%XCXHdj@`TLYKLmVBFc@qPa@`TKYcmP+',1eETH9-'DlSU5
+-)ThR#UDb%XCji"TVAGSlHNkQ8Fl6CPe@`MM2e9e&rcY21h[4rmjc*8A4rmjcc8R
+4rqEBFl)5aKa`LV8`lCfT1qYKfMZXff8PM$RfR-bLc(&e@&N*BiiV@-UXaKbjKDb
+%-GHHNj8`jYV6XK,'A(Y19X+BkrYN*BbjmL&C#@1Z+cR+*-GFEHYP*BajFJYC#@1
+H25FVBFac$3"C#@1H25%VBFbcjd6rQqIkRk,rcG2@Ar5rHDk"+IVII,Q&k(rcAGP
+6p,rjFJ[4rqE,%8ArQbq1L[ihhe9#4IqE,dF8r@qqp[ULrbe`E9E4raCSSbrkh`*
+l6[5r"Fk!L2kh3'iKqYm#ZBASI`YF@92d[`@ZXbMkhd*A%aApEk%p*rVI3YmRqYp
+#ZBASI`YGT96d[iAbCY(r&XSY42mlhp9K4Imlhp9'4Imlhji3rHpmHdld[r1T1bZ
+DfMZ`Ar5rmee,325rmm8jdIm@ZA+Xk(q,A*&8p,p&VJSUqYmLZB[SIi[NjD,r,A+
+PAG(r&SRpS[mY%SG%re[XbUDLrbffjd6r@qbk!U,r,CC$LrkhQ(jJ(94laqU@S[m
+YGK94dIm@ZckNk(mAf(1LrehJqd6rZd!q*rVI"ESELIjh!E9QV8alaaUCS[pGi&U
+MS[pGJ)E#fTPm5q`2dIq@Z&+#k(p,A,Y8p,mPpU,SId[N(+,r,E'ZS[mYN4q)rVG
+%6LRkha*V,2VI%VQ)k(p,A,Y8p,mPVN8UqKqqkkbrDHrS,G(rPMV',2VI8PFm&Ie
+[UBjKS[mY&AY%re[U@JZLrbf9pi[qYe6X&re[+6'Xd@R[i!'Lrbfe[dArklBr42r
+VGL9AdIqkl3r4rlVP6+,rGDYYL2lA,GD+rYGYIiMqeff2L[lAEAq)rYGY286rklB
+HS[peLm'Lrbf6YiRqYmaq&Ie[QEa6p,pPVViUqYmb9h`9r@qCXf1Lrbd64dAr@bB
+I&Ie[QCJRqYmbqEVSIm[%E0(rPVRDTZKrbq9jS[mYPdH+rVIFZ624rjDVEBMqYe`
+R10(rPX[242pElMV)S[mYYcp%re[ZZJkLrbfh2d6r@klf*[VIFVQqk(mVe"*%reX
+K4a6pEi9VdBVqYm+C*G(r9UKeLIkh`M@'42pEBHq+rVI#PCC&re[KfUVH9H3RAIY
+8p,m9VKNUJ5[!-PElY(F'#eMadpkCrQ(96hYRDX(+Rh`VAI06p,q9VLJUqYp+-)p
+931dGUkD+rVI5Y94&re[TUV#LrkedY9I4reDkJU[SIbYGV96d[j@ZmbVkhdVA(4A
+pEb@pa9UPpXld-'Z1mPe),9LRe0ka)URSIaHkiURSIaGD$p(r,U4[@028hY%VS[p
+Gk)U[S[pGk1UaS[pG#+k`[LRI+RU'P8hYRAN$Dj[D1eC@&Ie[P5ZrL[khbRP$dIp
+@ZFUXk(qVA-e8p,p9VJSVqYmUed)5r@m9[Fh+ThbVID[SIkYGJeAd[p@Z&#[khfT
+`La93l4hVd)VqYpS99NAr@qekV+,rVAD09Y(r9S0pV02+YiEqC1e@HfIHCYG8iSl
+e@%Ar@q1DXD,rVA%0@p(reYK2S[qYF9eDdIr@Z&kYk(pVa"M4rpD!@DcYbVH@hQ0
+e9hYRmV,#UlfMaU,rVAApA0(reVVUVHKrDm8jdIr@LQfLrkeeV9c4rpEk9Y(reY'
+hV2aUlqJRdIr@ZEUYk(rVA)&Ap,peiTESIq[%+Y(reVNqV1KrkebY9[5rGI!+9Vl
+PBpNeeX+eG`B,@!rAhTQkXb+Z[@20@p(r,K)[4Iqlb09h4Iqlb(9K4Iqlb&9M4Iq
+lb,9e4Iqlb29j4IpE$qkc2Ukp-aM('VRfc[3`kq6D1r0qeXUeGkce+rVIHYIV&Ie
+[[D[$L[khAJiKqYpkelF9r@mpI)QeFrNfZ#kXk(mE`%h@d,9hF!A4rcEiEY(r0[K
+ZdImfZ0U[k(mEd%&B1GMHXHDXk(mEA,p@p,m0m#T@&1EEk,UeS[pY"0GB9GMHQ9j
+PC@&lCpl'kX,fMTi@r@qMDrk+rVI4eAj&rpYSEiRqYa(1b@V$I*[N!D,rEE+R4Ir
+E"0D`mV#p-rh!kX2f$S`8r@q6EaApEj0i,2VI*[Q0k(qEa#h4rcD*@k,rE4BM4Ir
+EE$q*rVFCM'"0BAYRHS"eL1dGka+,rVGCr"$pEl1i*IVICYI$&Ie[XlJPqYm@9li
+9r@q,DqU+rVI&GAY&rpX#"YQCDqlJ(k,rED%@V&jXleM49r5r,Dj2,2VI&YFd&[e
+[Laa,p,qYiSISIeYGK9Id[kfZmb[kheE`MV@0lChT6eBfYRIJPZKr@ehE9r5rVDi
+9,2VI9VQ)k(pEIEISIcfq@r5r(R&,p,mHF9Vd[alV,ITI$lh01X$fcY51YAlY(9a
+%p,mHZBMSIcfZ#LckA`pmRY9mqEDj2V$SIpYmUqKrfjaY&re[QaJTqYmfDbckhcE
+HcfV(pSkH&[e[QcdYqYmf0![@2HEElYUqS[pY&lG%rp[ZQX5LrffhaU,rE3FI@AR
+ChS%PS[pYTaDX[fc[i1LLrfehY@24rlDl3V$SIc[N(k,rlA!eBp(rGXJM4IrE)@D
+)rVH$AQ+GBR[(UX1Lrqe`c@E4rbjf2@(4rbjf4@,4rbjfY@E4rbjfK@R4rbkfEd6
+rZjMqBG9QH`IA&rh[B[Q6k(mlAA9Bp,qGVPJXqYp1hbIkhdljK1Kr1m&69SqfGh!
+QdIpfbZp&rpYTr86rfb@(%2e[PkXHLrkh5b0ddIpff4qLrqebr@R4rhEj2Y(rGP%
+[9Q+fGq#Ck(qla@r4rhEE(k,rlCDML2khfrH*rVGEc8$d[peb"G(rGSXVS[rYMUX
+[fc[d#G(r,T&2LrjhLAaDp,p,A&GDp,p,A2YDp,p,`&r@TEChk#kLree#h9N&fpl
+"+8ArHjDV*B[qpbaAB4Ep,r6Q-`KQ0P,F2ZP@IfB[aB0l[QX3&!Eka6G#-KJB+AG
+F$&YT!11#*+*UL0YR"d$-'%Km(8V-im,H--&Bk"cVYYF0$1c'Dfe1ClEC2pfD'@J
+AVGVXG,FcX,ZfCq##rJX'DUhTcN#eABqc)5%MAh&&Mj!!PXqbJ[!DZfUfq3L&@E-
+K$'(eJhT(&G1pPQimQGZcBF`b-KX)MM1rb0`LmiV-+9TI3R-bMmM-),1)c!XbHmJ
+X)[1#GJPkFc*hb'`JXi,-!M)rb"bJc2q&+Rb0#j`NJcFRh62rH@q'TpdjRmU6UQS
+)h"F@D&CX#&efAfA2Ir,[2RqIjE#%$3rr$f1UIBdPaIZAa9rX2S2K$NX0"N5h8Y"
+-T-NGqZ,XE0FFGa$B-p[SeYF0cADkVCQ+hU1(LKVZSVN8UkGCLreSCD,DeAdd&im
+(+rkMaR,ejZE1"e+XVhYeR3kNa34iN!$ZKH%G+kS2a"Zm0K&lmd[bjS2KkqSGVEm
+2E'p!%AYcb$"EEc5+NR'4,E6*h-!H$V5TC1%"ASC,UdAc`4U[h6!QlFK(EYTF'@p
+hkc2eUrlME4LE)jmG"J*+iGALfIKRMAdpe*[cmr5j(G9Qh[KkNKh9cR5eFD6kNU+
+[r!`69PZBm-%@6X`MpNE['0l`8'LP38cikXl-0aYJChl9NHTILVXeaDeNZ21LThq
+lq)4A#NZdUjlmlbS4GDY@b-Q%aZkh(p**8!&dSQY`6S)UQ"0HJA+Lbd$ZJLXBi$)
+%MH*L#deZQk)+i2(i)RlCq$ai%eH"EU,,`"d,,KHX!0S%$N!f+@U!R8K3+AFCV&e
+`IjZ@J0V&CQ%k&PKUK`T%%ed"D+,li*Ri-MLli&)TI@"1"TYUpF-`#5S`6(30KNP
+3K@(#+c"-G"Q'AA#P[ef'S#PFE+8TUM!FMbrLNSh2`c"a&4JQZJc$XH"b`3S`61!
+!$*1L"X1*"*9bPf(B"IHhD3Q'A@`@KQ1"TADS`$$4&4JQZJq'L5r$X!XZPE)-`qX
+(Til#-!NU-%ad$BC*8)9K`LX`6(3CKPe`TEpGKU!TA'bP+DS`()m[iT+0cm-`F48
+B*VS-`l(JFX%+-%cJ!!b6SJE$L359FTGKf!AhYfN*KPeX&SCMJD9fU-!`d48B*VS
+2KSN[`l!,,T8b"m1RC+P"BHU80(9#R"U8T`B%UY-59Ep)05"6R45U6NT9&E&U8+l
+kVVKd5Pik*6!05%bR4DCqQDNU0!e)6B0Ldk$FG%Vk'44r6XNr*`5J33PS3!3k,32
+e#d%$8Y"*-HLN(&34K!BPSHm+1+FNR&-LcS#-FeV)kCGbUQ,1J*`c+1J-5MURj*9
+"JH@8a(*#C"Q8@3D%PY055lrB-L#hR"4F6NSZ&G&P8(EjVNKb5LBj*C3-5#@RaC*
+qZD3UQ!a)*S1LbD"XNT`B,8NBk54jZ%YR+!*H1NN!HHN8HG",CmM"AMj"[Krc@C)
+GQBp209kQF3,i+q4)BdXQK`q"kGJm#+BcP'!`RDB)K-8NrHA+J@%q`FRfb`*L2Mi
+1L8&`AfrQB6'GS4mB+i*(1NNr-&C%Mh55!@$X&6l5'@V!@"8rmPP+R9N83$+0-`#
+-C4%NNk-A'(Z&N!"dKP2!@"&$LNRkbe8$aUSNNXr5ehjPB#`+)lN%9@$X&8I5d*N
+EH3J5e2!j0IU3!!iZL2RT($P"2jqJMerNK2ed(p5Uh$YM&@3)UPbH(%VRU&@j-%'
+8MkqU"lND$ik[9!GB6JjN$)aNp!pP$)aP*!TINI$55IV*@dA'5bFC)'qp8Pik3if
+m9H@mI*B5)"3P[8cM$*!!Yl+XPmR45pjkTEedKP2NV5,[&C2dPkY'hUSLAcj,ArZ
+9b9Y4kXXPU*+hV0bApiI*iQ+3!#-*Ld'#$#S'19+J''4)BQ)K`FfG9M0@Zr$%@h1
+XE-[K2U+@iT-GA8SL$9d+GbeED,F8QPC5a0#TN!$#`p)J0!QP33+IiTAMqdVS5&i
+3Qi2T)%X'TDXjDQhJBh3TrN4$*a#k&!j!Pf1VRC+%jb$"#A41XqBJK8qE5r(9q[V
+%14-IL*j"MKSr##62)%Fr2mJ+RS8%9AjJReMK"aQjY"4IJj1d@&S+Vl9E2cr)+k@
+&&%9qN!$95B-%II`JUh+9%q6j39'$$E)-mS0!J5hNU2+$J[jD5P*Yk")rb)L[[I%
+9IT!!P9k$"!2m)#-CPZ+VpHhM"i'Z&Z5SmB0!93Ybp21$V+C@5&$P"rD*&Ak3!&(
+N5[%e1%RVFDA`@V[emi1m'&G)8H3(@5NZ50$($l)DF6P"RKm8CEiJbb!r#%5q3Si
+U2bK)I+8NeBBZmB1-[YFEAq%(*p5p[1SHT1MM"fRG[46ZDJKiTA0Nq8'3!#2*$i)
+%'Ai3j%MaJb"$NKm%#Ab!,m8RmD#842UP&&lVPa6!9e,%N!#YN!$#!rJJ0!R`33)
+Ii-[aI59d!"r%jJ!qb*)"q'U1@K[i!&q+2p(3#B![K32`jGKUTb3"2NL3!!6i)%%
+Di)-82X#AiU[e6IVbQAS1!Rb3!#-*m%'#$-!(19)!(f4)!Rb3!-!(q&*m%Jp+5D4
+I5Z'eINN"I#9&$0N++6b!$d+6!"mNm!'q(0pA3JI`3@`1i)-X'B#[jULeJ3r`TIJ
+6$Cd!q&)i!&q1VAC+%Z#$"%Q!$a+N!6j)i30m+EjDhd%'ElYpDl@jFlDk-rmQ(X3
+bP0k`VMAp-+Vi1GK1*CK!F(&*8Z'#-N6#aDA)JiY+%JBAj*-%2bD*)hkJp*BINUe
+K#[46B6'%Li9ji1kZNi$ZJP)pPi`5D%r'C!T5DVBFI,[)$'5Ril*&p+(CMbQd83+
+#r4"J0hQIVPB5APe3%P*G8"T'ACJ2RAj-ZKBq4")6f'5iZ#`X"@BB,Li(5eR,#aH
+8JD@#XB8IQ+KKaViL9X-F,190+Q*KF9M+@P'iS"`XC3E%Nc'CJJ5`9$5eF*%",!A
+@&E'i0#`9$#Vm`(3EqE#8FCj)a+4J+HX[iB,bX*3CC[GMdV9)`e)!59Ni#U!S"d0
+C#-V!6`&kdV#6JC`mh15K*J%c@BM*`8X'@V+`%N"+%8i#+!PJ*!-K"IK)3iF2'aR
+)b-*&$LTL5aS9@%Fm1XXpiU%"!iP(jhK)2$E,4Z+K'8k5LXa#DLSm!@DT3"p1%jA
+2FC9-F",X%m&ahK)2bV+AH'L1`k4M%d`Q(9NXAF"UiY&&EK12$aK10VUhp"QfNiU
+X0QLDqD3#(Ip*4a@UQq9#mG"HQ#Z4khKd,mb9L(BmZJ4c"G)G$bh#A*Q!Tm+cA45
+3!2&%j8X`ed[-%m%CQ#Z3!24iD!RQ!X+HMLb@VJ*c&3SIMkr!A)R1*k),-&HQpUR
+`3S2QB#iJqmR)!1B+a(pVIIY$A-l&CL(1"3B!jf*cm1BLXq$Q!M23jXGPqmB26R5
+0(qCh4kc118K,K5Dl1KBDKc-ANJ8c&jL$XQ4N!XL5F8'a!K"cX88)Fp%"J+9M#iA
+1J*FI9fl"0($jB3kfNM(jDQBKb`9Q!@[Gk'KP,C(R2!"CmHJXD-9$!pL+4qH!+ak
+EKDjiD!Dm8T(ChNQ&*lSR&HMh5U,b14$,"#Hl1a%F"l*i8"E+iU%j-%[(*Z!X(9N
+XA3"TmHJLU-AM!eM,4[H@2J0YUFKUJkEK,4AS!#iG9DKZ&Z6LS39H9K)IA'b"Pj@
+%"aGEj'8&dF%&"VbX,$Mi`@P5%)J0X6SAH9Q[d"!,6I'bJXMJ!SZm,"!BNR&"X8U
+mV#)YZ1J5,b[*#V(B2#mV5`TqF,i&-l`X%"-5F6PH9K!5iKV$ZRcll-kGH9%*-*5
+1AMmemB!bNCmqL!GRCK"5N4I06HHd["RG+V`X2Db3!!SX#S@9%K)GP,"hVLFHA#b
+KLkb@-$m'P!S-q(433"HE+Tq,bKI2K@C+jmF9#ZFRb!X$3G&+`"'M,GQLpB+'#`f
++9J--2d%H0BYJi5M0KNCV1pKGNcG0Q3j8Qc8I9j!!1$hQd+X@!p!$Mb5&HF1qmmD
+rT6p+JV,1+2%&h"XSG%c+kLed,,jFD+F3$6bb9ZKdJ[,F3+l3[R4BU%"5VmX@14Q
+G,l%[JG@Hee[HI(L[k&BXE3fUNT5h80SqQ2*CC1ejeG*@!#SIA@#@)23!FT46q05
+N9X'"4bCTc-lC*KNb%&J)cr+f62$!``LI[k"ZP%M%JV,VZQLl'iUUr#FG[r$"QBE
+c+i1e@Yf-8RG$RG*PlAmp'ITH6hcKp35@AqqkT[4f&epmZBY1[pZ&e9lGefmZ[[,
+UI+qjX-+V`lbqh'j4N3heSU-fHp0-hZaQkm+DBE6rTTPfUqL@Ll,e6'bpjhT0YG&
+Si4Df-@qdXl'YPD#)fN5ASQ"BfC!!@b2+49$fr05C$BV-CYAQ,CHfLNDYIjTellC
+@K[TPKHZVDjpD[rbLfMRpP-,'#FN``9k)8CR0reLZZIIN-Z8)AJ&6R01)1AD0M'r
+CCKBEQeNT*l,Z[SK-Aj!!*&ClZC6DFqXTPC&Y3q-E&KV!aXAl`5D9D[(!@29LYhE
+c[4ZVdrPLaIeQm,0kpA34UI+C4V2PbfcX%PRA@m`aPG%%jc)@RZ&D)p13!,'fNiF
+PZciINNP$Gq4$-QQSBMl%KjA$"j1QA-d,9ZIj92&#T)0bUH,&5!GYU-lN*IXb3AI
+N"9eYeLE(81p)cZUNM%dF+V*S`HH(G(ppEEdJ*TZ)!J8af858*iM*@jAi26lc`[V
+pH*X+5SANE8dLk`Jm8LhUH@GG4$6hhh2-cF&q)U-Rr-5FG5f`'a[$JfAD&,Th(iD
+$iL0FE40AA@[(k0TE+j[bDZ%i8+lmX4GRHb!H@BT,i(iL@5`N8b9dX%20GBG)35Q
+*)`[9$V06HcNZN@kKFM91p-ck`bf6CJ@C[LQ&ji2&HL5blZ#&Q$ji!F$KFq[YrU*
+66*FAqrah3e&`FDaDCa9)Fh'S8mYMT1'GjYq0+2EHcHe'F(ecLi[EZr8'IfmU0ED
+Mh1`TVQahqAqXHf@CB%marC3,`rpMeHeFl-eh0+TG(h1Xb(06APr[qVGlS5VfCPr
+jekY,pd*KZJp@aZE`8NPYZ,,&k9kS6RFX6hH[2Yd(#p4pX%)Q`LX4&ek0ZRY&kMj
+BTHjBTKZVHmSiqHmpfUZ([6K3RHjdChIX)0CFlDfA98X%FHG&QBY$jFYL&h%3-E-
+,92&)8)RPdS(0NIb+HJHTLCFPlVc+QKKhBGj&!ab0&A"h8S"i+@bP[2ViY6*iF+M
+9f0kD+pXJGV82@H1'SUaAr-VGQ2caUpZEpEP'2E4,iLjfCC)PlZblVbX,',mbL'A
++[@Hfk*5[L&qj'pX#lST'1TbcFkrA8pk9Zr(H*9IQ"Nb3!##j1Pc8Qpfb4q-hZeU
+c"@`cNGS2L6@0LdQ8aBAijABaLAC*[-C9a)A%X-i&a-!Q8j98S@*3NkP+)X6[c8a
+9dQ8R`'*c)NlZ$AqjP$&%2f-m*,8MYL8ImHZNBZd(`dr@6lB[hh'`X0!F`kRNJGh
+ha1i*4(N1"Eqq,&Xk9bEq-(6V)&U$Akp%61`Ud@'*Q)6Fl"A-A@l)ZaYDphC"2)3
+E#)VI2BQBj'#TpkciYHQbJke!3e*A4pZ0ZL3QF4@V51)PANI0T+95!6C$3XG1*,H
+j2'S%lh)APY6k!1%&q"#BM["ca&Sj'4$,kEGP1Q*IPM[KZQF([54hA#9kbBp2"AQ
+*BPG"q,kib(YLr$@lfAYfr3YrMMFcZjZDedh1k'EQj6+@X9NhdB5cTKYP5mrGTQG
+YCEif2RbAmR2-'#HQ"eLcIS+q-@$@#6(K#ZJF$K-1II%Te$flUX9-p4"T@8Z)DC&
+i5*iLq5hU3V,FbQpc&j*P*$Rb%qIEQHFR8k6BQ'-mlMV,i(,X+8r&mTc4alTXL%P
+mY&Fc3G&dK%NV%I&H-h#qDblm0kK1#KI"K4GLmL0XT9iN%BA*Xm+mQ%'b'jTA,$i
+L&R"J@X3i8K*kpm"ib!'(*2CFAK-824DH[!qQGA)61SQTR0#a5Cc3KUq*A@,VbSf
+RSb`-fl*dh*Ehhq'c#q5#"k&[J*!!`)1'J!IGpDXkZiUJ+R4RJHQ'XH'"q9[(AXZ
++QF&M4H[jHE'R`d#A'FbrVR!fRm'1ZdTpfNb`l3Nbfej'4+qVjF85BfL4i!Ierid
+(4X)00k-,#6aJ(ra6H""f4Ki6H+!#(RJ1,EHhRAS2Ba1A%RMJk3FKE!K3a!0lUE-
+60l@`GHVlkXE'*ST(ASfk[AYife4rifLHR#e$kV[hi$[Z1[U1[*P$pKfH"D3hCeE
+i4Je16)`q8[PV19HhfrpCpbIHXAEmQMh(mKJI&!TEbl'fdAPiH1Rd1cE[,REdFcj
+6elEbV@[A,`h3(cXR0`mY$I!1Lc$AlcU+-,i,6qpRhh(6p*&hj,e*NPm-1IGeCai
+"%IZ1r8HlqR6IK``JqB([`8Hm(J-F"6HNlliM&)"CA$ib86RfeX%qSqr0,1Ak4pl
+"YlFe2IY)Mi',eMdM&1!GI(1Q'`aVrV#ZpKhlUppMThEZLRHB!G`IpePff$[cG5d
+p`5KlaNB[2TBRl8C@V2b1dBH4kV[[#!eJJYX[h[KI#*bb95Ym1dCEfjF'U%G)"6-
+G`2+NY9cY(E21A5VJ(Id&qIYhe)$mIlpMN!!422'1'qD1&Z68&cDJ*2b`le&X3JB
+8J)(Z5,ND9[[M-#iB)3([f(1N3`El)elA2EZqMBarril$4pMlB&eMl`J28%L1jMZ
+A#-#c8!#P*Aa#f6LkUr%`AdalFKBq()A#!Gl"0iFQHDDZ1`kqidG0B[@'q$i%a54
+$PTj35%*101A`!!BA+U'pKLXJqHN[krH8q5BYqD%*QY,f9[jT6E$bMR#6kC!!Tc5
+iFRGm6i-lmBiR0EJ6lhK5Jc[jMLFdZ-&hK&*SF29lEpR2"&iNHrc@ekeF1hBUpar
+)([r'IGRM2RA0SET1ZR9p0VlbcK9hR2abiq[hhPCEU%F)J`CADE5R0EM"GcbT`I8
+qi`FDh)Ph2+A"&4m54U$"pHF3rr16l`J&B0bBV!r@,'[%R[p#2l5m-U"p6mZV-TQ
+`!#f[jb%T3VlfSG%YNipd%%`RI'+k+$aJ+LMXC(VQeU--cKKh-VNApr*-I6'Q%ci
+aK@-mYhq-DGilISM!XHQCJ5QF[kY(q-hdc,'P!(`kc@)j#bqX,+k#NrP'ISF4Q)I
+81[ST4R$L(8mbJK2[H",*6llM#53II%Gi!*+(,mc6pGBec''HVY*S6c1#`AFmb3K
+kRr%$4R$L(8pTHF@(a0ia)$1CGpL0P%lJd*(m5*raL"Xk8C6SHdFSJ*E(&b)`,mC
++'08[SGK8%Gqmip$fhGpqarEYZapqKdc[XkCANF)0r4p[&I1+5Sjrm&DT[H2dY-U
+J@Ka#-+hb)`q5'00j`S1NeKrK!@Vk2hKeP1[a2Dq1@Pe2UpHRqjl[5Bq0@MhX1jl
+`aULp3hCeUJc#G5cj-3IR&6LSr02UGH8Gi44cF%pTAP5eGl,K(c@[%qpi8[-kmBi
+R0Dq6lhK#maTm4hM!r0T6@P9[2@)-lLP0TrFG2p"d"YpaNJP@J&@qN!!+Pk4`!#d
+QYAA!d%H")&X(0#DRj0$6,l@HR,H1BmM+&`ShJf5r-lL,$65L0chhr0,pHY+CFbZ
+ZZI[*h+r+6RrarZa(VQXFUZ[%keGRQfjrdiTRAhfAmG'EUTpCU-FCIm8''Xr80Fc
+"YIS-h@8$M4#iVfGbC2LdN5BDpX'm@aQHDcGDaAGpIcI"38KVZ%MSLPeUD-cA-($
+5l-D4UHc!THH(!'-frrR*Di1rG$IFDHRXXJ22I%Efm4qmZ[0f3LEdEFa1(K[HY!@
+RSHZRUS@Z-IG06Qeq)[F268b8cPV[f&b[UISm@XflSXU(L8H2qhLl++Fm2VHK86A
+[ekH3!&(-rmHCa$LDpI@GY,jS`BM9MkjBj+(4HVD+[pH8GrZc-rRlKM,`hZb(q2H
+0XQDcpF&@*j9hFl+ePDc[CmUlml+RmHr&-4p@qQq2GjZcl14ha#IZjY6Bjr,C!*!
+!0A`-k,lrlHYffqX'"P5ejh4QQrhXiM'A)BZpXp2GcX$ZfTk"#rS[')$*(afSYZX
+$5j)dJ%CS-+"SIk%[hmJe3q2VKpG8eU`IR"VNlik4SDNe5kXd3#-l*hKI$![-mN-
+)KrZP60k1-d@B-(P'm2H@P+HG[lHQ2#2jHc$PkH6[SC4R&(m2Tca`cpY5RM(m2C,
+bM1A[dC4R%Rr[6(NQmrHZP!ISZMrPJ5rAaccQUTaR0F&e+Fp'JTY5RNebq90jc)b
+`1M(PkH([JC4R'hr[5AQB+AX6JS'(Kj8mGa2HN!$HFar"Be1HPa!m-Z9jJ1#1P1H
+Pr,dqeI&"`M[6Hhk+i#NTcrd%Mcq@j``)i8[YF0EbD"*NKl2UAJ'KTamlR1'D9E2
+,$MIj3Z0QN!$1j#jf1(ZQVQ%11bHFD96XF&DrpjEpj4k9NlHqEZADX91jrd$fq$I
+ZbalhU@X1eAA5VHZcmC9hVVMMj*FEAlrhYYT#2Fk-AhBiLpiA&3kd#FXePhHkeBI
+dZ*!!K)qp3N*N2SYTCb!)fmVpMiq'!,D9q`UEbrREbRhQCVH91qBfF'(UfmU&ebJ
+-pGRb93GYp@FLe*jcIiS,iaI#8"Zeq1T`Z@hckS'!8"JT[2NHk$E6p(RS([c#"k!
+pqCC,qUlY1h%C5mkj,k5JCbZ2!L8F8X6%N!"5eH`3'cQLkdF[f6DpTekE+&UlYdi
+bZK*G%U"`q[jKM[pAm1+kK6fFQcLhFDlLA-fjNA-,jpfFScR(F)lPR-3jQA-8CbG
+R1fFEj`M1NC`c1'rK[)rc*C`2F,k8md&i01XDARCX,6b6Kh80RjhbG2$hmT5(G3f
+[6(PBer#UP!IalHU8Kh80VdPj@0I`fT4R((q[5hPBer$'P!FamUD8"ijiAmV$91c
+V8KkceQ(NG5N2`emReL%dHFckKj%hT$aQrF2)De)Hl%9HQ2+`rZ%9+3rV(cirjB(
+aI#EPH5(KSe1H&r(h$5Q2@4-aFPh+BpBV2,R@SFPMeMp8I5N2DbGf(FYcjSh`SA2
+!$H&pjQcRl1$Xj"c&1CTcM*`I2JpAKiI$XH(2F'0i,j`@[JSAK4I#qH"cF$9iQ19
+BU686KckD"&NcXES19HMTjiEU&erdX,0`@-NA#MH$C,m`932+-&V$Y-B!KXm`2XY
+d3L(S6ZScQaX0f65qDA"XZ(pifcG`hNlH@[CVrXMrV*d4,hRb`C%$R(rqD1jLEG2
+S6Fmp[p3"*jdjYq+DZjr-rDVXp"I[chlNZXDKZNkmIR@fkIBhVAMfeAFC(lfTqTQ
+&HTca9kaYqNaG`aa@[6XMGeREp!`%BCR0,5b`bFFbQlZZ[AHCcBh2F*R0SfmR*,a
+NQFd`Qp8G)kG2GQYZmm,-c0&@)lp[QM@ffCieRq+NdbllNb83DK0HYlTM+!`'K-4
+mBET,iRA'T461l"1B8qN,SpMX08aJ1BNcq35qH(+YNc2["8BCEX)+``MH-j(c#h&
+$V5r'kGqrF#mpmhdTX[-[Pa[c4V)[aXlkDScrbh#[IMM'I5h'ICeYfIRqUTaBMQ4
+ha[ar(E[UEf+qEf52+IrrEAcR0m0rY6UqkqciIhVm2b2Qr9CmclGMh-3BpeKmrq1
+aMYm*HEb1#G9P8Q&RAi`(0@qmZ$AEV'%T9NaNA38`46*XLSdP[c1rG@66qZCXB`N
+!"l,3d!r"+DA6%f#$E(4LU6FAP2P#!0Ce-kqUVrDhC[r[%H"mcf$T31-@KJSGk*2
+HZc1lK1q-*81&5Ba0Kq'S-'Gf#9p)mIa,b)ZbmVekrYqlm,E[c(3"!cc"4B`(*55
+FaVR90SPDJ3fI$!,92Y4HqDVf`#@a+a`#&d*PqMl4UfG5%MJCl`SDZCd6Kfq'mh(
+%EZ$%+4ZAl$'FZ(@c-eJ(j`M1PSJ&Z(HhFJlPC0q`8C`iGSrN(-[Cb6PZ+BIb[Qf
+1lESL-jhZi9hIM[eUPUdf,MdK1KERmk('(6cF*M2j-j1iQqm0Dq"p)q2lkQlV"AD
+r`VE`hZI(+4E5Uir[mq0QdLI0qfHkjHD1#D4U)&rN,Z,BBM)4erK-rR60G$Z(mc@
+k$CV8bArIX"qMc@I2Y$Z(ihEF4)[[RHRZ2&bR4VCDLjc+ZkPhiRe0lqI2Vmed'ke
+liaEZ*IqULG&10e[q"AGIQacL1Rq$2h2+AGEU2[3HlXi,F3HI$p4X#R([(65(&cI
+bAm8J,qjAAX$Gh""hP(k0V!jahcR("T2hI8aFmZ)qi@k$bf+q4rRc8"NAIHSRZ9X
+Hqjlpe6D(I!ql41D+%0IbjX9q5K#ECc1('1[,4&bcZ9eI*Z)Dpbhf65+ZjAf,IC1
+)fr2V[IlirFZiNeeqphbdeam(a9AC$(1IQ#Vpm4XIjUiRa"e`efhTM`FrapeP-Hj
+RH[eal58@91*H[G!IGDqmNl[,Ber5Rejr4+IXb5Y#A)Fpj08TqT+riNj`m"G@,p3
+THVUB)CZUYPqd8+IS#phD8RC,I35mP$T&Alk&ZcXLlKVmN!!k45rl-qi-2YKm2pI
+Vil2&0[+$kp4'k[4+0d58h9mll$q[6[T*Rq)12+&pIRDK6VV2A[pfL"[bSB8kkCF
+kFrTBL*Yaad+Gp-@rc0hMXBrT6kp1H[LVh*PGk[L@[R1K6ZV2k5d(MGeLQeFRYCq
+P&Kh$(Q+0Qd,rIH9hL9XCFAU5A-UVklV2%bFlZcA*2b6IPrqCZ+YM(*[SHIRUAJY
+h8qAZGbD1hHfmI0'9p*EbAB5mTjI[VKF6*cMG4"p,(far#RdJHq"&6KBc[,KYY3Z
+)Hh1Xhk[i-cA8pHh'I65q!kiRrG&XAF&R)2'qKIl3,`*Ve0q%Z+%Z-1ReKci$6U6
+q0[)!qY*lRck0RPIr&2[l&EhhcB5R+V',IUAZdRm["`m82@*j#FZmbIZ@`@r99b*
+1rc*raT9aNAH!P9VqDm,(mGDfDd2FErdLFI"Gmld+rY%3qLEb02L`PYqDI,2Jah0
+[$A&AITBiq+lj4T!!3adIiUk&HfKj-Hrq2B[VaGh`am5"lF4pDU'ZN5IF5KbFQcJ
+ifA$MMXrrfpR%JIrJUhQ61LlNqp3r%LFFZdQHXc,%(3*lY([rm3lUEYpKS28"iLC
+%r[3R[%0f$A`aNp[DA4piKmNK1"(jrp4'4r`B$BG6TiDii@ka*rJa",i5Z6$%IC'
+HeR'Rf(fmThiLe1qVD!Mk#5(ZY@q&,lD(I!rF6Gc8%0FU"lSqa+hm#q+Q44b#-bd
+*F4I6NeUmSNlS&F0Lhm`Qc[5)M3-RT-q@fdr6Babm6ITXrkZ*NfA[4UTcr(D)H`p
+[dq+YqFj'$e"RKEK4p,D@Hj)2h(mia!eP0d)0[lCi4RpErR&mrN[`84ehqecm,Zk
+NRbDq4#iZIB-Z)6Md+*a@"hkXR[A&(Jlp+9a,"hkXpVb`Kd26fDT9"hkXpY+[$SI
+Qd%-kEUJi(plTF1J&Vb,1B,AY*lLAp-HGRb"Z3Dc(bhVpd3'2e%q*G@9h4-'26R"
+D2cA%E8,RF$Kd%Ea(Xd1LlH0hpA$SCA"F(IF5(UDZ*1qiiUA%A4$L0X06(3jp4*b
+!2e)RH+h8qe*Lp)q(Z0Ir83q(ERdpFD)(Y)Q$JN-cl$p2$e$Ai4cLiC!!@9'$r[$
+d!(8pQaFk(2ShD"XkkJ&M`"k(3epq*A(#cpVNiB*$M@#"M[bXaIF,$Mh(ZSTr3E[
+i+(dfrAELi)1d'$a-qZc2i-BkEPSl(ClUF1Kcm%XGYdImHIL3!-1KYlfE10Q%GXQ
+024cDLGDLikSI(El(im'4#ATBK`eXe9XqeX1Kc3HiJpp42rLcdcqmc6PX[VGm'Fc
+m303riR'40kZ2I6VU(iQi$KeDR2i4Mp1VA(GiAp3r%[R'LSq#IbhL)VU@HIH[`9m
+GrVd@(Up(3Yb(U+Z(ImIRri%lc@k5a2hqTKlqADA@*6V+'cl6`lpAQdpdP!jjTr6
+P#ML%MMV+-(QGlF[MmhI"QcA[XR@LVi5(I84H*AZd[J9mF[MhN!$i,FXr,j!![`V
+qAB9fSXXG+mdlf#YIm1qem'1p1G6[@q#T`lqAL+qbIhi,f1EKhr(j[r`)FHKA*Y9
+MD+`1rqTrMMM`h(a,h5&6m'mY'S'@6jP8Mm2I(!rl@lL3!0iDqV*1(9,`le+iVik
+kdI9I1SKraqFr)$m6h@L2pE,iGhcqGM"H4peS*(c&iGp9k-3kkNB,ZA0pGJ303$m
+RpJ&i)(hfQ(Km9BKlUhJLq(H*20[61I4ap+Z(ImIRhb0HHMU(2PiG3["[S4a,&SF
+p+Mm8([B&qEfhEV-q!9cfm1rir#I4)(6Fd,VeAaEa,llITPi&$fLk,H*I)Zj4GCc
+24[b,ad9'hD$@i9mLhbKU%m1r4,iMERlTi9rG(iKcKYq4Ec3mAr![qMbd62fL%$I
+M,3[mVqjkZ)F15f[VTi'TJRpe0mK6Aa$LKS"hJRr4Xq`ESrPBR(MP3Pp'XlmMcQ#
+[VCr*iI6#0m+9pG8acR!D`DhSFm3RlXhI&R"+m#pk$KLKeAQS+hUKKhr4&k$&k*G
+&r%"AN!"hX$QT$MU62NqYb-1rZLqK9HMr&h%DMG29qeH*)cqdefJcJRr4R`!l0$c
+8pMhij1&Ip!`d"5fI0Arh`Q@&rp@pPEN'$DFMEYk[,H"Ih4[T-Id,i4e[**r`[qK
+b0!r0HrRHl2XprKGYJR&DcC0hdbFHrNA24[[3kUl`*(L&p0RH$a,h81`$F%[dc[2
+3ZE@m$lS06RMi&jeKGe-0CbGZ2ca@q&rGAm1400S&FEI)%ccmLfk&BfYe$qU%rLf
+kmLr"bEAp6MkMK`VrUrX!ZE9e-(m2fK1HAKKj#4LQj4hQlf&Q1qSLRhL1ld!,jAe
+SXCiq&aN&Fl9kX[NHNFm,hSpr'h(SYm6"ai6RAI%QiPi6hMId$rRRkAD4[@J6@Th
+Ir$hI2[0dZmLBZSlT8q+1bVfN6S[S#DhHDrlH$MpdGET'r[(kq!jd5DR6@,LG9Qq
+(ek+h5CfDj8RHRUakcXehT%j[KPYVDQAMk$HTdb'iR9C$0Rr[kZQ,NBYqM`"2(p9
+AbKfP6K2JkYSj#22hERLfUe1RrIe`L,Z(A[(UC2LCd@)d1'rj4a`r)Um'1c5kQFh
+h"ldkGGe-!2Q*-jcHeHQ2k@hY,!Ed!Aj[kh4mrJjjfb-alS1p1Vd0E8@(29reci0
+9VNl23S28kY[d2Ea3k[40Z,j@4b81RLae@Lm2"XISEhLMe1R6B)%11mAUUpACT8k
+[&+F0YK2h)R&@qZNAdBVdlm3q0K`dFXS-HjV(Z40apkR(I@QQHYr'fir)JcfFDhi
+E'V5'Aj!!lhki8AfSGr-Pe%kMT4$h-R6+ZX!2QRm*,926bm3pf01IQYk2VUc9YBL
+MRlak0rmQ'V4fYS8iH-A9)@kRZLNk$h(`L6H'Z!I%!h!2qN#pjAh[rJ)"4YHbF3C
+2ACeZG6NKG"jJhf#'e+RTYp'U0"SbFDp5(jGk2b`rH(q-3kH81Xf#NqL`DDaq[EU
+fe1P+HPZr0mBaKq(9UHNVmM0i",#2VLh[Hm"h'pb`F8E2P6SeI36Xdmie!0HQ,ed
+rrD5D%r-[`#pp)rAq1*U)GTk)12LN9kHQVm)9p3GL($c%Ue26qq3I[a[MQ,f3!$T
+p5pd4[3iHKQiZGCU#4U$9Bi(hH$mel9HI0[K'h-1pIQVq@IX!hBCh`0qN6Tm8bm&
+Em!bq,rh8U2i02`9qk6qTdjqM9@Zd'Z,HUZiMIIm+Z)K@*`GqdF'ppcAHBTfBU5%
+1r9IH[3*ZS1NG'iIZ+A'2q1k24(k*VL&a9cPRi-eKk0qbYlbjMBEIK`2V-)HKhiP
+1*('0Tk(Yk6#(SGmPGjGmAd-ld'%13pmJYjDicm*&0&SaFEr1ZpAji4hhUQ-C$B'
+iGpJhZd2F,(NB1J"aCMBLmUS3plKkkLG#h$["!q(aM4H+LfBHMEKh`IrGqckYR[(
+*%2GZF9EHph*a&ai(c$+(+1qE3UpUjKTXR1'"lRdcl32$PBKl,rc%[HpCkVl-#J'
+rr*IhVD8(p+G$h2[8YH9pCm%4p5dacZ#1Hpm'iicH50a[dJrZIBqTVe0ri*Fj5RR
+I+p&H0E-*0Jlp5plh#E"!bq1)-h0)lRd2b*rXM0lr"`#3!edP!!!:
diff --git a/macos/osdep.h b/macos/osdep.h
new file mode 100644 (file)
index 0000000..5a69033
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __MACOS_OSDEP_H
+#define __MACOS_OSDEP_H 1
+
+#ifndef MACOS
+#  define MACOS
+#endif
+
+
+#include <setjmp.h>
+#include <types.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unix.h>
+#include <unistd.h>
+#include <console.h>
+
+#include <Errors.h>
+#include <Files.h>
+
+#include "unixlike.h"
+#include "macglob.h"
+
+#define NO_MKTEMP           1
+#define PASSWD_FROM_STDIN   1
+#define NO_SYMLINKS         1
+
+#define USE_ZIPMAIN         1
+
+#define USE_CASE_MAP        1  /* case_map is used to ignore case in comparisons */
+
+
+
+
+/*
+#define DEBUG_TIME
+ */
+
+#if (!defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME))
+#  define USE_EF_UT_TIME
+#endif
+
+#undef  IZ_CHECK_TZ
+
+#ifndef ZP_NEED_MEMCOMPR
+#  define ZP_NEED_MEMCOMPR
+#endif
+
+
+#define EXDEV  18
+
+#define PATHCUT ':'
+
+
+/* file operations use "b" for binary */
+#define FOPR  "rb"
+#define FOPM  "r+b"
+#define FOPW  "wb"
+
+/*
+#define DEBUG
+*/
+
+/* These functions are defined as a macro instead of a function.
+so we have to undefine them for replacing (see printf.c)  */
+#undef getc
+#undef getchar
+#undef putchar
+
+
+
+void setfiletype(char *file, unsigned long Creator, unsigned long Type);
+
+char *GetZipVersionsInfo(void);
+char *GetZipVersionLocal(void);
+char *GetZipCopyright(void);
+
+void InitAllVars(void);
+
+void PrintFileInfo(void);
+
+
+
+int fprintf(FILE *file, const char *format, ...);
+int printf(const char *format, ...);
+void perror(const char *parm1);
+int macgetch(void);
+
+
+int MacOpen(const char *path,int oflag,...);
+FILE *MacFopen(const char *path,const char *mode);
+#define fopen(path, mode)   MacFopen(path, mode)
+#define open(path, oflag)   MacOpen(path, oflag)
+
+
+char *GetComment(char *filename);
+int readlink(char *path, char *buf, int size);
+
+void PrintStatProgress(char *msg);
+void InformProgress(const long progressMax, const long progressSoFar );
+void ShowCounter(Boolean reset);
+void leftStatusString(char *status);
+
+
+
+
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+                     procname(n, 1))
+
+#endif   /* __MACOS_OSDEP_H */
diff --git a/macos/readme.1st b/macos/readme.1st
new file mode 100644 (file)
index 0000000..6182756
--- /dev/null
@@ -0,0 +1,16 @@
+This port is for Mac versions before Mac OS X.  As Mac OS X is build on Unix,
+use the Unix port for Mac OS X. - 7 June 2008
+
+
+Before you start:
+
+Extract "*.hqx" and "source:*.hqx" first and read the Readme.txt.
+
+The resource file and the compiler project files are in BinHex form because
+they contain Macintosh resource forks and as such can not be simply
+stored a normal file on a non-Macintosh system.  BinHex form is the
+traditional way for transferring such files via non-Macintosh systems.
+It's also the safest since it uses only printable characters.  The ".hqx"
+files must be converted with StuffitExpander or BinHex 4.0 (or equivalent)
+on a Macintosh system before using them.
+
diff --git a/macos/source/VolWarn.h b/macos/source/VolWarn.h
new file mode 100644 (file)
index 0000000..2d921eb
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+
+This is an Important note  about pathnames
+
+*/
+
+static char DuplicVolumeNote[] = {
+    "\rIMPORTANT NOTE:" \
+    "\r" \
+    "\r This port has one weak point: It is based on pathnames !! " \
+    "\r Because it's a port !! Unlike MacOS: As far as I know all other "\
+    "\r Operatingsystems  (eg.: Unix, DOS, OS/2, ...) are based on pathnames" \
+    "\r " \
+    /* a short quote from "Inside Macintintosh, Files"; slightly modified by me */
+    "\r On a Mac: Files and directories located in the same directory " \
+    "\r must all have unique names. However, there is no requirement " \
+    "\r that volumes have unique names. It is perfectly acceptable for two mounted" \
+    "\r volumes to have the same name. This is one reason why a application should " \
+    "\r use volume reference numbers rather than volume names to specify volumes," \
+    "\r but for this Zip-Port I can't use reference numbers. " \
+    "\r " \
+    /* end quote */
+    "\r" \
+    "\r From the developers point of view:"\
+    "\r The use of pathnames, however, is highly discouraged. If the user changes"\
+    "\r names or moves things around, they are worthless." \
+    "\r Full pathnames are particularly unreliable as a means of identifying files," \
+    "\r directories or volumes within your application," \
+    "\r for two primary reasons:" \
+    "\r" \
+    "\r*  The user can change the name of any element in the path at" \
+    "\r   virtually any time." \
+    "\r*  Volume names on the Macintosh are *not* unique. Multiple" \
+    "\r   mounted volumes can have the same name. For this reason, the use of" \
+    "\r   a full pathname to identify a specific volume may not produce the" \
+    "\r   results you expect. If more than one volume has the same name and" \
+    "\r   a full pathname is used, the File Manager currently uses the first" \
+    "\r   mounted volume it finds with a matching name in the volume queue." \
+    "\r" \
+    "\r" \
+    "\r The main reason is that an attempt to implement support exact saving of" \
+    "\r the MacOS specific internal file-structures would require a throughout" \
+    "\r rewrite of major parts of shared code, probably sacrifying compatibility" \
+    "\r with other systems." \
+    "\r I have no solution at the moment. The port will just warn you if you try" \
+    "\r zip from / to a volume which has a duplicate name." \
+    "\r MacZip has problems to find the archives and files." \
+    "\r" \
+    "\r" \
+    "\r ... and the moral of this story:" \
+    "\r" \
+    "\r Don't mount multiple volumes with the same " \
+    "\r name while zip/unzip is running" \
+    "\r and "\
+    "\r My (Big) recommendation: Name all your volumes with a unique name "\
+    "\r (e.g: add a space character to the name) and" \
+    "\r MacZip will run without any problem." \
+    "\r" \
+    "\r" \
+    "\r Dirk Haase" \
+    };
diff --git a/macos/source/charmap.h b/macos/source/charmap.h
new file mode 100644 (file)
index 0000000..5656b63
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __macos_charmap_h
+#define __macos_charmap_h
+
+/*
+
+Conversion table from MacOS Roman to
+"Western Europe & America" Windows codepage 1252
+
+     Notes on Mac OS Roman:
+     ----------------------
+
+       Mac OS Roman character set is used for at least the following Mac OS
+       localizations: U.S., British, Canadian French, French, Swiss
+       French, German, Swiss German, Italian, Swiss Italian, Dutch,
+       Swedish, Norwegian, Danish, Finnish, Spanish, Catalan,
+       Portuguese, Brazilian, and the default International system.
+
+       Not every char of the charset MacRoman has their equivalent
+       in Windows CodePage1252.
+       To make the mapping in most cases possible, I choosed
+       most similar chars or at least the BULLET. Chars that
+       do not have a direct match are marked with '***'
+
+       The Windows codepage 1252 contains the ISO 8859-1 "Latin 1" codepage,
+       with some additional printable characters in the range (0x80 - 0x9F),
+       that is reserved to control codes in the ISO 8859-1 character table.
+
+In all Mac OS encodings, character codes 0x00-0x7F are identical to ASCII
+
+*/
+
+
+
+ZCONST unsigned char MacRoman_to_WinCP1252[128] = {
+/*  Win CP1252          UniCode  UniCode Names       */
+    0xC4    ,       /*  0x00C4  #LATIN CAPITAL LETTER A WITH DIAERESIS      */
+    0xC5    ,       /*  0x00C5  #LATIN CAPITAL LETTER A WITH RING ABOVE     */
+    0xC7    ,       /*  0x00C7  #LATIN CAPITAL LETTER C WITH CEDILLA        */
+    0xC9    ,       /*  0x00C9  #LATIN CAPITAL LETTER E WITH ACUTE      */
+    0xD1    ,       /*  0x00D1  #LATIN CAPITAL LETTER N WITH TILDE      */
+    0xD6    ,       /*  0x00D6  #LATIN CAPITAL LETTER O WITH DIAERESIS      */
+    0xDC    ,       /*  0x00DC  #LATIN CAPITAL LETTER U WITH DIAERESIS      */
+    0xE1    ,       /*  0x00E1  #LATIN SMALL LETTER A WITH ACUTE        */
+    0xE0    ,       /*  0x00E0  #LATIN SMALL LETTER A WITH GRAVE        */
+    0xE2    ,       /*  0x00E2  #LATIN SMALL LETTER A WITH CIRCUMFLEX       */
+    0xE4    ,       /*  0x00E4  #LATIN SMALL LETTER A WITH DIAERESIS        */
+    0xE3    ,       /*  0x00E3  #LATIN SMALL LETTER A WITH TILDE        */
+    0xE5    ,       /*  0x00E5  #LATIN SMALL LETTER A WITH RING ABOVE       */
+    0xE7    ,       /*  0x00E7  #LATIN SMALL LETTER C WITH CEDILLA      */
+    0xE9    ,       /*  0x00E9  #LATIN SMALL LETTER E WITH ACUTE        */
+    0xE8    ,       /*  0x00E8  #LATIN SMALL LETTER E WITH GRAVE        */
+    0xEA    ,       /*  0x00EA  #LATIN SMALL LETTER E WITH CIRCUMFLEX       */
+    0xEB    ,       /*  0x00EB  #LATIN SMALL LETTER E WITH DIAERESIS        */
+    0xED    ,       /*  0x00ED  #LATIN SMALL LETTER I WITH ACUTE        */
+    0xEC    ,       /*  0x00EC  #LATIN SMALL LETTER I WITH GRAVE        */
+    0xEE    ,       /*  0x00EE  #LATIN SMALL LETTER I WITH CIRCUMFLEX       */
+    0xEF    ,       /*  0x00EF  #LATIN SMALL LETTER I WITH DIAERESIS        */
+    0xF1    ,       /*  0x00F1  #LATIN SMALL LETTER N WITH TILDE        */
+    0xF3    ,       /*  0x00F3  #LATIN SMALL LETTER O WITH ACUTE        */
+    0xF2    ,       /*  0x00F2  #LATIN SMALL LETTER O WITH GRAVE        */
+    0xF4    ,       /*  0x00F4  #LATIN SMALL LETTER O WITH CIRCUMFLEX       */
+    0xF6    ,       /*  0x00F6  #LATIN SMALL LETTER O WITH DIAERESIS        */
+    0xF5    ,       /*  0x00F5  #LATIN SMALL LETTER O WITH TILDE        */
+    0xFA    ,       /*  0x00FA  #LATIN SMALL LETTER U WITH ACUTE        */
+    0xF9    ,       /*  0x00F9  #LATIN SMALL LETTER U WITH GRAVE        */
+    0xFB    ,       /*  0x00FB  #LATIN SMALL LETTER U WITH CIRCUMFLEX       */
+    0xFC    ,       /*  0x00FC  #LATIN SMALL LETTER U WITH DIAERESIS        */
+    0x86    ,       /*  0x2020  #DAGGER     */
+    0xB0    ,       /*  0x00B0  #DEGREE SIGN        */
+    0xA2    ,       /*  0x00A2  #CENT SIGN      */
+    0xA3    ,       /*  0x00A3  #POUND SIGN     */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x95    ,       /*  0x2022  #BULLET     */
+    0xB6    ,       /*  0x00B6  #PILCROW SIGN       */
+    0xDF    ,       /*  0x00DF  #LATIN SMALL LETTER SHARP S     */
+    0xAE    ,       /*  0x00AE  #REGISTERED SIGN        */
+    0xA9    ,       /*  0x00A9  #COPYRIGHT SIGN     */
+    0x99    ,       /*  0x2122  #TRADE MARK SIGN        */
+    0xB4    ,       /*  0x00B4  #ACUTE ACCENT       */
+    0xA8    ,       /*  0x00A8  #DIAERESIS      */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0xC6    ,       /*  0x00C6  #LATIN CAPITAL LETTER AE        */
+    0xD8    ,       /*  0x00D8  #LATIN CAPITAL LETTER O WITH STROKE     */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0xB1    ,       /*  0x00B1  #PLUS-MINUS SIGN        */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0xA5    ,       /*  0x00A5  #YEN SIGN       */
+    0xB5    ,       /*  0x00B5  #MICRO SIGN     */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0xAA    ,       /*  0x00AA  #FEMININE ORDINAL INDICATOR     */
+    0xBA    ,       /*  0x00BA  #MASCULINE ORDINAL INDICATOR        */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0xE6    ,       /*  0x00E6  #LATIN SMALL LETTER AE      */
+    0xF8    ,       /*  0x00F8  #LATIN SMALL LETTER O WITH STROKE       */
+    0xBF    ,       /*  0x00BF  #INVERTED QUESTION MARK     */
+    0xA1    ,       /*  0x00A1  #INVERTED EXCLAMATION MARK      */
+    0xAC    ,       /*  0x00AC  #NOT SIGN       */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x83    ,       /*  0x0192  #LATIN SMALL LETTER F WITH HOOK     */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0xAB    ,       /*  0x00AB  #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK      */
+    0xBB    ,       /*  0x00BB  #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK     */
+    0x85    ,       /*  0x2026  #HORIZONTAL ELLIPSIS        */
+    0xA0    ,       /*  0x00A0  #NO-BREAK SPACE     */
+    0xC0    ,       /*  0x00C0  #LATIN CAPITAL LETTER A WITH GRAVE      */
+    0xC3    ,       /*  0x00C3  #LATIN CAPITAL LETTER A WITH TILDE      */
+    0xD5    ,       /*  0x00D5  #LATIN CAPITAL LETTER O WITH TILDE      */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x96    ,       /*  0x2013  #EN DASH        */
+    0x97    ,       /*  0x2014  #EM DASH        */
+    0x93    ,       /*  0x201C  #LEFT DOUBLE QUOTATION MARK     */
+    0x94    ,       /*  0x201D  #RIGHT DOUBLE QUOTATION MARK        */
+    0x91    ,       /*  0x2018  #LEFT SINGLE QUOTATION MARK     */
+    0x92    ,       /*  0x2019  #RIGHT SINGLE QUOTATION MARK        */
+    0xF7    ,       /*  0x00F7  #DIVISION SIGN      */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0xFF    ,       /*  0x00FF  #LATIN SMALL LETTER Y WITH DIAERESIS        */
+    0x9F    ,       /*  0x0178  #LATIN CAPITAL LETTER Y WITH DIAERESIS      */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0xA4    ,       /*  0x00A4  #CURRENCY SIGN      */
+    0x8B    ,       /*  0x2039  #SINGLE LEFT-POINTING ANGLE QUOTATION MARK      */
+    0x9B    ,       /*  0x203A  #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK     */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x87    ,       /*  0x2021  #DOUBLE DAGGER      */
+    0xB7    ,       /*  0x00B7  #MIDDLE DOT     */
+    0x82    ,       /*  0x201A  #SINGLE LOW-9 QUOTATION MARK        */
+    0x84    ,       /*  0x201E  #DOUBLE LOW-9 QUOTATION MARK        */
+    0x89    ,       /*  0x2030  #PER MILLE SIGN     */
+    0xC2    ,       /*  0x00C2  #LATIN CAPITAL LETTER A WITH CIRCUMFLEX     */
+    0xCA    ,       /*  0x00CA  #LATIN CAPITAL LETTER E WITH CIRCUMFLEX     */
+    0xC1    ,       /*  0x00C1  #LATIN CAPITAL LETTER A WITH ACUTE      */
+    0xCB    ,       /*  0x00CB  #LATIN CAPITAL LETTER E WITH DIAERESIS      */
+    0xC8    ,       /*  0x00C8  #LATIN CAPITAL LETTER E WITH GRAVE      */
+    0xCD    ,       /*  0x00CD  #LATIN CAPITAL LETTER I WITH ACUTE      */
+    0xCE    ,       /*  0x00CE  #LATIN CAPITAL LETTER I WITH CIRCUMFLEX     */
+    0xCF    ,       /*  0x00CF  #LATIN CAPITAL LETTER I WITH DIAERESIS      */
+    0xCC    ,       /*  0x00CC  #LATIN CAPITAL LETTER I WITH GRAVE      */
+    0xD3    ,       /*  0x00D3  #LATIN CAPITAL LETTER O WITH ACUTE      */
+    0xD4    ,       /*  0x00D4  #LATIN CAPITAL LETTER O WITH CIRCUMFLEX     */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0xD2    ,       /*  0x00D2  #LATIN CAPITAL LETTER O WITH GRAVE      */
+    0xDA    ,       /*  0x00DA  #LATIN CAPITAL LETTER U WITH ACUTE      */
+    0xDB    ,       /*  0x00DB  #LATIN CAPITAL LETTER U WITH CIRCUMFLEX     */
+    0xD9    ,       /*  0x00D9  #LATIN CAPITAL LETTER U WITH GRAVE      */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x88    ,       /*  0x02C6  #MODIFIER LETTER CIRCUMFLEX ACCENT      */
+    0x98    ,       /*  0x02DC  #SMALL TILDE        */
+    0xAF    ,       /*  0x00AF  #MACRON     */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0xB8    ,       /*  0x00B8  #CEDILLA        */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x95    ,       /*  0x2022  # ***  BULLET       */
+    0x95            /*  0x2022  # ***  BULLET       */
+ };
+
+
+
+ZCONST unsigned char WinCP1252_to_MacRoman[128] = {
+/*  Mac Roman           UniCode  UniCode Names       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xE2    ,       /*  0x201A  # SINGLE LOW-9 QUOTATION MARK       */
+    0xC4    ,       /*  0x0192  # LATIN SMALL LETTER F WITH HOOK        */
+    0xE3    ,       /*  0x201E  # DOUBLE LOW-9 QUOTATION MARK       */
+    0xC9    ,       /*  0x2026  # HORIZONTAL ELLIPSIS       */
+    0xA0    ,       /*  0x2020  # DAGGER        */
+    0xE0    ,       /*  0x2021  # DOUBLE DAGGER     */
+    0xF6    ,       /*  0x02C6  # MODIFIER LETTER CIRCUMFLEX ACCENT     */
+    0xE4    ,       /*  0x2030  # PER MILLE SIGN        */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xDC    ,       /*  0x2039  # SINGLE LEFT-POINTING ANGLE QUOTATION MARK     */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xD4    ,       /*  0x2018  # LEFT SINGLE QUOTATION MARK        */
+    0xD5    ,       /*  0x2019  # RIGHT SINGLE QUOTATION MARK       */
+    0xD2    ,       /*  0x201C  # LEFT DOUBLE QUOTATION MARK        */
+    0xD3    ,       /*  0x201D  # RIGHT DOUBLE QUOTATION MARK       */
+    0xA5    ,       /*  0x2022  # BULLET        */
+    0xD0    ,       /*  0x2013  # EN DASH       */
+    0xD1    ,       /*  0x2014  # EM DASH       */
+    0xF7    ,       /*  0x02DC  # SMALL TILDE       */
+    0xAA    ,       /*  0x2122  # TRADE MARK SIGN       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xDD    ,       /*  0x203A  # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK        */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xD9    ,       /*  0x0178  # LATIN CAPITAL LETTER Y WITH DIAERESIS     */
+    0xCA    ,       /*  0x00A0  # NO-BREAK SPACE        */
+    0xC1    ,       /*  0x00A1  # INVERTED EXCLAMATION MARK     */
+    0xA2    ,       /*  0x00A2  # CENT SIGN     */
+    0xA3    ,       /*  0x00A3  # POUND SIGN        */
+    0xDB    ,       /*  0x00A4  # CURRENCY SIGN     */
+    0xB4    ,       /*  0x00A5  # YEN SIGN      */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xAC    ,       /*  0x00A8  # DIAERESIS     */
+    0xA9    ,       /*  0x00A9  # COPYRIGHT SIGN        */
+    0xBB    ,       /*  0x00AA  # FEMININE ORDINAL INDICATOR        */
+    0xC7    ,       /*  0x00AB  # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK     */
+    0xC2    ,       /*  0x00AC  # NOT SIGN      */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA8    ,       /*  0x00AE  # REGISTERED SIGN       */
+    0xF8    ,       /*  0x00AF  # MACRON        */
+    0xA1    ,       /*  0x00B0  # DEGREE SIGN       */
+    0xB1    ,       /*  0x00B1  # PLUS-MINUS SIGN       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xAB    ,       /*  0x00B4  # ACUTE ACCENT      */
+    0xB5    ,       /*  0x00B5  # MICRO SIGN        */
+    0xA6    ,       /*  0x00B6  # PILCROW SIGN      */
+    0xE1    ,       /*  0x00B7  # MIDDLE DOT        */
+    0xFC    ,       /*  0x00B8  # CEDILLA       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xBC    ,       /*  0x00BA  # MASCULINE ORDINAL INDICATOR       */
+    0xC8    ,       /*  0x00BB  # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK        */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xC0    ,       /*  0x00BF  # INVERTED QUESTION MARK        */
+    0xCB    ,       /*  0x00C0  # LATIN CAPITAL LETTER A WITH GRAVE     */
+    0xE7    ,       /*  0x00C1  # LATIN CAPITAL LETTER A WITH ACUTE     */
+    0xE5    ,       /*  0x00C2  # LATIN CAPITAL LETTER A WITH CIRCUMFLEX        */
+    0xCC    ,       /*  0x00C3  # LATIN CAPITAL LETTER A WITH TILDE     */
+    0x80    ,       /*  0x00C4  # LATIN CAPITAL LETTER A WITH DIAERESIS     */
+    0x81    ,       /*  0x00C5  # LATIN CAPITAL LETTER A WITH RING ABOVE        */
+    0xAE    ,       /*  0x00C6  # LATIN CAPITAL LETTER AE       */
+    0x82    ,       /*  0x00C7  # LATIN CAPITAL LETTER C WITH CEDILLA       */
+    0xE9    ,       /*  0x00C8  # LATIN CAPITAL LETTER E WITH GRAVE     */
+    0x83    ,       /*  0x00C9  # LATIN CAPITAL LETTER E WITH ACUTE     */
+    0xE6    ,       /*  0x00CA  # LATIN CAPITAL LETTER E WITH CIRCUMFLEX        */
+    0xE8    ,       /*  0x00CB  # LATIN CAPITAL LETTER E WITH DIAERESIS     */
+    0xED    ,       /*  0x00CC  # LATIN CAPITAL LETTER I WITH GRAVE     */
+    0xEA    ,       /*  0x00CD  # LATIN CAPITAL LETTER I WITH ACUTE     */
+    0xEB    ,       /*  0x00CE  # LATIN CAPITAL LETTER I WITH CIRCUMFLEX        */
+    0xEC    ,       /*  0x00CF  # LATIN CAPITAL LETTER I WITH DIAERESIS     */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0x84    ,       /*  0x00D1  # LATIN CAPITAL LETTER N WITH TILDE     */
+    0xF1    ,       /*  0x00D2  # LATIN CAPITAL LETTER O WITH GRAVE     */
+    0xEE    ,       /*  0x00D3  # LATIN CAPITAL LETTER O WITH ACUTE     */
+    0xEF    ,       /*  0x00D4  # LATIN CAPITAL LETTER O WITH CIRCUMFLEX        */
+    0xCD    ,       /*  0x00D5  # LATIN CAPITAL LETTER O WITH TILDE     */
+    0x85    ,       /*  0x00D6  # LATIN CAPITAL LETTER O WITH DIAERESIS     */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xAF    ,       /*  0x00D8  # LATIN CAPITAL LETTER O WITH STROKE        */
+    0xF4    ,       /*  0x00D9  # LATIN CAPITAL LETTER U WITH GRAVE     */
+    0xF2    ,       /*  0x00DA  # LATIN CAPITAL LETTER U WITH ACUTE     */
+    0xF3    ,       /*  0x00DB  # LATIN CAPITAL LETTER U WITH CIRCUMFLEX        */
+    0x86    ,       /*  0x00DC  # LATIN CAPITAL LETTER U WITH DIAERESIS     */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA7    ,       /*  0x00DF  # LATIN SMALL LETTER SHARP S        */
+    0x88    ,       /*  0x00E0  # LATIN SMALL LETTER A WITH GRAVE       */
+    0x87    ,       /*  0x00E1  # LATIN SMALL LETTER A WITH ACUTE       */
+    0x89    ,       /*  0x00E2  # LATIN SMALL LETTER A WITH CIRCUMFLEX      */
+    0x8B    ,       /*  0x00E3  # LATIN SMALL LETTER A WITH TILDE       */
+    0x8A    ,       /*  0x00E4  # LATIN SMALL LETTER A WITH DIAERESIS       */
+    0x8C    ,       /*  0x00E5  # LATIN SMALL LETTER A WITH RING ABOVE      */
+    0xBE    ,       /*  0x00E6  # LATIN SMALL LETTER AE     */
+    0x8D    ,       /*  0x00E7  # LATIN SMALL LETTER C WITH CEDILLA     */
+    0x8F    ,       /*  0x00E8  # LATIN SMALL LETTER E WITH GRAVE       */
+    0x8E    ,       /*  0x00E9  # LATIN SMALL LETTER E WITH ACUTE       */
+    0x90    ,       /*  0x00EA  # LATIN SMALL LETTER E WITH CIRCUMFLEX      */
+    0x91    ,       /*  0x00EB  # LATIN SMALL LETTER E WITH DIAERESIS       */
+    0x93    ,       /*  0x00EC  # LATIN SMALL LETTER I WITH GRAVE       */
+    0x92    ,       /*  0x00ED  # LATIN SMALL LETTER I WITH ACUTE       */
+    0x94    ,       /*  0x00EE  # LATIN SMALL LETTER I WITH CIRCUMFLEX      */
+    0x95    ,       /*  0x00EF  # LATIN SMALL LETTER I WITH DIAERESIS       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0x96    ,       /*  0x00F1  # LATIN SMALL LETTER N WITH TILDE       */
+    0x98    ,       /*  0x00F2  # LATIN SMALL LETTER O WITH GRAVE       */
+    0x97    ,       /*  0x00F3  # LATIN SMALL LETTER O WITH ACUTE       */
+    0x99    ,       /*  0x00F4  # LATIN SMALL LETTER O WITH CIRCUMFLEX      */
+    0x9B    ,       /*  0x00F5  # LATIN SMALL LETTER O WITH TILDE       */
+    0x9A    ,       /*  0x00F6  # LATIN SMALL LETTER O WITH DIAERESIS       */
+    0xD6    ,       /*  0x00F7  # DIVISION SIGN     */
+    0xBF    ,       /*  0x00F8  # LATIN SMALL LETTER O WITH STROKE      */
+    0x9D    ,       /*  0x00F9  # LATIN SMALL LETTER U WITH GRAVE       */
+    0x9C    ,       /*  0x00FA  # LATIN SMALL LETTER U WITH ACUTE       */
+    0x9E    ,       /*  0x00FB  # LATIN SMALL LETTER U WITH CIRCUMFLEX      */
+    0x9F    ,       /*  0x00FC  # LATIN SMALL LETTER U WITH DIAERESIS       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xA5    ,       /*  0x2022  # ***  BULLET       */
+    0xD8            /*  0x00FF  # LATIN SMALL LETTER Y WITH DIAERESIS       */
+ };
+
+
+/*
+
+The following characters has no equivalent
+to each other:
+
+MacCodes
+164 0xA4    0x00A7  # SECTION SIGN
+253 0xFD    0x02DD  # DOUBLE ACUTE ACCENT
+189 0xBD    0x03A9  # GREEK CAPITAL LETTER OMEGA
+185 0xB9    0x03C0  # GREEK SMALL LETTER PI
+255 0xFF    0x02C7  # CARON
+249 0xF9    0x02D8  # BREVE
+250 0xFA    0x02D9  # DOT ABOVE
+251 0xFB    0x02DA  # RING ABOVE
+254 0xFE    0x02DB  # OGONEK
+218 0xDA    0x2044  # FRACTION SLASH
+182 0xB6    0x2202  # PARTIAL DIFFERENTIAL
+198 0xC6    0x2206  # INCREMENT
+184 0xB8    0x220F  # N-ARY PRODUCT
+183 0xB7    0x2211  # N-ARY SUMMATION
+195 0xC3    0x221A  # SQUARE ROOT
+176 0xB0    0x221E  # INFINITY
+186 0xBA    0x222B  # INTEGRAL
+197 0xC5    0x2248  # ALMOST EQUAL TO
+173 0xAD    0x2260  # NOT EQUAL TO
+178 0xB2    0x2264  # LESS-THAN OR EQUAL TO
+179 0xB3    0x2265  # GREATER-THAN OR EQUAL TO
+215 0xD7    0x25CA  # LOZENGE
+240 0xF0    0xF8FF  # Apple logo
+222 0xDE    0xFB01  # LATIN SMALL LIGATURE FI
+223 0xDF    0xFB02  # LATIN SMALL LIGATURE FL
+245 0xF5    0x0131  # LATIN SMALL LETTER DOTLESS I
+206 0xCE    0x0152  # LATIN CAPITAL LIGATURE OE
+207 0xCF    0x0153  # LATIN SMALL LIGATURE OE
+
+WinCodes
+129 0x81            #UNDEFINED
+141 0x8D            #UNDEFINED
+143 0x8F            #UNDEFINED
+144 0x90            #UNDEFINED
+157 0x9D            #UNDEFINED
+167 0xA7    0x00A7  #SECTION SIGN
+173 0xAD    0x00AD  #SOFT HYPHEN
+178 0xB2    0x00B2  #SUPERSCRIPT TWO
+179 0xB3    0x00B3  #SUPERSCRIPT THREE
+185 0xB9    0x00B9  #SUPERSCRIPT ONE
+188 0xBC    0x00BC  #VULGAR FRACTION ONE QUARTER
+189 0xBD    0x00BD  #VULGAR FRACTION ONE HALF
+190 0xBE    0x00BE  #VULGAR FRACTION THREE QUARTERS
+208 0xD0    0x00D0  #LATIN CAPITAL LETTER ETH
+215 0xD7    0x00D7  #MULTIPLICATION SIGN
+221 0xDD    0x00DD  #LATIN CAPITAL LETTER Y WITH ACUTE
+222 0xDE    0x00DE  #LATIN CAPITAL LETTER THORN
+240 0xF0    0x00F0  #LATIN SMALL LETTER ETH
+253 0xFD    0x00FD  #LATIN SMALL LETTER Y WITH ACUTE
+254 0xFE    0x00FE  #LATIN SMALL LETTER THORN
+140 0x8C    0x0152  #LATIN CAPITAL LIGATURE OE
+156 0x9C    0x0153  #LATIN SMALL LIGATURE OE
+138 0x8A    0x0160  #LATIN CAPITAL LETTER S WITH CARON
+154 0x9A    0x0161  #LATIN SMALL LETTER S WITH CARON
+142 0x8E    0x017D  #LATIN CAPITAL LETTER Z WITH CARON
+158 0x9E    0x017E  #LATIN SMALL LETTER Z WITH CARON
+128 0x80    0x20AC  #EURO SIGN
+166 0xA6    0x00A6  #BROKEN BAR
+
+
+*/
+
+
+
+
+#endif /* !__macos_charmap_h */
diff --git a/macos/source/extrafld.c b/macos/source/extrafld.c
new file mode 100644 (file)
index 0000000..a2efcdb
--- /dev/null
@@ -0,0 +1,920 @@
+/*
+  Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+  extrafld.c
+
+  contains functions to build extra-fields.
+
+  ---------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/*  Includes                                                                 */
+/*****************************************************************************/
+
+#include <sound.h>
+#include "zip.h"
+#include "unixlike.h"
+#include "helpers.h"
+#include "pathname.h"
+
+
+/*****************************************************************************/
+/*  Macros, typedefs                                                         */
+/*****************************************************************************/
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'MAC3' extra field to the zlist data pointed to by z.            */
+/* This is the (new) Info-zip extra block for Macintosh */
+#define EB_MAC3_HLEN          14    /* fixed length part of MAC3's header */
+#define EB_L_MAC3_FINFO_LEN   52    /* fixed part of MAC3 compressible data */
+
+#define EB_MAX_OF_VARDATA   1300    /* max possible datasize */
+
+#define EB_L_MAC3_SIZE    (EB_HEADSIZE + EB_MAC3_HLEN)
+#define EB_C_MAC3_SIZE    (EB_HEADSIZE + EB_MAC3_HLEN)
+
+/* maximum memcompress overhead is the sum of the compression header length */
+/* (6 = ush compression type, ulg CRC) and the worstcase deflate overhead   */
+/* when uncompressible data are kept in 2 "stored" blocks (5 per block =    */
+/* byte blocktype + 2 * ush blocklength) */
+#define MEMCOMPRESS_OVERHEAD    (EB_MEMCMPR_HSIZ + EB_DEFLAT_EXTRA)
+
+#define EB_M3_FL_COMPRESS   0x00
+#define EB_M3_FL_DATFRK     0x01    /* data is data-fork */
+#define EB_M3_FL_NOCHANGE   0x02    /* filename will be not changed */
+#define EB_M3_FL_UNCMPR     0x04    /* data is 'natural' (not compressed) */
+#define EB_M3_FL_TIME64     0x08    /* time is coded in 64 bit */
+#define EB_M3_FL_NOUTC      0x10    /* only 'local' time-stamps are stored */
+
+
+#define EB_L_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(2))
+#define EB_C_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(1))
+
+/* disable compressing of extra field
+#define MAC_EXTRAFLD_UNCMPR       */
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'JLEE' extra field to the zlist data pointed to by z.            */
+/* This is the (old) Info-zip resource-fork extra block for Macintosh
+(last Revision 1996-09-22) Layout made by Johnny Lee, Code made by me :-)  */
+#define EB_L_JLEE_LEN  40       /* fixed length of JLEE's header */
+#define EB_C_JLEE_LEN  40       /* fixed length of JLEE's header */
+
+#define EB_L_JLEE_SIZE    (EB_HEADSIZE + EB_L_JLEE_LEN)
+#define EB_C_JLEE_SIZE    (EB_HEADSIZE + EB_C_JLEE_LEN)
+
+
+
+/*****************************************************************************/
+/*  Global Vars                                                              */
+/*****************************************************************************/
+
+extern MacZipGlobals    MacZip;
+extern unsigned long count_of_Zippedfiles;
+
+
+
+/*****************************************************************************/
+/*  Prototypes                                                               */
+/*****************************************************************************/
+
+static int add_UT_ef(struct zlist far *z, iztimes *z_utim);
+static int add_JLEE_ef(struct zlist far *z);  /* old mac extra field */
+static int add_MAC3_ef(struct zlist far *z);  /* new mac extra field */
+
+static void make_extrafield_JLEE(char *l_ef);
+static unsigned make_extrafield_MAC3(char *ef);
+static char *make_EF_Head_MAC3(char *ef, unsigned compsize, ulg attrsize,
+                               unsigned flag);
+
+static void print_extra_info(void);
+void UserStop(void);
+
+
+/*****************************************************************************/
+/*  Functions                                                                */
+/*****************************************************************************/
+
+
+/*
+* Set the extra-field's for each compressed file
+*/
+int set_extra_field(struct zlist far *z, iztimes *z_utim)
+  /* store full data in local header but just modification time stamp info
+     in central header */
+{
+    int retval;
+
+    Assert_it(z, "set_extra_field","")
+    Assert_it(z_utim, "set_extra_field","")
+
+    z_utim = z_utim;
+
+    /* Check to make sure z is valid. */
+    if( z == NULL ) {
+        return ZE_LOGIC;
+    }
+
+    /* Resource forks are always binary */
+    if (MacZip.CurrentFork == ResourceFork) z->att = BINARY;
+
+    if (noisy)
+        {
+        count_of_Zippedfiles++;
+        InformProgress(MacZip.RawCountOfItems, count_of_Zippedfiles );
+        }
+
+    /*
+    PrintFileInfo();
+    */
+    switch (MacZip.MacZipMode)
+        {
+        case JohnnyLee_EF:
+            {
+            retval = add_JLEE_ef( z );
+            if (retval != ZE_OK) return retval;
+            break;
+            }
+        case NewZipMode_EF:
+            {     /*  */
+#ifdef USE_EF_UT_TIME
+            retval = add_UT_ef(z, z_utim);
+            if (retval != ZE_OK) return retval;
+#endif
+
+            retval = add_MAC3_ef( z );
+            if (retval != ZE_OK) return retval;
+            break;
+            }
+        default:
+            {
+            printerr("Unknown Extrafieldmode", -1, -1, __LINE__, __FILE__, "");
+            return ZE_LOGIC;  /* function should never reach this point */
+            }
+    }
+
+    /* MacStat information is now outdated and
+       must be refreshed for the next file */
+    MacZip.isMacStatValid = false;
+
+    return ZE_OK;
+}
+
+
+
+
+#ifdef USE_EF_UT_TIME
+/*
+* Build and add the Unix time extra-field. This extra field
+* will be included be default. Johnny Lee's implementation does
+* not use this kind of extra-field.
+* All datas are in Intel (=little-endian) format
+
+ Extra field info:
+   - 'UT' - UNIX time extra field
+
+   This is done the same way ../unix/unix.c stores the 'UT'/'Ux' fields
+   (full data in local header, only modification time in central header),
+   with the 'M3' field added to the end and the size of the 'M3' field
+   in the central header.
+ */
+
+static int add_UT_ef(struct zlist far *z, iztimes *z_utim)
+{
+    char        *l_ef = NULL;
+    char        *c_ef = NULL;
+
+    Assert_it(z, "add_UT_ef","")
+
+#ifdef IZ_CHECK_TZ
+    if (!zp_tz_is_valid)
+        return ZE_OK;           /* skip silently if no valid TZ info */
+#endif
+
+    /* We can't work if there's no entry to work on. */
+    if( z == NULL ) {
+        return ZE_LOGIC;
+    }
+
+    /* Check to make sure we've got enough room in the extra fields. */
+    if( z->ext + EB_L_UT_SIZE > EF_SIZE_MAX ||
+        z->cext + EB_C_UT_SIZE > EF_SIZE_MAX ) {
+        return ZE_MEM;
+    }
+
+    /* Allocate memory for the local and central extra fields. */
+    if( z->extra && z->ext != 0 ) {
+        l_ef = (char *)realloc( z->extra, z->ext + EB_L_UT_SIZE );
+    } else {
+        l_ef = (char *)malloc( EB_L_UT_SIZE );
+        z->ext = 0;
+    }
+    if( l_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->extra = l_ef;
+    l_ef += z->ext;
+
+    if( z->cextra && z->cext != 0 ) {
+        c_ef = (char *)realloc( z->cextra, z->cext + EB_C_UT_SIZE );
+    } else {
+        c_ef = (char *)malloc( EB_C_UT_SIZE );
+        z->cext = 0;
+    }
+    if( c_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->cextra = c_ef;
+    c_ef += z->cext;
+
+    /* Now add the local version of the field. */
+    *l_ef++ = 'U';
+    *l_ef++ = 'T';
+    *l_ef++ = (char)(EB_UT_LEN(2)); /* length of data in local EF */
+    *l_ef++ = (char)0;
+    *l_ef++ = (char)(EB_UT_FL_MTIME | EB_UT_FL_CTIME);
+    *l_ef++ = (char)(z_utim->mtime);
+    *l_ef++ = (char)(z_utim->mtime >> 8);
+    *l_ef++ = (char)(z_utim->mtime >> 16);
+    *l_ef++ = (char)(z_utim->mtime >> 24);
+    *l_ef++ = (char)(z_utim->ctime);
+    *l_ef++ = (char)(z_utim->ctime >> 8);
+    *l_ef++ = (char)(z_utim->ctime >> 16);
+    *l_ef++ = (char)(z_utim->ctime >> 24);
+
+    z->ext += EB_L_UT_SIZE;
+
+    /* Now add the central version. */
+    memcpy(c_ef, l_ef-EB_L_UT_SIZE, EB_C_UT_SIZE);
+    c_ef[EB_LEN] = (char)(EB_UT_LEN(1)); /* length of data in central EF */
+
+    z->cext += EB_C_UT_SIZE;
+
+    return ZE_OK;
+}
+#endif /* USE_EF_UT_TIME */
+
+
+/*
+* Build and add the old 'Johnny Lee' Mac extra field
+* All native datas are in Motorola (=big-endian) format
+*/
+
+static int add_JLEE_ef( struct zlist far *z )
+{
+    char *l_ef       = NULL;
+    char *c_ef       = NULL;
+
+    Assert_it(z, "add_JLEE_ef","")
+
+    /* Check to make sure we've got enough room in the extra fields. */
+    if ( z->ext + EB_L_JLEE_SIZE > EF_SIZE_MAX ||
+         z->cext + EB_C_JLEE_SIZE > EF_SIZE_MAX ) {
+        return ZE_MEM;
+    }
+
+
+    /* Allocate memory for the local extra fields. */
+    if ( z->extra && z->ext != 0 ) {
+        l_ef = (char *)realloc( z->extra, z->ext + EB_L_JLEE_SIZE );
+    } else {
+        l_ef = (char *)malloc( EB_L_JLEE_SIZE );
+        z->ext = 0;
+    }
+    if ( l_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->extra = l_ef;
+    l_ef += z->ext;
+
+    /* Allocate memory for the  central extra fields. */
+    if ( z->cextra && z->cext != 0 ) {
+        c_ef = (char *)realloc( z->cextra, z->cext + EB_C_JLEE_SIZE );
+    } else {
+        c_ef = (char *)malloc( EB_C_JLEE_SIZE );
+        z->cext = 0;
+    }
+    if ( c_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->cextra = c_ef;
+    c_ef += z->cext;
+
+
+    if ( verbose ) {
+        print_extra_info();
+    }
+
+
+    /**
+    **
+    **  Now add the local version of the field.
+    **/
+    make_extrafield_JLEE(l_ef);
+    z->ext += EB_L_JLEE_SIZE;
+
+
+    /**
+    **
+    **  Now add the central version of the field.
+    **  It's identical to the local header. I wonder why ??
+    *  the first two fields are in Intel little-endian format  */
+    make_extrafield_JLEE(c_ef);
+    z->cext += EB_C_JLEE_SIZE;
+
+    return ZE_OK;
+}
+
+
+
+/*
+* This is an implementation of Johnny Lee's extra field.
+* I never saw Johnny Lee's code. My code is based on the extra-field
+* definition mac (see latest appnote 1997-03-11)
+* and on some experiments with Johnny Lee's Zip-app version 1.0, 1992
+*
+* Unfortunately I cannot agree with his extra-field layout.
+*   - it wasted space
+*   - and holds not all mac-specific information
+*
+* I coded this extra-field only for testing purposes.
+* I don't want support this extra-field. Please use my implementation.
+*
+* This is old implementation of Johnny Lee's extra field.
+* All native datas are in Motorola (=big-endian) format
+*/
+
+static void make_extrafield_JLEE(char *ef)
+{
+
+    Assert_it(ef, "make_extrafield_JLEE","")
+
+    if (MacZip.isMacStatValid == false)
+        {
+        fprintf(stderr,"Internal Logic Error: [%d/%s] MacStat is out of sync !",
+                        __LINE__,__FILE__);
+        exit(-1);
+        }
+
+
+    /*  the first two fields are in Intel little-endian format  */
+    *ef++ = 0xC8;                             /* tag for this extra block */
+    *ef++ = 0x07;
+
+    *ef++ = (char)(EB_L_JLEE_LEN);            /* total data size this block */
+    *ef++ = (char)((EB_L_JLEE_LEN) >> 8);
+
+     /*  the following fields are in motorola big-endian format  */
+        *ef++ = 'J';                /* extra field signature:       4 Bytes */
+        *ef++ = 'L';                /* the old style extra field */
+        *ef++ = 'E';
+        *ef++ = 'E';
+
+                /* Start Macintosh Finder FInfo structure   16 Bytes overall */
+                                    /* Type:                        4 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 24);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 16);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType);
+
+                                    /* Creator:                     4 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 24);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 16);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator);
+
+                                     /* file Finder Flags:                2 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags);
+
+                                     /* Finders Icon position of a file*/
+                                     /* V/Y-Position:                2 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v);
+                                     /* H/X-Position:                2 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h);
+
+                               /* fdFldr Folder containing file    2 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFldr >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFldr);
+                /* End Macintosh Finder FInfo structure */
+
+
+                                                  /* Creation-time  4 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 24);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 16);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat);
+
+                                              /* Modification-time  4 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 24);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 16);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat);
+
+                                     /* info Bits                    4 Bytes */
+    *ef++ = 0x00;
+    *ef++ = 0x00;
+    *ef++ = 0x00;
+    if (MacZip.DataForkOnly)
+        {          /* don't convert filename for unzipping */
+                   /* 0x01 = data-fork; 0x00 = resource-fork */
+        *ef++ = (char) (MacZip.CurrentFork == DataFork) | 2;
+        }
+    else
+        {
+        *ef++ = (char) (MacZip.CurrentFork == DataFork);
+        }
+
+                                  /* file's location folder ID  4 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlParID >> 24);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlParID >> 16);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlParID >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlParID);
+                                                          /* ============  */
+                                                          /*     40 Bytes  */
+}
+
+
+
+/*
+* Build and add the new mac extra field
+* All native data are stored in Intel (=little-endian) format
+*/
+
+static int add_MAC3_ef( struct zlist far *z )
+{
+    char *l_ef        = NULL;
+    char *c_ef        = NULL;
+    char *attrbuff    = NULL;
+    off_t attrsize    = (EB_L_MAC3_FINFO_LEN + EB_MAX_OF_VARDATA);
+    char *compbuff    = NULL;
+    unsigned compsize = 0;
+    unsigned m3_compr;
+    Boolean compress_data = true;
+
+    Assert_it(z, "add_MAC3_ef","")
+
+    UserStop();  /* do event handling and let the user stop */
+
+    if( verbose ) {
+        print_extra_info();
+    }
+
+    /* allocate temporary buffer to collect the Mac extra field info */
+    attrbuff = (char *)malloc( (size_t)attrsize );
+    if( attrbuff == NULL ) {
+        return ZE_MEM;
+    }
+
+    /* fill the attribute buffer, to get its (uncompressed) size */
+    attrsize = make_extrafield_MAC3(attrbuff);
+
+    if (compress_data &&
+        ((compbuff = (char *)malloc((size_t)attrsize + MEMCOMPRESS_OVERHEAD))
+         != NULL))
+        {
+        /* Try compressing the data */
+        compsize = memcompress( compbuff,
+                                (size_t)attrsize + MEMCOMPRESS_OVERHEAD,
+                                attrbuff,
+                                (size_t)attrsize );
+#ifdef MAC_EXTRAFLD_UNCMPR
+        compsize = attrsize;
+#endif
+        }
+    else
+        {
+        compsize = attrsize;
+        }
+
+    if ((compsize) < attrsize) {
+        /* compression gained some space ... */
+        free(attrbuff);         /* no longer needed ... */
+        m3_compr = EB_M3_FL_COMPRESS;
+    } else {
+        /* compression does not help, store data in uncompressed mode */
+        if (compbuff != NULL) free(compbuff);
+        compbuff = attrbuff;
+        compsize = attrsize;
+        m3_compr = EB_M3_FL_UNCMPR;
+    }
+
+    /* Check to make sure we've got enough room in the extra fields. */
+    if( z->ext + (EB_L_MAC3_SIZE + compsize) > EF_SIZE_MAX ||
+        z->cext + EB_C_MAC3_SIZE > EF_SIZE_MAX ) {
+        if (compbuff != NULL) free(compbuff);
+        return ZE_MEM;
+    }
+
+    /* Allocate memory for the local extra fields. */
+    if( z->extra && z->ext != 0 ) {
+        l_ef = (char *)realloc( z->extra, z->ext +
+                                EB_L_MAC3_SIZE + compsize);
+    } else {
+        l_ef = (char *)malloc( EB_L_MAC3_SIZE + compsize);
+        z->ext = 0;
+    }
+    if( l_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->extra = l_ef;
+    l_ef += z->ext;
+
+    /* Allocate memory for the  central extra fields. */
+    if( z->cextra && z->cext != 0 ) {
+        c_ef = (char *)realloc( z->cextra, z->cext + EB_C_MAC3_SIZE);
+    } else {
+        c_ef = (char *)malloc( EB_C_MAC3_SIZE );
+        z->cext = 0;
+    }
+    if( c_ef == NULL ) {
+        return ZE_MEM;
+    }
+    z->cextra = c_ef;
+    c_ef += z->cext;
+
+    /**
+    **  Now add the local version of the field.
+    **/
+    l_ef = make_EF_Head_MAC3(l_ef, compsize, (ulg)attrsize, m3_compr);
+    memcpy(l_ef, compbuff, (size_t)compsize);
+    l_ef += compsize;
+    z->ext += EB_L_MAC3_SIZE + compsize;
+    free(compbuff);
+    /* And the central version. */
+    c_ef = make_EF_Head_MAC3(c_ef, 0, (ulg)attrsize, m3_compr);
+    z->cext += EB_C_MAC3_SIZE;
+
+    return ZE_OK;
+}
+
+
+
+
+/*
+* Build the new mac local extra field header.
+* It's identical with the central extra field.
+* All native data are in Intel (=little-endian) format
+*/
+static char *make_EF_Head_MAC3(char *ef, unsigned compsize, ulg attrsize,
+                               unsigned flag)
+{
+    unsigned info_flag = flag;
+
+    Assert_it(ef, "make_EF_Head_MAC3","")
+
+    /*  the first four fields are in Intel little-endian format  */
+    *ef++ = 'M';         /* tag for this extra block               2 Bytes */
+    *ef++ = '3';
+
+                                  /* total data size this block    2 Bytes */
+    *ef++ = (char) (EB_MAC3_HLEN + compsize);
+    *ef++ = (char)((EB_MAC3_HLEN + compsize) >> 8);
+
+    *ef++ = (char)(attrsize);
+    *ef++ = (char)(attrsize >> 8);
+    *ef++ = (char)(attrsize >> 16);
+    *ef++ = (char)(attrsize >> 24);
+
+                                   /* info Bits  (flags)           2 Bytes */
+
+    if (MacZip.DataForkOnly)            info_flag |= (EB_M3_FL_DATFRK |
+                                                      EB_M3_FL_NOCHANGE);
+    if (MacZip.CurrentFork == DataFork) info_flag |= EB_M3_FL_DATFRK;
+    if (!MacZip.HaveGMToffset)          info_flag |= EB_M3_FL_NOUTC;
+
+    *ef++ = (char)info_flag;
+    *ef++ = (char)0x00;            /* reserved at the moment */
+
+ /* Note: Apple defined File-Type/-Creator as OSType ( =unsigned long,
+          see Universal Headers 3.1). However, File-Type/-Creator are a
+          unique four-character sequence. Therefore the byteorder of the
+          File-Type/-Creator are NOT changed. The native format is used.  */
+
+                                                       /* Type:    4 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 24);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 16);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType);
+
+                                                       /* Creator: 4 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 24);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 16);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator);
+
+    return ef;
+}
+
+
+
+
+
+/*
+* Build the new mac local extra field header.
+* All native data are in Intel (=little-endian) format
+*/
+unsigned make_extrafield_MAC3(char *ef)
+{
+    char *ef_m3_begin = ef;
+    char *temp_Pathname;
+    char tmp_buffer[NAME_MAX];
+    unsigned char comment[257];
+    unsigned short FLength = 0;
+    unsigned short CLength = 0;
+    short   tempFork;
+    OSErr       err;
+
+    Assert_it(ef, "make_extrafield_MAC3","")
+
+    if (MacZip.isMacStatValid == false)
+    {
+        fprintf(stderr,
+                "Internal Logic Error: [%d/%s] MacStat is out of sync !",
+                __LINE__, __FILE__);
+        exit(-1);
+    }
+
+    /* Start Macintosh Finder FInfo structure except Type/Creator
+       (see make_EF_Head_MAC3()) 8 Bytes overall */
+
+                                             /* file Finder Flags: 2 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags >> 8);
+
+                                    /* Finders Icon position of a file*/
+                                   /* V/Y-Position:                2 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v >> 8);
+
+                                   /* H/X-Position:                2 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h >> 8);
+
+                               /* fdFldr Folder containing file    2 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFldr);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFldr >> 8);
+
+                /* End Macintosh Finder FInfo structure */
+
+                                                    /*    8 Bytes so far ... */
+
+                /* Start Macintosh Finder FXInfo structure  16 Bytes overall */
+                                                    /* Icon ID:    2 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdIconID);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdIconID >> 8);
+
+                                                        /* unused: 6 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[0]);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[0] >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[1]);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[1] >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[2]);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[2] >> 8);
+                                                   /* Script flag: 1 Byte */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdScript);
+                                                /* More flag bits: 1 Byte */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdXFlags);
+                                                /* Comment ID      2 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdComment);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdComment >> 8);
+
+                                                   /* Home Dir ID: 4 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdPutAway);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdPutAway >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdPutAway >> 16);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdPutAway >> 24);
+                /* End Macintosh Finder FXInfo structure */
+
+                                                    /*   24 Bytes so far ... */
+
+                                            /* file version number 1 Byte */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFVersNum);
+
+                                        /* directory access rights 1 Byte */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioACUser);
+
+                                                 /* Creation-time  4 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat  >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 16);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 24);
+                                             /* Modification-time  4 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 16);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 24);
+                                                   /* Backup-time  4 Bytes */
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlBkDat);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlBkDat >> 8);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlBkDat >> 16);
+    *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlBkDat >> 24);
+
+                                                    /*   38 Bytes so far ... */
+#ifdef USE_EF_UT_TIME
+    if (MacZip.HaveGMToffset) {
+                                              /* GMT-Offset times  12 Bytes */
+        *ef++ = (char)(MacZip.Cr_UTCoffs);
+        *ef++ = (char)(MacZip.Cr_UTCoffs >> 8);
+        *ef++ = (char)(MacZip.Cr_UTCoffs >> 16);
+        *ef++ = (char)(MacZip.Cr_UTCoffs >> 24);
+        *ef++ = (char)(MacZip.Md_UTCoffs);
+        *ef++ = (char)(MacZip.Md_UTCoffs >> 8);
+        *ef++ = (char)(MacZip.Md_UTCoffs >> 16);
+        *ef++ = (char)(MacZip.Md_UTCoffs >> 24);
+        *ef++ = (char)(MacZip.Bk_UTCoffs);
+        *ef++ = (char)(MacZip.Bk_UTCoffs >> 8);
+        *ef++ = (char)(MacZip.Bk_UTCoffs >> 16);
+        *ef++ = (char)(MacZip.Bk_UTCoffs >> 24);
+    }
+                                                    /*   50 Bytes so far ... */
+#endif
+
+                                  /* Text Encoding Base (charset)  2 Bytes */
+    *ef++ = (char)(MacZip.CurrTextEncodingBase);
+    *ef++ = (char)(MacZip.CurrTextEncodingBase >> 8);
+                                                    /*   52 Bytes so far ... */
+
+    /* MacZip.CurrentFork will be changed, so we have to save it  */
+    tempFork = MacZip.CurrentFork;
+    if (!MacZip.StoreFullPath)  {
+        temp_Pathname = StripPartialDir(tmp_buffer, MacZip.SearchDir,
+                                        MacZip.FullPath);
+    } else {
+        temp_Pathname = MacZip.FullPath;
+    }
+    MacZip.CurrentFork = tempFork;
+
+    FLength = strlen(temp_Pathname) + 1;
+    memcpy( ef, temp_Pathname, (size_t)FLength );
+    ef += FLength;          /* make room for the string -  variable length */
+
+    err = FSpLocationFromFullPath(strlen(MacZip.FullPath), MacZip.FullPath,
+                                  &MacZip.fileSpec);
+    printerr("FSpLocationFromFullPath:", err, err,
+             __LINE__, __FILE__, tmp_buffer);
+
+    err = FSpDTGetComment(&MacZip.fileSpec, comment);
+    printerr("FSpDTGetComment:", (err != -5012) && (err != 0), err,
+             __LINE__, __FILE__, "");
+    PToCCpy(comment,tmp_buffer);
+
+    CLength = strlen(tmp_buffer) + 1;
+    memcpy( ef, tmp_buffer, (size_t)CLength );
+    ef += CLength;          /* make room for the string -  variable length */
+
+    if (verbose) printf("\n comment: [%s]", tmp_buffer);
+
+    return (unsigned)(ef - ef_m3_begin);
+}
+
+
+
+
+
+
+/*
+* Print all native data of the new mac local extra field.
+* It's for debugging purposes and disabled by default.
+*/
+
+static void PrintFileInfo(void)
+{
+DateTimeRec  MacTime;
+
+printf("\n\n---------------------------------------------"\
+       "----------------------------------");
+printf("\n FullPath Name =                   [%s]",  MacZip.FullPath);
+printf("\n File Attributes =                  %s  0x%x  %d",
+          sBit2Str(MacZip.fpb.hFileInfo.ioFlAttrib),
+          MacZip.fpb.hFileInfo.ioFlAttrib,
+          MacZip.fpb.hFileInfo.ioFlAttrib);
+printf("\n Enclosing Folder ID# =             0x%x  %d",
+          MacZip.fpb.hFileInfo.ioFlParID,
+          MacZip.fpb.hFileInfo.ioFlParID);
+
+if (!MacZip.isDirectory)
+{
+printf("\n File Type =                        [%c%c%c%c]  0x%lx",
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 24,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 16,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 8,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType);
+
+printf("\n File Creator =                     [%c%c%c%c]  0x%lx",
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 24,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 16,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 8,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator);
+
+printf("\n Data Fork :" );
+printf("\n    Actual (Logical) Length =       %d  0x%x ",
+              MacZip.fpb.hFileInfo.ioFlLgLen,
+              MacZip.fpb.hFileInfo.ioFlLgLen);
+printf("\n    Allocated (Physical) Length =   %d  0x%x",
+              MacZip.fpb.hFileInfo.ioFlPyLen,
+              MacZip.fpb.hFileInfo.ioFlPyLen);
+printf("\n Resource Fork :" );
+printf("\n    Actual (Logical) Length =       %d  0x%x",
+              MacZip.fpb.hFileInfo.ioFlRLgLen,
+              MacZip.fpb.hFileInfo.ioFlRLgLen );
+printf("\n    Allocated (Physical) Length =   %d  0x%x",
+              MacZip.fpb.hFileInfo.ioFlRPyLen,
+              MacZip.fpb.hFileInfo.ioFlRPyLen );
+}
+
+printf("\n Dates :               ");
+
+SecondsToDate (MacZip.CreatDate, &MacTime);
+printf("\n    Created  =                       %4d/%2d/%2d %2d:%2d:%2d  ",
+    MacTime.year,
+    MacTime.month,
+    MacTime.day,
+    MacTime.hour,
+    MacTime.minute,
+    MacTime.second);
+
+SecondsToDate (MacZip.BackDate, &MacTime);
+printf("\n    Backup   =                       %4d/%2d/%2d %2d:%2d:%2d  ",
+    MacTime.year,
+    MacTime.month,
+    MacTime.day,
+    MacTime.hour,
+    MacTime.minute,
+    MacTime.second);
+
+SecondsToDate (MacZip.ModDate, &MacTime);
+printf("\n    Modified =                       %4d/%2d/%2d %2d:%2d:%2d  ",
+    MacTime.year,
+    MacTime.month,
+    MacTime.day,
+    MacTime.hour,
+    MacTime.minute,
+    MacTime.second);
+
+if (!MacZip.isDirectory)
+{
+printf("\n Finder Flags :                     %s  0x%x  %d",
+          sBit2Str(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags),
+          MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags,
+          MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags);
+printf("\n Finder Icon Position =          X: %d  0x%x ",
+          MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h,
+          MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h);
+printf("\n                                  Y: %d  0x%x ",
+          MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v,
+          MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v);
+}
+else
+{
+printf("\n Finder Flags :                     %s  0x%x  %d",
+          sBit2Str(MacZip.fpb.dirInfo.ioDrUsrWds.frFlags),
+          MacZip.fpb.dirInfo.ioDrUsrWds.frFlags,
+          MacZip.fpb.dirInfo.ioDrUsrWds.frFlags);
+printf("\n Finder Icon Position =          X: %d  0x%x ",
+          MacZip.fpb.dirInfo.ioDrUsrWds.frLocation.h,
+          MacZip.fpb.dirInfo.ioDrUsrWds.frLocation.h);
+printf("\n                                  Y: %d  0x%x ",
+          MacZip.fpb.dirInfo.ioDrUsrWds.frLocation.v,
+          MacZip.fpb.dirInfo.ioDrUsrWds.frLocation.v);
+}
+
+printf("\n----------------------------------------------------"\
+        "---------------------------\n");
+}
+
+
+
+/*
+* If the switch '-v' is used, print some more info.
+*/
+
+static void print_extra_info(void)
+{
+char Fork[20];
+
+if (MacZip.CurrentFork == DataFork) sstrcpy(Fork,"<DataFork>");
+else  sstrcpy(Fork,"<ResourceFork>");
+
+printf("\n%16s [%c%c%c%c]  [%c%c%c%c]",Fork,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 24,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 16,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 8,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType,
+
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 24,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 16,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 8,
+    MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator);
+}
diff --git a/macos/source/getenv.c b/macos/source/getenv.c
new file mode 100644 (file)
index 0000000..3b22327
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+
+This file implements the getenv() function.
+
+#  Background:
+#  Under Unix: Each Process (= running Program) has a set of
+#  associated variables. The variables are called enviroment
+#  variables and, together, constitute the process environment.
+#  These variables include the search path, the terminal type,
+#  and the user's login name.
+
+#  Unfortunatelly the MacOS has no equivalent. So we need
+#  a file to define the environment variables.
+#  Name of this file is "MacZip.Env". It can be placed
+#  in the current folder of MacZip or in the
+#  preference folder of the system disk.
+#  If MacZip founds the "MacZip.Env" file in the current
+#  the folder of MacZip the "MacZip.Env" file in the
+#  preference folder will be ignored.
+
+#  An environment variable has a name and a value:
+#  Name=Value
+#  Note: Spaces are significant:
+#  ZIPOPT=-r  and
+#  ZIPOPT = -r are different !!!
+
+
+ */
+
+/*****************************************************************************/
+/*  Includes                                                                 */
+/*****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unix.h>
+#include <Files.h>
+#include <Folders.h>
+
+#include "pathname.h"
+#include "helpers.h"
+
+/*****************************************************************************/
+/*  Module level Vars                                                        */
+/*****************************************************************************/
+
+static char ListAllKeyValues = 0;
+static unsigned LineNumber   = 0;
+static char CompletePath[NAME_MAX];
+Boolean IgnoreEnvironment    = false;  /* used by dialog.c and initfunc.c
+                                          of the Mainapp */
+
+/*****************************************************************************/
+/*  Macros, typedefs                                                         */
+/*****************************************************************************/
+
+typedef struct _EnviromentPair {
+    char *key;
+    char *value;
+} EnviromentPair;
+
+
+#define MAX_COMMAND 1024
+
+
+/*****************************************************************************/
+/*  Prototypes                                                               */
+/*****************************************************************************/
+
+
+int get_char(FILE *file);
+void unget_char(int ch,FILE *file);
+int get_string(char *string,int size, FILE *file, char *terms);
+void skip_comments(FILE *file);
+char *load_entry(FILE *file);
+char *getenv(const char *name);
+EnviromentPair *ParseLine(char *line);
+OSErr FSpFindFolder_Name(short vRefNum, OSType folderType,
+                         Boolean createFolder,FSSpec *spec, unsigned char *name);
+FILE * FSp_fopen(ConstFSSpecPtr spec, const char * open_mode);
+void ShowAllKeyValues(void);
+void Set_LineNum(unsigned ln);
+
+/*****************************************************************************/
+/*  Functions                                                                */
+/*****************************************************************************/
+
+
+/* get_string(str, max, file, termstr) : like fgets() but
+ *      (1) has terminator string which should include \n
+ *      (2) will always leave room for the null
+ *      (3) uses get_char() so LineNumber will be accurate
+ *      (4) returns EOF or terminating character, whichever
+ */
+int get_string(char *string, int size, FILE *file, char *terms)
+{
+    int ch;
+
+    while (EOF != (ch = get_char(file)) && !strchr(terms, ch)) {
+        if (size > 1) {
+            *string++ = (char) ch;
+            size--;
+        }
+    }
+
+    if (size > 0)
+        {
+        *string = '\0';
+        }
+
+    return ch;
+}
+
+
+
+
+void Set_LineNum(unsigned ln)
+{
+ LineNumber = ln;
+}
+
+
+
+/* get_char(file) : like getc() but increment LineNumber on newlines
+ */
+int get_char(FILE *file)
+{
+    int ch;
+
+    ch = getc(file);
+    if (ch == '\n')
+        {
+        Set_LineNum(LineNumber + 1);
+        }
+
+    return ch;
+}
+
+
+
+
+/* skip_comments(file) : read past comment (if any)
+ */
+void skip_comments(FILE *file)
+{
+    int ch;
+
+    while (EOF != (ch = get_char(file)))
+        {
+        /* ch is now the first character of a line.
+         */
+
+        while (ch == ' ' || ch == '\t')
+            {
+            ch = get_char(file);
+            }
+
+        if (ch == EOF)
+            {
+            break;
+            }
+
+        /* ch is now the first non-blank character of a line.
+         */
+
+        if (ch != '\n' && ch != '#')
+            {
+            break;
+            }
+
+        /* ch must be a newline or comment as first non-blank
+         * character on a line.
+         */
+
+        while (ch != '\n' && ch != EOF)
+            {
+            ch = get_char(file);
+            }
+
+        /* ch is now the newline of a line which we're going to
+         * ignore.
+         */
+    }
+
+    if (ch != EOF)
+        {
+        unget_char(ch, file);
+        }
+}
+
+
+
+
+/* unget_char(ch, file) : like ungetc but do LineNumber processing
+ */
+void unget_char(int ch, FILE *file)
+{
+    ungetc(ch, file);
+    if (ch == '\n')
+        {
+        Set_LineNum(LineNumber - 1);
+        }
+}
+
+
+/* this function reads one file entry -- the next -- from a file.
+*  it skips any leading blank lines, ignores comments, and returns
+*  NULL if for any reason the entry can't be read and parsed.
+*/
+
+char *load_entry(FILE *file)
+{
+    int ch;
+    static char cmd[MAX_COMMAND];
+
+    skip_comments(file);
+
+    ch = get_string(cmd, MAX_COMMAND, file, "\n");
+
+    if (ch == EOF)
+        {
+        return NULL;
+        }
+
+    return cmd;
+}
+
+
+
+
+
+EnviromentPair *ParseLine(char *line)
+{
+char *tmpPtr;
+static EnviromentPair *Env;
+unsigned short length = strlen(line);
+
+Env->key   = "";
+Env->value = "";
+
+for (tmpPtr = line; *tmpPtr; tmpPtr++)
+    {
+    if (*tmpPtr == '=')
+        {
+        *tmpPtr = 0;
+        Env->key = line;
+        if (strlen(Env->key) < length)
+            {
+            Env->value = ++tmpPtr;
+            }
+        return Env;
+        }
+    }
+return Env;
+}
+
+
+
+
+
+char *getenv(const char *name)
+{
+FILE *fp;
+char *LineStr = NULL;
+EnviromentPair *Env1;
+FSSpec spec;
+OSErr err;
+
+if (IgnoreEnvironment)
+    return NULL;  /* user wants to ignore the environment vars */
+
+if (name == NULL)
+    return NULL;
+
+GetCompletePath(CompletePath,"MacZip.Env",&spec,&err);
+
+/* try open the file in the current folder */
+fp = FSp_fopen(&spec,"r");
+if (fp == NULL)
+    { /* Okey, lets try open the file in the preference folder */
+    FSpFindFolder_Name(
+                   kOnSystemDisk,
+                   kPreferencesFolderType,
+                   kDontCreateFolder,
+                   &spec,
+                   "\pMacZip.Env");
+    fp = FSp_fopen(&spec,"r");
+    if (fp == NULL)
+        {
+        return NULL; /* there is no enviroment-file */
+        }
+    }
+
+LineStr = load_entry(fp);
+while (LineStr != NULL)
+    {   /* parse the file line by line */
+    Env1 = ParseLine(LineStr);
+    if (strlen(Env1->value) > 0)
+        {       /* we found a key/value pair */
+        if (ListAllKeyValues)
+            printf("\n   Line:%3d   [%s] = [%s]",LineNumber,Env1->key,Env1->value);
+        if (stricmp(name,Env1->key) == 0)
+            {   /* we found the value of a given key */
+            return Env1->value;
+            }
+        }
+    LineStr = load_entry(fp);  /* read next line */
+    }
+fclose(fp);
+
+return NULL;
+}
+
+
+
+
+
+OSErr FSpFindFolder_Name(
+    short vRefNum,          /* Volume reference number. */
+    OSType folderType,      /* Folder type taken by FindFolder. */
+    Boolean createFolder,   /* Should we create it if non-existant. */
+    FSSpec *spec,           /* Pointer to resulting directory. */
+    unsigned char *name)    /* Name of the file in the folder */
+{
+    short foundVRefNum;
+    long foundDirID;
+    OSErr err;
+
+    err = FindFolder(vRefNum, folderType, createFolder,
+                     &foundVRefNum, &foundDirID);
+    if (err != noErr)
+        {
+        return err;
+        }
+
+    err = FSMakeFSSpec(foundVRefNum, foundDirID, name, spec);
+    return err;
+}
+
+
+
+
+void ShowAllKeyValues(void)
+{
+OSErr err;
+FSSpec spec;
+Boolean tmpIgnoreEnvironment = IgnoreEnvironment;
+
+ListAllKeyValues = 1;
+IgnoreEnvironment = false;
+
+GetCompletePath(CompletePath,"MacZip.Env",&spec,&err);
+if (err != 0)
+    { /* Okey, lets try open the file in the preference folder */
+    FSpFindFolder_Name(
+                   kOnSystemDisk,
+                   kPreferencesFolderType,
+                   kDontCreateFolder,
+                   &spec,
+                   "\pMacZip.Env");
+    GetFullPathFromSpec(CompletePath,&spec, &err);
+    if (err != 0)
+        {
+        return; /* there is no enviroment-file */
+        }
+    }
+
+printf("\nLocation of the current \"MacZip.Env\" file:\n [%s]",CompletePath);
+
+printf("\n\nList of all environment variables\n");
+getenv(" ");
+printf("\n\nEnd\n\n");
+
+/* restore used variables */
+ListAllKeyValues = 0;
+LineNumber = 0;
+IgnoreEnvironment = tmpIgnoreEnvironment;
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/macos/source/helpers.c b/macos/source/helpers.c
new file mode 100644 (file)
index 0000000..36b5bef
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+  Copyright (c) 1990-2001 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+  helpers.c
+
+  Some useful functions Used by unzip and zip.
+
+  ---------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/*  Includes                                                                 */
+/*****************************************************************************/
+
+#include "zip.h"
+#include <ctype.h>
+#include <time.h>
+#include <sound.h>
+
+#include "macstuff.h"
+#include "helpers.h"
+#include "pathname.h"
+
+
+/*****************************************************************************/
+/*  Global Vars                                                              */
+/*****************************************************************************/
+
+
+extern int noisy;
+extern char MacPathEnd;
+extern char *zipfile;   /* filename of the Zipfile */
+extern char *tempzip;   /* Temporary zip file name */
+extern ZCONST unsigned char MacRoman_to_WinCP1252[128];
+
+
+static char         argStr[1024];
+static char         *argv[MAX_ARGS + 1];
+
+
+
+/*****************************************************************************/
+/*  Functions                                                                */
+/*****************************************************************************/
+
+
+/*
+**  Copy a C string to a Pascal string
+**
+*/
+
+unsigned char *CToPCpy(unsigned char *pstr, char *cstr)
+{
+    register char *dptr;
+    register unsigned len;
+
+        len=0;
+        dptr=(char *)pstr+1;
+    while (len<255 && (*dptr++ = *cstr++)!='\0') ++len;
+    *pstr= (unsigned char)len;
+  return pstr;
+}
+
+
+/*
+**  Copy a Pascal string to a C string
+**
+*/
+
+char *PToCCpy(unsigned char *pstr, char *cstr)
+{
+strncpy(cstr, (char *) &pstr[1], *pstr);
+    cstr[pstr[0]] = '\0';  /* set endmarker for c-string */
+return cstr;
+}
+
+
+/*
+**  strcpy() and strcat() work-alikes which allow overlapping buffers.
+*/
+
+char *sstrcpy(char *to,const char *from)
+{
+    memmove(to, from, 1+strlen(from));
+    return to;
+}
+
+char *sstrcat(char *to,const char *from)
+{
+    sstrcpy(to + strlen(to), from);
+    return to;
+}
+
+
+
+/*
+**  Alloc memory and init it
+**
+*/
+
+char *StrCalloc(unsigned short size)
+{
+char *strPtr = NULL;
+
+if ((strPtr = calloc(size, sizeof(char))) == NULL)
+    printerr("StrCalloc failed:", -1, size, __LINE__, __FILE__, "");
+
+Assert_it(strPtr,"strPtr == NULL","")
+return strPtr;
+}
+
+
+
+/*
+**  Release only non NULL pointers
+**
+*/
+
+char *StrFree(char *strPtr)
+{
+
+if (strPtr != NULL)
+    {
+    free(strPtr);
+    }
+
+return NULL;
+}
+
+
+
+
+/*
+**  Return a value in a binary string
+**
+*/
+
+char *sBit2Str(unsigned short value)
+{
+  static char str[sizeof(value)*8];
+  int biz    = 16;
+  int strwid = 16;
+  int i, j;
+  char *tempPtr = str;
+
+      j = strwid - (biz + (biz >> 2)- (biz % 4 ? 0 : 1));
+
+      for (i = 0; i < j; i++) {
+            *tempPtr++ = ' ';
+      }
+      while (--biz >= 0)
+      {
+            *tempPtr++ = ((value >> biz) & 1) + '0';
+            if (!(biz % 4) && biz) {
+                  *tempPtr++ = ' ';
+            }
+      }
+      *tempPtr = '\0';
+
+  return str;
+}
+
+
+
+
+/*
+**  Parse commandline style arguments
+**
+*/
+
+int ParseArguments(char *s, char ***arg)
+{
+    int  n = 1, Quote = 0;
+    char *p = s, *p1, c;
+
+    argv[0] = GetAppName();
+
+    *arg = argv;
+
+    p1 = (char *) argStr;
+    while ((c = *p++) != 0) {
+        if (c==' ') continue;
+        argv[n++] = p1;
+        if (n > MAX_ARGS)
+            return (n-1);
+        do {
+            if (c=='\\' && *p++)
+                c = *p++;
+            else
+                if ((c=='"') || (c == '\'')) {
+                    if (!Quote) {
+                        Quote = c;
+                        continue;
+                    }
+                    if (c == Quote) {
+                        Quote = 0;
+                        continue;
+                    }
+                }
+            *p1++ = c;
+        } while (*p && ((c = *p++) != ' ' || Quote));
+        *p1++ = '\0';
+    }
+    return n;
+}
+
+
+
+/*
+**  Print commandline style arguments
+**
+*/
+
+void PrintArguments(int argc, char **argv)
+{
+
+printf("\n Arguments:");
+printf("\n --------------------------");
+
+while(--argc >= 0)
+    printf("\n argc: %d  argv: [%s]", argc, &*argv[argc]);
+
+printf("\n --------------------------\n\n");
+return;
+}
+
+
+
+/*
+**  return some error-msg on file-system
+**
+*/
+
+int PrintUserHFSerr(int cond, int err, char *msg2)
+{
+char *msg;
+
+if (cond != 0)
+    {
+    switch (err)
+        {
+         case -35:
+            msg = "No such Volume";
+         break;
+
+         case -56:
+            msg = "No such Drive";
+         break;
+
+         case -37:
+            msg = "Bad Volume Name";
+         break;
+
+         case -49:
+            msg = "File is already open for writing";
+         break;
+
+         case -43:
+            msg = "Directory/File not found";
+         break;
+
+         case -120:
+            msg = "Directory/File not found or incomplete pathname";
+         break;
+
+        default: return err;
+         }
+    fprintf(stderr, "\n\n Error: %s ->%s", msg, msg2);
+    exit(err);
+    }
+
+return 0;
+}
+
+
+
+/*
+**  Check mounted volumes and return number of volumes
+**  with the same name.
+*/
+
+short CheckMountedVolumes(char *FullPath)
+{
+FSSpec  volumes[50];        /* 50 Volumes should be enough */
+char VolumeName[257], volume[257];
+short actVolCount, volIndex = 1, VolCount = 0;
+OSErr err;
+int i;
+
+GetVolumeFromPath(FullPath, VolumeName);
+
+err = OnLine(volumes, 50, &actVolCount, &volIndex);
+printerr("OnLine:", (err != -35) && (err != 0), err, __LINE__, __FILE__, "");
+
+for (i=0; i < actVolCount; i++)
+    {
+    PToCCpy(volumes[i].name,volume);
+    if (stricmp(volume, VolumeName) == 0) VolCount++;
+    }
+printerr("OnLine: ", (VolCount == 0), VolCount, __LINE__, __FILE__, FullPath);
+
+return VolCount;
+}
+
+
+
+
+
+
+
+
+/*
+**  compares strings, ignoring differences in case
+**
+*/
+
+int stricmp(const char *p1, const char *p2)
+{
+int diff;
+
+while (*p1 && *p2)
+    {
+    if (*p1 != *p2)
+        {
+        if (isalpha(*p1) && isalpha(*p2))
+            {
+            diff = toupper(*p1) - toupper(*p2);
+            if (diff) return diff;
+            }
+            else break;
+        }
+        p1++;
+        p2++;
+    }
+return *p1 - *p2;
+}
+
+
+
+/*
+** Convert the MacOS-Strings (Filenames/Findercomments) to a most compatible.
+** These strings will be stored in the public area of the zip-archive.
+** Every foreign platform (outside macos) will access these strings
+** for extraction.
+*/
+
+void MakeCompatibleString(char *MacOS_Str,
+            const char SpcChar1, const char SpcChar2,
+            const char SpcChar3, const char SpcChar4,
+            short CurrTextEncodingBase)
+{
+    char *tmpPtr;
+    register uch curch;
+
+    Assert_it(MacOS_Str,"MakeCompatibleString MacOS_Str == NULL","")
+    for (tmpPtr = MacOS_Str; (curch = *tmpPtr) != '\0'; tmpPtr++)
+    {
+        if (curch == SpcChar1)
+            *tmpPtr = SpcChar2;
+        else
+        if (curch == SpcChar3)
+            *tmpPtr = SpcChar4;
+        else  /* default */
+        /* now convert from MacRoman to ISO-8859-1 */
+        /* but convert only if MacRoman is activ */
+            if ((CurrTextEncodingBase == kTextEncodingMacRoman) &&
+                (curch > 127))
+                   {
+                    *tmpPtr = (char)MacRoman_to_WinCP1252[curch - 128];
+                   }
+    }  /* end for */
+}
+
+
+
+
+Boolean CheckForSwitch(char *Switch, int argc, char **argv)
+{
+  char *p;              /* steps through option arguments */
+  int i;                /* arg counter, root directory flag */
+
+  for (i = 1; i < argc; i++)
+  {
+    if (argv[i][0] == '-')
+    {
+      if (argv[i][1])
+        {
+        for (p = argv[i]+1; *p; p++)
+            {
+            if (*p == Switch[0])
+                {
+                return true;
+                }
+            if ((Switch[1] != NULL) &&
+                ((*p == Switch[0]) && (*p == Switch[1])))
+                {
+                return true;
+                }
+            }
+         }
+     }
+  }
+
+return false;
+}
+
+
+
+
+
+
+
+#if (defined(USE_SIOUX) || defined(MACUNZIP_STANDALONE))
+
+/*
+**  checks the condition and returns an error-msg
+**  this function is for internal use only
+*/
+
+OSErr printerr(const char *msg, int cond, int err, int line, char *file,
+              const char *msg2)
+{
+
+if (cond != 0)
+    {
+    fprintf(stderr, "\nint err: %d: %s %d [%d/%s] {%s}\n", clock(), msg, err,
+            line, file, msg2);
+    }
+
+return cond;
+}
+
+
+/*
+fake-functions:
+Not Implemented for metrowerks SIOUX
+*/
+
+void leftStatusString(char *status)
+{
+status = status;
+}
+
+
+void rightStatusString(char *status)
+{
+status = status;
+}
+
+
+
+void DoWarnUserDupVol( char *FullPath )
+{
+  char VolName[257];
+  GetVolumeFromPath(FullPath,  VolName);
+
+  printf("\n There are more than one volume that has the same name !!\n");
+
+  printf("\n Volume: %s\n",VolName);
+
+  printf("\n This port has one weak point:");
+  printf("\n It is based on pathnames. As you may be already know:");
+  printf("\n Pathnames are not unique on a Mac !");
+  printf("\n MacZip has problems to find the correct location of");
+  printf("\n the archive or the files.\n");
+
+  printf("\n My (Big) recommendation:  Name all your volumes with an");
+  printf("\n unique name and MacZip will run without any problem.");
+}
+
+
+
+#endif
diff --git a/macos/source/helpers.h b/macos/source/helpers.h
new file mode 100644 (file)
index 0000000..a9df5d8
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+  Copyright (c) 1990-2001 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef HELPERS_H
+#define HELPERS_H       1
+
+ /* Convert a C string to a Pascal string */
+unsigned char *CToPCpy(unsigned char *pstr, char *cstr);
+
+ /* Convert a Pascal string to a C string */
+char *PToCCpy(unsigned char *pstr, char *cstr);
+
+char *sstrcpy(char *to,const char *from);
+char *sstrcat(char *to,const char *from);
+
+char *StrCalloc(unsigned short size);
+char *StrFree(char *strPtr);
+
+char *sBit2Str(unsigned short value);
+
+void print_extra_info(void);
+
+int ParseArguments(char *s, char ***arg);
+void PrintArguments(int argc, char **argv);
+
+Boolean IsZipFile(char *name);
+OSErr printerr(const char *msg, int cond, int err, int line, char *file,
+               const char *msg2);
+int PrintUserHFSerr(int cond, int err, char *msg2);
+
+short CheckMountedVolumes(char *FullPath);
+void DoWarnUserDupVol(char *path);
+
+void PrintFileInfo(void);
+
+int stricmp(const char *p1, const char *p2);
+void leftStatusString(char *status);
+void rightStatusString(char *status);
+
+Boolean isZipFile(FSSpec *fileToOpen);
+
+unsigned long MacFileDate_to_UTime(unsigned long mactime);
+Boolean CheckForSwitch(char *Switch, int argc, char **argv);
+
+void MakeCompatibleString(char *MacOS_Str,
+            const char SpcChar1, const char SpcChar2,
+            const char SpcChar3, const char SpcChar4,
+            short CurrTextEncodingBase);
+
+#define     MAX_ARGS    25
+
+#endif   /*  HELPERS_H   */
diff --git a/macos/source/macglob.h b/macos/source/macglob.h
new file mode 100644 (file)
index 0000000..17415e1
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef _MACGLOBAL_
+#define _MACGLOBAL_
+
+#include <time.h>
+
+/*
+all my Global vars are defined here.
+*/
+
+#define ResourceFork    -1
+#define DataFork        1
+#define NoFork          0
+
+/*
+all my Global vars are defined here.
+*/
+typedef struct {
+    short       CurrentFork;
+    short       MacZipMode;
+
+    Boolean     isMacStatValid;
+    Boolean     HaveGMToffset;
+
+    short CurrTextEncodingBase;
+
+    /* info about the current file */
+    Boolean         isDirectory;
+    char            FullPath[NAME_MAX];
+    char            FileName[NAME_MAX];
+    FSSpec          fileSpec;
+
+    long            dirID;
+    CInfoPBRec      fpb;
+
+    /* time infos about the current file */
+    time_t          CreatDate;
+    time_t          ModDate;
+    time_t          BackDate;
+    long            Cr_UTCoffs; /* offset "local time - UTC" for CreatDate */
+    long            Md_UTCoffs; /* offset "local time - UTC" for ModDate */
+    long            Bk_UTCoffs; /* offset "local time - UTC" for BackDate */
+
+    /* some statistics over all*/
+    unsigned long   FoundFiles;
+    unsigned long   FoundDirectories;
+    unsigned long   RawCountOfItems;
+    unsigned long   BytesOfData;
+
+    unsigned long   attrsize;
+
+    /* some switches and user parameters */
+    Boolean         DataForkOnly;
+    Boolean         StoreFullPath;
+    Boolean         StoreFoldersAlso;  /* internal switch is true if '-r' is set */
+    unsigned short  SearchLevels;
+    char            Pattern[NAME_MAX];
+    Boolean         IncludeInvisible;
+    Boolean         StatingProgress;
+
+    char            SearchDir[NAME_MAX];
+    char            CurrentPath[NAME_MAX];
+
+    /* current zip / tempzip file info */
+    char            ZipFullPath[NAME_MAX];
+
+    FSSpec          ZipFileSpec;
+    unsigned long   ZipFileType;
+    char            TempZipFullPath[NAME_MAX];
+    FSSpec          TempZipFileSpec;
+
+} MacZipGlobals;
+
+
+
+void UserStop(void);
+
+
+#endif
diff --git a/macos/source/macopen.c b/macos/source/macopen.c
new file mode 100644 (file)
index 0000000..9e18730
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*** macopen.c; stuff only required for the Mac port ***/
+
+#include "zip.h"
+
+#include <string.h>
+#include <fcntl.h>
+#include <unix.h>
+#include <sound.h>
+
+#include "helpers.h"
+#include "pathname.h"
+#include "macopen.h"
+#include "macstuff.h"
+
+#ifdef MACZIP
+#include "macglob.h"
+
+extern char *zipfile;   /* filename of the Zipfile */
+extern char *tempzip;   /* Temporary zip file name */
+
+extern MacZipGlobals    MacZip;
+
+
+/* don't include "osdep.h" otherwise we will trap into endless loop */
+#undef open
+#undef fopen
+
+
+
+FILE *MacFopen(const char *path, const char *mode)
+{
+static char TruncPath[NAME_MAX];
+OSErr   err = 0;
+
+AssertStr(path,path)
+
+            /* open zipfile or tempzip */
+if (strcmp(zipfile,path) == 0)
+    {
+    GetCompletePath(MacZip.ZipFullPath,path,&MacZip.ZipFileSpec,&err);
+    err = PrintUserHFSerr((err != -43) && (err != 0), err, path);
+    printerr("GetCompletePath:",err,err,__LINE__,__FILE__,path);
+    if (CheckMountedVolumes(MacZip.ZipFullPath) > 1)
+        DoWarnUserDupVol(MacZip.ZipFullPath);
+
+    /* tempfile should appear in the same directory of the zipfile
+       -> save path of zipfile */
+    TruncFilename(TruncPath, MacZip.ZipFullPath);
+    return fopen(MacZip.ZipFullPath, mode);
+    }
+
+if (strcmp(tempzip,path) == 0)
+    {  /* add path of zipfile */
+    sstrcat(TruncPath,tempzip);
+    GetCompletePath(MacZip.TempZipFullPath,TruncPath,&MacZip.TempZipFileSpec,&err);
+    err = PrintUserHFSerr((err != -43) && (err != 0), err, path);
+    printerr("GetCompletePath:",err,err,__LINE__,__FILE__,path);
+
+    return fopen(MacZip.TempZipFullPath, mode);
+    }
+
+printerr("MacFopen:",err,err,__LINE__,__FILE__,path);
+return NULL;
+}
+
+
+
+
+int MacOpen(const char *path,int oflag, ...)
+{
+char RealFname[NAME_MAX];
+
+AssertStr(path,path)
+
+RfDfFilen2Real(RealFname,path, MacZip.MacZipMode, MacZip.DataForkOnly, &MacZip.CurrentFork);
+/* convert to real fname and init global var  MacZip.CurrentFork  !!  */
+
+switch (MacZip.CurrentFork)
+    {
+    case DataFork:
+        {
+        return my_open(RealFname, oflag);
+        break;
+        }
+    case ResourceFork:
+        {
+        return my_open( RealFname, oflag | O_RSRC);
+        break;
+        }
+    default:  /* for now (Zip ver 2.3b) MacOpen should never reach this point */
+        {     /* however, this may change in the future ... */
+        printerr("open: no resource / datafork ",-1,-1,__LINE__,__FILE__,path);
+        return -1;
+        }
+    }
+}
+
+
+#ifdef muell
+ /* file to delete */
+int destroy(char *path)
+{
+static char lastpath[NAME_MAX];
+char    currpath[NAME_MAX];
+static Boolean FirstCall = true;
+long rc;
+
+AssertStr(path,path)
+
+RfDfFilen2Real(currpath, path, MacZip.MacZipMode, MacZip.DataForkOnly, &MacZip.CurrentFork);
+
+if (FirstCall == true)
+    {
+    FirstCall = false;
+    rc = remove(currpath);
+    }
+else if (strcmp(currpath,lastpath) == 0) return 0; /* ignore, file is already deleted */
+        else rc = remove(currpath); /* we are removeing all the files only by their
+        pathname this is dangerous on a mac but there is no other way without
+         a complete rewrite of the port  */
+
+strcpy(lastpath,currpath);
+
+return rc;
+}
+#endif
+
+
+
+
+/* this function replaces the function "replace()" defined in fileio.c */
+int replace(char *new_f, char *temp_f)  /* destination and source file names */
+{
+OSErr   err = 0;
+char    newfname[NAME_MAX];
+
+AssertStr(new_f,new_f)
+AssertStr(temp_f,temp_f)
+
+UserStop();
+
+GetFilename(newfname, new_f);
+
+/* check zipfile name and tempfile name */
+/* we are using this function only for replacing the tempfile with the zipfile */
+if ((strcmp(zipfile,new_f) == 0) || (strcmp(tempzip,temp_f) == 0))
+    {
+    remove(MacZip.ZipFullPath);
+
+    /* rename the temp file to the zip file */
+    err = rename(MacZip.TempZipFullPath,MacZip.ZipFullPath);
+    printerr("rename:",err,err,__LINE__,__FILE__,MacZip.TempZipFullPath);
+if (err != 0) return ZE_CREAT;
+    else return ZE_OK;
+    }
+else return ZE_CREAT;
+}
+
+
+
+ /* file to delete */
+ /* we are removeing all the files only by their
+    pathname this is dangerous on a mac but there is no
+    other way without a complete rewrite of the port  */
+
+int destroy(char *path)
+{
+static char lastpath[NAME_MAX];
+static FSSpec  trashfolder;
+static Boolean FirstCall = true;
+static char Num = 0;
+static Boolean  Immediate_File_Deletion = false;
+char    currpath[NAME_MAX], *envptr;
+FSSpec  fileToDelete;
+OSErr   err;
+
+/* init this function */
+if ((path == NULL) ||
+    (strlen(path) == 0))
+    {
+    FirstCall = true;
+    Num = 0;
+    return -1;
+    }
+
+UserStop();
+
+RfDfFilen2Real(currpath, path, MacZip.MacZipMode,
+                MacZip.DataForkOnly, &MacZip.CurrentFork);
+GetCompletePath(currpath,currpath,&fileToDelete, &err);
+
+if (FirstCall == true)
+    {
+    FirstCall = false;
+    sstrcpy(lastpath,currpath);
+    err = FSpFindFolder(fileToDelete.vRefNum, kTrashFolderType,
+                      kDontCreateFolder,&trashfolder);
+    printerr("FSpFindFolder:",err,err,__LINE__,__FILE__,path);
+
+    envptr = getenv("Immediate_File_Deletion");
+    if (!(envptr == (char *)NULL || *envptr == '\0'))
+        {
+        if (stricmp(envptr,"yes") == 0)
+            Immediate_File_Deletion = true;
+        else
+            Immediate_File_Deletion = false;
+        }
+
+    if (Immediate_File_Deletion)
+        {
+        err = FSpDelete(&fileToDelete);
+        return err;
+        }
+
+    err = CatMove (fileToDelete.vRefNum, fileToDelete.parID,
+                   fileToDelete.name, trashfolder.parID, trashfolder.name);
+    return err;
+    }
+
+if (strcmp(currpath,lastpath) == 0)
+    {
+    return 0; /* ignore, file is already deleted */
+    }
+else
+    {
+
+    if (Immediate_File_Deletion)
+        {
+        err = FSpDelete(&fileToDelete);
+        sstrcpy(lastpath,path);
+        return err;
+        }
+
+    err = CatMove (fileToDelete.vRefNum, fileToDelete.parID,
+                   fileToDelete.name, trashfolder.parID, trashfolder.name);
+
+    /* -48 = file is already existing so we have to rename it before
+       moving the file */
+    if (err == -48)
+        {
+        Num++;
+        if (fileToDelete.name[0] >= 28) /* cut filename if to long */
+            fileToDelete.name[0] = 28;
+        P2CStr(fileToDelete.name);
+        sprintf(currpath,"%s~%d",(char *)fileToDelete.name,Num);
+        C2PStr(currpath);
+        C2PStr((char *)fileToDelete.name);
+        err = HRename (fileToDelete.vRefNum, fileToDelete.parID,
+                       fileToDelete.name, (unsigned char *) currpath);
+        err = CatMove (fileToDelete.vRefNum, fileToDelete.parID,
+                       (unsigned char *) currpath, trashfolder.parID,
+                       trashfolder.name);
+        }
+    }
+
+sstrcpy(lastpath,currpath);
+return err;
+}
+
+
+
+#endif  /* #ifdef MACZIP */
+
+
+
+
+/*
+ *  int open(const char *path, int oflag)
+ *
+ *      Opens a file stream.
+ */
+int my_open(char *path, int oflag)
+{
+    FSSpec          spec;
+    char            permission;
+    HParamBlockRec  hpb;
+    OSErr           err, errno;
+    Boolean targetIsFolder, wasAliased;
+
+    AssertStr(path,path)
+
+    /* Setup permission */
+    if ((oflag & 0x03) == O_RDWR)
+        permission = fsRdWrPerm;
+    else
+        permission = (oflag & O_RDONLY) ? fsRdPerm : 0 + (oflag & O_WRONLY) ? fsWrPerm : 0;
+
+        FSpLocationFromFullPath(strlen(path),path, &spec);
+        if ((oflag & (O_ALIAS | O_NRESOLVE)) == 0)
+            ResolveAliasFile(&spec, true, &targetIsFolder, &wasAliased);
+        hpb.fileParam.ioNamePtr = spec.name;
+        hpb.fileParam.ioVRefNum = spec.vRefNum;
+        hpb.fileParam.ioDirID = spec.parID;
+        hpb.ioParam.ioPermssn = permission;
+
+        if (oflag & O_RSRC)         /* open the resource fork of the file */
+            err = PBHOpenRFSync(&hpb);
+        else                        /* open the data fork of the file */
+            err = PBHOpenDFSync(&hpb);
+
+    if ((err == fnfErr) && (oflag & O_CREAT)) {
+        hpb.fileParam.ioFlVersNum = 0;
+        err = PBHCreateSync(&hpb);
+        if (err == noErr) {
+            /* Set the finder info */
+            unsigned long secs;
+            unsigned long isbinary = oflag & O_BINARY;
+
+            hpb.fileParam.ioFlFndrInfo.fdType = '\?\?\?\?';
+            hpb.fileParam.ioFlFndrInfo.fdCreator = '\?\?\?\?';
+            hpb.fileParam.ioFlFndrInfo.fdFlags = 0;
+            if (oflag & O_ALIAS)        /* set the alias bit */
+                hpb.fileParam.ioFlFndrInfo.fdFlags = kIsAlias;
+            else                                        /* clear all flags */
+                hpb.fileParam.ioFlFndrInfo.fdFlags = 0;
+
+            GetDateTime(&secs);
+            hpb.fileParam.ioFlCrDat = hpb.fileParam.ioFlMdDat = secs;
+            PBHSetFInfoSync(&hpb);
+        }
+
+        if (err && (err != dupFNErr)) {
+            errno = err; return -1;
+        }
+
+            if (oflag & O_RSRC)         /* open the resource fork of the file */
+                err = PBHOpenRFSync(&hpb);
+            else                        /* open the data fork of the file */
+                err = PBHOpenDFSync(&hpb);
+    }
+
+    if (err && (err != dupFNErr) && (err != opWrErr)) {
+        errno = err; return -1;
+    }
+
+    if (oflag & O_TRUNC) {
+        IOParam pb;
+
+        pb.ioRefNum = hpb.ioParam.ioRefNum;
+        pb.ioMisc = 0L;
+        err = PBSetEOFSync((ParmBlkPtr)&pb);
+        if (err != noErr) {
+            errno = err; return -1;
+        }
+    }
+
+    if (oflag & O_APPEND) lseek(hpb.ioParam.ioRefNum,0,SEEK_END);
+
+    return (hpb.ioParam.ioRefNum);
+}
+
+
+
+
+
diff --git a/macos/source/macopen.h b/macos/source/macopen.h
new file mode 100644 (file)
index 0000000..152bceb
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef __MACOPEN_H__
+#define __MACOPEN_H__
+
+#include <stdio.h>
+#include <Files.h>
+
+
+FILE *MacFopen(const char *path, const char *mode);
+int MacOpen(const char *path, int oflag, ...);
+
+int my_open(char *path, int oflag);
+
+#endif /* __MACOPEN_H__  */
diff --git a/macos/source/macos.c b/macos/source/macos.c
new file mode 100644 (file)
index 0000000..935c9a1
--- /dev/null
@@ -0,0 +1,1079 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+  macos.c
+
+  Macintosh-specific routines for use with Info-ZIP's Zip 2.3 and later.
+
+  ---------------------------------------------------------------------------*/
+
+
+/*****************************************************************************/
+/*  Includes                                                                 */
+/*****************************************************************************/
+
+#include "zip.h"
+
+#include "revision.h"
+#include "crypt.h"
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sound.h>
+
+#include <unistd.h>
+
+#include <Strings.h>
+#include <setjmp.h>
+
+/* #include "charmap.h" */
+#include "helpers.h"
+#include "macstuff.h"
+#include "pathname.h"
+#include "recurse.h"
+
+
+/*****************************************************************************/
+/*  Macros, typedefs                                                         */
+/*****************************************************************************/
+
+#define PATH_END   MacPathEnd
+
+/*****************************************************************************/
+/*  Global Vars                                                              */
+/*****************************************************************************/
+
+int error_level;   /* used only in ziperr() */
+
+
+/*  Note: sizeof() returns the size of this allusion
+          13 is current length of "XtraStuf.mac:"      */
+extern const char ResourceMark[13]; /* var is initialized in file pathname.c */
+
+
+extern jmp_buf EnvForExit;
+MacZipGlobals   MacZip;
+
+unsigned long count_of_Zippedfiles = 0;
+
+
+/*****************************************************************************/
+/*  Module level Vars                                                        */
+/*****************************************************************************/
+
+static const char MacPathEnd = ':';   /* the Macintosh dir separator */
+
+/*  Inform Progress vars */
+long    estTicksToFinish;
+long    createTime;
+long    updateTicks;
+
+static char *Time_Est_strings[] = {
+        "Zipping Files; Items done:",
+        "More than 24 hours",
+        "More than %s hours",
+        "About %s hours, %s minutes",
+        "About an hour",
+        "Less than an hour",
+        "About %s minutes, %s seconds",
+        "About a minute",
+        "Less than a minute",
+        "About %s seconds",
+        "About a second",
+        "About 1 minute, %s seconds"};
+
+
+
+/*****************************************************************************/
+/*  Prototypes                                                               */
+/*****************************************************************************/
+
+int DoCurrentDir(void);
+
+void DoAboutBox(void);
+void DoQuit(void);
+void DoEventLoop(void);
+
+void ZipInitAllVars(void);
+void UserStop(void);
+Boolean IsZipFile(char *name);
+
+static long EstimateCompletionTime(const long progressMax,
+                            const long progressSoFar, unsigned char percent);
+static void UpdateTimeToComplete(void);
+
+
+
+
+#ifdef USE_SIOUX
+#include <sioux.h>
+void DoWarnUserDupVol( char *FullPath );
+
+/*****************************************************************************/
+/*  Functions                                                                */
+/*****************************************************************************/
+
+/*
+** Standalone Unzip with Metrowerks SIOUX starts here
+**
+*/
+int main(int argc, char **argv)
+{
+    int return_code;
+
+    SIOUXSettings.asktosaveonclose = FALSE;
+    SIOUXSettings.showstatusline = TRUE;
+
+    SIOUXSettings.columns = 100;
+    SIOUXSettings.rows    = 40;
+
+    /* 30 = MacZip Johnny Lee's; 40 = new (my) MacZip */
+    MacZip.MacZipMode = NewZipMode_EF;
+
+    argc = ccommand(&argv);
+    if (verbose) PrintArguments(argc, argv);
+
+    ZipInitAllVars();
+
+    return_code = zipmain(argc, argv);
+
+    if (verbose) printf("\n\n Finish");
+    return return_code;
+}
+
+
+
+/*
+** SIOUX needs no extra event handling
+**
+*/
+
+void UserStop(void)
+{
+};
+
+
+
+
+/*
+** Password enter function '*' printed for each char
+**
+*/
+
+int macgetch(void)
+{
+    WindowPtr whichWindow;
+    EventRecord theEvent;
+    char c;                     /* one-byte buffer for read() to use */
+
+    do {
+        SystemTask();
+        if (!GetNextEvent(everyEvent, &theEvent))
+            theEvent.what = nullEvent;
+        else {
+            switch (theEvent.what) {
+            case keyDown:
+                c = theEvent.message & charCodeMask;
+                break;
+            case mouseDown:
+                if (FindWindow(theEvent.where, &whichWindow) ==
+                    inSysWindow)
+                    SystemClick(&theEvent, whichWindow);
+                break;
+            case updateEvt:
+                break;
+            }
+        }
+    } while (theEvent.what != keyDown);
+
+    printf("*");
+    fflush(stdout);
+
+    return (int)c;
+}
+
+#endif
+
+
+
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+/*
+** Print Compilers version and compile time/date
+**
+*/
+
+void version_local()
+{
+/* prints e.g:
+Compiled with  Metrowerks CodeWarrior version 2000 for  PowerPC Processor
+ compile time:  Feb  4 1998 17:49:49.
+*/
+
+static ZCONST char CompiledWith[] =
+                        "\n\nCompiled with %s %x for %s \n %s %s %s.\n\n";
+
+    printf(CompiledWith,
+
+
+#ifdef __MWERKS__
+      " Metrowerks CodeWarrior version", __MWERKS__,
+#endif
+
+
+#ifdef __MC68K__
+      " MC68K Processor",
+#else
+      " PowerPC Processor",
+#endif
+
+#ifdef __DATE__
+      "compile time: ", __DATE__, __TIME__
+#else
+      "", "", ""
+#endif
+    );
+} /* end function version_local() */
+
+
+
+
+
+/*
+** Deletes a dir if the switch '-m' is used
+**
+*/
+
+int deletedir(char *path)
+{
+static char     Num = 0;
+static FSSpec   trashfolder;
+static Boolean  FirstCall = true;
+static Boolean  Immediate_File_Deletion = false;
+OSErr           err;
+FSSpec          dirToDelete;
+char            currpath[NAME_MAX], *envptr;
+CInfoPBRec      fpb;
+
+/* init this function */
+if ((path == NULL) ||
+    (strlen(path) == 0))
+    {
+    Num = 0;
+    FirstCall = true;
+    return -1;
+    }
+
+UserStop();
+
+GetCompletePath(currpath,path,&dirToDelete, &err);
+
+if (FirstCall == true)
+    {
+    FirstCall = false;
+    envptr = getenv("Immediate_File_Deletion");
+    if (!(envptr == (char *)NULL || *envptr == '\0'))
+        {
+        if (stricmp(envptr,"yes") == 0)
+            Immediate_File_Deletion = true;
+        else
+            Immediate_File_Deletion = false;
+        }
+    err = FSpFindFolder(dirToDelete.vRefNum, kTrashFolderType,
+                      kDontCreateFolder,&trashfolder);
+    printerr("FSpFindFolder:",err,err,__LINE__,__FILE__,path);
+    }
+
+    fpb.dirInfo.ioNamePtr   = dirToDelete.name;
+    fpb.dirInfo.ioVRefNum   = dirToDelete.vRefNum;
+    fpb.dirInfo.ioDrDirID   = dirToDelete.parID;
+    fpb.dirInfo.ioFDirIndex = 0;
+
+    err = PBGetCatInfoSync(&fpb);
+    printerr("PBGetCatInfo deletedir ", err, err,
+             __LINE__, __FILE__, "");
+
+if (fpb.dirInfo.ioDrNmFls > 0)
+    {
+    return 0;  /* do not move / delete folders which are not empty */
+    }
+
+if (Immediate_File_Deletion)
+    {
+    err = FSpDelete(&dirToDelete);
+    return err;
+    }
+
+err = CatMove (dirToDelete.vRefNum, dirToDelete.parID,
+               dirToDelete.name, trashfolder.parID, trashfolder.name);
+
+/* -48 = file is already existing so we have to rename it before
+   moving the file */
+if (err == -48)
+    {
+    Num++;
+    if (dirToDelete.name[0] >= 28) /* cut foldername if to long */
+        dirToDelete.name[0] = 28;
+    P2CStr(dirToDelete.name);
+    sprintf(currpath,"%s~%d",(char *)dirToDelete.name,Num);
+    C2PStr(currpath);
+    C2PStr((char *)dirToDelete.name);
+    err = HRename (dirToDelete.vRefNum, dirToDelete.parID,
+                   dirToDelete.name, (unsigned char *) currpath);
+
+    err = CatMove (dirToDelete.vRefNum, dirToDelete.parID,
+                   (unsigned char *) currpath, trashfolder.parID,
+                   trashfolder.name);
+    }
+
+return err;
+}
+
+
+
+
+/*
+** Set the file-type so the archive will get the correct icon, type
+** and creator code.
+*/
+
+void setfiletype(char *new_f, unsigned long Creator, unsigned long Type)
+{
+OSErr   err;
+
+if (strcmp(zipfile, new_f) == 0)
+    err = FSpChangeCreatorType(&MacZip.ZipFileSpec, Creator, Type);
+printerr("FSpChangeCreatorType:", err, err, __LINE__, __FILE__, new_f);
+
+return;
+}
+
+
+
+
+
+/*
+** Convert the external (native) filename into Zip's internal Unix compatible
+** name space.
+*/
+
+char *ex2in(char *externalFilen, int isdir, int *pdosflag)
+/* char *externalFilen     external file name */
+/* int isdir               input: externalFilen is a directory */
+/* int *pdosflag           output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *internalFilen;              /* internal file name (malloc'ed) */
+  char *t;                          /* shortened name */
+  char *Pathname;
+  char buffer[NAME_MAX];
+  int dosflag;
+
+  AssertStr(externalFilen, externalFilen)
+  AssertBool(isdir,"")
+
+  dosflag = dosify;  /* default for non-DOS and non-OS/2 */
+
+  /* Find starting point in name before doing malloc */
+  for (t = externalFilen; *t == PATH_END; t++)
+      ;
+
+  if (!MacZip.StoreFullPath)
+        {
+        Pathname = StripPartialDir(buffer, MacZip.SearchDir,t);
+        }
+  else
+        {
+        Pathname = t;
+        }
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+  if (!pathput)
+    {
+    t = last(Pathname, PATH_END);
+    }
+  else t = Pathname;
+
+  /* Malloc space for internal name and copy it */
+  if ((internalFilen = malloc(strlen(t) + 10 + strlen(ResourceMark) )) == NULL)
+    return NULL;
+
+  sstrcpy(internalFilen, t);
+
+    /* we have to eliminate illegal chars:
+     * The name space for Mac filenames and Zip filenames (unix style names)
+     * do both include all printable extended-ASCII characters.  The only
+     * difference we have to take care of is the single special character
+     * used as path delimiter:
+     * ':' on MacOS and '/' on Unix and '\' on Dos.
+     * So, to convert between Mac filenames and Unix filenames without any
+     * loss of information, we simply interchange ':' and '/'.  Additionally,
+     * we try to convert the coding of the extended-ASCII characters into
+     * InfoZip's standard ISO 8859-1 codepage table.
+     */
+  MakeCompatibleString(internalFilen, ':', '/', '/', ':',
+                       MacZip.CurrTextEncodingBase);
+
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+
+  if (isdir)
+    {
+    return internalFilen;      /* avoid warning on unused variable */
+    }
+
+  if (dosify)
+    {
+    msname(internalFilen);
+    printf("\n ex2in: %s",internalFilen);
+    }
+
+  return internalFilen;
+}
+
+
+
+/*
+** Collect all filenames. Go through all directories
+**
+*/
+
+int wild(char *Pathpat)
+                /* path/pattern to match */
+/* If not in exclude mode, expand the pattern based on the contents of the
+   file system.  Return an error code in the ZE_ class. */
+{
+FSSpec Spec;
+char fullpath[NAME_MAX];
+OSErr   err;
+
+AssertStr(Pathpat, Pathpat);
+
+if (noisy) printf("%s \n\n",GetZipVersionsInfo());
+
+if (extra_fields == 0)
+    {
+    MacZip.DataForkOnly = true;
+    }
+
+/* for switch '-R' -> '.' means current dir */
+if (strcmp(Pathpat,".") == 0) sstrcpy(Pathpat,"*");
+
+sstrcpy(MacZip.Pattern,Pathpat);
+
+if (recurse)
+    {
+    MacZip.StoreFoldersAlso = true;
+    MacZip.SearchLevels = 0; /* if 0 we aren't checking levels */
+    }
+else
+    {
+    MacZip.StoreFoldersAlso = false;
+    MacZip.SearchLevels = 1;
+    }
+
+/* make complete path */
+GetCompletePath(fullpath, MacZip.Pattern, &Spec,&err);
+err = PrintUserHFSerr((err != -43) && (err != 0), err, MacZip.Pattern);
+printerr("GetCompletePath:", err, err, __LINE__, __FILE__, fullpath);
+
+/* extract the filepattern */
+GetFilename(MacZip.Pattern, fullpath);
+
+/* extract Path and get FSSpec of search-path */
+/* get FSSpec of search-path  ; we need a dir to start
+   searching for filenames */
+TruncFilename(MacZip.SearchDir, fullpath);
+GetCompletePath(MacZip.SearchDir, MacZip.SearchDir, &Spec,&err);
+
+if (noisy) {
+    if (MacZip.SearchLevels == 0)
+        {
+        printf("\nSearch Pattern: [%s]   Levels: all", MacZip.Pattern);
+        }
+    else
+        {
+        printf("\nSearch Pattern: [%s]   Levels: %d", MacZip.Pattern,
+               MacZip.SearchLevels);
+        }
+    printf("\nSearch Path:    [%s]", MacZip.SearchDir);
+    printf("\nZip-File:       [%s] \n",MacZip.ZipFullPath);
+
+}
+
+/* we are working only with pathnames;
+ * this can cause big problems on a mac ...
+ */
+if (CheckMountedVolumes(MacZip.SearchDir) > 1)
+    DoWarnUserDupVol(MacZip.SearchDir);
+
+/* start getting all filenames */
+err = FSpRecurseDirectory(&Spec, MacZip.SearchLevels);
+printerr("FSpRecurseDirectory:", err, err, __LINE__, __FILE__, "");
+
+return ZE_OK;
+}
+
+
+
+/*
+** Convert the internal filename into a external (native).
+** The user will see this modified filename.
+** For more performance:
+** I do not completly switch back to the native macos filename.
+** The user will still see directory separator '/' and the converted
+** charset.
+*/
+
+char *in2ex(char *n)    /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+
+  AssertStr(n,n)
+
+  if ((x = malloc(strlen(n) + 1)) == NULL)
+    return NULL;
+
+  RfDfFilen2Real(x, n, MacZip.MacZipMode, MacZip.DataForkOnly,
+                 &MacZip.CurrentFork);
+
+  return x;
+}
+
+
+
+
+/*
+** Process on filenames. This function will be called to collect
+** the filenames.
+*/
+
+int procname(char *filename,         /* name to process */
+             int caseflag)           /* true to force case-sensitive match
+                                        (always false on a Mac) */
+/* Process a name .  Return
+   an error code in the ZE_ class. */
+{
+  int rc;                /* matched flag */
+
+AssertBool(caseflag,"caseflag")
+AssertStr(filename,filename)
+
+        /* add or remove name of file */
+rc = newname(filename, MacZip.isDirectory, caseflag);
+
+return rc;
+}
+
+
+
+
+ulg filetime(
+char *f,                /* name of file to get info on */
+ulg *a,                 /* return value: file attributes */
+long *n,                /* return value: file size */
+iztimes *t)             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+
+  AssertStr(f,f)
+
+  if (strlen(f) == 0) return 0;
+
+  if (SSTAT(f, &s) != 0)
+             /* Accept about any file kind including directories
+              * (stored with trailing : with -r option)
+              */
+    return 0;
+
+  if (a != NULL) {
+    *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+    if (MacZip.isDirectory) {
+      *a |= MSDOS_DIR_ATTR;
+    }
+  }
+  if (n != NULL)
+    *n = (s.st_mode & UNX_IFMT) == UNX_IFREG ? s.st_size : -1L;
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = s.st_ctime;   /* on Mac, st_ctime contains creation time! */
+  }
+
+  return unix2dostime(&s.st_mtime);
+}
+
+
+
+void stamp(char *f, ulg d)
+/* char *f;                name of file to change */
+/* ulg d;                  dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+  time_t u[2];          /* argument for utime() */
+
+f = f;
+
+  /* Convert DOS time to time_t format in u */
+
+  u[0] = u[1] = dos2unixtime(d);
+/*  utime(f, u);  */
+}
+
+
+
+
+/*
+**  return only the longest part of the path:
+**  second parameter: Volume:test folder:second folder:
+**  third parameter:  Volume:test folder:second folder:third folder:file
+**  result will be:   third folder:file
+**  first parameter:  contains string buffer that will be used to prepend
+**                    the "resource mark" part in front of the result when
+**                    a resource fork is processed in "M3" mode.
+**
+*/
+
+char *StripPartialDir(char *CompletePath,
+                      const char *PartialPath, const char *FullPath)
+{
+const char *tmpPtr1 = PartialPath;
+const char *tmpPtr2 = FullPath;
+int     result;
+
+Assert_it(CompletePath,"StripPartialDir","")
+AssertStrNoOverlap(FullPath,PartialPath,PartialPath)
+
+if (MacZip.DataForkOnly)
+        {
+        tmpPtr2 += strlen(tmpPtr1);
+        return (char *)tmpPtr2;
+        }
+
+switch (MacZip.MacZipMode)
+    {
+    case JohnnyLee_EF:
+        {
+        tmpPtr2 += strlen(tmpPtr1);
+        return (char *)tmpPtr2;
+        break;
+        }
+
+    case NewZipMode_EF:
+        {           /* determine Fork type */
+        result = strncmp(FullPath, ResourceMark, sizeof(ResourceMark)-2);
+        if (result != 0)
+            {                               /* data fork  */
+            MacZip.CurrentFork = DataFork;
+            tmpPtr2 += strlen(tmpPtr1);
+             return (char *)tmpPtr2;
+            }
+        else
+            {                                /* resource fork  */
+            MacZip.CurrentFork = ResourceFork;
+            sstrcpy(CompletePath, ResourceMark);
+            tmpPtr2 += strlen(tmpPtr1);
+            tmpPtr2 += sizeof(ResourceMark);
+            sstrcat(CompletePath, tmpPtr2);
+            return (char *)CompletePath;
+            }
+        break;
+        }
+    }
+
+ return NULL;    /* function should never reach this point */
+}
+
+
+
+
+/*
+** Init all global variables
+** Must be called for each zip-run
+*/
+
+void ZipInitAllVars(void)
+{
+getcwd(MacZip.CurrentPath, sizeof(MacZip.CurrentPath));
+/* MacZip.MacZipMode = JohnnyLee_EF;     */
+MacZip.MacZipMode = NewZipMode_EF;
+
+MacZip.DataForkOnly = false;
+MacZip.CurrentFork = NoFork;
+
+MacZip.StoreFoldersAlso = false;
+
+MacZip.FoundFiles = 0;
+MacZip.FoundDirectories = 0;
+MacZip.RawCountOfItems = 0;
+MacZip.BytesOfData = 0;
+
+MacZip.StoreFullPath = false;
+MacZip.StatingProgress = false;
+MacZip.IncludeInvisible = false;
+
+MacZip.isMacStatValid = false;
+
+MacZip.CurrTextEncodingBase = FontScript();
+
+MacZip.HaveGMToffset = false;
+
+createTime = TickCount();
+estTicksToFinish = -1;
+updateTicks = 0;
+
+/* init some functions */
+IsZipFile(NULL);
+
+destroy(NULL);
+deletedir(NULL);
+ShowCounter(true);
+
+extra_fields = 1;
+error_level = 0;
+count_of_Zippedfiles = 0;
+}
+
+
+
+
+/*
+** Get the findercomment and store it as file-comment in the Zip-file
+**
+*/
+char *GetComment(char *filename)
+{
+OSErr       err;
+static char buffer[NAME_MAX];
+char buffer2[NAME_MAX];
+char *tmpPtr;
+
+if (filename == NULL) return NULL;
+
+    /* now we can convert Unix-Path in HFS-Path */
+for (tmpPtr = filename; *tmpPtr; tmpPtr++)
+    if (*tmpPtr == '/')
+      *tmpPtr = ':';
+
+if (MacZip.StoreFullPath)
+    {  /* filename is already a fullpath */
+    sstrcpy(buffer,filename);
+    }
+else
+    {  /* make a fullpath */
+    sstrcpy(buffer,MacZip.SearchDir);
+    sstrcat(buffer,filename);
+    }
+
+/* make fullpath and get FSSpec */
+/* Unfortunately: I get only the converted filename here */
+/* so filenames with extended characters can not be found  */
+GetCompletePath(buffer2,buffer, &MacZip.fileSpec, &err);
+printerr("GetCompletePath:",(err != -43) && (err != -120) && (err != 0) ,
+          err,__LINE__,__FILE__,buffer);
+
+err = FSpDTGetComment(&MacZip.fileSpec, (unsigned char *) buffer);
+printerr("FSpDTGetComment:", (err != -5012) && (err != 0), err,
+         __LINE__, __FILE__, filename);
+P2CStr((unsigned char *) buffer);
+if (err == -5012) return NULL;  /* no finder-comments found */
+
+if (noisy) printf("\n%32s -> %s",filename, buffer);
+/*
+Beside the script change we need only to change 0x0d in 0x0a
+so the last two arguments are not needed and does nothing.
+*/
+MakeCompatibleString(buffer, 0x0d, 0x0a, ' ', ' ',
+                     MacZip.CurrTextEncodingBase);
+
+return buffer;
+}
+
+
+
+
+/*
+** Print a progress indicator for stating the files
+**
+*/
+
+void PrintStatProgress(char *msg)
+{
+
+if (!noisy) return;     /* do no output if noisy is false */
+
+MacZip.StatingProgress = true;
+
+if (strcmp(msg,"done") == 0)
+    {
+    MacZip.StatingProgress = false;
+    printf("\n ... done \n\n");
+    }
+else printf("\n %s",msg);
+
+}
+
+
+
+
+void InformProgress(const long progressMax, const long progressSoFar )
+{
+int curr_percent;
+char no_time[5] = "...";
+
+curr_percent = percent(progressMax, progressSoFar);
+
+if (curr_percent < 95)
+    {
+    estTicksToFinish = EstimateCompletionTime(progressMax,
+                                                  progressSoFar, curr_percent);
+    }
+else
+    {
+    rightStatusString(no_time);
+    leftStatusString(no_time);
+    }
+
+updateTicks = TickCount() + 60;
+return;
+}
+
+
+void ShowCounter(Boolean reset)
+{
+static char statusline[100];
+static unsigned long filecount = 0;
+
+if (reset)
+        {
+        filecount = 0;
+        return;
+        }
+
+if (noisy)
+    {
+    sprintf(statusline, "%6d", filecount++);
+    rightStatusString(statusline);
+    }
+}
+
+
+static long EstimateCompletionTime(const long progressMax,
+                                const long progressSoFar,
+                                unsigned char curr_percent)
+{
+    long  max = progressMax, value = progressSoFar;
+    static char buf[100];
+    unsigned long ticksTakenSoFar = TickCount() - createTime;
+    float currentRate = (float) ticksTakenSoFar / (float) value;
+    long  newEst = (long)( currentRate * (float)( max - value ));
+
+    sprintf(buf, "%d [%d%%]",progressSoFar, curr_percent);
+    rightStatusString(buf);
+
+    estTicksToFinish = newEst;
+
+    UpdateTimeToComplete();
+
+return estTicksToFinish;
+}
+
+
+
+
+
+static void UpdateTimeToComplete(void)
+{
+    short       days, hours, minutes, seconds;
+    char    estStr[255];
+    Str15   xx, yy;
+    short   idx = 0;
+
+    if ( estTicksToFinish == -1 )
+        return;
+
+    days    =   estTicksToFinish / 5184000L;
+    hours   = ( estTicksToFinish - ( days * 5184000L )) / 216000L;
+    minutes = ( estTicksToFinish - ( days * 5184000L ) -
+              ( hours * 216000L )) / 3600L;
+    seconds = ( estTicksToFinish - ( days * 5184000L ) -
+              ( hours * 216000L ) - ( minutes * 3600L )) / 60L;
+
+        xx[0] = 0;
+        yy[0] = 0;
+
+        if ( days )
+        {
+            /* "more than 24 hours" */
+
+            idx = 1;
+            goto setEstTimeStr;
+        }
+
+        if ( hours >= 8 )
+        {
+            /* "more than x hours" */
+
+            NumToString( hours, xx );
+            idx = 2;
+            goto setEstTimeStr;
+        }
+
+        if ( estTicksToFinish > 252000L  )      /* > 1hr, 10 minutes */
+        {
+            /* "about x hours, y minutes" */
+
+            NumToString( hours, xx );
+            NumToString( minutes, yy );
+            idx = 3;
+            goto setEstTimeStr;
+        }
+
+        if ( estTicksToFinish > 198000L )   /* > 55 minutes */
+        {
+            /* "about an hour" */
+            idx = 4;
+            goto setEstTimeStr;
+        }
+
+        if ( estTicksToFinish > 144000L )   /* > 40 minutes */
+        {
+            /* "less than an hour" */
+
+            idx = 5;
+            goto setEstTimeStr;
+        }
+
+        if ( estTicksToFinish > 4200L )     /* > 1 minute, 10 sec */
+        {
+            /* "about x minutes, y seconds */
+
+            NumToString( minutes, xx );
+            NumToString( seconds, yy );
+
+            if ( minutes == 1 )
+                idx = 11;
+            else
+                idx = 6;
+            goto setEstTimeStr;
+        }
+
+        if ( estTicksToFinish > 3000L )     /* > 50 seconds */
+        {
+            /* "about a minute" */
+
+            idx = 7;
+            goto setEstTimeStr;
+        }
+
+        if ( estTicksToFinish > 1500L )     /* > 25 seconds */
+        {
+            /* "less than a minute" */
+
+            idx = 8;
+            goto setEstTimeStr;
+        }
+
+        if ( estTicksToFinish > 120L )      /* > 2 seconds */
+        {
+            NumToString( seconds, xx );
+            idx = 9;
+            goto setEstTimeStr;
+        }
+
+        idx = 10;
+
+    setEstTimeStr:
+        sprintf(estStr,Time_Est_strings[idx],P2CStr(xx),P2CStr(yy));
+        leftStatusString((char *)estStr);
+}
+
+
+
+
+
+/*
+** Just return the zip version
+**
+*/
+
+char *GetZipVersionsInfo(void)
+{
+static char ZipVersion[100];
+
+sprintf(ZipVersion, "Zip Module\n%d.%d%d%s of %s", Z_MAJORVER, Z_MINORVER,
+        Z_PATCHLEVEL, Z_BETALEVEL, REVDATE);
+
+return ZipVersion;
+}
+
+
+
+
+#ifndef USE_SIOUX
+
+/*
+** Just return the copyright message
+**
+*/
+
+char *GetZipCopyright(void)
+{
+static char CopyR[300];
+
+sstrcpy(CopyR, copyright[0]);
+sstrcat(CopyR, copyright[1]);
+sstrcat(CopyR, "\r\rPlease send bug reports to the authors at\r"\
+              "Zip-Bugs@lists.wku.edu");
+
+return CopyR;
+}
+
+
+
+
+/*
+** Just return the compilers date/time
+**
+*/
+
+char *GetZipVersionLocal(void)
+{
+static char ZipVersionLocal[50];
+
+sprintf(ZipVersionLocal, "[%s %s]", __DATE__, __TIME__);
+
+return ZipVersionLocal;
+}
+
+#endif  /*   #ifndef USE_SIOUX  */
+
+
+
+
diff --git a/macos/source/macstuff.c b/macos/source/macstuff.c
new file mode 100644 (file)
index 0000000..0323607
--- /dev/null
@@ -0,0 +1,1724 @@
+/*
+These Functions were originally part of More Files version 1.4.8
+
+More Files fixes many of the broken or underfunctional
+parts of the file system.
+
+More Files
+
+A collection of File Manager and related routines
+
+by Jim Luther (Apple Macintosh Developer Technical Support Emeritus)
+with significant code contributions by Nitin Ganatra
+(Apple Macintosh Developer Technical Support Emeritus)
+Copyright  1992-1998 Apple Computer, Inc.
+Portions copyright  1995 Jim Luther
+All rights reserved.
+
+The Package "More Files" is distributed under the following
+license terms:
+
+         "You may incorporate this sample code into your
+          applications without restriction, though the
+          sample code has been provided "AS IS" and the
+          responsibility for its operation is 100% yours.
+          However, what you are not permitted to do is to
+          redistribute the source as "DSC Sample Code" after
+          having made changes. If you're going to
+          redistribute the source, we require that you make
+          it clear in the source that the code was descended
+          from Apple Sample Code, but that you've made
+          changes."
+
+
+The following changes are made by Info-ZIP:
+
+- The only changes are made by pasting the functions
+  (mostly found in MoreFilesExtras.c / MoreFiles.c)
+  directly into macstuff.c / macstuff.h and slightly
+  reformatting the text (replacement of TABs by spaces,
+  removal/replacement of non-ASCII characters).
+  The code itself is NOT changed.
+
+This file has been modified by Info-ZIP for use in MacZip.
+This file is NOT part of the original package More Files.
+
+More Files can be found on the MetroWerks CD and Developer CD from
+Apple. You can also download the latest version from:
+
+    http://members.aol.com/JumpLong/#MoreFiles
+
+Jim Luther's Home-page:
+    http://members.aol.com/JumpLong/
+
+
+*/
+
+#include <string.h>
+
+
+#include "macstuff.h"
+
+
+
+extern int errno;
+
+static  OSErr   GetCommentFromDesktopFile(short vRefNum,
+                                          long dirID,
+                                          ConstStr255Param name,
+                                          Str255 comment);
+
+static  OSErr   GetCommentID(short vRefNum,
+                             long dirID,
+                             ConstStr255Param name,
+                             short *commentID);
+
+static  OSErr   GetDesktopFileName(short vRefNum,
+                                   Str255 desktopName);
+
+
+enum
+{
+    kBNDLResType    = 'BNDL',
+    kFREFResType    = 'FREF',
+    kIconFamResType = 'ICN#',
+    kFCMTResType    = 'FCMT',
+    kAPPLResType    = 'APPL'
+};
+
+
+/*****************************************************************************/
+
+/*
+**  File Manager FSp calls
+*/
+
+/*****************************************************************************/
+
+pascal  OSErr   FSMakeFSSpecCompat(short vRefNum,
+                                   long dirID,
+                                   ConstStr255Param fileName,
+                                   FSSpec *spec)
+{
+    OSErr   result;
+
+#if !__MACOSSEVENORLATER
+    if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+    {
+        Boolean isDirectory;
+
+        result = GetObjectLocation(vRefNum, dirID, fileName,
+                                    &(spec->vRefNum), &(spec->parID), spec->name,
+                                    &isDirectory);
+    }
+    else
+#endif  /* !__MACOSSEVENORLATER */
+    {
+     /* Let the file system create the FSSpec if it can since it does the job */
+     /* much more efficiently than I can. */
+        result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
+
+        /* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
+        /* returned in the parID field when making an FSSpec to the volume's */
+        /* root directory by passing a full pathname in MakeFSSpec's */
+        /* fileName parameter. Fixed in Mac OS 8.1 */
+        if ( (result == noErr) && (spec->parID == 0) )
+            spec->parID = fsRtParID;
+    }
+    return ( result );
+}
+
+
+/*****************************************************************************/
+/* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
+
+#if !__MACOSSEVENORLATER
+static  Boolean FSHasFSSpecCalls(void)
+{
+    long            response;
+#if !GENERATENODATA
+    static Boolean  tested = false;
+    static Boolean  result = false;
+#else
+    Boolean result = false;
+#endif
+
+#if !GENERATENODATA
+    if ( !tested )
+    {
+        tested = true;
+#endif
+        if ( Gestalt(gestaltFSAttr, &response) == noErr )
+        {
+            result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
+        }
+#if !GENERATENODATA
+    }
+#endif
+    return ( result );
+}
+#endif  /* !__MACOSSEVENORLATER */
+
+
+
+/*****************************************************************************/
+/* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
+/* except for FSpExchangeFiles. */
+
+#if !__MACOSSEVENORLATER
+static  Boolean QTHasFSSpecCalls(void)
+{
+    long            response;
+#if !GENERATENODATA
+    static Boolean  tested = false;
+    static Boolean  result = false;
+#else
+    Boolean result = false;
+#endif
+
+#if !GENERATENODATA
+    if ( !tested )
+    {
+        tested = true;
+#endif
+        result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
+#if !GENERATENODATA
+    }
+#endif
+    return ( result );
+}
+#endif  /* !__MACOSSEVENORLATER */
+
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpGetDefaultDir --
+ *
+ *  This function gets the current default directory.
+ *
+ * Results:
+ *  The provided FSSpec is changed to point to the "default"
+ *  directory.  The function returns what ever errors
+ *  FSMakeFSSpecCompat may encounter.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int FSpGetDefaultDir(FSSpecPtr dirSpec) /* On return the default directory. */
+{
+    OSErr err;
+    short vRefNum = 0;
+    long int dirID = 0;
+
+    err = HGetVol(NULL, &vRefNum, &dirID);
+
+    if (err == noErr) {
+    err = FSMakeFSSpecCompat(vRefNum, dirID, (ConstStr255Param) NULL,
+        dirSpec);
+    }
+
+    return err;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpSetDefaultDir --
+ *
+ *  This function sets the default directory to the directory
+ *  pointed to by the provided FSSpec.
+ *
+ * Results:
+ *  The function returns what ever errors HSetVol may encounter.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int FSpSetDefaultDir(FSSpecPtr dirSpec) /* The new default directory. */
+{
+    OSErr err;
+
+    /*
+     * The following special case is needed to work around a bug
+     * in the Macintosh OS.  (Acutally PC Exchange.)
+     */
+
+    if (dirSpec->parID == fsRtParID) {
+    err = HSetVol(NULL, dirSpec->vRefNum, fsRtDirID);
+    } else {
+    err = HSetVol(dirSpec->name, dirSpec->vRefNum, dirSpec->parID);
+    }
+
+    return err;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpFindFolder --
+ *
+ *  This function is a version of the FindFolder function that
+ *  returns the result as a FSSpec rather than a vRefNum and dirID.
+ *
+ * Results:
+ *  Results will be simaler to that of the FindFolder function.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+OSErr
+FSpFindFolder(
+    short vRefNum,      /* Volume reference number. */
+    OSType folderType,      /* Folder type taken by FindFolder. */
+    Boolean createFolder,   /* Should we create it if non-existant. */
+    FSSpec *spec)       /* Pointer to resulting directory. */
+{
+    short foundVRefNum;
+    long foundDirID;
+    OSErr err;
+
+    err = FindFolder(vRefNum, folderType, createFolder,
+        &foundVRefNum, &foundDirID);
+    if (err != noErr) {
+    return err;
+    }
+
+    err = FSMakeFSSpecCompat(foundVRefNum, foundDirID, "\p", spec);
+    return err;
+}
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpPathFromLocation --
+ *
+ *  This function obtains a full path name for a given macintosh
+ *  FSSpec.  Unlike the More Files function FSpGetFullPath, this
+ *  function will return a C string in the Handle.  It also will
+ *  create paths for FSSpec that do not yet exist.
+ *
+ * Results:
+ *  OSErr code.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+OSErr
+FSpPathFromLocation(
+    FSSpec *spec,       /* The location we want a path for. */
+    int *length,        /* Length of the resulting path. */
+    Handle *fullPath)       /* Handle to path. */
+{
+    OSErr err;
+    FSSpec tempSpec;
+    CInfoPBRec pb;
+
+    *fullPath = NULL;
+
+    /*
+     * Make a copy of the input FSSpec that can be modified.
+     */
+    BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
+
+    if (tempSpec.parID == fsRtParID) {
+    /*
+     * The object is a volume.  Add a colon to make it a full
+     * pathname.  Allocate a handle for it and we are done.
+     */
+    tempSpec.name[0] += 2;
+    tempSpec.name[tempSpec.name[0] - 1] = ':';
+    tempSpec.name[tempSpec.name[0]] = '\0';
+
+    err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
+    } else {
+    /*
+     * The object isn't a volume.  Is the object a file or a directory?
+     */
+    pb.dirInfo.ioNamePtr = tempSpec.name;
+    pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
+    pb.dirInfo.ioDrDirID = tempSpec.parID;
+    pb.dirInfo.ioFDirIndex = 0;
+    err = PBGetCatInfoSync(&pb);
+
+    if ((err == noErr) || (err == fnfErr)) {
+        /*
+         * If the file doesn't currently exist we start over.  If the
+         * directory exists everything will work just fine.  Otherwise we
+         * will just fail later.  If the object is a directory, append a
+         * colon so full pathname ends with colon.
+         */
+        if (err == fnfErr) {
+        BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
+        } else if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) {
+        tempSpec.name[0] += 1;
+        tempSpec.name[tempSpec.name[0]] = ':';
+        }
+
+        /*
+         * Create a new Handle for the object - make it a C string.
+         */
+        tempSpec.name[0] += 1;
+        tempSpec.name[tempSpec.name[0]] = '\0';
+        err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
+        if (err == noErr) {
+        /*
+         * Get the ancestor directory names - loop until we have an
+         * error or find the root directory.
+         */
+        pb.dirInfo.ioNamePtr = tempSpec.name;
+        pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
+        pb.dirInfo.ioDrParID = tempSpec.parID;
+        do {
+            pb.dirInfo.ioFDirIndex = -1;
+            pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
+            err = PBGetCatInfoSync(&pb);
+            if (err == noErr) {
+            /*
+             * Append colon to directory name and add
+             * directory name to beginning of fullPath.
+             */
+            ++tempSpec.name[0];
+            tempSpec.name[tempSpec.name[0]] = ':';
+
+            (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1],
+                tempSpec.name[0]);
+            err = MemError();
+            }
+        } while ( (err == noErr) &&
+            (pb.dirInfo.ioDrDirID != fsRtDirID) );
+        }
+    }
+    }
+
+    /*
+     * On error Dispose the handle, set it to NULL & return the err.
+     * Otherwise, set the length & return.
+     */
+    if (err == noErr) {
+    *length = GetHandleSize(*fullPath) - 1;
+    } else {
+    if ( *fullPath != NULL ) {
+        DisposeHandle(*fullPath);
+    }
+    *fullPath = NULL;
+    *length = 0;
+    }
+
+    return err;
+}
+
+
+
+/*****************************************************************************/
+
+pascal  OSErr   FSpGetDirectoryID(const FSSpec *spec,
+                                  long *theDirID,
+                                  Boolean *isDirectory)
+{
+    return ( GetDirectoryID(spec->vRefNum, spec->parID, spec->name,
+             theDirID, isDirectory) );
+}
+
+
+/*****************************************************************************/
+
+pascal  OSErr   GetDirectoryID(short vRefNum,
+                               long dirID,
+                               ConstStr255Param name,
+                               long *theDirID,
+                               Boolean *isDirectory)
+{
+    CInfoPBRec pb;
+    OSErr error;
+
+    error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+    if ( error == noErr )
+    {
+        *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
+        if ( *isDirectory )
+        {
+            *theDirID = pb.dirInfo.ioDrDirID;
+        }
+        else
+        {
+            *theDirID = pb.hFileInfo.ioFlParID;
+        }
+    }
+
+    return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal  OSErr GetCatInfoNoName(short vRefNum,
+                               long dirID,
+                               ConstStr255Param name,
+                               CInfoPBPtr pb)
+{
+    Str31 tempName;
+    OSErr error;
+
+    /* Protection against File Sharing problem */
+    if ( (name == NULL) || (name[0] == 0) )
+    {
+        tempName[0] = 0;
+        pb->dirInfo.ioNamePtr = tempName;
+        pb->dirInfo.ioFDirIndex = -1;   /* use ioDirID */
+    }
+    else
+    {
+        pb->dirInfo.ioNamePtr = (StringPtr)name;
+        pb->dirInfo.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
+    }
+    pb->dirInfo.ioVRefNum = vRefNum;
+    pb->dirInfo.ioDrDirID = dirID;
+    error = PBGetCatInfoSync(pb);
+    pb->dirInfo.ioNamePtr = NULL;
+    return ( error );
+}
+
+
+
+/*****************************************************************************/
+
+pascal  OSErr   GetObjectLocation(short vRefNum,
+                                  long dirID,
+                                  ConstStr255Param pathname,
+                                  short *realVRefNum,
+                                  long *realParID,
+                                  Str255 realName,
+                                  Boolean *isDirectory)
+{
+    OSErr error;
+    CInfoPBRec pb;
+    Str255 tempPathname;
+
+    /* clear results */
+    *realVRefNum = 0;
+    *realParID = 0;
+    realName[0] = 0;
+
+    /*
+    **  Get the real vRefNum
+    */
+    error = DetermineVRefNum(pathname, vRefNum, realVRefNum);
+    if ( error == noErr )
+    {
+        /*
+        **  Determine if the object already exists and if so,
+        **  get the real parent directory ID if it's a file
+        */
+
+        /* Protection against File Sharing problem */
+        if ( (pathname == NULL) || (pathname[0] == 0) )
+        {
+            tempPathname[0] = 0;
+            pb.hFileInfo.ioNamePtr = tempPathname;
+            pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
+        }
+        else
+        {
+            pb.hFileInfo.ioNamePtr = (StringPtr)pathname;
+            pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
+        }
+        pb.hFileInfo.ioVRefNum = vRefNum;
+        pb.hFileInfo.ioDirID = dirID;
+        error = PBGetCatInfoSync(&pb);
+        if ( error == noErr )
+        {
+            /*
+            **  The file system object is present and we have the file's
+            **  real parID
+            */
+
+            /*  Is it a directory or a file? */
+            *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
+            if ( *isDirectory )
+            {
+                /*
+                **  It's a directory, get its name and parent dirID, and then
+                **  we're done
+                */
+
+                pb.dirInfo.ioNamePtr = realName;
+                pb.dirInfo.ioVRefNum = *realVRefNum;
+                /* pb.dirInfo.ioDrDirID already contains the dirID of the
+                   directory object */
+                pb.dirInfo.ioFDirIndex = -1;    /* get information about ioDirID */
+                error = PBGetCatInfoSync(&pb);
+
+                /* get the parent ID here, because the file system can return the */
+                /* wrong parent ID from the last call. */
+                *realParID = pb.dirInfo.ioDrParID;
+            }
+            else
+            {
+                /*
+                **  It's a file - use the parent directory ID from the last call
+                **  to GetCatInfoparse, get the file name, and then we're done
+                */
+                *realParID = pb.hFileInfo.ioFlParID;
+                error = GetFilenameFromPathname(pathname, realName);
+            }
+        }
+        else if ( error == fnfErr )
+        {
+            /*
+            **  The file system object is not present - see if its parent is present
+            */
+
+            /*
+            **  Parse to get the object name from end of pathname
+            */
+            error = GetFilenameFromPathname(pathname, realName);
+
+            /* if we can't get the object name from the end, we can't continue */
+            if ( error == noErr )
+            {
+                /*
+                **  What we want now is the pathname minus the object name
+                **  for example:
+                **  if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:'
+                **  if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:'
+                **  if pathname is ':dir:file' tempPathname becomes ':dir:'
+                **  if pathname is ':dir:file:' tempPathname becomes ':dir:'
+                **  if pathname is ':file' tempPathname becomes ':'
+                **  if pathname is 'file or file:' tempPathname becomes ''
+                */
+
+                /* get a copy of the pathname */
+                BlockMoveData(pathname, tempPathname, pathname[0] + 1);
+
+                /* remove the object name */
+                tempPathname[0] -= realName[0];
+                /* and the trailing colon (if any) */
+                if ( pathname[pathname[0]] == ':' )
+                {
+                    --tempPathname[0];
+                }
+
+                /* OK, now get the parent's directory ID */
+
+                /* Protection against File Sharing problem */
+                pb.hFileInfo.ioNamePtr = (StringPtr)tempPathname;
+                if ( tempPathname[0] != 0 )
+                {
+                    pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
+                }
+                else
+                {
+                    pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
+                }
+                pb.hFileInfo.ioVRefNum = vRefNum;
+                pb.hFileInfo.ioDirID = dirID;
+                error = PBGetCatInfoSync(&pb);
+                *realParID = pb.dirInfo.ioDrDirID;
+
+                *isDirectory = false;   /* we don't know what the object is
+                                           really going to be */
+            }
+
+            if ( error != noErr )
+            {
+                error = dirNFErr;   /* couldn't find parent directory */
+            }
+            else
+            {
+                error = fnfErr; /* we found the parent, but not the file */
+            }
+        }
+    }
+
+    return ( error );
+}
+
+
+
+/*****************************************************************************/
+
+pascal  OSErr   DetermineVRefNum(ConstStr255Param pathname,
+                                 short vRefNum,
+                                 short *realVRefNum)
+{
+    HParamBlockRec pb;
+    OSErr error;
+
+    error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
+    if ( error == noErr )
+    {
+        *realVRefNum = pb.volumeParam.ioVRefNum;
+    }
+    return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal  OSErr   GetFilenameFromPathname(ConstStr255Param pathname,
+                                        Str255 filename)
+{
+    short   index;
+    short   nameEnd;
+    OSErr   error;
+
+    /* default to no filename */
+    filename[0] = 0;
+
+    /* check for no pathname */
+    if ( pathname != NULL )
+    {
+        /* get string length */
+        index = pathname[0];
+
+        /* check for empty string */
+        if ( index != 0 )
+        {
+            /* skip over last trailing colon (if any) */
+            if ( pathname[index] == ':' )
+            {
+                --index;
+            }
+
+            /* save the end of the string */
+            nameEnd = index;
+
+            /* if pathname ends with multiple colons, then this pathname refers */
+            /* to a directory, not a file */
+            if ( pathname[index] != ':' )
+            {
+                /* parse backwards until we find a colon or hit the beginning
+                   of the pathname */
+                while ( (index != 0) && (pathname[index] != ':') )
+                {
+                    --index;
+                }
+
+                /* if we parsed to the beginning of the pathname and the
+                   pathname ended */
+                /* with a colon, then pathname is a full pathname to a volume,
+                   not a file */
+                if ( (index != 0) || (pathname[pathname[0]] != ':') )
+                {
+                    /* get the filename and return noErr */
+                    filename[0] = (char)(nameEnd - index);
+                    BlockMoveData(&pathname[index+1], &filename[1], nameEnd - index);
+                    error = noErr;
+                }
+                else
+                {
+                    /* pathname to a volume, not a file */
+                    error = notAFileErr;
+                }
+            }
+            else
+            {
+                /* directory, not a file */
+                error = notAFileErr;
+            }
+        }
+        else
+        {
+            /* empty string isn't a file */
+            error = notAFileErr;
+        }
+    }
+    else
+    {
+        /* NULL pathname isn't a file */
+        error = notAFileErr;
+    }
+
+    return ( error );
+}
+
+
+
+/*****************************************************************************/
+
+/*
+**  GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync
+**  in cases where the returned volume name is not needed by the caller.
+**  The pathname and vRefNum parameters are not touched, and the pb
+**  parameter is initialized by PBHGetVInfoSync except that ioNamePtr in
+**  the parameter block is always returned as NULL (since it might point
+**  to the local tempPathname).
+**
+**  I noticed using this code in several places, so here it is once.
+**  This reduces the code size of MoreFiles.
+*/
+pascal  OSErr   GetVolumeInfoNoName(ConstStr255Param pathname,
+                                    short vRefNum,
+                                    HParmBlkPtr pb)
+{
+    Str255 tempPathname;
+    OSErr error;
+
+    /* Make sure pb parameter is not NULL */
+    if ( pb != NULL )
+    {
+        pb->volumeParam.ioVRefNum = vRefNum;
+        if ( pathname == NULL )
+        {
+            pb->volumeParam.ioNamePtr = NULL;
+            pb->volumeParam.ioVolIndex = 0;     /* use ioVRefNum only */
+        }
+        else
+        {                                   /* make a copy of the string and */
+            BlockMoveData(pathname, tempPathname, pathname[0] + 1);
+                                    /* use the copy so original isn't trashed */
+            pb->volumeParam.ioNamePtr = (StringPtr)tempPathname;
+                                       /* use ioNamePtr/ioVRefNum combination */
+            pb->volumeParam.ioVolIndex = -1;
+        }
+        error = PBHGetVInfoSync(pb);
+        pb->volumeParam.ioNamePtr = NULL;   /* ioNamePtr may point to local
+                                            tempPathname, so don't return it */
+    }
+    else
+    {
+        error = paramErr;
+    }
+    return ( error );
+}
+
+
+
+
+/*****************************************************************************/
+
+pascal  OSErr   FSpGetFullPath(const FSSpec *spec,
+                               short *fullPathLength,
+                               Handle *fullPath)
+{
+    OSErr       result;
+    OSErr       realResult;
+    FSSpec      tempSpec;
+    CInfoPBRec  pb;
+
+    *fullPathLength = 0;
+    *fullPath = NULL;
+
+    /* Default to noErr */
+    realResult = noErr;
+
+    /* Make a copy of the input FSSpec that can be modified */
+    BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
+
+    if ( tempSpec.parID == fsRtParID )
+    {
+        /* The object is a volume */
+
+        /* Add a colon to make it a full pathname */
+        ++tempSpec.name[0];
+        tempSpec.name[tempSpec.name[0]] = ':';
+
+        /* We're done */
+        result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
+    }
+    else
+    {
+        /* The object isn't a volume */
+
+        /* Is the object a file or a directory? */
+        pb.dirInfo.ioNamePtr = tempSpec.name;
+        pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
+        pb.dirInfo.ioDrDirID = tempSpec.parID;
+        pb.dirInfo.ioFDirIndex = 0;
+        result = PBGetCatInfoSync(&pb);
+        /* Allow file/directory name at end of path to not exist. */
+        realResult = result;
+        if ( (result == noErr) || (result == fnfErr) )
+        {
+            /* if the object is a directory, append a colon so full pathname
+               ends with colon */
+            if ( (result == noErr) && (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+            {
+                ++tempSpec.name[0];
+                tempSpec.name[tempSpec.name[0]] = ':';
+            }
+
+            /* Put the object name in first */
+            result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
+            if ( result == noErr )
+            {
+                /* Get the ancestor directory names */
+                pb.dirInfo.ioNamePtr = tempSpec.name;
+                pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
+                pb.dirInfo.ioDrParID = tempSpec.parID;
+                do  /* loop until we have an error or find the root directory */
+                {
+                    pb.dirInfo.ioFDirIndex = -1;
+                    pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
+                    result = PBGetCatInfoSync(&pb);
+                    if ( result == noErr )
+                    {
+                        /* Append colon to directory name */
+                        ++tempSpec.name[0];
+                        tempSpec.name[tempSpec.name[0]] = ':';
+
+                        /* Add directory name to beginning of fullPath */
+                        (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1],
+                                      tempSpec.name[0]);
+                        result = MemError();
+                    }
+                } while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) );
+            }
+        }
+    }
+    if ( result == noErr )
+    {
+        /* Return the length */
+        *fullPathLength = InlineGetHandleSize(*fullPath);
+        result = realResult;    /* return realResult in case it was fnfErr */
+    }
+    else
+    {
+        /* Dispose of the handle and return NULL and zero length */
+        if ( *fullPath != NULL )
+        {
+            DisposeHandle(*fullPath);
+        }
+        *fullPath = NULL;
+        *fullPathLength = 0;
+    }
+
+    return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr FSpLocationFromFullPath(short fullPathLength,
+                                     const void *fullPath,
+                                     FSSpec *spec)
+{
+    AliasHandle alias;
+    OSErr       result;
+    Boolean     wasChanged;
+    Str32       nullString;
+
+    /* Create a minimal alias from the full pathname */
+    nullString[0] = 0;  /* null string to indicate no zone or server name */
+    result = NewAliasMinimalFromFullPath(fullPathLength, fullPath, nullString,
+                                         nullString, &alias);
+
+    if ( result == noErr )
+    {
+        /* Let the Alias Manager resolve the alias. */
+        result = ResolveAlias(NULL, alias, spec, &wasChanged);
+
+        DisposeHandle((Handle)alias);   /* Free up memory used */
+    }
+
+    return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal  OSErr   GetFullPath(short vRefNum,
+                            long dirID,
+                            ConstStr255Param name,
+                            short *fullPathLength,
+                            Handle *fullPath)
+{
+    OSErr       result;
+    FSSpec      spec;
+
+    *fullPathLength = 0;
+    *fullPath = NULL;
+
+    result = FSMakeFSSpecCompat(vRefNum, dirID, name, &spec);
+    if ( (result == noErr) || (result == fnfErr) )
+    {
+        result = FSpGetFullPath(&spec, fullPathLength, fullPath);
+    }
+
+    return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal  OSErr   ChangeCreatorType(short vRefNum,
+                                  long dirID,
+                                  ConstStr255Param name,
+                                  OSType creator,
+                                  OSType fileType)
+{
+    CInfoPBRec pb;
+    OSErr error;
+    short realVRefNum;
+    long parID;
+
+    pb.hFileInfo.ioNamePtr = (StringPtr)name;
+    pb.hFileInfo.ioVRefNum = vRefNum;
+    pb.hFileInfo.ioDirID = dirID;
+    pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
+    error = PBGetCatInfoSync(&pb);
+    if ( error == noErr )
+    {
+        if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 )   /* if file */
+        {                            /* save parent dirID for BumpDate call */
+            parID = pb.hFileInfo.ioFlParID;
+
+            /* If creator not 0x00000000, change creator */
+            if ( creator != (OSType)0x00000000 )
+            {
+                pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
+            }
+
+            /* If fileType not 0x00000000, change fileType */
+            if ( fileType != (OSType)0x00000000 )
+            {
+                pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
+            }
+
+            pb.hFileInfo.ioDirID = dirID;
+            error = PBSetCatInfoSync(&pb);  /* now, save the new information
+                                               back to disk */
+
+            if ( (error == noErr) && (parID != fsRtParID) ) /* can't
+                                                            bump fsRtParID */
+            {
+                /* get the real vRefNum in case a full pathname was passed */
+                error = DetermineVRefNum(name, vRefNum, &realVRefNum);
+                if ( error == noErr )
+                {
+                    error = BumpDate(realVRefNum, parID, NULL);
+                        /* and bump the parent directory's mod date to wake
+                           up the Finder */
+                        /* to the change we just made */
+                }
+            }
+        }
+        else
+        {
+            /* it was a directory, not a file */
+            error = notAFileErr;
+        }
+    }
+
+    return ( error );
+}
+
+/*****************************************************************************/
+
+pascal  OSErr   FSpChangeCreatorType(const FSSpec *spec,
+                                     OSType creator,
+                                     OSType fileType)
+{
+    return ( ChangeCreatorType(spec->vRefNum, spec->parID, spec->name,
+             creator, fileType) );
+}
+
+/*****************************************************************************/
+
+pascal  OSErr   BumpDate(short vRefNum,
+                         long dirID,
+                         ConstStr255Param name)
+/* Given a file or directory, change its modification date to the
+   current date/time. */
+{
+    CInfoPBRec pb;
+    Str31 tempName;
+    OSErr error;
+    unsigned long secs;
+
+    /* Protection against File Sharing problem */
+    if ( (name == NULL) || (name[0] == 0) )
+    {
+        tempName[0] = 0;
+        pb.hFileInfo.ioNamePtr = tempName;
+        pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
+    }
+    else
+    {
+        pb.hFileInfo.ioNamePtr = (StringPtr)name;
+        pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
+    }
+    pb.hFileInfo.ioVRefNum = vRefNum;
+    pb.hFileInfo.ioDirID = dirID;
+    error = PBGetCatInfoSync(&pb);
+    if ( error == noErr )
+    {
+        GetDateTime(&secs);
+        /* set mod date to current date, or one second into the future
+            if mod date = current date */
+        pb.hFileInfo.ioFlMdDat =
+                          (secs == pb.hFileInfo.ioFlMdDat) ? (++secs) : (secs);
+        if ( pb.dirInfo.ioNamePtr == tempName )
+        {
+            pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID;
+        }
+        else
+        {
+            pb.hFileInfo.ioDirID = dirID;
+        }
+        error = PBSetCatInfoSync(&pb);
+    }
+
+    return ( error );
+}
+
+/*****************************************************************************/
+
+pascal  OSErr   FSpBumpDate(const FSSpec *spec)
+{
+    return ( BumpDate(spec->vRefNum, spec->parID, spec->name) );
+}
+
+
+/*****************************************************************************/
+
+pascal  OSErr   OnLine(FSSpecPtr volumes,
+                       short reqVolCount,
+                       short *actVolCount,
+                       short *volIndex)
+{
+    HParamBlockRec pb;
+    OSErr error = noErr;
+    FSSpec *endVolArray;
+
+    if ( *volIndex > 0 )
+    {
+        *actVolCount = 0;
+        for ( endVolArray = volumes + reqVolCount;
+              (volumes < endVolArray) && (error == noErr); ++volumes )
+        {
+            pb.volumeParam.ioNamePtr = (StringPtr) & volumes->name;
+            pb.volumeParam.ioVolIndex = *volIndex;
+            error = PBHGetVInfoSync(&pb);
+            if ( error == noErr )
+            {
+                volumes->parID = fsRtParID;     /* the root directory's
+                                                   parent is 1 */
+                volumes->vRefNum = pb.volumeParam.ioVRefNum;
+                ++*volIndex;
+                ++*actVolCount;
+            }
+        }
+    }
+    else
+    {
+        error = paramErr;
+    }
+
+    return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal  OSErr   DTGetComment(short vRefNum,
+                             long dirID,
+                             ConstStr255Param name,
+                             Str255 comment)
+{
+    DTPBRec pb;
+    OSErr error;
+    short dtRefNum;
+    Boolean newDTDatabase;
+
+    if (comment != NULL)
+    {
+        comment[0] = 0; /* return nothing by default */
+
+        /* attempt to open the desktop database */
+        error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
+        if ( error == noErr )
+        {
+            /* There was a desktop database and it's now open */
+
+            if ( !newDTDatabase )
+            {
+                pb.ioDTRefNum = dtRefNum;
+                pb.ioNamePtr = (StringPtr)name;
+                pb.ioDirID = dirID;
+                pb.ioDTBuffer = (Ptr)&comment[1];
+                /*
+                **  IMPORTANT NOTE #1: Inside Macintosh says that comments
+                **  are up to 200 characters. While that may be correct for
+                **  the HFS file system's Desktop Manager, other file
+                **  systems (such as Apple Photo Access) return up to
+                **  255 characters. Make sure the comment buffer is a Str255
+                **  or you'll regret it.
+                **
+                **  IMPORTANT NOTE #2: Although Inside Macintosh doesn't
+                **  mention it, ioDTReqCount is a input field to
+                **  PBDTGetCommentSync. Some file systems (like HFS) ignore
+                **  ioDTReqCount and always return the full comment --
+                **  others (like AppleShare) respect ioDTReqCount and only
+                **  return up to ioDTReqCount characters of the comment.
+                */
+                pb.ioDTReqCount = sizeof(Str255) - 1;
+                error = PBDTGetCommentSync(&pb);
+                if (error == noErr)
+                {
+                    comment[0] = (unsigned char)pb.ioDTActCount;
+                }
+            }
+        }
+        else
+        {
+            /* There is no desktop database - try the Desktop file */
+            error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
+            if ( error != noErr )
+            {
+                error = afpItemNotFound;    /* return an expected error */
+            }
+        }
+    }
+    else
+    {
+        error = paramErr;
+    }
+
+    return (error);
+}
+
+/*****************************************************************************/
+
+pascal  OSErr   FSpDTGetComment(const FSSpec *spec,
+                              Str255 comment)
+{
+    return (DTGetComment(spec->vRefNum, spec->parID, spec->name, comment));
+}
+
+
+/*****************************************************************************/
+
+pascal  OSErr   DTSetComment(short vRefNum,
+                             long dirID,
+                             ConstStr255Param name,
+                             ConstStr255Param comment)
+{
+    DTPBRec pb;
+    OSErr error;
+    short dtRefNum;
+    Boolean newDTDatabase;
+
+    error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
+    if ( error == noErr )
+    {
+        pb.ioDTRefNum = dtRefNum;
+        pb.ioNamePtr = (StringPtr)name;
+        pb.ioDirID = dirID;
+        pb.ioDTBuffer = (Ptr)&comment[1];
+        /* Truncate the comment to 200 characters just in case */
+        /* some file system doesn't range check */
+        if ( comment[0] <= 200 )
+        {
+            pb.ioDTReqCount = comment[0];
+        }
+        else
+        {
+            pb.ioDTReqCount = 200;
+        }
+        error = PBDTSetCommentSync(&pb);
+    }
+    return (error);
+}
+
+/*****************************************************************************/
+
+pascal  OSErr   FSpDTSetComment(const FSSpec *spec,
+                              ConstStr255Param comment)
+{
+    return (DTSetComment(spec->vRefNum, spec->parID, spec->name, comment));
+}
+
+
+/*****************************************************************************/
+
+pascal  OSErr   DTOpen(ConstStr255Param volName,
+                       short vRefNum,
+                       short *dtRefNum,
+                       Boolean *newDTDatabase)
+{
+    OSErr error;
+    GetVolParmsInfoBuffer volParmsInfo;
+    long infoSize;
+    DTPBRec pb;
+
+    /* Check for volume Desktop Manager support before calling */
+    infoSize = sizeof(GetVolParmsInfoBuffer);
+    error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
+    if ( error == noErr )
+    {
+        if ( hasDesktopMgr(volParmsInfo) )
+        {
+            pb.ioNamePtr = (StringPtr)volName;
+            pb.ioVRefNum = vRefNum;
+            error = PBDTOpenInform(&pb);
+            /* PBDTOpenInform informs us if the desktop was just created */
+            /* by leaving the low bit of ioTagInfo clear (0) */
+            *newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
+            if ( error == paramErr )
+            {
+                error = PBDTGetPath(&pb);
+                /* PBDTGetPath doesn't tell us if the database is new */
+                /* so assume it is not new */
+                *newDTDatabase = false;
+            }
+            *dtRefNum = pb.ioDTRefNum;
+        }
+        else
+        {
+            error = paramErr;
+        }
+    }
+    return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+**  GetCommentFromDesktopFile
+**
+**  Get a file or directory's Finder comment field (if any) from the
+**  Desktop file's 'FCMT' resources.
+*/
+static  OSErr   GetCommentFromDesktopFile(short vRefNum,
+                                          long dirID,
+                                          ConstStr255Param name,
+                                          Str255 comment)
+{
+    OSErr error;
+    short commentID;
+    short realVRefNum;
+    Str255 desktopName;
+    short savedResFile;
+    short dfRefNum;
+    StringHandle commentHandle;
+
+    /* Get the comment ID number */
+    error = GetCommentID(vRefNum, dirID, name, &commentID);
+    if ( error == noErr )
+    {
+        if ( commentID != 0 )   /* commentID == 0 means there's no comment */
+        {
+            error = DetermineVRefNum(name, vRefNum, &realVRefNum);
+            if ( error == noErr )
+            {
+                error = GetDesktopFileName(realVRefNum, desktopName);
+                if ( error == noErr )
+                {
+                    savedResFile = CurResFile();
+                    /*
+                    **  Open the 'Desktop' file in the root directory. (because
+                    **  opening the resource file could preload unwanted resources,
+                    **  bracket the call with SetResLoad(s))
+                    */
+                    SetResLoad(false);
+                    dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName,
+                                            fsRdPerm);
+                    SetResLoad(true);
+
+                    if ( dfRefNum != -1)
+                    {
+                        /* Get the comment resource */
+                        commentHandle = (StringHandle)Get1Resource(kFCMTResType,
+                                                                   commentID);
+                        if ( commentHandle != NULL )
+                        {
+                            if ( InlineGetHandleSize((Handle)commentHandle) > 0 )
+                            {
+                                BlockMoveData(*commentHandle, comment,
+                                              *commentHandle[0] + 1);
+                            }
+                            else
+                            {                       /* no comment available */
+                                error = afpItemNotFound;
+                            }
+                        }
+                        else
+                        {                           /* no comment available */
+                            error = afpItemNotFound;
+                        }
+
+                        /* restore the resource chain and close
+                           the Desktop file */
+                        UseResFile(savedResFile);
+                        CloseResFile(dfRefNum);
+                    }
+                    else
+                    {
+                        error = afpItemNotFound;
+                    }
+                }
+                else
+                {
+                    error = afpItemNotFound;
+                }
+            }
+        }
+        else
+        {
+            error = afpItemNotFound;    /* no comment available */
+        }
+    }
+
+    return ( error );
+}
+
+/*****************************************************************************/
+
+pascal  OSErr   HGetVolParms(ConstStr255Param volName,
+                             short vRefNum,
+                             GetVolParmsInfoBuffer *volParmsInfo,
+                             long *infoSize)
+{
+    HParamBlockRec pb;
+    OSErr error;
+
+    pb.ioParam.ioNamePtr = (StringPtr)volName;
+    pb.ioParam.ioVRefNum = vRefNum;
+    pb.ioParam.ioBuffer = (Ptr)volParmsInfo;
+    pb.ioParam.ioReqCount = *infoSize;
+    error = PBHGetVolParmsSync(&pb);
+    if ( error == noErr )
+    {
+        *infoSize = pb.ioParam.ioActCount;
+    }
+    return ( error );
+}
+
+/*****************************************************************************/
+/*
+**  GetCommentID
+**
+**  Get the comment ID number for the Desktop file's 'FCMT' resource ID from
+**  the file or folders fdComment (frComment) field.
+*/
+static  OSErr   GetCommentID(short vRefNum,
+                             long dirID,
+                             ConstStr255Param name,
+                             short *commentID)
+{
+    CInfoPBRec pb;
+    OSErr error;
+
+    error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+    *commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
+    return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+**  GetDesktopFileName
+**
+**  Get the name of the Desktop file.
+*/
+static  OSErr   GetDesktopFileName(short vRefNum,
+                                   Str255 desktopName)
+{
+    OSErr           error;
+    HParamBlockRec  pb;
+    short           index;
+    Boolean         found;
+
+    pb.fileParam.ioNamePtr = desktopName;
+    pb.fileParam.ioVRefNum = vRefNum;
+    pb.fileParam.ioFVersNum = 0;
+    index = 1;
+    found = false;
+    do
+    {
+        pb.fileParam.ioDirID = fsRtDirID;
+        pb.fileParam.ioFDirIndex = index;
+        error = PBHGetFInfoSync(&pb);
+        if ( error == noErr )
+        {
+            if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
+                 (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
+            {
+                found = true;
+            }
+        }
+        ++index;
+    } while ( (error == noErr) && !found );
+
+    return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal  OSErr   XGetVInfo(short volReference,
+                          StringPtr volName,
+                          short *vRefNum,
+                          UnsignedWide *freeBytes,
+                          UnsignedWide *totalBytes)
+{
+    OSErr           result;
+    long            response;
+    XVolumeParam    pb;
+
+    /* See if large volume support is available */
+    if ( ( Gestalt(gestaltFSAttr, &response) == noErr ) && ((response & (1L << gestaltFSSupports2TBVols)) != 0) )
+    {
+        /* Large volume support is available */
+        pb.ioVRefNum = volReference;
+        pb.ioNamePtr = volName;
+        pb.ioXVersion = 0;  /* this XVolumeParam version (0) */
+        pb.ioVolIndex = 0;  /* use ioVRefNum only, return volume name */
+        result = PBXGetVolInfoSync(&pb);
+        if ( result == noErr )
+        {
+            /* The volume name was returned in volName (if not NULL) and */
+            /* we have the volume's vRefNum and allocation block size */
+            *vRefNum = pb.ioVRefNum;
+
+            /* return the freeBytes and totalBytes */
+            *totalBytes = pb.ioVTotalBytes;
+            *freeBytes = pb.ioVFreeBytes;
+        }
+    }
+    else
+    {
+        /* No large volume support */
+
+        /* Use HGetVInfo to get the results */
+        result = HGetVInfo(volReference, volName, vRefNum, &freeBytes->lo, &totalBytes->lo);
+        if ( result == noErr )
+        {
+            /* zero the high longs of totalBytes and freeBytes */
+            totalBytes->hi = 0;
+            freeBytes->hi = 0;
+        }
+    }
+    return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal  OSErr   HGetVInfo(short volReference,
+                          StringPtr volName,
+                          short *vRefNum,
+                          unsigned long *freeBytes,
+                          unsigned long *totalBytes)
+{
+    HParamBlockRec  pb;
+    unsigned long   allocationBlockSize;
+    unsigned short  numAllocationBlocks;
+    unsigned short  numFreeBlocks;
+    VCB             *theVCB;
+    Boolean         vcbFound;
+    OSErr           result;
+
+    /* Use the File Manager to get the real vRefNum */
+    pb.volumeParam.ioVRefNum = volReference;
+    pb.volumeParam.ioNamePtr = volName;
+    pb.volumeParam.ioVolIndex = 0;  /* use ioVRefNum only, return volume name */
+    result = PBHGetVInfoSync(&pb);
+
+    if ( result == noErr )
+    {
+        /* The volume name was returned in volName (if not NULL) and */
+        /* we have the volume's vRefNum and allocation block size */
+        *vRefNum = pb.volumeParam.ioVRefNum;
+        allocationBlockSize = (unsigned long)pb.volumeParam.ioVAlBlkSiz;
+
+        /* System 7.5 (and beyond) pins the number of allocation blocks and */
+        /* the number of free allocation blocks returned by PBHGetVInfo to */
+        /* a value so that when multiplied by the allocation block size, */
+        /* the volume will look like it has $7fffffff bytes or less. This */
+        /* was done so older applications that use signed math or that use */
+        /* the GetVInfo function (which uses signed math) will continue to work. */
+        /* However, the unpinned numbers (which we want) are always available */
+        /* in the volume's VCB so we'll get those values from the VCB if possible. */
+
+        /* Find the volume's VCB */
+        vcbFound = false;
+        theVCB = (VCB *)(GetVCBQHdr()->qHead);
+        while ( (theVCB != NULL) && !vcbFound )
+        {
+            /* Check VCB signature before using VCB. Don't have to check for */
+            /* MFS (0xd2d7) because they can't get big enough to be pinned */
+            if ( theVCB->vcbSigWord == 0x4244 )
+            {
+                if ( theVCB->vcbVRefNum == *vRefNum )
+                {
+                    vcbFound = true;
+                }
+            }
+
+            if ( !vcbFound )
+            {
+                theVCB = (VCB *)(theVCB->qLink);
+            }
+        }
+
+        if ( theVCB != NULL )
+        {
+            /* Found a VCB we can use. Get the un-pinned number of allocation blocks */
+            /* and the number of free blocks from the VCB. */
+            numAllocationBlocks = (unsigned short)theVCB->vcbNmAlBlks;
+            numFreeBlocks = (unsigned short)theVCB->vcbFreeBks;
+        }
+        else
+        {
+            /* Didn't find a VCB we can use. Return the number of allocation blocks */
+            /* and the number of free blocks returned by PBHGetVInfoSync. */
+            numAllocationBlocks = (unsigned short)pb.volumeParam.ioVNmAlBlks;
+            numFreeBlocks = (unsigned short)pb.volumeParam.ioVFrBlk;
+        }
+
+        /* Now, calculate freeBytes and totalBytes using unsigned values */
+        *freeBytes = numFreeBlocks * allocationBlockSize;
+        *totalBytes = numAllocationBlocks * allocationBlockSize;
+    }
+
+    return ( result );
+}
+
+
+/*
+**  PBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync
+**  File Manager requests from CFM-based programs. At some point, Apple
+**  will get around to adding this to the standard libraries you link with
+**  and you'll get a duplicate symbol link error. At that time, just delete
+**  this code (or comment it out).
+**
+**  Non-CFM 68K programs don't needs this glue (and won't get it) because
+**  they instead use the inline assembly glue found in the Files.h interface
+**  file.
+*/
+
+#if __WANTPASCALELIMINATION
+#undef  pascal
+#endif
+
+#if GENERATINGCFM
+pascal OSErr PBXGetVolInfoSync(XVolumeParamPtr paramBlock)
+{
+    enum
+    {
+        kXGetVolInfoSelector = 0x0012,  /* Selector for XGetVolInfo */
+
+        uppFSDispatchProcInfo = kRegisterBased
+             | REGISTER_RESULT_LOCATION(kRegisterD0)
+             | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
+             | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(long)))  /* trap word */
+             | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(long)))  /* selector */
+             | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr)))
+    };
+
+    return ( CallOSTrapUniversalProc(NGetTrapAddress(_FSDispatch, OSTrap),
+                                        uppFSDispatchProcInfo,
+                                        _FSDispatch,
+                                        kXGetVolInfoSelector,
+                                        paramBlock) );
+}
+#endif
+
+#if __WANTPASCALELIMINATION
+#define pascal
+#endif
+
+/*****************************************************************************/
+
+pascal  OSErr   GetDirName(short vRefNum,
+                           long dirID,
+                           Str31 name)
+{
+    CInfoPBRec pb;
+    OSErr error;
+
+    if ( name != NULL )
+    {
+        pb.dirInfo.ioNamePtr = name;
+        pb.dirInfo.ioVRefNum = vRefNum;
+        pb.dirInfo.ioDrDirID = dirID;
+        pb.dirInfo.ioFDirIndex = -1;    /* get information about ioDirID */
+        error = PBGetCatInfoSync(&pb);
+    }
+    else
+    {
+        error = paramErr;
+    }
+
+    return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal  OSErr   GetVolFileSystemID(ConstStr255Param pathname,
+                                   short vRefNum,
+                                   short *fileSystemID)
+{
+    HParamBlockRec pb;
+    OSErr error;
+
+    error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
+    if ( error == noErr )
+    {
+        *fileSystemID = pb.volumeParam.ioVFSID;
+    }
+
+    return ( error );
+}
+
+/*****************************************************************************/
+
+pascal  OSErr GetDInfo(short vRefNum,
+                       long dirID,
+                       ConstStr255Param name,
+                       DInfo *fndrInfo)
+{
+    CInfoPBRec pb;
+    OSErr error;
+
+    error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+    if ( error == noErr )
+    {
+        if ( (pb.dirInfo.ioFlAttrib & ioDirMask) != 0 )
+        {
+            /* it's a directory, return the DInfo */
+            *fndrInfo = pb.dirInfo.ioDrUsrWds;
+        }
+        else
+        {
+            /* oops, a file was passed */
+            error = dirNFErr;
+        }
+    }
+
+    return ( error );
+}
+
+/*****************************************************************************/
+
+pascal  OSErr FSpGetDInfo(const FSSpec *spec,
+                          DInfo *fndrInfo)
+{
+    return ( GetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) );
+}
+
+
diff --git a/macos/source/macstuff.h b/macos/source/macstuff.h
new file mode 100644 (file)
index 0000000..9e92dce
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+  Copyright (c) 1990-2001 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef _MACSTUFF_H
+#define _MACSTUFF_H     1
+
+#include "MoreFilesExtras.h"
+#include "MoreDesktopMgr.h"
+#include "MoreFiles.h"
+#include "FSpCompat.h"
+#include "FullPath.h"
+
+#endif               /*  _MACSTUFF_H  */
diff --git a/macos/source/mactime.c b/macos/source/mactime.c
new file mode 100644 (file)
index 0000000..af9ad5e
--- /dev/null
@@ -0,0 +1,451 @@
+/*
+  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* -----------------------------------------------------------------------------
+
+The original functions (Metrowerks Codewarrior pro 3.0) gmtime, localtime,
+mktime and time do not work correctly. The supplied link library mactime.c
+contains replacement functions for them.
+
+ *     Caveat: On a Mac, we only know the GMT and DST offsets for
+ *     the current time, not for the time in question.
+ *     Mac has no support for DST handling.
+ *     DST changeover is all manually set by the user.
+
+
+------------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/*  Includes                                                                 */
+/*****************************************************************************/
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <OSUtils.h>
+
+#include "mactime.h"
+
+
+/*
+The MacOS function GetDateTime returns  the
+number of seconds elapsed since midnight, January 1, 1904.
+*/
+const unsigned long MacOS_2_Unix = 2082844800L;
+
+
+/*****************************************************************************/
+/*  Macros, typedefs                                                         */
+/*****************************************************************************/
+
+
+#ifndef TEST_TIME_LIB
+#define my_gmtime    gmtime
+#define my_localtime localtime
+#define my_mktime    mktime
+#define my_time      time
+#endif
+
+
+/*****************************************************************************/
+/*  Prototypes                                                               */
+/*****************************************************************************/
+/* internal prototypes */
+static void clear_tm(struct tm * tm);
+static long GMTDelta(void);
+static Boolean DaylightSaving(void);
+static time_t GetTimeMac(void);
+static time_t Mactime(time_t *timer);
+static void   normalize(int *i,int *j,int norm);
+static struct tm *time2tm(const time_t *timer);
+static time_t tm2time(struct tm *tp);
+
+/* Because serial port and SLIP conflict with ReadXPram calls,
+   we cache the call here so we don't hang on calling ReadLocation()  */
+static void myReadLocation(MachineLocation * loc);
+
+
+/* prototypes for STD lib replacement functions */
+struct tm *my_gmtime(const time_t *t);
+struct tm *my_localtime(const time_t *t);
+time_t my_mktime(struct tm *tp);
+time_t my_time(time_t *t);
+
+
+/*****************************************************************************/
+/*  Functions                                                                */
+/*****************************************************************************/
+
+ /*
+ *  Mac file times are based on 1904 Jan 1 00:00 local time,
+ *  not 1970 Jan 1 00:00 UTC.
+ *  So we have to convert the time stamps into UNIX UTC
+ *  compatible values.
+ */
+time_t MacFtime2UnixFtime(unsigned long macftime)
+{
+    long UTCoffset;
+
+    GetGMToffsetMac(macftime, &UTCoffset);
+    MACOS_TO_UNIX(macftime);
+    macftime -= UTCoffset;
+
+    return macftime;
+}
+
+
+ /*
+ *  Mac file times are based on 1904 Jan 1 00:00 local time,
+ *  not 1970 Jan 1 00:00 UTC.
+ *  So we have to convert the time stamps into MacOS local
+ *  compatible values.
+ */
+unsigned long UnixFtime2MacFtime(time_t unxftime)
+{
+    long UTCoffset;
+    unsigned long macftime = unxftime;
+
+    UNIX_TO_MACOS(macftime);
+    GetGMToffsetMac(macftime, &UTCoffset);
+    macftime += UTCoffset;
+
+    return macftime;
+}
+
+
+
+
+
+/*
+* This function convert a file-localtime to an another
+* file-localtime.
+*/
+time_t AdjustForTZmoveMac(unsigned long macloctim, long s_gmtoffs)
+{
+    time_t MacGMTTime;
+    long UTCoffset;
+
+    /* convert macloctim into corresponding UTC value */
+    MacGMTTime = macloctim - s_gmtoffs;
+    GetGMToffsetMac(macloctim, &UTCoffset);
+
+    return (MacGMTTime + UTCoffset);
+} /* AdjustForTZmove() */
+
+
+
+
+/*
+ * This function calculates the difference between the supplied Mac
+ * ftime value (local time) and the corresponding UTC time in seconds.
+ */
+Boolean GetGMToffsetMac(unsigned long mactime, long *UTCoffset)
+{
+
+mactime = mactime;
+/*
+ *     Caveat: On a Mac, we only know the GMT and DST offsets for
+ *     the current time, not for the time in question.
+ *     Mac has no support for DST handling.
+ *     DST changeover is all manually set by the user.
+
+ May be later I can include a support of GMT offset calculation for the
+ time in question here.
+*/
+    *UTCoffset = GMTDelta();
+
+    return true;
+}
+
+
+
+
+
+
+
+/*****************************************************************************
+ *  Standard Library Replacement Functions
+ *  gmtime(), mktime(), localtime(), time()
+ *
+ *  The unix epoch is used here.
+ *  These functions gmtime(), mktime(), localtime() and time()
+ *  expects and returns unix times.
+ *
+ * At midnight Jan. 1, 1970 GMT, the local time was
+ *    midnight Jan. 1, 1970 + GMTDelta().
+ *
+ *
+ *****************************************************************************/
+
+
+struct tm *my_gmtime(const time_t *timer)
+{
+    return time2tm(timer);
+}
+
+
+
+
+struct tm *my_localtime(const time_t *timer)
+{
+    time_t maclocal;
+
+    maclocal = *timer;
+    maclocal += GMTDelta();
+
+    return time2tm(&maclocal);
+}
+
+
+
+
+time_t my_mktime(struct tm *tp)
+{
+    time_t maclocal;
+
+    maclocal = tm2time(tp);
+    maclocal -= GMTDelta();
+
+    return maclocal;
+}
+
+
+
+
+
+
+time_t my_time(time_t *time)
+{
+time_t tmp_time;
+
+GetDateTime(&tmp_time);
+
+MACOS_TO_UNIX(tmp_time);
+
+if (time)
+    {
+    *time = tmp_time;
+    }
+
+return tmp_time;
+}
+
+
+
+/*****************************************************************************/
+/*  static module level functions
+/*****************************************************************************/
+
+
+/*
+ * The geographic location and time zone information of a Mac
+ * are stored in extended parameter RAM.  The ReadLocation
+ * produdure uses the geographic location record, MachineLocation,
+ * to read the geographic location and time zone information in
+ * extended parameter RAM.
+ *
+ * Because serial port and SLIP conflict with ReadXPram calls,
+ * we cache the call here.
+ *
+ * Caveat: this caching will give the wrong result if a session
+ * extend across the DST changeover time, but
+ * this function resets itself every 2 hours.
+ */
+static void myReadLocation(MachineLocation * loc)
+{
+    static MachineLocation storedLoc;   /* InsideMac, OSUtilities, page 4-20  */
+    static time_t first_call = 0, last_call = 86400;
+
+    if ((last_call - first_call) > 7200)
+        {
+        GetDateTime(&first_call);
+        ReadLocation(&storedLoc);
+        }
+
+    GetDateTime(&last_call);
+    *loc = storedLoc;
+}
+
+
+
+
+static Boolean DaylightSaving(void)
+{
+    MachineLocation loc;
+    unsigned char dlsDelta;
+
+    myReadLocation(&loc);
+    dlsDelta =  loc.u.dlsDelta;
+
+    return (dlsDelta != 0);
+}
+
+
+
+
+/* current local time = GMTDelta() + GMT
+   GMT = local time - GMTDelta()    */
+static long GMTDelta(void)
+{
+    MachineLocation loc;
+    long gmtDelta;
+
+    myReadLocation(&loc);
+
+    /*
+     * On a Mac, the GMT value is in seconds east of GMT.  For example,
+     * San Francisco is at -28,800 seconds (8 hours * 3600 seconds per hour)
+     * east of GMT.  The gmtDelta field is a 3-byte value contained in a
+     * long word, so you must take care to get it properly.
+     */
+    gmtDelta = loc.u.gmtDelta & 0x00FFFFFF;
+    if ((gmtDelta & 0x00800000) != 0)
+        {
+        gmtDelta |= 0xFF000000;
+        }
+
+    return gmtDelta;
+}
+
+
+
+/* This routine simulates stdclib time(), time in seconds since 1.1.1970
+   The time is in GMT  */
+static time_t GetTimeMac(void)
+{
+    unsigned long maclocal;
+
+
+    /*
+     * Get the current time expressed as the number of seconds
+     * elapsed since the Mac epoch, midnight, Jan. 1, 1904 (local time).
+     * On a Mac, current time accuracy is up to a second.
+     */
+
+    GetDateTime(&maclocal);     /* Get Mac local time  */
+    maclocal -= GMTDelta();     /* Get Mac GMT  */
+    MACOS_TO_UNIX(maclocal);
+
+    return maclocal;            /* return unix GMT  */
+}
+
+
+
+
+/*
+ *  clear_tm - sets a broken-down time to the equivalent of 1970/1/1 00:00:00
+ */
+
+static void clear_tm(struct tm * tm)
+{
+    tm->tm_sec   =  0;
+    tm->tm_min   =  0;
+    tm->tm_hour  =  0;
+    tm->tm_mday  =  1;
+    tm->tm_mon   =  0;
+    tm->tm_year  =  0;
+    tm->tm_wday  =  1;
+    tm->tm_yday  =  0;
+    tm->tm_isdst = -1;
+}
+
+
+static void normalize(int *i,int *j,int norm)
+{
+  while(*i < 0)
+    {
+    *i += norm;
+    (*j)--;
+    }
+
+  while(*i >= norm)
+    {
+    *i -= norm;
+    (*j)++;
+    }
+}
+
+
+
+/*  Returns the GMT times  */
+static time_t Mactime(time_t *timer)
+{
+    time_t t = GetTimeMac();
+
+    if (timer != NULL)
+        *timer = t;
+
+    return t;
+}
+
+
+
+
+static struct tm *time2tm(const time_t *timer)
+{
+    DateTimeRec dtr;
+    MachineLocation loc;
+    time_t macLocal = *timer;
+
+    static struct tm statictime;
+    static const short monthday[12] =
+        {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+
+    UNIX_TO_MACOS(macLocal);
+    SecondsToDate(macLocal, &dtr);
+
+    statictime.tm_sec  = dtr.second;         /* second, from 0 to 59 */
+    statictime.tm_min  = dtr.minute;         /* minute, from 0 to 59 */
+    statictime.tm_hour = dtr.hour;           /* hour, from 0 to 23 */
+    statictime.tm_mday = dtr.day;            /* day of the month, from 1 to 31 */
+    statictime.tm_mon  = dtr.month     - 1;  /* month, 1= January and 12 = December */
+    statictime.tm_year = dtr.year   - 1900;  /* year, ranging from 1904 to 2040 */
+    statictime.tm_wday = dtr.dayOfWeek - 1;  /* day of the week, 1 = Sun, 7 = Sat */
+
+    statictime.tm_yday = monthday[statictime.tm_mon]
+                         + statictime.tm_mday - 1;
+
+    if (2 < statictime.tm_mon && !(statictime.tm_year & 3))
+        {
+        ++statictime.tm_yday;
+        }
+
+    myReadLocation(&loc);
+    statictime.tm_isdst = DaylightSaving();
+
+    return(&statictime);
+}
+
+
+
+
+
+static time_t tm2time(struct tm *tp)
+{
+time_t intMacTime;
+DateTimeRec  dtr;
+
+ normalize(&tp->tm_sec, &tp->tm_min, 60);
+ normalize(&tp->tm_min, &tp->tm_hour,60);
+ normalize(&tp->tm_hour,&tp->tm_mday,24);
+ normalize(&tp->tm_mon, &tp->tm_year,12);
+
+ dtr.year    = tp->tm_year + 1900;  /* years since 1900 */
+ dtr.month   = tp->tm_mon  +    1;  /* month, 0 = January and 11 = December */
+ dtr.day     = tp->tm_mday;         /* day of the month, from 1 to 31 */
+ dtr.hour    = tp->tm_hour;         /* hour, from 0 to 23 */
+ dtr.minute  = tp->tm_min;          /* minute, from 0 to 59 */
+ dtr.second  = tp->tm_sec;          /* second, from 0 to 59 */
+
+ DateToSeconds(&dtr, &intMacTime);
+
+ MACOS_TO_UNIX(intMacTime);
+
+ return intMacTime;
+}
diff --git a/macos/source/mactime.h b/macos/source/mactime.h
new file mode 100644 (file)
index 0000000..cb76aa4
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef _MACTIME_H_
+#define _MACTIME_H_
+/* -----------------------------------------------------------------------------
+
+The original functions (Metrowerks Codewarrior pro 3.0) gmtime, localtime,
+mktime and time do not work correctly. The supplied link library mactime.c
+contains replacement functions for them.
+
+ *     Caveat: On a Mac, we only know the GMT and DST offsets for
+ *     the current time, not for the time in question.
+ *     Mac has no support for DST handling.
+ *     DST changeover is all manually set by the user.
+
+
+------------------------------------------------------------------------------*/
+
+#include <time.h>
+#include <mactypes.h>
+
+/*****************************************************************************/
+/*  Macros, typedefs                                                         */
+/*****************************************************************************/
+
+
+  /*
+   * ARGH.  Mac times are based on 1904 Jan 1 00:00, not 1970 Jan 1 00:00.
+   *  So we have to diddle time_t's appropriately:  add or subtract 66 years'
+   *  worth of seconds == number of days times 86400 == (66*365 regular days +
+   *  17 leap days ) * 86400 == (24090 + 17) * 86400 == 2082844800L seconds.
+   *  We hope time_t is an unsigned long (ulg) on the Macintosh...
+   */
+/*
+This Offset is only used by MacFileDate_to_UTime()
+*/
+
+#define MACOS_TO_UNIX(x)  (x) -= (unsigned long)MacOS_2_Unix
+#define UNIX_TO_MACOS(x)  (x) += (unsigned long)MacOS_2_Unix
+
+/*
+The MacOS function GetDateTime returns  the
+number of seconds elapsed since midnight, January 1, 1904.
+*/
+extern const unsigned long MacOS_2_Unix;
+
+
+/* prototypes for public utility functions */
+time_t MacFtime2UnixFtime(unsigned long macftime);
+unsigned long UnixFtime2MacFtime(time_t unxftime);
+time_t  AdjustForTZmoveMac(unsigned long macloctim, long s_gmtoffs);
+Boolean GetGMToffsetMac(unsigned long macftime, long *UTCoffset);
+
+
+#endif
diff --git a/macos/source/pathname.c b/macos/source/pathname.c
new file mode 100644 (file)
index 0000000..6bf1003
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+  Copyright (c) 1990-2003 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+  pathname.c
+
+  Function dealing with the pathname. Mostly C-string work.
+
+  ---------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/*  Includes                                                                 */
+/*****************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sound.h>
+
+#include "pathname.h"
+#include "helpers.h"
+#include "macstuff.h"
+
+
+/*****************************************************************************/
+/*  Global Vars                                                              */
+/*****************************************************************************/
+
+const char  ResourceMark[] = "XtraStuf.mac:";  /* see also macos.c */
+
+
+#include "zip.h"
+
+
+
+
+/*****************************************************************************/
+/*  Functions                                                                */
+/*****************************************************************************/
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpFindFolder --
+ *
+ *  This function is a version of the FindFolder function that
+ *  returns the result as a FSSpec rather than a vRefNum and dirID.
+ *
+ * Results:
+ *  Results will be simaler to that of the FindFolder function.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+OSErr
+FSpFindFolder(
+    short vRefNum,      /* Volume reference number. */
+    OSType folderType,      /* Folder type taken by FindFolder. */
+    Boolean createFolder,   /* Should we create it if non-existant. */
+    FSSpec *spec)       /* Pointer to resulting directory. */
+{
+    short foundVRefNum;
+    long foundDirID;
+    OSErr err;
+
+    err = FindFolder(vRefNum, folderType, createFolder,
+        &foundVRefNum, &foundDirID);
+    if (err != noErr) {
+    return err;
+    }
+
+    err = FSMakeFSSpecCompat(foundVRefNum, foundDirID, "\p", spec);
+    return err;
+}
+
+
+/*
+**  return volumename from pathname
+**
+*/
+
+unsigned short GetVolumeFromPath(const char *FullPath, char *VolumeName)
+{
+const char *VolEnd, *tmpPtr1;
+char *tmpPtr2 = VolumeName;
+
+AssertStr(FullPath,"GetVolumeFromPath")
+
+for (VolEnd = FullPath; *VolEnd != '\0' && *VolEnd != ':'; VolEnd++)
+      ;
+if (*VolEnd == '\0') return 0;
+
+for (tmpPtr1 = FullPath; tmpPtr1 != VolEnd;)
+    {
+    *tmpPtr2++ = *tmpPtr1++;
+    }
+
+*tmpPtr2 = '\0';
+
+return (unsigned short) strlen(VolumeName);
+}
+
+
+
+/***********************************/
+/* Function FindNewExtractFolder() */
+/***********************************/
+
+char *FindNewExtractFolder(char *ExtractPath, Boolean uniqueFolder)
+{
+char buffer[NAME_MAX], *tmpPtr, *namePtr;
+char *last_dotpos         = ExtractPath;
+short count = 0, folderCount = 0;
+OSErr err;
+FSSpec Spec;
+long theDirID;
+Boolean isDirectory;
+unsigned short namelen, pathlen = strlen(ExtractPath);
+unsigned long ext_length  = 0;
+unsigned long num_to_cut  = 0;
+long firstpart_length = pathlen;
+
+AssertStr(ExtractPath,"FindNewExtractFolder ExtractPath == NULL")
+
+for (tmpPtr = ExtractPath; *tmpPtr; tmpPtr++)
+    if (*tmpPtr == ':')
+        {
+        folderCount++;
+        namePtr = tmpPtr;
+        }
+
+if (folderCount > 1) {
+    namelen = strlen(namePtr);
+} else {
+    namelen = strlen(ExtractPath);
+}
+
+if (uniqueFolder) {
+    for (count = 0; count < 99; count++)
+        {
+        memset(buffer,0,sizeof(buffer));
+
+        if (namelen >= 28)
+            ExtractPath[pathlen-2] = 0x0;
+        else
+            ExtractPath[pathlen-1] = 0x0;
+
+        sprintf(buffer,"%s%d",ExtractPath,count);
+        GetCompletePath(ExtractPath, buffer, &Spec,&err);
+        err = FSpGetDirectoryID(&Spec, &theDirID, &isDirectory);
+        if (err == -43) break;
+        }
+} else {
+    /* Look for the last extension pos */
+    for (tmpPtr = ExtractPath; *tmpPtr; tmpPtr++)
+        if (*tmpPtr == '.') last_dotpos = tmpPtr;
+
+    ext_length = strlen(last_dotpos);
+
+    if (ext_length < 6) {  /* up to 5 chars are treated as a */
+                           /* normal extension like ".html" or ".class"  */
+        int nameLength = last_dotpos - ExtractPath;
+        if (nameLength > 1) {
+            ExtractPath[nameLength] = 0x0;
+        } else {
+            ExtractPath[pathlen-1] = 0x0;
+        }
+    } else {
+        ExtractPath[pathlen-1] = 0x0;
+    }
+
+    GetCompletePath(ExtractPath, ExtractPath, &Spec,&err);
+}
+
+/* Foldernames must always end with a colon  */
+sstrcat(ExtractPath,":");
+return ExtractPath;
+}
+
+
+
+/*
+**  creates an archive file name
+**
+*/
+
+void createArchiveName(char *thePath)
+{
+char *tmpPtr, *namePtr;
+short folderCount = 0;
+unsigned short namelen, pathlen = strlen(thePath);
+
+if (thePath[pathlen-1] == ':') thePath[pathlen-1] = 0x0;
+
+for (tmpPtr = thePath; *tmpPtr; tmpPtr++)
+    if (*tmpPtr == ':')
+        {
+        folderCount++;
+        namePtr = tmpPtr;
+        }
+
+namelen = strlen(namePtr);
+
+    /* we have to eliminate illegal chars:
+     * The name space for Mac filenames and Zip filenames (unix style names)
+     * do both include all printable extended-ASCII characters.  The only
+     * difference we have to take care of is the single special character
+     * used as path delimiter:
+     * ':' on MacOS and '/' on Unix and '\\' on Dos.
+     * So, to convert between Mac filenames and Unix filenames without any
+     * loss of information, we simply interchange ':' and '/'.  Additionally,
+     * we try to convert the coding of the extended-ASCII characters into
+     * InfoZip's standard ISO 8859-1 codepage table.
+     */
+  MakeCompatibleString(namePtr, '/', '_', '.', '-', -1);
+
+ /* Avoid filenames like: "Archive..zip"  */
+if (thePath[pathlen-1] == '.')
+    {
+    thePath[pathlen-1] = 0;
+    }
+
+if (folderCount >= 1)
+    { /* path contains at least one folder */
+
+    if (namelen >= 28)
+        {
+        pathlen = pathlen-4;
+        }
+
+    thePath[pathlen]   = '.';
+    thePath[pathlen+1] = 'z';
+    thePath[pathlen+2] = 'i';
+    thePath[pathlen+3] = 'p';
+    thePath[pathlen+4] = 0x0;
+    return;
+    }
+else
+    {  /* path contains no folder */
+    FindDesktopFolder(thePath);
+    createArchiveName(thePath);
+    }
+}
+
+
+
+/*
+** finds the desktop-folder on a volume with
+** largest amount of free-space.
+*/
+
+void FindDesktopFolder(char *Path)
+{
+char buffer[255];
+FSSpec  volumes[50];        /* 50 Volumes should be enough */
+short   actVolCount, volIndex = 1, VolCount = 0;
+OSErr   err;
+short     i, foundVRefNum;
+FSSpec spec;
+UInt64 freeBytes;
+UInt64 totalBytes;
+UInt64 MaxFreeBytes;
+
+err = OnLine(volumes, 50, &actVolCount, &volIndex);
+printerr("OnLine:", (err != -35) && (err != 0), err, __LINE__, __FILE__, "");
+
+MaxFreeBytes = 0;
+
+for (i=0; i < actVolCount; i++)
+    {
+    XGetVInfo(volumes[i].vRefNum,
+              volumes[i].name,
+              &volumes[i].vRefNum,
+              &freeBytes,
+              &totalBytes);
+
+    if (MaxFreeBytes < freeBytes) {
+        MaxFreeBytes = freeBytes;
+        foundVRefNum = volumes[i].vRefNum;
+    }
+
+    if ((freeBytes == 0) && (MaxFreeBytes < freeBytes)) {
+        MaxFreeBytes = freeBytes;
+        foundVRefNum = volumes[i].vRefNum;
+    }
+
+}
+
+ FSpFindFolder(foundVRefNum, kDesktopFolderType,
+            kDontCreateFolder,&spec);
+
+ GetFullPathFromSpec(buffer, &spec , &err);
+ sstrcat(buffer,Path);
+ sstrcpy(Path,buffer);
+}
+
+
+/*
+**  return the path without the filename
+**
+*/
+
+char *TruncFilename(char *DirPath, const char *FilePath)
+{
+char *tmpPtr;
+char *dirPtr = NULL;
+
+AssertStr(DirPath,"TruncFilename")
+Assert_it(Spec,"TruncFilename","")
+
+sstrcpy(DirPath, FilePath);
+
+for (tmpPtr = DirPath; *tmpPtr; tmpPtr++)
+    if (*tmpPtr == ':')
+        dirPtr = tmpPtr;
+
+if (dirPtr)
+    *++dirPtr = '\0';
+else
+    printerr("TruncFilename: FilePath has no Folders", -1,
+         -1, __LINE__, __FILE__, FilePath);
+
+return DirPath;
+}
+
+
+
+/*
+**  return only filename
+**
+*/
+
+char *GetFilename(char *FileName, const char *FilePath)
+{
+const char *tmpPtr;
+const char *dirPtr = NULL;
+
+Assert_it(FileName,"GetFilename","")
+Assert_it(FilePath,"GetFilename","")
+
+for (tmpPtr = FilePath; *tmpPtr; tmpPtr++)
+    {
+    if (*tmpPtr == ':')
+        {
+        dirPtr = tmpPtr;
+        }
+    }
+
+if (dirPtr)
+    {
+    ++dirPtr;  /* jump over the ':' */
+    }
+else
+    {
+    return strcpy(FileName, FilePath); /* FilePath has no Folders */
+    }
+
+return strcpy(FileName, dirPtr);
+}
+
+
+
+/*
+**  return fullpathname from folder/dir-id
+**
+*/
+
+char *GetFullPathFromID(char *CompletePath, short vRefNum, long dirID,
+                        ConstStr255Param name, OSErr *err)
+{
+FSSpec      spec;
+
+    *err = FSMakeFSSpecCompat(vRefNum, dirID, name, &spec);
+    printerr("FSMakeFSSpecCompat:", (*err != -43) && (*err != 0), *err,
+             __LINE__, __FILE__, "");
+    if ( (*err == noErr) || (*err == fnfErr) )
+        {
+        return GetFullPathFromSpec(CompletePath, &spec, err);
+        }
+
+return NULL;
+}
+
+
+
+/*
+**  convert real-filename to archive-filename
+**
+*/
+
+char *Real2RfDfFilen(char *RfDfFilen, const char *RealPath,
+                    short CurrentFork, short MacZipMode, Boolean DataForkOnly)
+{
+
+AssertStr(RealPath,"Real2RfDfFilen")
+AssertStr(RfDfFilen,"Real2RfDfFilen")
+
+if (DataForkOnly) /* make no changes */
+    {
+    return sstrcpy(RfDfFilen, RealPath);
+    }
+
+switch (MacZipMode)
+    {
+    case JohnnyLee_EF:
+        {
+        sstrcpy(RfDfFilen, RealPath);
+        if (CurrentFork == DataFork)            /* data-fork  */
+            return sstrcat(RfDfFilen, "d");
+        if (CurrentFork == ResourceFork)        /* resource-fork */
+            return sstrcat(RfDfFilen, "r");
+        break;
+        }
+
+    case NewZipMode_EF:
+        {
+        switch (CurrentFork)
+            {
+            case DataFork:
+                {
+                sstrcpy(RfDfFilen, RealPath);
+                return RfDfFilen;  /* data-fork  */
+                break;
+                }
+            case ResourceFork:
+                {
+                sstrcpy(RfDfFilen, ResourceMark);
+                sstrcat(RfDfFilen, RealPath);  /* resource-fork */
+                return RfDfFilen;
+                break;
+                }
+            default:
+                {
+                printerr("Real2RfDfFilen:", -1, -1,
+                         __LINE__, __FILE__, RealPath);
+                return NULL;  /* function should never reach this point */
+                }
+            }
+        break;
+        }
+    default:
+        {
+        printerr("Real2RfDfFilen:", -1, -1, __LINE__, __FILE__, RealPath);
+        return NULL;  /* function should never reach this point */
+        }
+    }
+
+printerr("Real2RfDfFilen:", -1, -1, __LINE__, __FILE__, RealPath);
+return NULL;  /* function should never come reach this point */
+}
+
+
+
+/*
+**  convert archive-filename into a real filename
+**
+*/
+
+char *RfDfFilen2Real(char *RealFn, const char *RfDfFilen, short MacZipMode,
+                     Boolean DataForkOnly, short *CurrentFork)
+{
+short   length;
+int     result;
+
+AssertStr(RfDfFilen,"RfDfFilen2Real")
+
+if (DataForkOnly ||
+    (MacZipMode == UnKnown_EF) ||
+    (MacZipMode < JohnnyLee_EF))
+    {
+    *CurrentFork = DataFork;
+    return sstrcpy(RealFn,RfDfFilen);
+    }
+
+result = strncmp(RfDfFilen, ResourceMark, sizeof(ResourceMark)-2);
+if (result == 0)
+    {
+    MacZipMode = NewZipMode_EF;
+    }
+
+switch (MacZipMode)
+    {
+    case JohnnyLee_EF:
+        {
+        sstrcpy(RealFn, RfDfFilen);
+        length = strlen(RealFn);       /* determine Fork type */
+        if (RealFn[length-1] == 'd') *CurrentFork = DataFork;
+        else *CurrentFork = ResourceFork;
+        RealFn[length-1] = '\0';       /* simply cut one char  */
+        return RealFn;
+        break;
+        }
+
+    case NewZipMode_EF:
+        {                                   /* determine Fork type */
+        result = strncmp(RfDfFilen, ResourceMark, sizeof(ResourceMark)-2);
+        if (result != 0)
+            {
+            *CurrentFork = DataFork;
+            sstrcpy(RealFn, RfDfFilen);
+            return RealFn;  /* data-fork  */
+            }
+        else
+            {
+            *CurrentFork = ResourceFork;
+            if (strlen(RfDfFilen) > (sizeof(ResourceMark) - 1))
+                {
+                sstrcpy(RealFn, &RfDfFilen[sizeof(ResourceMark)-1]);
+                }
+            else RealFn[0] = '\0';
+            return RealFn;  /* resource-fork */
+            }
+        break;
+        }
+    default:
+        {
+        *CurrentFork = NoFork;
+        printerr("RfDfFilen2Real():", -1, MacZipMode,
+                 __LINE__, __FILE__, RfDfFilen);
+        return NULL;  /* function should never reach this point */
+        }
+    }
+
+printerr("RfDfFilen2Real():", -1, MacZipMode, __LINE__, __FILE__, RfDfFilen);
+return NULL;  /* function should never reach this point */
+}
+
+
+
+/*
+**  return the applications name (argv[0])
+**
+*/
+
+char *GetAppName(void)
+{
+ProcessSerialNumber psn;
+static Str255       AppName;
+ProcessInfoRec      pinfo;
+OSErr               err;
+
+GetCurrentProcess(&psn);
+pinfo.processName = AppName;
+pinfo.processInfoLength = sizeof(pinfo);
+pinfo.processAppSpec = NULL;
+
+err = GetProcessInformation(&psn,&pinfo);
+AppName[AppName[0]+1] = 0x00;
+
+return (char *)&AppName[1];
+}
+
+
+
+/*
+**  return fullpathname from FSSpec
+**
+*/
+
+char *GetFullPathFromSpec(char *FullPath, FSSpec *Spec, OSErr *err)
+{
+Handle hFullPath;
+short len;
+
+Assert_it(Spec,"GetFullPathFromSpec","")
+
+*err = FSpGetFullPath(Spec, &len, &hFullPath);
+printerr("FSpGetFullPath:", (*err != -43) && (*err != 0), *err,
+         __LINE__, __FILE__, "");
+
+memmove(FullPath, (Handle) *hFullPath, len);
+FullPath[len] = '\0';  /* make c-string */
+
+DisposeHandle((Handle)hFullPath);   /* we don't need it any more */
+
+printerr("Warning path length exceeds limit: ", len >= NAME_MAX, len,
+         __LINE__, __FILE__, " chars ");
+
+return FullPath;
+}
+
+
+
+
+/*
+* This function expands a given partial path to a complete path.
+* Path expansions are relative to the running app.
+* This function follows the notation:
+*   1. relative path:
+*       a: ":subfolder:filename"    -> ":current folder:subfolder:filename"
+*       b: "::folder2:filename"     -> folder2 is beside the current
+*                                      folder on the same level
+*       c: "filename"               -> in current folder
+*
+* An absolute path will be returned.
+
+The following characteristics of Macintosh pathnames should be noted:
+
+       A full pathname never begins with a colon, but must contain at
+       least one colon.
+       A partial pathname always begins with a colon separator except in
+       the case where the file partial pathname is a simple file or
+       directory name.
+       Single trailing separator colons in full or partial pathnames are
+       ignored except in the case of full pathnames to volumes.
+       In full pathnames to volumes, the trailing separator colon is required.
+       Consecutive separator colons can be used to ascend a level from a
+       directory to its parent directory. Two consecutive separator colons
+       will ascend one level, three consecutive separator colons will ascend
+       two levels, and so on. Ascending can only occur from a directory;
+       not a file.
+*/
+
+char *GetCompletePath(char *CompletePath, const char *name, FSSpec *Spec,
+                      OSErr *err)
+{
+Boolean hasDirName = false;
+char currentdir[NAME_MAX];
+char *tmpPtr;
+unsigned short pathlen;
+
+AssertStr(name,"GetCompletePath")
+Assert_it(Spec,"GetCompletePath","")
+Assert_it((CompletePath != name),"GetCompletePath","")
+
+for (tmpPtr = name; *tmpPtr; tmpPtr++)
+    if (*tmpPtr == ':') hasDirName = true;
+
+if (name[0] != ':')   /* case c: path including volume name or only filename */
+    {
+    if (hasDirName)
+        {   /* okey, starts with volume name, so it must be a complete path */
+        sstrcpy(CompletePath, name);
+        }
+    else
+        {   /* only filename: add cwd and return */
+        getcwd(currentdir, NAME_MAX);
+        sstrcat(currentdir, name);
+        sstrcpy(CompletePath, currentdir);
+        }
+    }
+else if (name[1] == ':')    /* it's case b: "::folder2:filename"  */
+    {
+    printerr("GetCompletePath ", -1, *err, __LINE__, __FILE__, "not implemented");
+            /* it's not yet implemented; do we really need this case ?*/
+    return NULL;
+    }
+else                        /* it's case a: ":subfolder:filename" */
+    {
+    getcwd(CompletePath, NAME_MAX);     /* we don't need a second colon */
+    CompletePath[strlen(CompletePath)-1] = '\0';
+    sstrcat(CompletePath, name);
+    }
+
+pathlen = strlen(CompletePath);
+*err = FSpLocationFromFullPath(pathlen, CompletePath, Spec);
+
+return CompletePath;
+}
+
+
+
+char *MakeFilenameShorter(const char *LongFilename)
+{
+static char filename[35];  /* contents should be never longer than 32 chars */
+static unsigned char Num = 0; /* change the number for every call */
+                              /* this var will rollover without a problem */
+char tempLongFilename[1024], charnum[5];
+char *last_dotpos         = tempLongFilename;
+unsigned long full_length = strlen(LongFilename);
+unsigned long ext_length  = 0;
+unsigned long num_to_cut  = 0;
+long firstpart_length;
+char *tmpPtr;
+short MaxLength = 31;
+
+if (full_length <= MaxLength) /* filename is not long */
+    {
+    return strcpy(filename,LongFilename);
+    }
+
+Num++;
+strcpy(tempLongFilename,LongFilename);
+
+/* Look for the last extension pos */
+for (tmpPtr = tempLongFilename; *tmpPtr; tmpPtr++)
+    if (*tmpPtr == '.') last_dotpos = tmpPtr;
+
+ext_length = strlen(last_dotpos);
+firstpart_length = last_dotpos - tempLongFilename;
+
+if (ext_length > 6)  /* up to 5 chars are treated as a */
+    {                /* normal extension like ".html" or ".class"  */
+    firstpart_length = 0;
+    }
+
+num_to_cut = full_length - MaxLength;
+
+/* number the files to make the names unique */
+sprintf(charnum,"~%x", Num);
+num_to_cut += strlen(charnum);
+
+if (firstpart_length == 0)
+    {
+    firstpart_length = full_length;
+    tempLongFilename[firstpart_length - num_to_cut] = 0;
+    sprintf(filename,"%s%s", tempLongFilename, charnum);
+    }
+else
+    {
+    tempLongFilename[firstpart_length - num_to_cut] = 0;
+    sprintf(filename,"%s%s%s", tempLongFilename, charnum, last_dotpos);
+    }
+
+return filename;
+}
diff --git a/macos/source/pathname.h b/macos/source/pathname.h
new file mode 100644 (file)
index 0000000..1a39ed3
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+  Copyright (c) 1990-2001 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef PATHNAME_H
+#define PATHNAME_H 1
+
+
+char *StripPartialDir(char *CompletePath,
+                      const char *PartialPath, const char *FullPath);
+
+char *Real2RfDfFilen(char *RfDfFilen, const char *RealPath, short CurrentFork,
+                     short MacZipMode, Boolean DataForkOnly);
+char *RfDfFilen2Real(char *RealFn, const char *RfDfFilen, short MacZipMode,
+                     Boolean DataForkOnly, short *CurrentFork);
+
+unsigned short GetVolumeFromPath(const char *FullPath, char *VolumeName);
+char *GetCompletePath(char *CompletePath, const char *name, FSSpec *Spec,
+                      OSErr *err);
+char *TruncFilename(char *DirPath, const char *FilePath);
+char *GetFilename(char *CompletePath, const char *name);
+char *GetFullPathFromSpec(char *CompletePath, FSSpec *Spec, OSErr *err);
+char *GetFullPathFromID(char *CompletePath, short vRefNum, long dirID,
+                        ConstStr255Param name, OSErr *err);
+
+char *GetAppName(void);
+void createArchiveName(char *Path);
+void FindDesktopFolder(char *Path);
+char *FindNewExtractFolder(char *ExtractPath, Boolean uniqueFolder);
+OSErr FSpFindFolder(
+    short vRefNum,          /* Volume reference number. */
+    OSType folderType,      /* Folder type taken by FindFolder. */
+    Boolean createFolder,   /* Should we create it if non-existant. */
+    FSSpec *spec);          /* Pointer to resulting directory. */
+
+char *MakeFilenameShorter(const char *LongFilename);
+
+/*
+Rule: UnKnown_EF should always be zero.
+      JohnnyLee_EF, NewZipMode_EF should always greater than all
+      other definitions
+*/
+#define UnKnown_EF           0
+#define TomBrownZipIt1_EF   10
+#define TomBrownZipIt2_EF   20
+#define JohnnyLee_EF        30
+#define NewZipMode_EF       40
+
+
+
+#define ResourceFork    -1
+#define DataFork        1
+#define NoFork          0
+
+
+#ifndef NAME_MAX
+#define NAME_MAX    1024
+#endif
+
+#endif   /*  PATHNAME_H  */
diff --git a/macos/source/recurse.c b/macos/source/recurse.c
new file mode 100644 (file)
index 0000000..e87db3c
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+These functions are based on Jim Luther's IterateDirectory() found in MoreFiles
+However, it's heavily modified by Dirk Haase
+*/
+
+/*
+**  IterateDirectory: File Manager directory iterator routines.
+**
+**  by Jim Luther
+**
+**  File:       IterateDirectory.c
+**
+**  Copyright (c) 1995-1998 Jim Luther and Apple Computer, Inc.
+**  All rights reserved.
+**
+**  You may incorporate this sample code into your applications without
+**  restriction, though the sample code has been provided "AS IS" and the
+**  responsibility for its operation is 100% yours.
+**
+**  IterateDirectory is designed to drop into the MoreFiles sample code
+**  library I wrote while in Apple Developer Technical Support
+*/
+
+/*****************************************************************************/
+/*  Includes                                                                 */
+/*****************************************************************************/
+
+#include <Types.h>
+#include <Errors.h>
+#include <Files.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#include "zip.h"
+#include "macstuff.h"
+#include "helpers.h"
+#include "recurse.h"
+#include "macglob.h"
+#include "pathname.h"
+
+
+
+
+/*****************************************************************************/
+/*  Macros, typedefs                                                         */
+/*****************************************************************************/
+
+/* The RecurseGlobals structure is used to minimize the amount of
+** stack space used when recursively calling RecurseDirectoryLevel
+** and to hold global information that might be needed at any time.
+*/
+struct RecurseGlobals
+{
+    short                   vRefNum;
+    CInfoPBRec              cPB;            /* the parameter block used for
+                                               PBGetCatInfo calls */
+    unsigned char           *itemName;      /* the name of the current item */
+    char                    *FullPath;
+    short                   FullPathLen;
+    OSErr                   result;         /* temporary holder of results -
+                                            saves 2 bytes of stack each level */
+    Boolean                 quitFlag;       /* set to true if filter wants to
+                                               kill interation */
+    unsigned short          maxLevels;      /* Maximum levels to
+                                               iterate through */
+    unsigned short          currentLevel;   /* The current level
+                                               IterateLevel is on */
+};
+
+typedef struct RecurseGlobals RecurseGlobals;
+typedef RecurseGlobals *RecurseGlobalsPtr;
+
+
+/*****************************************************************************/
+/*  Global Vars                                                              */
+/*****************************************************************************/
+
+extern MacZipGlobals    MacZip;
+extern const char ResourceMark[13]; /* "XtraStuf.mac:" var is initialized in file pathname.c */
+extern int extra_fields;            /* do not create extra fields if false */
+
+static RecurseGlobals theGlobals;
+
+static unsigned long    DirLevels = 0;
+static char *buffer;
+extern int verbose;        /* 1=report oddities in zip file structure */
+
+/*****************************************************************************/
+/*  Prototypes                                                               */
+/*****************************************************************************/
+
+int procname(char *filename, int caseflag);
+int MatchWild( char *pPat, char *pStr, int case_sens);
+Boolean IsZipFile(char *name);
+
+static  void    RecurseDirectoryLevel(long DirID, RecurseGlobals *Globals);
+static Boolean isRegularItem( RecurseGlobals *Globals);
+static void ProcessFiles(RecurseGlobals *Globals,
+                         Boolean hasDataFork, Boolean hasResourceFork);
+static void ProcessDirectory(RecurseGlobals *Globals,
+                             Boolean IncludeItem, long DirID);
+static void ProcessItem(RecurseGlobals *Globals, long DirID);
+
+/*****************************************************************************/
+/*  Functions                                                                */
+/*****************************************************************************/
+
+static  void    RecurseDirectoryLevel(long DirID, RecurseGlobals *Globals)
+{
+char buffer2[23];
+
+                 /* if maxLevels is zero, we aren't checking levels */
+    if ( (Globals->maxLevels == 0) ||
+                 /* if currentLevel < maxLevels, look at this level */
+         (Globals->currentLevel < Globals->maxLevels) )
+    {
+        short index = 1;
+
+        ++Globals->currentLevel;    /* go to next level */
+        if (DirLevels < Globals->currentLevel) DirLevels = Globals->currentLevel;
+        sprintf(buffer2,"Globals->currentLevel: %d",Globals->currentLevel);
+
+        do
+        {   /* Isn't C great... What I'd give for a "WITH
+                theGlobals DO" about now... */
+
+            /* Get next source item at the current directory level */
+            Globals->cPB.dirInfo.ioFDirIndex = index;
+            Globals->cPB.dirInfo.ioDrDirID = DirID;
+            Globals->result = PBGetCatInfoSync((CInfoPBPtr)&Globals->cPB);
+
+                        ShowCounter(false);
+
+            if ( Globals->result == noErr )
+                {
+                ProcessItem(Globals, DirID);
+                } /* if ( Globals->result == noErr ) */
+
+            ++index; /* prepare to get next item */
+                                         /* time to fall back a level? */
+        } while ( (Globals->result == noErr) && (!Globals->quitFlag) );
+
+        if ( (Globals->result == fnfErr) || /* fnfErr is OK -
+                                               it only means we hit
+                                               the end of this level */
+             (Globals->result == afpAccessDenied) ) /* afpAccessDenied is OK,
+                      too - it only means we cannot see inside a directory */
+        {
+            Globals->result = noErr;
+        }
+
+        --Globals->currentLevel;    /* return to previous level as we leave */
+    }
+}
+
+
+
+/*****************************************************************************/
+
+pascal  OSErr   RecurseDirectory(short vRefNum,
+                                 long thedirID,
+                                 ConstStr255Param name,
+                                 unsigned short maxLevels)
+{
+    OSErr           result;
+    short           theVRefNum;
+    Boolean         isDirectory;
+    long            DirID;
+
+        /* Get the real directory ID and make sure it is a directory */
+        result = GetDirectoryID(vRefNum, thedirID, name, &DirID, &isDirectory);
+        if ( result == noErr )
+        {
+            if ( isDirectory == true )
+            {
+                /* Get the real vRefNum */
+                result = DetermineVRefNum(name, vRefNum, &theVRefNum);
+                if ( result == noErr )
+                {
+                    /* Set up the globals we need to access from
+                       the recursive routine. */
+                    theGlobals.cPB.hFileInfo.ioNamePtr = theGlobals.itemName;
+                    theGlobals.cPB.hFileInfo.ioVRefNum = theVRefNum;
+                    theGlobals.itemName[0] = 0;
+                    theGlobals.result = noErr;
+                    theGlobals.quitFlag = false;
+                    theGlobals.maxLevels = maxLevels;
+                    theGlobals.currentLevel = 0;    /* start at level 0 */
+
+                    /* Here we go into recursion land... */
+                    RecurseDirectoryLevel(DirID, &theGlobals);
+
+                    result = theGlobals.result; /* set the result */
+                }
+            }
+            else
+            {
+                result = dirNFErr;  /* a file was passed instead
+                                       of a directory */
+            }
+        }
+
+    return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal  OSErr   FSpRecurseDirectory(const FSSpec *spec,
+                                    unsigned short maxLevels)
+{
+    OSErr rc;
+
+    theGlobals.vRefNum = spec->vRefNum;
+
+    /* make room for pathnames  */
+    theGlobals.itemName = (unsigned char *) StrCalloc(NAME_MAX);
+    theGlobals.FullPath = StrCalloc(NAME_MAX);
+    buffer = StrCalloc(NAME_MAX);
+
+
+    if ((noisy) && (MacZip.DataForkOnly))
+        printf("\n Warning: Datafork only \n");
+
+    /* reset the count to zero */
+    ShowCounter(true);
+
+    if (noisy) leftStatusString("Build File List; Items done:");
+    if (noisy) printf("\n Collecting Filenames ...");
+    rc = RecurseDirectory(spec->vRefNum, spec->parID, spec->name,maxLevels);
+    printerr("RecurseDirectory:",rc,rc,__LINE__,__FILE__,"");
+
+    if (noisy) printf("\n... done \n\n %6d matched files found  \n",
+                      MacZip.FoundFiles);
+    if (noisy) printf(" %6d folders found in %d Levels \n",
+                         MacZip.FoundDirectories,DirLevels);
+
+    if (MacZip.BytesOfData > (1024*1024))
+        if (noisy) printf(" %4.3f MBytes unzipped size\n\n",
+                            (float) MacZip.BytesOfData/(1024*1024));
+    else
+        if (noisy) printf(" %4.3f KBytes unzipped size\n\n",
+                           (float) MacZip.BytesOfData/1024);
+
+    /* free all memory of pathnames  */
+    theGlobals.itemName = (unsigned char *) StrFree((char *)theGlobals.itemName);
+    theGlobals.FullPath = StrFree(theGlobals.FullPath);
+    buffer = StrFree(buffer);
+
+    return rc;
+}
+
+
+
+
+/*
+* Return true if filename == zipfile
+* After the first match no further check will be done !
+*
+*/
+Boolean IsZipFile(char *filen)
+{
+static firstMatch = false;
+
+if (filen == NULL)
+    firstMatch = false;
+
+if (!firstMatch)
+    {
+    if (stricmp(filen, MacZip.ZipFullPath) == 0)
+        {
+        firstMatch = true;
+        return true;
+        }
+    }
+
+return false;
+}
+
+
+
+static Boolean isRegularItem( RecurseGlobals *Globals)
+{
+Boolean     isInvisible = false,
+            isAlias     = false,
+            isSystem    = false;
+
+isSystem    = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags &
+              (1 << 12)) == 0 );
+isInvisible = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags &
+              (1 << 14)) == 0 );
+isAlias     = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags &
+              (1 << 15)) == 0);
+
+if (isAlias == true)
+    {
+    return false;
+    }
+
+if (MacZip.IncludeInvisible == true)
+    {
+    return true;
+    }
+
+if  ((isSystem == true) ||
+    (isInvisible == true))
+    {
+    return false;
+    }
+
+return true;
+}
+
+
+
+
+static void ProcessFiles(RecurseGlobals *Globals,
+                         Boolean hasDataFork, Boolean hasResourceFork)
+{
+ /* some file statistics */
+MacZip.FoundFiles++;
+
+if (hasDataFork == true)
+    {
+    MacZip.BytesOfData =
+                Globals->cPB.hFileInfo.ioFlLgLen +
+                MacZip.BytesOfData;
+    MacZip.CurrentFork = DataFork;
+    MacZip.RawCountOfItems++;
+
+    if (MacZip.DataForkOnly == true)
+        {
+        procname(Globals->FullPath, false);
+        hasResourceFork = false;
+        }
+        else
+        {
+        procname(Real2RfDfFilen(buffer,Globals->FullPath,
+                 DataFork, MacZip.MacZipMode,
+                 MacZip.DataForkOnly), false);
+        }
+    }
+
+if (hasResourceFork == true)
+    {
+    MacZip.BytesOfData =
+                Globals->cPB.hFileInfo.ioFlRLgLen +
+                MacZip.BytesOfData;
+    MacZip.CurrentFork = ResourceFork;
+    MacZip.RawCountOfItems++;
+
+    procname(Real2RfDfFilen(buffer, Globals->FullPath,
+             ResourceFork, MacZip.MacZipMode,
+             MacZip.DataForkOnly), false);
+    }
+}
+
+
+
+
+static void ProcessDirectory(RecurseGlobals *Globals,
+                             Boolean IncludeItem, long DirID)
+{
+OSErr       rc;
+
+MacZip.isDirectory = true;
+
+GetFullPathFromID(Globals->FullPath,Globals->vRefNum, DirID,
+                  Globals->itemName, &rc);
+
+MacZip.RawCountOfItems++;
+MacZip.FoundDirectories++;
+
+if  (MacZip.StoreFoldersAlso)
+    {
+    procname(Globals->FullPath, false);
+    }
+
+     /* We have a directory */
+    if ( !Globals->quitFlag && IncludeItem)
+    {
+   /* Dive again if the IterateFilterProc didn't say "quit" and dir is
+      not an alias */
+        RecurseDirectoryLevel(Globals->cPB.dirInfo.ioDrDirID,
+                              Globals);
+    }
+}
+
+
+
+static void ProcessItem(RecurseGlobals *Globals, long DirID)
+{
+OSErr rc;
+Boolean     IncludeItem = false, hasDataFork = false;
+Boolean     hasResourceFork = false;
+
+IncludeItem = isRegularItem(Globals);
+
+/* Is it a File? */
+if ( (Globals->cPB.hFileInfo.ioFlAttrib & ioDirMask) == 0 )
+    {
+    PToCCpy(Globals->itemName,MacZip.FileName);
+    MacZip.isDirectory = false;
+
+    hasDataFork     = (Globals->cPB.hFileInfo.ioFlLgLen != 0);
+    hasResourceFork = (Globals->cPB.hFileInfo.ioFlRLgLen != 0);
+
+    /* include also files with zero recource- and data-fork */
+    if ((hasDataFork == 0) && (hasResourceFork == 0))
+        hasDataFork = true;
+
+    if ((hasDataFork     == 0) &&
+        (hasResourceFork != 0) &&
+        (extra_fields    == false))
+        {
+        IncludeItem = false;
+        }
+
+    GetFullPathFromID(Globals->FullPath,Globals->vRefNum,
+                      DirID, Globals->itemName, &rc);
+    printerr("GetFullPathFromID:",rc,rc,__LINE__,
+              __FILE__,MacZip.FileName);
+
+    if  (IncludeItem  &&       /* don't include the zipfile itself */
+        (!IsZipFile(Globals->FullPath))   )
+        {
+        if (MATCH(MacZip.Pattern, MacZip.FileName, false) == true)
+            {
+            ProcessFiles(Globals, hasDataFork, hasResourceFork);
+            } /* if (MatchWild( MacZip.FileName,MacZip.Pattern ) ==
+                    true) */
+        }  /* if (!IsZipFile(Globals->FullPath)) */
+    } /* Is it a File? */
+
+/* Is it a directory? */
+if ( (Globals->cPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+    {
+    ProcessDirectory(Globals,IncludeItem, DirID);
+    } /* Is it a directory? */
+}
diff --git a/macos/source/recurse.h b/macos/source/recurse.h
new file mode 100644 (file)
index 0000000..cfbc4b0
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+**  IterateDirectory: File Manager directory iterator routines.
+**
+**  by Jim Luther
+**
+**  File:       IterateDirectory.h
+**
+**  Copyright (c) 1995-1998 Jim Luther and Apple Computer, Inc.
+**  All rights reserved.
+**
+**  You may incorporate this sample code into your applications without
+**  restriction, though the sample code has been provided "AS IS" and the
+**  responsibility for its operation is 100% yours.
+**
+**  IterateDirectory is designed to drop into the MoreFiles sample code
+**  library I wrote while in Apple Developer Technical Support
+*/
+
+#ifndef __RECURSEDIRECTORY__
+#define __RECURSEDIRECTORY__
+
+#include <Types.h>
+#include <Files.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*****************************************************************************/
+
+pascal  OSErr   RecurseDirectory(short vRefNum,
+                                 long dirID,
+                                 ConstStr255Param name,
+                                 unsigned short maxLevels );
+/*   Iterate (scan) through a directory's content.
+    The IterateDirectory function performs a recursive iteration (scan) of
+    the specified directory and calls your IterateFilterProc function once
+    for each file and directory found.
+
+    The maxLevels parameter lets you control how deep the recursion goes.
+    If maxLevels is 1, IterateDirectory only scans the specified directory;
+    if maxLevels is 2, IterateDirectory scans the specified directory and
+    one subdirectory below the specified directory; etc. Set maxLevels to
+    zero to scan all levels.
+
+    The yourDataPtr parameter can point to whatever data structure you might
+    want to access from within the IterateFilterProc.
+
+    vRefNum         input:  Volume specification.
+    dirID           input:  Directory ID.
+    name            input:  Pointer to object name, or nil when dirID
+                            specifies a directory that's the object.
+    maxLevels       input:  Maximum number of directory levels to scan or
+                            zero to scan all directory levels.
+    iterateFilter   input:  A pointer to the routine you want called once
+                            for each file and directory found by
+                            IterateDirectory.
+    yourDataPtr     input:  A pointer to whatever data structure you might
+                            want to access from within the IterateFilterProc.
+
+    Result Codes
+        noErr               0       No error
+        nsvErr              -35     No such volume
+        ioErr               -36     I/O error
+        bdNamErr            -37     Bad filename
+        fnfErr              -43     File not found
+        paramErr            -50     No default volume or iterateFilter was NULL
+        dirNFErr            -120    Directory not found or incomplete pathname
+                                    or a file was passed instead of a directory
+        afpAccessDenied     -5000   User does not have the correct access
+        afpObjectTypeErr    -5025   Directory not found or incomplete pathname
+
+    __________
+
+    See also:   RecurseFilterProcPtr, FSpRecurseDirectory
+*/
+
+/*****************************************************************************/
+
+pascal  OSErr   FSpRecurseDirectory(const FSSpec *spec,
+                                    unsigned short maxLevels);
+/*   Iterate (scan) through a directory's content.
+    The FSpIterateDirectory function performs a recursive iteration (scan)
+    of the specified directory and calls your IterateFilterProc function once
+    for each file and directory found.
+
+    The maxLevels parameter lets you control how deep the recursion goes.
+    If maxLevels is 1, FSpIterateDirectory only scans the specified directory;
+    if maxLevels is 2, FSpIterateDirectory scans the specified directory and
+    one subdirectory below the specified directory; etc. Set maxLevels to
+    zero to scan all levels.
+
+    The yourDataPtr parameter can point to whatever data structure you might
+    want to access from within the IterateFilterProc.
+
+    spec            input:  An FSSpec record specifying the directory to scan.
+    maxLevels       input:  Maximum number of directory levels to scan or
+                            zero to scan all directory levels.
+    iterateFilter   input:  A pointer to the routine you want called once
+                            for each file and directory found by
+                            FSpIterateDirectory.
+    yourDataPtr     input:  A pointer to whatever data structure you might
+                            want to access from within the IterateFilterProc.
+
+    Result Codes
+        noErr               0       No error
+        nsvErr              -35     No such volume
+        ioErr               -36     I/O error
+        bdNamErr            -37     Bad filename
+        fnfErr              -43     File not found
+        paramErr            -50     No default volume or iterateFilter was NULL
+        dirNFErr            -120    Directory not found or incomplete pathname
+        afpAccessDenied     -5000   User does not have the correct access
+        afpObjectTypeErr    -5025   Directory not found or incomplete pathname
+
+    __________
+
+    See also:   RecurseFilterProcPtr, RecurseDirectory
+*/
+
+
+
+/*****************************************************************************/
+
+
+
+#endif /* __RECURSEDIRECTORY__ */
diff --git a/macos/source/unixlike.c b/macos/source/unixlike.c
new file mode 100644 (file)
index 0000000..4eb55da
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+  unixlike.c
+
+  Macintosh-specific routines to emulate unixfunctions.
+
+  ---------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/*  Includes                                                                 */
+/*****************************************************************************/
+
+#include "zip.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <sound.h>
+
+#include "unixlike.h"
+#include "helpers.h"
+#include "pathname.h"
+#include "macstuff.h"
+#include "macglob.h"
+#include "mactime.h"
+
+/*****************************************************************************/
+/*  Global Vars                                                              */
+/*****************************************************************************/
+
+extern MacZipGlobals    MacZip;
+extern int errno;
+
+
+/*****************************************************************************/
+/*  Prototypes                                                               */
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+/*  Functions                                                                */
+/*****************************************************************************/
+
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * MacStat --
+ *
+ *  This function replaces the library version of stat.  The stat
+ *  function provided by most Mac compiliers is rather broken and
+ *  incomplete.
+ *
+ * Results:
+ *  See stat documentation.
+ *
+ * Side effects:
+ *  See stat documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int Zmacstat(const char *Fname, struct stat *buf)
+{
+    OSErr           err, rc;
+    short           fullPathLength;
+    Handle          hFullPath;
+    char            path[NAME_MAX], path2[NAME_MAX];
+    HVolumeParam    vpb;
+    static unsigned long count_of_files = 0;
+
+    AssertStr(Fname,Fname)
+    Assert_it(buf,"","")
+
+    UserStop();
+
+    memset(buf, 0, sizeof(buf));    /* zero out all fields */
+
+    RfDfFilen2Real(path2, Fname, MacZip.MacZipMode, MacZip.DataForkOnly,
+                   &MacZip.CurrentFork);
+    GetCompletePath(path, path2, &MacZip.fileSpec, &err);
+    err = PrintUserHFSerr((err != -43) && (err != 0), err, path);
+    printerr("GetCompletePath:", err, err, __LINE__, __FILE__, path);
+
+    if (err != noErr) {
+        errno = err;
+        return -1;
+    }
+
+    /*  Collect here some more information, it's not related to Macstat.
+        (note: filespec gets changed later in this function) */
+    /* clear string-buffer */
+    memset(MacZip.FullPath, 0x00, sizeof(MacZip.FullPath));
+    rc = FSpGetFullPath(&MacZip.fileSpec, &fullPathLength, &hFullPath);
+    strncpy(MacZip.FullPath, *hFullPath, fullPathLength);
+    DisposeHandle(hFullPath);   /* we don't need it any more */
+    /*  Collect some more information not related to Macstat */
+
+
+    /*
+     * Fill the fpb & vpb struct up with info about file or directory.
+     */
+
+    FSpGetDirectoryID(&MacZip.fileSpec, &MacZip.dirID, &MacZip.isDirectory);
+    vpb.ioVRefNum = MacZip.fpb.hFileInfo.ioVRefNum =  MacZip.fileSpec.vRefNum;
+    vpb.ioNamePtr = MacZip.fpb.hFileInfo.ioNamePtr =  MacZip.fileSpec.name;
+
+    if (MacZip.isDirectory) {
+        MacZip.fpb.hFileInfo.ioDirID =  MacZip.fileSpec.parID;
+        /*
+         * Directories are executable by everyone.
+         */
+        buf->st_mode |= UNX_IXUSR | UNX_IXGRP | UNX_IXOTH | UNX_IFDIR;
+    } else {
+        MacZip.fpb.hFileInfo.ioDirID = MacZip.dirID;
+    }
+
+    MacZip.fpb.hFileInfo.ioFDirIndex = 0;
+    err = PBGetCatInfoSync((CInfoPBPtr)&MacZip.fpb);
+
+    if (err == noErr) {
+        vpb.ioVolIndex = 0;
+        err = PBHGetVInfoSync((HParmBlkPtr)&vpb);
+        if (err == noErr && buf != NULL) {
+            /*
+             * Files are always readable by everyone.
+             */
+            buf->st_mode |= UNX_IRUSR | UNX_IRGRP | UNX_IROTH;
+
+            /*
+             * Use the Volume Info & File Info to fill out stat buf.
+             */
+            if (MacZip.fpb.hFileInfo.ioFlAttrib & 0x10) {
+                buf->st_mode |= UNX_IFDIR;
+                buf->st_nlink = 2;
+            } else {
+                buf->st_nlink = 1;
+                if (MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000) {
+                    buf->st_mode |= UNX_IFLNK;
+                } else {
+                    buf->st_mode |= UNX_IFREG;
+                }
+            }
+
+            if (MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType == 'APPL') {
+                /*
+                 * Applications are executable by everyone.
+                 */
+                buf->st_mode |= UNX_IXUSR | UNX_IXGRP | UNX_IXOTH;
+            }
+            if ((MacZip.fpb.hFileInfo.ioFlAttrib & 0x01) == 0){
+                /*
+                 * If not locked, then everyone has write acces.
+                 */
+                buf->st_mode |= UNX_IWUSR | UNX_IWGRP | UNX_IWOTH;
+            }
+
+            buf->st_ino = MacZip.fpb.hFileInfo.ioDirID;
+            buf->st_dev = MacZip.fpb.hFileInfo.ioVRefNum;
+            buf->st_uid = -1;
+            buf->st_gid = -1;
+            buf->st_rdev = 0;
+
+            if (MacZip.CurrentFork == ResourceFork)
+                buf->st_size = MacZip.fpb.hFileInfo.ioFlRLgLen;
+            else
+                buf->st_size = MacZip.fpb.hFileInfo.ioFlLgLen;
+
+            buf->st_blksize = vpb.ioVAlBlkSiz;
+            buf->st_blocks = (buf->st_size + buf->st_blksize - 1)
+                            / buf->st_blksize;
+
+            /*
+             * The times returned by the Mac file system are in the
+             * local time zone.  We convert them to GMT so that the
+             * epoch starts from GMT.  This is also consistent with
+             * what is returned from "clock seconds".
+             */
+            if (!MacZip.isDirectory) {
+                MacZip.CreatDate  = MacZip.fpb.hFileInfo.ioFlCrDat;
+                MacZip.ModDate    = MacZip.fpb.hFileInfo.ioFlMdDat;
+                MacZip.BackDate   = MacZip.fpb.hFileInfo.ioFlBkDat;
+            } else {
+                MacZip.CreatDate  = MacZip.fpb.dirInfo.ioDrCrDat;
+                MacZip.ModDate    = MacZip.fpb.dirInfo.ioDrMdDat;
+                MacZip.BackDate   = MacZip.fpb.dirInfo.ioDrBkDat;
+            }
+
+#ifdef IZ_CHECK_TZ
+            if (!zp_tz_is_valid)
+            {
+                MacZip.HaveGMToffset = false;
+                MacZip.Md_UTCoffs = 0L;
+                MacZip.Cr_UTCoffs = 0L;
+                MacZip.Bk_UTCoffs = 0L;
+            }
+            else
+#endif
+            {
+                /* Do not use GMT offsets when Md_UTCoffs calculation
+                 * fails, since this time stamp is used for time
+                 * comparisons in Zip and UnZip operations.
+                 * We do not bother when GMT offset calculation fails for
+                 * any other time stamp value. Instead we simply assume
+                 * a default value of 0.
+                 */
+                MacZip.HaveGMToffset =
+                    GetGMToffsetMac(MacZip.ModDate, &MacZip.Md_UTCoffs);
+                if (MacZip.HaveGMToffset) {
+                    GetGMToffsetMac(MacZip.CreatDate, &MacZip.Cr_UTCoffs);
+                    GetGMToffsetMac(MacZip.BackDate, &MacZip.Bk_UTCoffs);
+                } else {
+                    MacZip.Cr_UTCoffs = 0L;
+                    MacZip.Bk_UTCoffs = 0L;
+                }
+            }
+#ifdef DEBUG_TIME
+            {
+            printf("\nZmacstat:  MacZip.HaveGMToffset: %d",
+               MacZip.HaveGMToffset);
+            printf("\nZmacstat:  Mac modif: %lu local -> UTOffset: %d",
+              MacZip.ModDate, MacZip.Md_UTCoffs);
+            printf("\nZmacstat:  Mac creat: %lu local -> UTOffset: %d",
+              MacZip.CreatDate, MacZip.Cr_UTCoffs);
+            printf("\nZmacstat:  Mac  back: %lu local -> UTOffset: %d",
+              MacZip.BackDate, MacZip.Bk_UTCoffs);
+            }
+#endif /* DEBUG_TIME */
+
+
+            buf->st_mtime = MacFtime2UnixFtime(MacZip.ModDate);
+            buf->st_ctime = MacFtime2UnixFtime(MacZip.CreatDate);
+            buf->st_atime = buf->st_mtime;
+
+#ifdef DEBUG_TIME
+            {
+            printf("\nZmacstat:  Unix modif: %lu UTC; Mac: %lu local",
+              buf->st_mtime, MacZip.ModDate);
+            printf("\nZmacstat:  Unix creat: %lu UTC; Mac: %lu local\n",
+              buf->st_ctime, MacZip.CreatDate);
+            }
+#endif /* DEBUG_TIME */
+
+            if (noisy)
+            {
+                if (MacZip.StatingProgress)
+                {
+                    count_of_files++;
+                    InformProgress(MacZip.RawCountOfItems, count_of_files );
+                }
+                else
+                    count_of_files = 0;
+            }
+        }
+    }
+
+    if (err != noErr) {
+        errno = err;
+    }
+
+    MacZip.isMacStatValid = true;
+    return (err == noErr ? 0 : -1);
+}
+
+
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * chmod --
+ *
+ * Results:
+ *  See chmod documentation.
+ *
+ * Side effects:
+ *  See chmod documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int chmod(char *path, int mode)
+{
+    HParamBlockRec hpb;
+    OSErr err;
+
+    hpb.fileParam.ioNamePtr = C2PStr(path);
+    hpb.fileParam.ioVRefNum = 0;
+    hpb.fileParam.ioDirID = 0;
+
+    if (mode & 0200) {
+        err = PBHRstFLockSync(&hpb);
+    } else {
+        err = PBHSetFLockSync(&hpb);
+    }
+
+    if (err != noErr) {
+        errno = err;
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/macos/source/unixlike.h b/macos/source/unixlike.h
new file mode 100644 (file)
index 0000000..e61a354
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ *      Directory Operations for Mac based on BSD 4.3   <macdir.h>
+ *      By Jason Linhart, January 1997
+ */
+
+#ifndef _UNIXLIKE_H
+#define _UNIXLIKE_H       1
+
+#include <stat.h>
+
+#ifndef NAME_MAX
+#define NAME_MAX    2048
+#endif
+
+#define UNX_IFMT        0170000     /* Unix file type mask */
+#define UNX_IFSOCK      0140000     /* Unix socket (BSD, not SysV or Amiga) */
+#define UNX_IFLNK       0120000     /* Unix symbolic link (not SysV, Amiga) */
+#define UNX_IFREG       0100000     /* Unix regular file */
+#define UNX_IFBLK       0060000     /* Unix block special       (not Amiga) */
+#define UNX_IFDIR       0040000     /* Unix directory */
+#define UNX_IFCHR       0020000     /* Unix character special   (not Amiga) */
+#define UNX_IFIFO       0010000     /* Unix fifo    (BCC, not MSC or Amiga) */
+
+#define UNX_ISUID       04000       /* Unix set user id on execution */
+#define UNX_ISGID       02000       /* Unix set group id on execution */
+#define UNX_ISVTX       01000       /* Unix directory permissions control */
+#define UNX_ENFMT       UNX_ISGID   /* Unix record locking enforcement flag */
+
+#define UNX_IRWXU       00700       /* Unix read, write, execute: owner */
+#define UNX_IRUSR       00400       /* Unix read permission: owner */
+#define UNX_IWUSR       00200       /* Unix write permission: owner */
+#define UNX_IXUSR       00100       /* Unix execute permission: owner */
+
+#define UNX_IRWXG       00070       /* Unix read, write, execute: group */
+#define UNX_IRGRP       00040       /* Unix read permission: group */
+#define UNX_IWGRP       00020       /* Unix write permission: group */
+#define UNX_IXGRP       00010       /* Unix execute permission: group */
+
+#define UNX_IRWXO       00007       /* Unix read, write, execute: other */
+#define UNX_IROTH       00004       /* Unix read permission: other */
+#define UNX_IWOTH       00002       /* Unix write permission: other */
+#define UNX_IXOTH       00001       /* Unix execute permission: other */
+
+/* historical file modes */
+#define S_IREAD    0x100
+#define S_IWRITE   0x80
+#define S_IEXEC    0x40
+
+
+#define isatty(arg) 1
+
+
+#define EINVAL          22      /* Invalid argument */
+#define ENAMETOOLONG    63      /* File name too long */
+
+
+struct dirent {
+        char            d_name[NAME_MAX];
+};
+
+/*
+ * The following definitions are usually found in fcntl.h.
+ * However, MetroWerks has screwed that file up a couple of times
+ * and all we need are the defines.
+ */
+#define O_APPEND  0x0100    /* open the file in append mode */
+#define O_CREAT   0x0200    /* create the file if it doesn't exist */
+#define O_EXCL    0x0400    /* if the file exists don't create it again */
+#define O_TRUNC   0x0800    /* truncate the file after opening it */
+
+
+int Zmacstat (const char *path, struct stat *buf);
+int chmod(char *path, int mode);
+
+
+#include "macstuff.h"
+
+#endif /* _UNIXLIKE_H  */
diff --git a/macos/source/zip_rc.hqx b/macos/source/zip_rc.hqx
new file mode 100644 (file)
index 0000000..99e0d25
--- /dev/null
@@ -0,0 +1,43 @@
+(This file must be converted with BinHex 4.0)
+:#RTTF#jbBbjcDA3!8dP84&0*9#%!N!3([`#3"&(E8dP8)3!"!!!([h*-BA8#Q3#
+3!aDCQ3d!"RTTF#jbB`!!&[Bi"2[rG!"-5QS!N!1!!*!%"32,j+m2!*!Drj!%8P0
+53e*6483"",#mXHDaqlGG!!!GmJ#3"JFj!*!%6Mi!N!MGc!`!P@6pq1R*k4&+Z,d
+p"5$(b(-Upcc#j%EiHCfjPTq%8h+X8d)MR$`rF[b9Vh`pTLc2jqZ9r'RNq9VN1'&
+'MMmj6Sk6#5HFc0J4lN8iHFU2--,*K%Z1NIR+#1XNR("#bE-)2I+FF$*G@H6BL+`
+*!&6IV1ml1d+22#-$4UEm*#01"T`m*4`Ji(03ThM'$-EBilf-V8-e6Q8bXEVD@Xi
+2bilcmGEY"lV6QGjZrK)I1CKZ$BfR4pSbLD'f`F'qVPKb+*(-*V2CPLfaGj1CE+a
+Z+-$kpr4hpHrCf@d%f66E!A2P-rA6phmUj)QrdYP4r[6)H+cZF"hRV``NHSG5`b!
+F6-0YBZ$!JH&%#frIb,2TmH4`LVGN4c1(%U1Q8#cf)P44dU"#-`D)I($H4I5qc[j
+NJLI5)qpN5)Ic[S(-`-&1H(U2L*U'-H`1Y1p&qc#*YVk4(RNUbp(ae(#'R,B[d%B
+(Nd40$id1C`FhmUlKNBmbkAf$Sra8qpDYcm0,H%GIhbiej(!EESbmC+a*'3dqdlC
+j)%*H#+!,D!K4#J#3!$9H-J)mB*6L!50R"%"&hi6DD*61[-qq22%f1hkXPq@r)'`
+(1hjQJ19cKP'bY0#60RQ3!&kd,r))mj-X,LBCCa&CeiX#f`ibZ$9##+[1HUJ34G5
+584+#&@p9i[UDj-&PD2rAi0qYdMpMQ""M8FLBT`#FUMje-i6rVXl2qI`jK@XY#eH
++%JH[5(`6,qEcH@K,(FfA4rZDNG,4mp60fALH@TT,SC!!5Sf0$HHP31&mP"AfKN)
+K-!N[&XjM@##`1I,(a"V"#L%@#U9'*'lT-5CaU8GqpLTFkUP"%klmfMLJ1QpH5r2
+djNdfhIXJFIqqN!!&1QHe$jUlHF`jZ2I41X8k$@ZbKF1C2"Cq6YZaF(Z+5Yra&63
+"alCh62Vm6N(RqR90&)#m`cE3mILqV`@qBmcQkf0"9Ei%#**RRRpcS0DmV!N6DB-
+&#R112Ym4-1d)GJ(R0,i,0!TEJ!%$#Mj$SFqp80)XU4&"+j!!DmFJk)S2*[(KNMR
+mHApd)4Im@I2aqEBrpd,EVi3ehd@qETI[eprhmmlp0UGjqhe`q#[[Ljk#GDclAll
+[P91j$d[[ir`4X1LcbmVcI$8cCd49rY*`E2l+F1l-Uk0CV,edY8%d('d@pD*qVRk
+L@64FE9KlU9Q%E`3$i@+cD"BSp)'26f,8K%[iL[#3!$-h&aDPY5L2CJBBpF5Kh5k
++ASJVqckQ9kG`*C95rEka+29B5U+f"eYIqF&ZC()P-%GbHXQ44)a!l[Z9q3[c5Z!
+aN!!pGHT"X#q,IJ$8lG#i224dkNXMhd,#3I"ap4JkEk@YlrKEp1r14erRqIYVJY@
+RbX4G0GVTc4A5A20`[E`GcX60GGI#0@$KHMqfFB9BIV4&%kr6+kH*J`(FR3lKcJj
+pNqpN!JiZ-`'&1jQ!a*e-31RCQB$%R8c!dY1CJ19(C`+@AjGIa[qCCq8qH,K8FA%
+LH$LpGbZiFpp0ehUR[lZTL-[HU3T8q*FVkd5&AaDBjrX##ha2S$UImK6,r-Z9MDM
+#PaVqNfUH+VqmXplAGpG!G`k,I&I!i[ZC`J,Iba3@rEQC`J,Iba5@rFQGIhNq5h`
+r-lM2ArAJIYjp(jEjYX!5he+i`cIhZRrjYq)%rjNh@"K4Ej!!V8&p!,8@0C*$l3L
+bk#`f"%i9DMaRk,i*YC&aj0dFH6G(hXf4Gh2Nh4ajYp5aY(5[I@a#hBBDeh9E'*X
+Kq3q,)QS*99$0SCj&R68Va[9Ie6lJ9444KDk%dDE9%CrPQhJ,hbD#)RJ8936RJK1
+bjb%HMTILXr&#r&Um++SIZ#*1fAP1hM-c'CG*VekG*BkGApkj'DZA13GkPA1JPcN
+(iC4c%*m@1&[2l0@LLCK%pFUBG%kj4M@2,@pY&UjA+*Y2#Zil5%pF&GI[LBAVh-2
+$3I"aCG,5ekC[qL[MlZ1QRP32Ga5YQFY`Cf-[rZ!JX+GrCir-1R)J6J!jdY[ekRU
+IXFT6',*jNmH[B69Hq&&6$N-NlS3K8Xm03mM2+VTKb253!iSqNDRHIKqNq$hqV6$
+%pVF8KPMc@68N$0Q#[KXH1UJL$1P'',*PpB``C"5M'eXG)JbTfDal(BB!AfdN$-'
+cjq2P-%6bli8Kq,pej"NCErJr%NGk[[Pkpa44M+pBl4Mq$SC![ij'pZ[3j20d)N[
+i$qR%J5hSI`01r3hJcl+!m54`kMY9f'+N1PrYaRqe4SCq@E8Hr)$%dK,,5@`LdR2
+b$cBKPr+"5-q*AH`)BBm-4AUqlG-DHk"a9QQ`Yi"0+Beefb-pTlj6'Z(2`,ZS0"j
++!KY9'SpQ-0f,5U2Q'(Lr+Sd(h`3fV65DpX2VT0+)[!EHKdUMS4ABTdVMX4IJG8T
+T'*pJ6K'P8IXk0+iTMFB8I'L[i9r!Qp6c`!dlH9,2idGJTp9PD'b(MjH9AZ0cQ02
+TqYdI$#8c2*2-$Kr+**,r!`#3!dm4!!!:
diff --git a/macos/zipup.h b/macos/zipup.h
new file mode 100644 (file)
index 0000000..ce2af4a
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+#  include <fcntl.h>
+#endif
+
+#define fhow            (O_RDONLY|O_BINARY)
+#define fbad            (-1)
+
+typedef int ftype;
+
+
+#define zopen(n,p)      MacOpen(n,p)
+#define zread(f,b,n)    read(f,b,n)
+#define zclose(f)       close(f)
+#define zerr(f)         (k == (extent)(-1L))
+#define zstdin          0
+
+
diff --git a/man/zip.1 b/man/zip.1
new file mode 100644 (file)
index 0000000..0c2fce0
--- /dev/null
+++ b/man/zip.1
@@ -0,0 +1,2840 @@
+.\" =========================================================================
+.\" Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+.\"
+.\" See the accompanying file LICENSE, version 2007-Mar-4 or later
+.\" (the contents of which are also included in zip.h) for terms of use.
+.\" If, for some reason, all these files are missing, the Info-ZIP license
+.\" also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+.\" ==========================================================================
+.\"
+.\" zip.1 by Mark Adler, Jean-loup Gailly and  R. P. C. Rodgers
+.\" updated by E. Gordon for Zip 3.0 (8 May 2005, 24 December 2006,
+.\" 4 February 2007, 27 May 2007, 4 June 2007 by EG; 12 June 2007 by CS;
+.\" 30 August 2007, 27 April 2008, 25 May 2008, 27 May 2008 by EG,
+.\" 7 June 2008 by SMS and EG; 12 June 2008 by EG)
+.\"
+.TH ZIP 1L "16 June 2008 (v3.0)" Info-ZIP
+.SH NAME
+zip \- package and compress (archive) files
+.SH SYNOPSIS
+.B zip
+.RB [\- aABcdDeEfFghjklLmoqrRSTuvVwXyz!@$ ]
+[\-\-longoption ...]
+.RB [\- b " path]"
+.RB [\- n " suffixes]"
+.RB [\- t " date]"
+.RB [\- tt " date]"
+[\fIzipfile\fR [\fIfile\fR \.\|.\|.]]
+[\fB-xi\fR list]
+.PP
+.B zipcloak
+(see separate man page)
+.PP
+.B zipnote
+(see separate man page)
+.PP
+.B zipsplit
+(see separate man page)
+.PP
+Note:  Command line processing in
+.I zip
+has been changed to support long options and handle all
+options and arguments more consistently.  Some old command
+lines that depend on command line inconsistencies may no longer
+work.
+.SH DESCRIPTION
+.I zip
+is a compression and file packaging utility for Unix, VMS, MSDOS,
+OS/2, Windows 9x/NT/XP, Minix, Atari, Macintosh, Amiga, and Acorn
+RISC OS.  It is analogous to a combination of the Unix commands
+.IR tar (1)
+and
+.IR compress (1)
+and is compatible with PKZIP (Phil Katz's ZIP for MSDOS systems).
+.LP
+A companion program
+.RI ( unzip (1L))
+unpacks
+.I zip
+archives.
+The
+.I zip
+and
+.IR unzip (1L)
+programs can work with archives produced by PKZIP (supporting
+most PKZIP features up to PKZIP version 4.6),
+and PKZIP and PKUNZIP can work with archives produced by
+\fIzip\fP (with some exceptions, notably streamed archives,
+but recent changes in the zip file standard may facilitate
+better compatibility).
+.I zip
+version 3.0 is compatible with PKZIP 2.04 and also supports
+the Zip64 extensions of PKZIP 4.5 which allow archives
+as well as files to exceed the previous 2 GB limit (4 GB in
+some cases).  \fIzip\fP also now supports \fBbzip2\fP compression
+if the \fBbzip2\fP library is included when \fIzip\fP is compiled.
+Note that PKUNZIP 1.10 cannot extract files produced by
+PKZIP 2.04 or
+\fIzip\ 3.0\fP. You must use PKUNZIP 2.04g or
+\fIunzip\ 5.0p1\fP (or later versions) to extract them.
+.PP
+See the \fBEXAMPLES\fP section at the bottom of this page
+for examples of some typical uses of \fIzip\fP.
+.PP
+\fBLarge\ Archives\ and\ Zip64.\fP
+.I zip
+automatically uses the Zip64 extensions when files larger than 4 GB are
+added to an archive, an archive containing Zip64 entries is updated
+(if the resulting archive still needs Zip64),
+the size of the archive will exceed 4 GB, or when the
+number of entries in the archive will exceed about 64K.
+Zip64 is also used for archives streamed from standard input as the size
+of such archives are not known in advance, but the option \fB\-fz\-\fP can
+be used to force \fIzip\fP to create PKZIP 2 compatible archives (as long
+as Zip64 extensions are not needed).  You must use a PKZIP 4.5
+compatible unzip, such as \fIunzip\ 6.0\fP or later, to extract files
+using the Zip64 extensions.
+.PP
+In addition, streamed archives, entries encrypted with standard encryption,
+or split archives created with the pause option may not be compatible with
+PKZIP as data descriptors are used
+and PKZIP at the time of this writing does not support data descriptors
+(but recent changes in the PKWare published zip standard now include some
+support for the data descriptor format \fIzip\fP uses).
+
+.PP
+\fBMac OS X.\fP  Though previous Mac versions had their own \fIzip\fP port,
+\fIzip\fP supports Mac OS X as part of the Unix port and most Unix features
+apply.  References to "MacOS" below generally refer to MacOS versions older
+than OS X.  Support for some Mac OS features in the Unix Mac OS X port, such
+as resource forks, is expected in the next \fIzip\fP release.
+
+.PP
+For a brief help on \fIzip\fP and \fIunzip\fP,
+run each without specifying any parameters on the command line.
+
+.SH "USE"
+.PP
+The program is useful for packaging a set of files for distribution;
+for archiving files;
+and for saving disk space by temporarily
+compressing unused files or directories.
+.LP
+The
+.I zip
+program puts one or more compressed files into a single
+.I zip
+archive,
+along with information about the files
+(name, path, date, time of last modification, protection,
+and check information to verify file integrity).
+An entire directory structure can be packed into a
+.I zip
+archive with a single command.
+Compression ratios of 2:1 to 3:1 are common for text files.
+.I zip
+has one compression method (deflation) and can also store files without
+compression.  (If \fBbzip2\fP support is added, \fIzip\fP can also
+compress using \fBbzip2\fP compression, but such entries require a
+reasonably modern unzip to decompress.  When \fBbzip2\fP compression
+is selected, it replaces deflation as the default method.)
+.I zip
+automatically chooses the better of the two (deflation or store or, if
+\fBbzip2\fP is selected, \fBbzip2\fP or store) for each file to be
+compressed.
+.LP
+\fBCommand\ format.\fP  The basic command format is
+.IP
+\fBzip\fR options archive inpath inpath ...
+.LP
+where \fBarchive\fR is a new or existing \fIzip\fR archive
+and \fBinpath\fR is a directory or file path optionally including wildcards.
+When given the name of an existing
+.I zip
+archive,
+.I zip
+will replace identically named entries in the
+.I zip
+archive (matching the relative names as stored in
+the archive) or add entries for new names.
+For example,
+if
+.I foo.zip
+exists and contains
+.I foo/file1
+and
+.IR foo/file2 ,
+and the directory
+.I foo
+contains the files
+.I foo/file1
+and
+.IR foo/file3 ,
+then:
+.IP
+\fCzip -r foo.zip foo\fP
+.LP
+or more concisely
+.IP
+\fCzip -r foo foo\fP
+.LP
+will replace
+.I foo/file1
+in
+.I foo.zip
+and add
+.I foo/file3
+to
+.IR foo.zip .
+After this,
+.I foo.zip
+contains
+.IR foo/file1 ,
+.IR foo/file2 ,
+and
+.IR foo/file3 ,
+with
+.I foo/file2
+unchanged from before.
+.LP
+So if before the zip command is executed \fIfoo.zip\fP has:
+.IP
+\fC foo/file1 foo/file2
+.LP
+and directory foo has:
+.IP
+\fC file1 file3\fP
+.LP
+then \fIfoo.zip\fP will have:
+.IP
+\fC foo/file1 foo/file2 foo/file3\fP
+.LP
+where \fIfoo/file1\fP is replaced and
+\fIfoo/file3\fP is new.
+.LP
+\fB\-@\ file\ lists.\fP  If a file list is specified as
+\fB\-@\fP
+[Not on MacOS],
+.I zip
+takes the list of input files from standard input instead of from
+the command line.  For example,
+.IP
+\fCzip -@ foo\fP
+.LP
+will store the files listed one per line on stdin in \fIfoo.zip\fP.
+.LP
+Under Unix,
+this option can be used to powerful effect in conjunction with the
+\fIfind\fP\ (1)
+command.
+For example,
+to archive all the C source files in the current directory and
+its subdirectories:
+.IP
+\fCfind . -name "*.[ch]" -print | zip source -@\fP
+.LP
+(note that the pattern must be quoted to keep the shell from expanding it).
+.LP
+\fBStreaming\ input\ and\ output.\fP
+.I zip
+will also accept a single dash ("-") as the zip file name, in which case it
+will write the zip file to standard output, allowing the output to be piped
+to another program. For example:
+.IP
+\fCzip -r - . | dd of=/dev/nrst0 obs=16k\fP
+.LP
+would write the zip output directly to a tape with the specified block size
+for the purpose of backing up the current directory.
+.LP
+.I zip
+also accepts a single dash ("-") as the name of a file to be compressed, in
+which case it will read the file from standard input, allowing zip to take
+input from another program. For example:
+.IP
+\fCtar cf - . | zip backup -\fP
+.LP
+would compress the output of the tar command for the purpose of backing up
+the current directory. This generally produces better compression than
+the previous example using the -r option because
+.I zip
+can take advantage of redundancy between files. The backup can be restored
+using the command
+.IP
+\fCunzip -p backup | tar xf -\fP
+.LP
+When no zip file name is given and stdout is not a terminal,
+.I zip
+acts as a filter, compressing standard input to standard output.
+For example,
+.IP
+\fCtar cf - . | zip | dd of=/dev/nrst0 obs=16k\fP
+.LP
+is equivalent to
+.IP
+\fCtar cf - . | zip - - | dd of=/dev/nrst0 obs=16k\fP
+.LP
+.I zip
+archives created in this manner can be extracted with the program
+.I funzip
+which is provided in the
+.I unzip
+package, or by
+.I gunzip
+which is provided in the
+.I gzip
+package (but some
+.I gunzip
+may not support this if
+.I zip
+used the Zip64 extensions). For example:
+.IP
+\fPdd if=/dev/nrst0  ibs=16k | funzip | tar xvf -\fC
+.LP
+The stream can also be saved to a file and
+.I unzip
+used.
+.LP
+If Zip64 support for large files and archives is enabled and
+\fIzip\fR is used as a filter, \fIzip\fR creates a Zip64 archive
+that requires a PKZIP 4.5 or later compatible unzip to read it.  This is
+to avoid amgibuities in the zip file structure as defined in the current
+zip standard (PKWARE AppNote) where the decision to use Zip64 needs to
+be made before data is written for the entry, but for a stream the size
+of the data is not known at that point.  If the data is known to be smaller
+than 4 GB, the option \fB\-fz\-\fP can be used to prevent use of Zip64,
+but \fIzip\fP will exit with an error if Zip64 was in fact needed.
+\fIzip\ 3\fR and \fIunzip\ 6\fR and later can read archives with Zip64
+entries.  Also, \fIzip\fP removes the Zip64 extensions if not needed
+when archive entries are copied (see the \fB\-U\fP (\fB\-\-copy\fP)
+option).
+.LP
+When directing the output to another file, note that all options should be
+before the redirection including \fB-x\fP.  For example:
+.IP
+\fPzip archive "*.h" "*.c" -x donotinclude.h orthis.h > tofile\fC
+.LP
+\fBZip\ files.\fP  When changing an existing
+.I zip
+archive,
+.I zip
+will write a temporary file with the new contents,
+and only replace the old one when the process of creating the new version
+has been completed without error.
+.LP
+If the name of the
+.I zip
+archive does not contain an extension, the extension
+\fB.zip\fP
+is added. If the name already contains an extension other than
+\fB.zip\fP,
+the existing extension is kept unchanged.  However, split archives
+(archives split over multiple files) require the \fB.zip\fP extension
+on the last split.
+.PP
+\fBScanning\ and\ reading\ files.\fP
+When \fIzip\fP starts, it scans for files to process (if needed).  If
+this scan takes longer than about 5 seconds, \fIzip\fP will display
+a "Scanning files" message and start displaying progress dots every 2 seconds
+or every so many entries processed, whichever takes longer.  If there is more
+than 2 seconds between dots it could indicate that finding each file is taking
+time and could mean a slow network connection for example.
+(Actually the initial file scan is
+a two-step process where the directory scan is followed by a sort and these
+two steps are separated with a space in the dots.  If updating an existing
+archive, a space also appears between the existing file scan and the new
+file scan.)  The scanning files dots are not controlled by the \fB\-ds\fP
+dot size option, but the dots are turned off by the \fB\-q\fP quiet option.  The
+\fB\-sf\fP show files option can be used to scan for files and get the list of
+files scanned without actually processing them.
+.LP
+If \fIzip\fR is not able to read a file, it
+issues a warning but
+continues.  See the \fB\-MM\fP option below for more on how \fIzip\fP handles
+patterns that are not matched and files that are not readable.
+If some files were skipped, a
+warning is issued at the end of the zip operation noting how many files
+were read and how many skipped.
+.PP
+\fBCommand\ modes.\fP  \fIzip\fP now supports two distinct types of command
+modes, \fBexternal\fP and \fBinternal\fP.  The \fBexternal\fP modes
+(add, update, and freshen) read files from the file system (as well as from an
+existing archive) while the \fBinternal\fP modes (delete and copy) operate
+exclusively on entries in an existing archive.
+.LP
+.TP
+.BI add\ \ \ \ \ \ 
+Update existing entries and add new files.  If the archive does not exist
+create it.  This is the default mode.
+.TP
+.BI update\ \fP(\fB\-u\fP)
+Update existing entries if newer on the file system and add new files.  If
+the archive does not exist issue warning then create a new archive.
+.TP
+.BI freshen\ \fP(\fB\-f\fP)
+Update existing entries of an archive if newer on the file system.
+Does not add new files to the archive.
+.TP
+.BI delete\ \fP(\fB\-d\fP)
+Select entries in an existing archive and delete them.
+.TP
+.BI copy\ \fP(\fB\-U\fP)
+Select entries in an existing archive and copy them to a new archive.
+This new mode is similar to \fBupdate\fP but command line patterns
+select entries in the existing archive rather than files from
+the file system and it uses the \fB\-\-out\fP option to write the
+resulting archive to a new file rather than update the existing
+archive, leaving the original archive unchanged.
+.LP
+The new File Sync option (\fB\-FS\fP) is also considered a new mode,
+though it is similar to \fBupdate\fP.  This mode synchronizes the
+archive with the files on the OS, only replacing files in the
+archive if the file time or size of the OS file is different, adding
+new files, and deleting entries from the archive where there is
+no matching file.  As this mode can delete entries from the archive,
+consider making a backup copy of the archive.
+
+Also see \fB\-DF\fP for creating difference archives.
+
+See each option description below for details and the \fBEXAMPLES\fP section
+below for examples.
+.PP
+\fBSplit\ archives.\fP  \fIzip\fP version 3.0 and later can create split
+archives.  A
+\fBsplit archive\fP is a standard zip archive split over multiple
+files.  (Note that split archives are not just archives split in to
+pieces, as the offsets of entries are now based on the start of each
+split.  Concatenating the pieces together will invalidate these offsets,
+but \fIunzip\fP can usually deal with it.  \fIzip\fP will usually refuse
+to process such a spliced archive unless the \fB\-FF\fP fix option is
+used to fix the offsets.)
+.LP
+One use of split archives is storing a large archive on multiple
+removable media.
+For a split archive with 20 split files the files are typically named (replace
+ARCHIVE with the name of your archive) ARCHIVE.z01, ARCHIVE.z02, ..., ARCHIVE.z19,
+ARCHIVE.zip.  Note that the last file is the \fB.zip\fP file.  In contrast,
+\fBspanned archives\fP are the original multi-disk archive generally requiring
+floppy disks and using volume labels to store disk numbers.  \fIzip\fP supports
+split archives but not spanned archives, though a procedure exists for converting
+split archives of the right size to spanned archives.  The reverse is also true,
+where each file of a spanned archive can be copied in order to files with the
+above names to create a split archive.
+.LP
+Use \fB\-s\fP to set the split size and create a split archive.  The size is
+given as a number followed optionally by one of k (kB), m (MB), g (GB), or t (TB)
+(the default is m).  The \fB\-sp\fP option can be used to pause \fIzip\fP between
+splits to allow changing removable media, for example, but read the descriptions
+and warnings for both \fB\-s\fP and \fB\-sp\fP below.
+.LP
+Though \fIzip\fP does not update split archives, \fIzip\fP provides the new
+option \fB\-O\fP (\fB\-\-output\-file\fP or \fB\-\-out\fP) to allow split archives
+to be updated and saved in a new archive.  For example,
+.IP
+\fCzip inarchive.zip foo.c bar.c \-\-out outarchive.zip\fP
+.LP
+reads archive \fBinarchive.zip\fP, even if split, adds the files \fBfoo.c\fP and
+\fBbar.c\fP, and writes the resulting archive to \fBoutarchive.zip\fP.  If
+\fBinarchive.zip\fP is split then \fBoutarchive.zip\fP defaults to the same
+split size.  Be aware that if \fBoutarchive.zip\fP and any split files that are
+created with it already exist, these are always overwritten as needed without
+warning.  This may be changed in the future.
+.PP
+\fBUnicode.\fP  Though the zip standard requires storing paths in an archive using
+a specific character set, in practice zips have stored paths in archives in whatever
+the local character set is.  This creates problems when an archive is created or
+updated on a system using one character set and then extracted on another system
+using a different character set.  When compiled with Unicode support enabled on
+platforms that support wide characters, \fIzip\fP now stores, in addition to the
+standard local path for backward compatibility, the UTF-8 translation of the path.
+This provides a common universal character set for storing paths that allows these
+paths to be fully extracted on other systems that support Unicode and to match as
+close as possible on systems that don't.
+
+On Win32 systems where paths are internally stored as Unicode but represented in
+the local character set, it's possible that some paths will be skipped during a
+local character set directory scan.  \fIzip\fP with Unicode support now can read
+and store these paths.  Note that Win 9x systems and FAT file systems don't fully
+support Unicode.
+
+Be aware that console windows on Win32 and Unix, for example, sometimes don't
+accurately show all characters due to how each operating system switches in
+character sets for display.  However, directory navigation tools should show the
+correct paths if the needed fonts are loaded.
+.PP
+\fBCommand line format.\fP  This version of
+.I zip
+has updated command line processing and support for long options.
+.PP
+Short options take the form
+.IP
+\fC-s[-][s[-]...][value][=value][\ value]\fP
+.LP
+where s is a one or two character short option.  A short option
+that takes a value is last in an argument and anything after it is
+taken as the value.  If the option can be negated and "-" immediately
+follows the option, the option is negated.
+Short options can also be given as separate arguments
+.IP
+\fC-s[-][value][=value][\ value]\ -s[-][value][=value][\ value]\ ...\fP
+.LP
+Short options in general take values either as part of the same
+argument or as the following argument.  An optional = is also supported.
+So
+.IP
+\fC-ttmmddyyyy\fP
+.LP
+and
+.IP
+\fC-tt=mmddyyyy\fP
+.LP
+and
+.IP
+\fC-tt mmddyyyy\fP
+.LP
+all work.  The \fB\-x\fP and \fB\-i\fP options accept lists of values
+and use a slightly different format described below.  See the
+\fB\-x\fP and \fB\-i\fP options.
+.PP
+Long options take the form
+.IP
+\fC--longoption[-][=value][ value]\fP
+.LP
+where the option starts with --, has a multicharacter name, can
+include a trailing dash to negate the option (if the option
+supports it), and can have a value (option argument) specified by
+preceeding it with = (no spaces).  Values can also follow the
+argument.  So
+.IP
+\fC--before-date=mmddyyyy\fP
+.LP
+and
+.IP
+\fC--before-date mmddyyyy\fP
+.LP
+both work.
+
+Long option names can be shortened to the shortest unique
+abbreviation.  See the option descriptions below for which
+support long options.  To avoid confusion, avoid abbreviating
+a negatable option with an embedded dash ("-") at the dash
+if you plan to negate it (the parser would consider
+a trailing dash, such as for the option \fB\-\-some\-option\fP using
+\fB\-\-some\-\fP as the option, as part of the name rather
+than a negating dash).  This may be changed to force the last
+dash in \fB\-\-some\-\fP to be negating in the future.
+.SH "OPTIONS"
+.TP
+.PD 0
+.BI \-a
+.TP
+.PD
+.B \-\-ascii
+[Systems using EBCDIC] Translate file to ASCII format.
+
+.TP
+.PD 0
+.B \-A
+.TP
+.PD
+.B \-\-adjust-sfx
+Adjust self-extracting executable archive.
+A self-extracting executable archive is created by prepending
+the SFX stub to an existing archive. The
+.B \-A
+option tells
+.I zip
+to adjust the entry offsets stored
+in the archive to take into account this "preamble" data.
+.LP
+Note: self-extracting archives for the Amiga are a special case.
+At present, only the Amiga port of \fIzip\fP is capable of adjusting
+or updating these without corrupting them. -J can be used to remove
+the SFX stub if other updates need to be made.
+
+.TP
+.PD 0
+.B \-AC
+.TP
+.PD
+.B \-\-archive-clear
+[WIN32]  Once archive is created (and tested if \fB\-T\fP is used,
+which is recommended), clear the archive bits of files processed.  WARNING:
+Once the bits are cleared they are cleared.  You may want to use the
+\fB\-sf\fP show files option to store the list of files processed in case
+the archive operation must be repeated.  Also consider using
+the \fB\-MM\fP must match option.  Be sure to check out \fB\-DF\fP as a
+possibly better way to do incremental backups.
+
+.TP
+.PD 0
+.B \-AS
+.TP
+.PD
+.B \-\-archive-set
+[WIN32]  Only include files that have the archive bit set.  Directories
+are not stored when \fB\-AS\fP is used, though by default the paths
+of entries, including directories, are stored as usual and can be used
+by most unzips to recreate directories.
+
+The archive bit is set by the operating system when a file is modified
+and, if used with \fB\-AC\fP, \fB\-AS\fP can provide an
+incremental backup capability.  However, other applications can
+modify the archive bit and it may not be a reliable indicator of
+which files have changed since the last archive operation.  Alternative
+ways to create incremental backups are using \fB\-t\fP to use file dates,
+though this won't catch old files copied to directories being archived,
+and \fB\-DF\fP to create a differential archive.
+
+.TP
+.PD 0
+.B \-B
+.TP
+.PD
+.B \-\-binary
+[VM/CMS and MVS] force file to be read binary (default is text).
+
+.TP
+.B \-B\fRn
+[TANDEM] set Edit/Enscribe formatting options with n defined as
+.RS
+bit  0: Don't add delimiter (Edit/Enscribe)
+.RE
+.RS
+bit  1: Use LF rather than CR/LF as delimiter (Edit/Enscribe)
+.RE
+.RS
+bit  2: Space fill record to maximum record length (Enscribe)
+.RE
+.RS
+bit  3: Trim trailing space (Enscribe)
+.RE
+.RS
+bit  8: Force 30K (Expand) large read for unstructured files
+.RE
+
+.TP
+.PD 0
+.BI \-b\ \fRpath
+.TP
+.PD
+.B \-\-temp-path\ \fRpath
+Use the specified
+.I path
+for the temporary
+.I zip
+archive. For example:
+.RS
+.IP
+\fCzip -b /tmp stuff *\fP
+.RE
+.IP
+will put the temporary
+.I zip
+archive in the directory
+.IR /tmp ,
+copying over
+.I stuff.zip
+to the current directory when done. This option is useful when
+updating an existing archive and the file system containing this
+old archive does not have enough space to hold both old and new archives
+at the same time.  It may also be useful when streaming in some
+cases to avoid the need for data descriptors.  Note that using
+this option may require \fIzip\fP take additional time to copy
+the archive file when done to the destination file system.
+
+.TP
+.PD 0
+.B \-c
+.TP
+.PD
+.B \-\-entry-comments
+Add one-line comments for each file.
+File operations (adding, updating) are done first,
+and the user is then prompted for a one-line comment for each file.
+Enter the comment followed by return, or just return for no comment.
+
+.TP
+.PD 0
+.B \-C
+.TP
+.PD
+.B \-\-preserve-case
+[VMS]  Preserve case all on VMS.  Negating this option
+(\fB\-C-\fP) downcases.
+
+.TP
+.PD 0
+.B \-C2
+.TP
+.PD
+.BI \-\-preserve-case-2
+[VMS]  Preserve case ODS2 on VMS.  Negating this option
+(\fB\-C2-\fP) downcases.
+
+.TP
+.PD 0
+.B \-C5
+.TP
+.PD
+.B \-\-preserve-case-5
+[VMS]  Preserve case ODS5 on VMS.  Negating this option
+(\fB\-C5-\fP) downcases.
+
+.TP
+.PD 0
+.B \-d
+.TP
+.PD
+.B \-\-delete
+Remove (delete) entries from a
+.I zip
+archive.
+For example:
+.RS
+.IP
+\fCzip -d foo foo/tom/junk foo/harry/\\* \\*.o\fP
+.RE
+.IP
+will remove the entry
+.IR foo/tom/junk ,
+all of the files that start with
+.IR foo/harry/ ,
+and all of the files that end with
+.B \&.o
+(in any path).
+Note that shell pathname expansion has been inhibited with backslashes,
+so that
+.I zip
+can see the asterisks,
+enabling
+.I zip
+to match on the contents of the
+.I zip
+archive instead of the contents of the current directory.
+(The backslashes are not used on MSDOS-based platforms.)
+Can also use quotes to escape the asterisks as in
+.RS
+.IP
+\fCzip -d foo foo/tom/junk "foo/harry/*" "*.o"\fP
+.RE
+.IP
+Not escaping the asterisks on a system where the shell expands
+wildcards could result in the asterisks being converted to a
+list of files in the current directory and that list used to
+delete entries from the archive.
+.IP
+Under MSDOS,
+.B \-d
+is case sensitive when it matches names in the
+.I zip
+archive.
+This requires that file names be entered in upper case if they were
+zipped by PKZIP on an MSDOS system.  (We considered making this
+case insensitive on systems where paths were case insensitive,
+but it is possible the archive came from a system where case does
+matter and the archive could include both \fBBar\fP and \fBbar\fP
+as separate files in the archive.)  But see the new option \fB\-ic\fP
+to ignore case in the archive.
+
+.TP
+.PD 0
+.B \-db
+.TP
+.PD
+.B \-\-display-bytes
+Display running byte counts showing the bytes zipped and the bytes to go.
+
+.TP
+.PD 0
+.B \-dc
+.TP
+.PD
+.B \-\-display-counts
+Display running count of entries zipped and entries to go.
+
+.TP
+.PD 0
+.B \-dd
+.TP
+.PD
+.B \-\-display-dots
+Display dots while each entry is zipped (except on ports that have their own
+progress indicator).  See \fB-ds\fR below for setting dot size.  The default is
+a dot every 10 MB of input file processed.  The \fB-v\fR option
+also displays dots (previously at a much higher rate than this but now \fB\-v\fP
+also defaults to 10 MB) and this rate is also controlled by \fB-ds\fR.
+
+.TP
+.PD 0
+.B \-df
+.TP
+.PD
+.B \-\-datafork
+[MacOS] Include only data-fork of files zipped into the archive.
+Good for exporting files to foreign operating-systems.
+Resource-forks will be ignored at all.
+
+.TP
+.PD 0
+.B \-dg
+.TP
+.PD
+.B \-\-display-globaldots
+Display progress dots for the archive instead of for each file.  The command
+.RS
+.IP
+    zip -qdgds 10m
+.RE
+.IP
+will turn off most output except dots every 10 MB.
+
+.TP
+.PD 0
+.B \-ds\ \fRsize
+.TP
+.PD
+.B \-\-dot-size\ \fRsize
+Set amount of input file processed for each dot displayed.  See \fB-dd\fR to
+enable displaying dots.  Setting this option implies \fB-dd\fR.  Size is
+in the format nm where n is a number and m is a multiplier.  Currently m can
+be k (KB), m (MB), g (GB), or t (TB), so if n is 100 and m is k, size would be
+100k which is 100 KB.  The default is 10 MB.
+.IP
+The \fB-v\fR option also displays dots and now defaults to
+10 MB also.  This rate is also controlled by this option.  A size of 0 turns dots off.
+.IP
+This option does not control the dots from the "Scanning files" message as
+\fIzip\fP scans for input files.  The dot size for that is fixed at 2 seconds
+or a fixed number of entries, whichever is longer.
+
+.TP
+.PD 0
+.B \-du
+.TP
+.PD
+.B \-\-display-usize
+Display the uncompressed size of each entry.
+
+.TP
+.PD 0
+.B \-dv
+.TP
+.PD
+.B \-\-display-volume
+Display the volume (disk) number each entry is being read from,
+if reading an existing archive, and being written to.
+
+.TP
+.PD 0
+.B \-D
+.TP
+.PD
+.B \-\-no-dir-entries
+Do not create entries in the
+.I zip
+archive for directories.  Directory entries are created by default so that
+their attributes can be saved in the zip archive.
+The environment variable ZIPOPT can be used to change the default options. For
+example under Unix with sh:
+.RS
+.IP
+ZIPOPT="-D"; export ZIPOPT
+.RE
+.IP
+(The variable ZIPOPT can be used for any option, including \fB\-i\fP and \fB\-x\fP
+using a new option format detailed below, and can include several options.) The option
+.B \-D
+is a shorthand
+for
+.B \-x
+"*/" but the latter previously could not be set as default in the ZIPOPT
+environment variable as the contents of ZIPOPT gets inserted near the beginning
+of the command line and the file list had to end at the end of the line.
+.IP
+This version of
+.I zip
+does allow
+.B \-x
+and
+.B \-i
+options in ZIPOPT if the form
+.IP
+\fC
+.BR \-x \ file\ file\ ... \ @\fP
+.IP
+is used, where the @ (an argument that is just @) terminates
+the list.
+
+.TP
+.PD 0
+.B \-DF
+.TP
+.PD
+.B \-\-difference-archive
+Create an archive that contains all new and changed files since
+the original archive was created.  For this to work, the input
+file list and current directory must be the same as during the
+original \fIzip\fP operation.
+.IP
+For example, if the existing archive was created using
+.RS
+.IP
+\fCzip -r foofull .
+.RE
+.IP
+from the \fIbar\fP directory, then the command
+.RS
+.IP
+\fCzip -r foofull . -DF --out foonew
+.RE
+.IP
+also from the \fIbar\fP directory creates the archive \fIfoonew\fP
+with just the files not in \fIfoofull\fP and the files where
+the size or file time of the files do not match those in \fIfoofull\fP.
+
+Note that the timezone environment variable TZ should be set according to
+the local timezone in order for this option to work correctly.  A
+change in timezone since the original archive was created could
+result in no times matching and all files being included.
+
+A possible approach to backing up a directory might be to create
+a normal archive of the contents of the directory as a full
+backup, then use this option to create incremental backups.
+
+.TP
+.PD 0
+.B \-e
+.TP
+.PD
+.B \-\-encrypt
+Encrypt the contents of the
+.I zip
+archive using a password which is entered on the terminal in response
+to a prompt
+(this will not be echoed; if standard error is not a tty,
+.I zip
+will exit with an error).
+The password prompt is repeated to save the user from typing errors.
+
+.TP
+.PD 0
+.B \-E
+.TP
+.PD
+.B \-\-longnames
+[OS/2] Use the .LONGNAME Extended Attribute (if found) as filename.
+
+.TP
+.PD 0
+.B \-f
+.TP
+.PD
+.B \-\-freshen
+Replace (freshen) an existing entry in the
+.I zip
+archive only if it has been modified more recently than the
+version already in the
+.I zip
+archive;
+unlike the update option
+.RB ( \-u )
+this will not add files that are not already in the
+.I zip
+archive.
+For example:
+.RS
+.IP
+\fCzip -f foo\fP
+.RE
+.IP
+This command should be run from the same directory from which the original
+.I zip
+command was run, since paths stored in
+.I zip
+archives are always relative.
+.IP
+Note that the timezone environment variable TZ should be set according to
+the local timezone in order for the
+\fB\-f\fP, \fB\-u\fP and \fB\-o\fP
+options to work correctly.
+.IP
+The reasons behind this are somewhat subtle but have to do with the differences
+between the Unix-format file times (always in GMT) and most of the other
+operating systems (always local time) and the necessity to compare the two.
+A typical TZ value is ``MET-1MEST'' (Middle European time with automatic
+adjustment for ``summertime'' or Daylight Savings Time).
+.IP
+The format is TTThhDDD, where TTT is the time zone such as MET, hh is the
+difference between GMT and local time such as -1 above, and DDD is
+the time zone when daylight savings time is in effect.  Leave off
+the DDD if there is no daylight savings time.  For the US Eastern
+time zone EST5EDT.
+
+.TP
+.PD 0
+.B \-F
+.TP
+.B \-\-fix\ \ \ \ \ \ 
+.TP
+.B \-FF
+.TP
+.PD
+.B \-\-fixfix\ \ 
+Fix the
+.I zip
+archive. The \fB\-F\fP option can be used if some portions of the archive
+are missing, but requires a reasonably intact central directory.
+The input archive is scanned as usual, but \fIzip\fP will ignore
+some problems.  The resulting archive should be valid, but any
+inconsistent entries will be left out.
+.IP
+When doubled as in
+\fB\-FF\fP,
+the archive is scanned from the beginning and \fIzip\fP scans for special
+signatures to identify the limits between the archive members. The
+single
+.B \-F
+is more reliable if the archive is not too much damaged, so try this
+option first.
+.IP
+If the archive is too damaged or the end has been truncated, you
+must use \fB\-FF\fP.  This is a change from \fIzip\ 2.32\fP, where
+the \fB\-F\fP option is able to read a truncated archive.  The
+\fB\-F\fP option now more reliably fixes archives with minor
+damage and the \fB\-FF\fP option is needed to fix archives where
+\fB\-F\fP might have been sufficient before.
+.IP
+Neither option will recover archives that have been incorrectly
+transferred in ascii mode instead of binary. After the repair, the
+.B \-t
+option of
+.I unzip
+may show that some files have a bad CRC. Such files cannot be recovered;
+you can remove them from the archive using the
+.B \-d
+option of
+\fIzip\fP.
+.IP
+Note that \fB\-FF\fP may have trouble fixing archives that include an
+embedded zip archive that was stored (without compression) in the archive
+and, depending on the damage, it may find the entries in the embedded
+archive rather than the archive itself.  Try \fB\-F\fP first as it
+does not have this problem.
+.IP
+The format of the fix commands have changed.  For example, to fix
+the damaged archive \fIfoo.zip\fP,
+.RS
+.IP
+\fCzip -F foo --out foofix
+.RE
+.IP
+tries to read the entries normally, copying good entries to the
+new archive \fIfoofix.zip\fP.  If this doesn't work, as when the
+archive is truncated, or if some entries you know are in the archive
+are missed, then try
+.RS
+.IP
+\fCzip -FF foo --out foofixfix
+.RE
+.IP
+and compare the resulting archive to the archive created by \fB\-F\fP.  The
+\fB\-FF\fP option may create an inconsistent archive.  Depending on
+what is damaged, you can then use the \fB\-F\fP option to fix that archive.
+.IP
+A split archive with missing split files can be fixed using
+\fB\-F\fP if you have the last split of the archive (the \fB\.zip\fP file).
+If this file is missing, you must use \fB\-FF\fP to fix the archive,
+which will prompt you for the splits you have.
+.IP
+Currently the fix options can't recover entries that have a bad checksum
+or are otherwise damaged.
+
+.TP
+.PD 0
+.B \-FI
+.TP
+.PD
+.B \-\-fifo
+[Unix]  Normally \fIzip\fP skips reading any FIFOs (named pipes) encountered, as
+\fIzip\fP can hang if the FIFO is not being fed.  This option tells \fIzip\fP to
+read the contents of any FIFO it finds.
+
+.TP
+.PD 0
+.B \-FS
+.TP
+.PD
+.B \-\-filesync
+Synchronize the contents of an archive with the files on the OS.
+Normally when an archive is updated, new files are added and changed
+files are updated but files that no longer exist on the OS are not
+deleted from the archive.  This option enables a new mode that checks
+entries in the archive against the file system.  If the file time and
+file size of the entry matches that of the OS file, the entry is
+copied from the old archive instead of being read from the file system
+and compressed.  If the OS file has changed, the entry is read and
+compressed as usual.  If the entry in the archive does not match a
+file on the OS, the entry is deleted.  Enabling this option should
+create archives that are the same as new archives, but since existing
+entries are copied instead of compressed, updating an existing archive
+with \fB\-FS\fP can be much faster than creating a new archive.  Also
+consider using \fB\-u\fP for updating an archive.
+.IP
+For this option to work, the archive should be updated from the same
+directory it was created in so the relative paths match.  If few files
+are being copied from the old archive, it may be faster to create a
+new archive instead.
+.IP
+Note that the timezone environment variable TZ should be set according to
+the local timezone in order for this option to work correctly.  A
+change in timezone since the original archive was created could
+result in no times matching and recompression of all files.
+.IP
+This option deletes files from the archive.  If you need to preserve
+the original archive, make a copy of the archive first or use the
+\fB\-\-out\fP option to output the updated archive to a new file.
+Even though it may be slower, creating a new archive with a new archive
+name is safer, avoids mismatches between archive and OS paths, and
+is preferred.
+
+.TP
+.PD 0
+.B \-g
+.TP
+.PD
+.B \-\-grow \ \ \ \ \ \ 
+Grow (append to) the specified
+.I zip
+archive, instead of creating a new one. If this operation fails,
+.I zip
+attempts to restore the archive to its original state. If the restoration
+fails, the archive might become corrupted. This option is ignored when
+there's no existing archive or when at least one archive member must be
+updated or deleted.
+
+.TP
+.PD 0
+.B \-h
+.TP
+.PD 0
+.B \-?
+.TP
+.PD
+.B \-\-help \ \ \ \ \ \ 
+Display the
+.I zip
+help information (this also appears if
+.I zip
+is run with no arguments).
+
+.TP
+.PD 0
+.B \-h2
+.TP
+.PD
+.B \-\-more-help
+Display extended help including more on command line format, pattern matching, and
+more obscure options.
+
+.TP
+.PD 0
+.B \-i\ \fRfiles
+.TP
+.PD
+.B \-\-include\ \fRfiles
+Include only the specified files, as in:
+.RS
+.IP
+\fCzip -r foo . -i \\*.c\fP
+.RE
+.IP
+which will include only the files that end in
+.IR \& .c
+in the current directory and its subdirectories. (Note for PKZIP
+users: the equivalent command is
+.RS
+.IP
+\fCpkzip -rP foo *.c\fP
+.RE
+.IP
+PKZIP does not allow recursion in directories other than the current one.)
+The backslash avoids the shell filename substitution, so that the
+name matching is performed by
+.I zip
+at all directory levels.
+[This is for Unix and other systems where \\  escapes the
+next character.  For other systems where the shell does not
+process * do not use \\ and the above is
+.RS
+.IP
+\fCzip -r foo . -i *.c\fP
+.RE
+.IP
+Examples are for Unix unless otherwise specified.]  So to include dir,
+a directory directly under the current directory, use
+.RS
+.IP
+\fCzip -r foo . -i dir/\\*
+.RE
+.IP
+or
+.RS
+.IP
+\fCzip -r foo . -i "dir/*"
+.RE
+.IP
+to match paths such as dir/a and dir/b/file.c [on
+ports without wildcard expansion in the shell such as MSDOS and Windows
+.RS
+.IP
+\fCzip -r foo . -i dir/*
+.RE
+.IP
+is used.]  Note that currently the trailing / is needed
+for directories (as in
+.RS
+.IP
+\fCzip -r foo . -i dir/
+.RE
+.IP
+to include directory dir).
+.IP
+The long option form of the first example is
+.RS
+.IP
+\fCzip -r foo . --include \\*.c
+.RE
+.IP
+and does the same thing as the short option form.
+.IP
+Though the command syntax used to require \fB-i\fR at
+the end of the command line, this version actually
+allows \fB\-i\fP (or \fB\-\-include\fP) anywhere.  The
+list of files terminates at the next argument starting
+with \fB-\fR, the end of the command line, or the list
+terminator \fB@\fR (an argument that is just @).  So
+the above can be given as
+.RS
+.IP
+zip -i \\*.c @ -r foo .\fP
+.RE
+.IP
+for example.  There must be a space between
+the option and the first file of a list.  For just
+one file you can use the single value form
+.RS
+.IP
+\fCzip -i\\*.c -r foo .\fP
+.RE
+.IP
+(no space between option and value) or
+.RS
+.IP
+\fCzip --include=\\*.c -r foo .\fP
+.RE
+.IP
+as additional examples.  The single value forms are
+not recommended because they can be confusing and,
+in particular, the \fB\-ifile\fP format can cause
+problems if the first letter of \fBfile\fP combines with
+\fBi\fP to form a two-letter option starting with
+\fBi\fP.  Use \fB\-sc\fP to see how your command line
+will be parsed.
+.IP
+Also possible:
+.RS
+.IP
+\fCzip -r foo  . -i@include.lst\fP
+.RE
+.IP
+which will only include the files in the current directory and its
+subdirectories that match the patterns in the file include.lst.
+.IP
+Files to \fB\-i\fR and \fB\-x\fR are patterns matching internal archive paths.  See
+\fB-R\fR for more on patterns.
+
+.TP
+.PD 0
+.B \-I
+.TP
+.PD
+.B \-\-no-image
+[Acorn RISC OS] Don't scan through Image files.  When used, \fIzip\fP will not
+consider Image files (eg. DOS partitions or Spark archives when SparkFS
+is loaded) as directories but will store them as single files.
+
+For example, if you have SparkFS loaded, zipping a Spark archive will result
+in a zipfile containing a directory (and its content) while using the 'I'
+option will result in a zipfile containing a Spark archive. Obviously this
+second case will also be obtained (without the 'I' option) if SparkFS isn't
+loaded.
+
+.TP
+.PD 0
+.B \-ic
+.TP
+.PD
+.B \-\-ignore-case
+[VMS, WIN32] Ignore case when matching archive entries.  This option is
+only available on systems where the case of files is ignored.  On systems
+with case-insensitive file systems, case is normally ignored when matching files
+on the file system but is not ignored for -f (freshen), -d (delete), -U (copy),
+and similar modes when matching against archive entries (currently -f
+ignores case on VMS) because archive entries can be from systems where
+case does matter and names that are the same except for case can exist
+in an archive.  The \fB\-ic\fR option makes all matching case insensitive.
+This can result in multiple archive entries matching a command line pattern.
+
+.TP
+.PD 0
+.B \-j
+.TP
+.PD
+.B \-\-junk-paths
+Store just the name of a saved file (junk the path), and do not store
+directory names. By default,
+.I zip
+will store the full path (relative to the current directory).
+
+.TP
+.PD 0
+.B \-jj
+.TP
+.PD
+.B \-\-absolute-path
+[MacOS] record Fullpath (+ Volname). The complete path including
+volume will be stored. By default the relative path will be stored.
+
+.TP
+.PD 0
+.B \-J
+.TP
+.PD
+.B \-\-junk-sfx
+Strip any prepended data (e.g. a SFX stub) from the archive.
+.TP
+.PD 0
+.B \-k
+.TP
+.PD
+.B \-\-DOS-names
+Attempt to convert the names and paths to conform to MSDOS,
+store only the MSDOS attribute (just the user write attribute from Unix),
+and mark the entry as made under MSDOS (even though it was not);
+for compatibility with PKUNZIP under MSDOS which cannot handle certain
+names such as those with two dots.
+.TP
+.PD 0
+.B \-l
+.TP
+.PD
+.B \-\-to-crlf
+Translate the Unix end-of-line character LF into the
+MSDOS convention CR LF. This option should not be used on binary files.
+This option can be used on Unix if the zip file is intended for PKUNZIP
+under MSDOS. If the input files already contain CR LF, this option adds
+an extra CR. This is to ensure that
+\fBunzip -a\fP
+on Unix will get back an exact copy of the original file,
+to undo the effect of
+\fBzip -l\fP.  See \fB-ll\fR for how binary files are handled.
+.TP
+.PD 0
+.B \-la
+.TP
+.PD
+.B \-\-log-append
+Append to existing logfile.  Default is to overwrite.
+.TP
+.PD 0
+.B \-lf\ \fPlogfilepath
+.TP
+.PD
+.B \-\-logfile-path\ \fPlogfilepath
+Open a logfile at the given path.  By default any existing file at that location
+is overwritten, but the \fB\-la\fP option will result in an existing file being
+opened and the new log information appended to any existing information.
+Only warnings and errors are written to the log unless the \fB\-li\fP option is
+also given, then all information messages are also written to the log.
+.TP
+.PD 0
+.B \-li
+.TP
+.PD
+.B \-\-log-info
+Include information messages, such as file names being zipped, in the log.
+The default is to only include the command line, any warnings and errors, and
+the final status.
+.TP
+.PD 0
+.B \-ll
+.TP
+.PD
+.B \-\-from-crlf
+Translate the MSDOS end-of-line CR LF into Unix LF.
+This option should not be used on binary files.
+This option can be used on MSDOS if the zip file is intended for unzip
+under Unix.  If the file is converted and the file is later determined
+to be binary a warning is issued and the file is probably
+corrupted.  In this release if \fB-ll\fR detects binary in the first buffer
+read from a file, \fIzip\fR now issues a warning and skips line end
+conversion on the file.  This check seems to catch all binary files
+tested, but the original check remains and if a converted file is
+later determined to be binary that warning is still issued.  A new algorithm
+is now being used for binary detection that should allow line end conversion
+of text files in \fBUTF-8\fR and similar encodings.
+.TP
+.PD 0
+.B \-L
+.TP
+.PD
+.B \-\-license
+Display the
+.I zip
+license.
+.TP
+.PD 0
+.B \-m
+.TP
+.PD
+.B \-\-move \ \ \ 
+Move the specified files into the
+.I zip
+archive; actually,
+this deletes the target directories/files after making the specified
+.I zip
+archive. If a directory becomes empty after removal of the files, the
+directory is also removed. No deletions are done until
+.I zip
+has created the archive without error.
+This is useful for conserving disk space,
+but is potentially dangerous so it is recommended to use it in
+combination with
+.B \-T
+to test the archive before removing all input files.
+.TP
+.PD 0
+.B \-MM
+.TP
+.PD
+.B \-\-must-match
+All input patterns must match at least one file and all input files
+found must be readable.  Normally when an input pattern does not match
+a file the "name not matched" warning is issued and when an input file
+has been found but later is missing or not readable a missing or not
+readable warning is issued.  In either case
+.I zip
+continues creating the archive, with missing or unreadable new files
+being skipped and files already in the archive remaining unchanged.
+After the archive is created, if any files were not readable
+.I zip
+returns the OPEN error code (18 on most systems) instead of the normal
+success return (0 on most systems).  With \fB\-MM\fP set,
+.I zip
+exits as soon as an input pattern is not matched (whenever the
+"name not matched" warning would be issued) or when an input file is
+not readable.  In either case \fIzip\fR exits with an OPEN error
+and no archive is created.
+.IP
+This option is useful when a known list of files is to be zipped so
+any missing or unreadable files will result in an error.  It is less
+useful when used with wildcards, but \fIzip\fR will still exit with an
+error if any input pattern doesn't match at least one file and if any
+matched files are unreadable.  If you want to create the archive
+anyway and only need to know if files were skipped, don't use
+.B \-MM
+and just check the return code.  Also \fB\-lf\fP could be useful.
+.TP
+.PD 0
+.BI \-n\ \fRsuffixes
+.TP
+.PD
+.B \-\-suffixes\ \fRsuffixes
+Do not attempt to compress files named with the given
+\fBsuffixes\fR.
+Such files are simply stored (0% compression) in the output zip file,
+so that
+.I zip
+doesn't waste its time trying to compress them.
+The suffixes are separated by
+either colons or semicolons.  For example:
+.RS
+.IP
+\fCzip -rn .Z:.zip:.tiff:.gif:.snd  foo foo\fP
+.RE
+.IP
+will copy everything from
+.I foo
+into
+.IR foo.zip ,
+but will store any files that end in
+.IR .Z ,
+.IR .zip ,
+.IR .tiff ,
+.IR .gif ,
+or
+.I .snd
+without trying to compress them
+(image and sound files often have their own specialized compression methods).
+By default,
+.I zip
+does not compress files with extensions in the list
+.I .Z:.zip:.zoo:.arc:.lzh:.arj.
+Such files are stored directly in the output archive.
+The environment variable ZIPOPT can be used to change the default options. For
+example under Unix with csh:
+.RS
+.IP
+setenv ZIPOPT "-n .gif:.zip"
+.RE
+.IP
+To attempt compression on all files, use:
+.RS
+.IP
+zip -n : foo
+.RE
+.IP
+The maximum compression option
+.B \-9
+also attempts compression on all files regardless of extension.
+.IP
+On Acorn RISC OS systems the suffixes are actually filetypes (3 hex digit
+format). By default, \fIzip\fP does not compress files with filetypes in the list
+DDC:D96:68E (i.e. Archives, CFS files and PackDir files).
+.TP
+.PD 0
+.B \-nw
+.TP
+.PD
+.B \-\-no-wild
+Do not perform internal wildcard processing (shell processing of wildcards is still done
+by the shell unless the arguments are escaped).  Useful if a list of paths is being
+read and no wildcard substitution is desired.
+.TP
+.PD 0
+.B \-N
+.TP
+.PD
+.B \-\-notes
+[Amiga, MacOS] Save Amiga or MacOS filenotes as zipfile comments. They can be
+restored by using the -N option of \fIunzip\fP. If -c is used also, you are
+prompted for comments only for those files that do not have filenotes.
+.TP
+.PD 0
+.B \-o
+.TP
+.PD
+.B \-\-latest-time
+Set the "last modified" time of the
+.I zip
+archive to the latest (oldest) "last modified" time
+found among the entries in the
+.I zip
+archive.
+This can be used without any other operations, if desired.
+For example:
+.IP
+\fCzip -o foo\fP
+.IP
+will change the last modified time of
+\fBfoo.zip\fP
+to the latest time of the entries in
+.BR foo.zip .
+.TP
+.PD 0
+.B \-O \fPoutput-file
+.TP
+.PD
+.B \-\-output-file \fPoutput-file
+Process the archive changes as usual, but instead of updating the existing archive,
+output the new archive to output-file.  Useful for updating an archive
+without changing the existing archive and the input archive must be a different file
+than the output archive.
+
+This option can be used to create updated split archives.
+It can also be used with \fB\-U\fP to copy entries from an existing archive to a new
+archive.  See the \fBEXAMPLES\fP section below.
+
+Another use is converting \fIzip\fP files from one split size to another.  For instance,
+to convert an archive with 700 MB CD splits to one with 2 GB DVD splits, can use:
+.RS
+.IP
+zip -s 2g cd-split.zip --out dvd-split.zip
+.RE
+.IP
+which uses copy mode.  See \fB\-U\fP below.  Also:
+.RS
+.IP
+zip -s 0 split.zip --out unsplit.zip
+.RE
+.IP
+will convert a split archive to a single-file archive.
+
+Copy mode will convert stream entries (using data descriptors and which
+should be compatible with most unzips) to normal entries (which should
+be compatible
+with all unzips), except if standard encryption was used.  For archives
+with encrypted entries, \fIzipcloak\fP will decrypt the entries and convert
+them to normal entries.
+.TP
+.PD 0
+.B \-p
+.TP
+.PD
+.B \-\-paths
+Include relative file paths as part of the names of files stored in the archive.
+This is the default.  The \fB\-j\fP option junks the paths and just stores the
+names of the files.
+.TP
+.PD 0
+.B \-P\ \fRpassword
+.TP
+.PD
+.B \-\-password\ \fRpassword
+Use \fIpassword\fP to encrypt zipfile entries (if any).  \fBTHIS IS
+INSECURE!\fP  Many multi-user operating systems provide ways for any user to
+see the current command line of any other user; even on stand-alone systems
+there is always the threat of over-the-shoulder peeking.  Storing the plaintext
+password as part of a command line in an automated script is even worse.
+Whenever possible, use the non-echoing, interactive prompt to enter passwords.
+(And where security is truly important, use strong encryption such as Pretty
+Good Privacy instead of the relatively weak standard encryption provided by
+zipfile utilities.)
+.TP
+.PD 0
+.B \-q
+.TP
+.PD
+.B \-\-quiet
+Quiet mode;
+eliminate informational messages and comment prompts.
+(Useful, for example, in shell scripts and background tasks).
+.TP
+.PD 0
+.BI \-Q\fRn
+.TP
+.PD
+.B \-\-Q\-flag\ \fRn
+[QDOS] store information about the file in the file header with n defined as
+.RS
+bit  0: Don't add headers for any file
+.RE
+.RS
+bit  1: Add headers for all files
+.RE
+.RS
+bit  2: Don't wait for interactive key press on exit
+.RE
+.TP
+.PD 0
+.B \-r
+.TP
+.PD
+.B \-\-recurse\-paths
+Travel the directory structure recursively;
+for example:
+.RS
+.IP
+zip -r foo.zip foo
+.RE
+.IP
+or more concisely
+.RS
+.IP
+zip -r foo foo
+.RE
+.IP
+In this case, all the files and directories in
+.B foo
+are saved in a
+.I zip
+archive named \fBfoo.zip\fP,
+including files with names starting with \fB"."\fP,
+since the recursion does not use the shell's file-name substitution mechanism.
+If you wish to include only a specific subset of the files in directory
+\fBfoo\fP
+and its subdirectories, use the
+\fB\-i\fP
+option to specify the pattern of files to be included.
+You should not use
+\fB\-r\fP
+with the name \fB".*"\fP,
+since that matches \fB".."\fP
+which will attempt to zip up the parent directory
+(probably not what was intended).
+.IP
+Multiple source directories are allowed as in
+.RS
+.IP
+\fCzip -r foo foo1 foo2\fP
+.RE
+.IP
+which first zips up \fBfoo1\fP and then \fBfoo2\fP, going down each directory.
+.IP
+Note that while wildcards to \fB-r\fR are typically resolved while recursing down
+directories in the file system, any \fB-R\fN, \fB-x\fR, and \fB-i\fR wildcards
+are applied to internal archive pathnames once the directories are scanned.
+To have wildcards apply to files in subdirectories when recursing on
+Unix and similar systems where the shell does wildcard substitution, either
+escape all wildcards or put all arguments with wildcards in quotes.  This lets
+\fIzip\fR see the wildcards and match files in subdirectories using them as
+it recurses.
+.TP
+.PD 0
+.B \-R
+.TP
+.PD
+.B \-\-recurse\-patterns
+Travel the directory structure recursively starting at the
+current directory;
+for example:
+.RS
+.IP
+\fCzip -R foo "*.c"\fP
+.RE
+.IP
+In this case, all the files matching \fB*.c\fP in the tree starting at the
+current directory are stored into a
+.I zip
+archive named
+\fBfoo.zip\fP.
+Note that \fB*.c\fP will match \fBfile.c\fP, \fBa/file.c\fP
+and \fBa/b/.c\fP.  More than one pattern can be listed as separate
+arguments.
+Note for PKZIP users: the equivalent command is
+.RS
+.IP
+\fCpkzip -rP foo *.c\fP
+.RE
+.IP
+Patterns are relative file paths as they appear in the archive, or will after
+zipping, and can have optional wildcards in them.  For example, given
+the current directory is \fBfoo\fP and under it are directories \fBfoo1\fP and \fBfoo2\fP
+and in \fBfoo1\fP is the file \fBbar.c\fP,
+.RS
+.IP
+\fCzip -R foo/*\fP
+.RE
+.IP
+will zip up \fBfoo\fP, \fBfoo/foo1\fP, \fBfoo/foo1/bar.c\fP, and \fBfoo/foo2\fP.
+.RS
+.IP
+\fCzip -R */bar.c\fP
+.RE
+.IP
+will zip up \fBfoo/foo1/bar.c\fP.  See the note for \fB-r\fR on escaping wildcards.
+
+.TP
+.PD 0
+.B \-RE
+.TP
+.PD
+.B \-\-regex
+[WIN32]  Before \fIzip\fP \fI3.0\fP, regular expression list matching was
+enabled by default on Windows platforms.  Because of confusion resulting
+from the need to escape "[" and "]" in names, it is now off by default for
+Windows so "[" and "]" are just normal characters in names.  This option
+enables [] matching again.
+
+.TP
+.PD 0
+.B \-s\ \fPsplitsize
+.TP
+.PD
+.B \-\-split\-size\ \fPsplitsize
+Enable creating a split archive and set the split size.  A split archive is an archive
+that could be split over many files.  As the archive is created, if the size of the
+archive reaches the specified split size, that split is closed and the next split
+opened.  In general all splits but the last will be the split size and the last
+will be whatever is left.  If the entire archive is smaller than the split size a
+single-file archive is created.
+
+Split archives are stored in numbered files.  For example, if the output
+archive is named \fBarchive\fP and three splits are required, the resulting
+archive will be in the three files \fBarchive.z01\fP, \fBarchive.z02\fP, and
+\fBarchive.zip\fP.  Do not change the numbering of these files or the archive
+will not be readable as these are used to determine the order the splits are read.
+
+Split size is a number optionally followed by a multiplier.  Currently the
+number must be an integer.  The multiplier can currently be one of
+\fBk\fP (kilobytes), \fBm\fP (megabytes), \fBg\fP (gigabytes), or \fBt\fP
+(terabytes).  As 64k is the minimum split size, numbers without multipliers
+default to megabytes.  For example, to create a split archive called \fBfoo\fP
+with the contents of the \fBbar\fP directory with splits of 670 MB that might
+be useful for burning on CDs, the command:
+.RS
+.IP
+zip -s 670m -r foo bar
+.RE
+.IP
+could be used.
+
+Currently the old splits of a split archive are not excluded from a new
+archive, but they can be specifically excluded.  If possible, keep
+the input and output archives out of the path being zipped when creating
+split archives.
+
+Using \fB\-s\fP without \fB\-sp\fP as above creates all the splits where
+\fBfoo\fP is being written, in this case the current directory.  This split
+mode updates the splits as the archive is being created, requiring all
+splits to remain writable, but creates split archives that are readable by
+any unzip that supports split archives.  See \fB\-sp\fP below for enabling
+split pause mode which allows splits to be written directly to removable
+media.
+
+The option \fB\-sv\fP can be used to enable verbose splitting and provide details of
+how the splitting is being done.  The \fB\-sb\fP option can be used to ring the bell
+when \fIzip\fP pauses for the next split destination.
+
+Split archives cannot be updated, but see the \fB\-O\fP (\fB\-\-out\fP) option for
+how a split archive can be updated as it is copied to a new archive.
+A split archive can also be converted into a single-file archive using a
+split size of 0 or negating the \fB\-s\fP option:
+.RS
+.IP
+zip -s 0 split.zip --out single.zip
+.RE
+.IP
+Also see \fB\-U\fP (\fB\-\-copy\fP) for more on using copy mode.
+.TP
+.PD 0
+.B \-sb
+.TP
+.PD
+.B \-\-split\-bell
+If splitting and using split pause mode, ring the bell when \fIzip\fP pauses
+for each split destination.
+.TP
+.PD 0
+.B \-sc
+.TP
+.PD
+.B \-\-show\-command
+Show the command line starting \fIzip\fP as processed and exit.  The new command parser
+permutes the arguments, putting all options and any values associated with them
+before any non-option arguments.  This allows an option to appear anywhere in the
+command line as long as any values that go with the option go with it.  This option
+displays the command line as \fIzip\fP sees it, including any arguments from
+the environment such as from the \fBZIPOPT\fP variable.  Where allowed, options later
+in the command line can override options earlier in the command line.
+.TP
+.PD 0
+.B \-sf
+.TP
+.PD
+.B \-\-show\-files
+Show the files that would be operated on, then exit.  For instance, if creating
+a new archive, this will list the files that would be added.  If the option is
+negated, \fB\-sf\-\fP, output only to an open log file.  Screen display is
+not recommended for large lists.
+.TP
+.PD 0
+.B \-so
+.TP
+.PD
+.B \-\-show\-options
+Show all available options supported by \fIzip\fP as compiled on the current system.
+As this command reads the option table, it should include all options.  Each line
+includes the short option (if defined), the long option (if defined), the format
+of any value that goes with the option, if the option can be negated, and a
+small description.  The value format can be no value, required value, optional
+value, single character value, number value, or a list of values.  The output of
+this option is not intended to show how to use any option but only
+show what options are available.
+.TP
+.PD 0
+.B \-sp
+.TP
+.PD
+.B \-\-split\-pause
+If splitting is enabled with \fB\-s\fP, enable split pause mode.  This
+creates split archives as \fB\-s\fP does, but stream writing is used so each
+split can be closed as soon as it is written and \fIzip\fP will pause between each
+split to allow changing split destination or media.
+
+Though this split mode allows writing splits directly to removable media, it
+uses stream archive format that may not be readable by some unzips.  Before
+relying on splits created with \fB\-sp\fP, test a split archive with the unzip
+you will be using.
+
+To convert a stream split archive (created with \fB\-sp\fP) to a standard archive
+see the \fB\-\-out\fP option.
+.TP
+.PD 0
+.B \-su
+.TP
+.PD
+.B \-\-show\-unicode
+As \fB\-sf\fP, but also show Unicode version of the path if exists.
+.TP
+.PD 0
+.B \-sU
+.TP
+.PD
+.B \-\-show\-just\-unicode
+As \fB\-sf\fP, but only show Unicode version of the path if exists, otherwise show
+the standard version of the path.
+.TP
+.PD 0
+.B \-sv
+.TP
+.PD
+.B \-\-split\-verbose
+Enable various verbose messages while splitting, showing how the splitting is being
+done.
+.TP
+.PD 0
+.B \-S
+.TP
+.PD
+.B \-\-system-hidden
+[MSDOS, OS/2, WIN32 and ATARI] Include system and hidden files.
+.RS
+[MacOS] Includes finder invisible files, which are ignored otherwise.
+.RE
+.TP
+.PD 0
+.BI \-t\ \fRmmddyyyy
+.TP
+.PD
+.B \-\-from\-date\ \fRmmddyyyy
+Do not operate on files modified prior to the specified date,
+where
+.B mm
+is the month (00-12),
+.B dd
+is the day of the month (01-31),
+and
+.B yyyy
+is the year.
+The
+.I ISO\ 8601
+date format
+.B yyyy\-mm\-dd
+is also accepted.
+For example:
+.RS
+.IP
+\fCzip -rt 12071991 infamy foo\fP
+
+\fCzip -rt 1991-12-07 infamy foo\fP
+.RE
+.IP
+will add all the files in
+.B foo
+and its subdirectories that were last modified on or after 7 December 1991,
+to the
+.I zip
+archive
+.BR infamy.zip .
+.TP
+.PD 0
+.BI \-tt\ \fRmmddyyyy
+.TP
+.PD
+.B \-\-before\-date\ \fRmmddyyyy
+Do not operate on files modified after or at the specified date,
+where
+.B mm
+is the month (00-12),
+.B dd
+is the day of the month (01-31),
+and
+.B yyyy
+is the year.
+The
+.I ISO\ 8601
+date format
+.B yyyy\-mm\-dd
+is also accepted.
+For example:
+.RS
+.IP
+\fCzip -rtt 11301995 infamy foo\fP
+
+\fCzip -rtt 1995-11-30 infamy foo\fP
+.RE
+.IP
+will add all the files in
+.B foo
+and its subdirectories that were last modified before 30 November 1995,
+to the
+.I zip
+archive
+.BR infamy.zip .
+.TP
+.PD 0
+.B \-T
+.TP
+.PD
+.B \-\-test\ \ \ \ 
+Test the integrity of the new zip file. If the check fails, the old zip file
+is unchanged and (with the
+.B -m
+option) no input files are removed.
+.TP
+.PD 0
+.B \-TT\ \fPcmd
+.TP
+.PD
+.B \-\-unzip-command\ \fPcmd
+Use command cmd instead of 'unzip -tqq' to test an archive when the \fB\-T\fP
+option is used.  On Unix, to use a copy of unzip in the current directory instead
+of the standard system unzip, could use:
+.IP
+\fC zip archive file1 file2 -T -TT "./unzip -tqq"\fP
+.IP
+In cmd, {} is replaced by the name of the temporary archive, otherwise the name
+of the archive is appended to the end of the command.
+The return code is checked for success (0 on Unix).
+.TP
+.PD 0
+.B \-u
+.TP
+.PD
+.B \-\-update
+Replace (update) an existing entry in the
+.I zip
+archive only if it has been modified more recently
+than the version already in the
+.I zip
+archive.
+For example:
+.RS
+.IP
+\fCzip -u stuff *\fP
+.RE
+.IP
+will add any new files in the current directory,
+and update any files which have been modified since the
+.I zip
+archive
+.I stuff.zip
+was last created/modified (note that
+.I zip
+will not try to pack
+.I stuff.zip
+into itself when you do this).
+.IP
+Note that the
+.B \-u
+option with no input file arguments acts like the
+.B \-f
+(freshen) option.
+.TP
+.PD 0
+.B \-U
+.TP
+.PD
+.B \-\-copy\-entries
+Copy entries from one archive to another.  Requires the \fB\-\-out\fP
+option to specify a different output file than the input archive.  Copy
+mode is the reverse of \fB\-d\fP delete.  When delete is being used
+with \fB\-\-out\fP, the selected entries are deleted from the archive
+and all other entries are copied to the new archive, while copy mode
+selects the files to include in the new archive.  Unlike \fB\-u\fP
+update, input patterns on the command line are matched against archive
+entries only and not the file system files.  For instance,
+.RS
+.IP
+\fCzip inarchive "*.c" --copy --out outarchive\fP
+.RE
+.IP
+copies entries with names ending in \fB\.c\fP from \fBinarchive\fP
+to \fBoutarchive\fP.  The wildcard must be escaped on some systems
+to prevent the shell from substituting names of files from the
+file system which may have no relevance to the entries in the archive.
+
+If no input files appear on the command line and \fB\-\-out\fP is
+used, copy mode is assumed:
+.RS
+.IP
+\fCzip inarchive --out outarchive\fP
+.RE
+.IP
+This is useful for changing split size for instance.  Encrypting
+and decrypting entries is not yet supported using copy mode.  Use
+\fIzipcloak\fP for that.
+.TP
+.PD 0
+.B \-UN\ \fRv
+.TP
+.PD
+.B \-\-unicode\ \fRv
+Determine what \fIzip\fP should do with Unicode file names.
+\fIzip\ 3.0\fP, in addition to the standard file path, now
+includes the UTF\-8 translation of the path if the entry path
+is not entirely 7-bit ASCII.  When an entry
+is missing the Unicode path, \fIzip\fP reverts back to the
+standard file path.  The problem with using the standard path
+is this path is in the local character set of the zip that created
+the entry, which may contain characters that are not valid in
+the character set being used by the unzip.  When \fIzip\fP is
+reading an archive, if an entry also has a Unicode path,
+\fIzip\fP now defaults to using the Unicode path to recreate
+the standard path using the current local character set.
+
+This option can be used to determine what \fIzip\fP should do
+with this path if there is a mismatch between the stored standard path
+and the stored UTF-8 path (which can happen if the standard path was
+updated).  In all cases, if there is a mismatch it is
+assumed that the standard path is more current and
+\fIzip\fP uses that.  Values for \fBv\fP are
+.RS
+.IP
+q \- quit if paths do not match
+.IP
+w \- warn, continue with standard path
+.IP
+i \- ignore, continue with standard path
+.IP
+n \- no Unicode, do not use Unicode paths
+.RE
+.IP
+The default is to warn and continue.
+
+Characters that are not valid in the current character set are
+escaped as \fB#Uxxxx\fP and \fB#Lxxxxxx\fP, where x is an
+ASCII character for a hex digit.  The first is used if a 16-bit
+character number is sufficient to represent the Unicode character
+and the second if the character needs more than 16 bits to
+represent it's Unicode character code.  Setting \fB\-UN\fP to
+.RS
+.IP
+e \- escape
+.RE
+.IP
+as in
+.RS
+.IP
+\fCzip archive -sU -UN=e\fP
+.RE
+.IP
+forces \fIzip\fP to escape all characters that are not printable 7-bit
+ASCII.
+
+Normally \fIzip\fP stores UTF\-8 directly in the standard path field
+on systems where UTF\-8 is the current character set and stores the
+UTF\-8 in the new extra fields otherwise.  The option
+.RS
+.IP
+u \- UTF\-8
+.RE
+.IP
+as in
+.RS
+.IP
+\fCzip archive dir -r -UN=UTF8\fP
+.RE
+.IP
+forces \fIzip\fP to store UTF\-8 as native in the archive.  Note that
+storing UTF\-8 directly is the default on Unix systems that support it.
+This option could be useful on Windows systems where the escaped
+path is too large to be a valid path and the UTF\-8 version of the
+path is smaller, but native UTF\-8 is not backward compatible on
+Windows systems.
+
+.TP
+.PD 0
+.B \-v
+.TP
+.PD
+.B \-\-verbose
+Verbose mode or print diagnostic version info.
+.IP
+Normally, when applied to real operations, this option enables the display of a
+progress indicator during compression (see \fB-dd\fR for more on dots) and
+requests verbose diagnostic info about zipfile structure oddities.
+.IP
+However, when
+.B \-v
+is the only command line argument a diagnostic screen is printed instead.  This
+should now work even if stdout is redirected to a file, allowing easy saving
+of the information for sending with bug reports to Info-ZIP.  The version
+screen provides the help screen header with program name, version, and release
+date, some pointers to the Info-ZIP home and distribution sites, and shows
+information about the target environment (compiler type and version, OS
+version, compilation date and the enabled optional features used to create the
+.I zip
+executable).
+.TP
+.PD 0
+.B \-V
+.TP
+.PD
+.B \-\-VMS\-portable
+[VMS] Save VMS file attributes.
+(Files are  truncated at EOF.)   When a -V archive is unpacked on a
+non-VMS system,  some file types (notably Stream_LF
+text files  and  pure binary files  like fixed-512)
+should be extracted intact.  Indexed files and file
+types with embedded record sizes (notably variable-length record types)
+will probably be seen as corrupt elsewhere.
+.TP
+.PD 0
+.B \-VV
+.TP
+.PD
+.B \-\-VMS\-specific
+[VMS] Save VMS file attributes, and  all allocated
+blocks in a file,  including  any  data beyond EOF.
+Useful for moving ill-formed files  among  VMS systems.   When a -VV archive is
+unpacked on a non-VMS system, almost all files will appear corrupt.
+.TP
+.PD 0
+.B \-w
+.TP
+.PD
+.B \-\-VMS\-versions
+[VMS] Append the version number of the files to the name,
+including multiple versions of files.  Default is to use only
+the most recent version of a specified file.
+.TP
+.PD 0
+.B \-ww
+.TP
+.PD
+.B \-\-VMS\-dot\-versions
+[VMS] Append the version number of the files to the name,
+including multiple versions of files, using the \.nnn format.
+Default is to use only the most recent version of a specified
+file.
+.TP
+.PD 0
+.BI \-ws
+.TP
+.PD
+.B \-\-wild\-stop\-dirs
+Wildcards match only at a directory level.  Normally \fIzip\fP handles
+paths as strings and given the paths
+.RS
+.IP
+/foo/bar/dir/file1.c
+.IP
+/foo/bar/file2.c
+.RE
+.IP
+an input pattern such as
+.RS
+.IP
+/foo/bar/*
+.RE
+.IP
+normally would match both paths, the * matching \fBdir/file1.c\fP
+and \fBfile2.c\fP.  Note that in the first case a directory
+boundary (/) was crossed in the match.  With \fB\-ws\fP no
+directory bounds will be included in the match, making
+wildcards local to a specific directory level.  So, with
+\fB\-ws\fP enabled, only the second path would be matched.
+
+When using \fB\-ws\fP, use ** to match across directory boundaries as
+* does normally.
+.TP
+.PD 0
+.BI \-x\ \fRfiles
+.TP
+.PD
+.B \-\-exclude\ \fRfiles
+Explicitly exclude the specified files, as in:
+.RS
+.IP
+\fCzip -r foo foo -x \\*.o\fP
+.RE
+.IP
+which will include the contents of
+.B foo
+in
+.B foo.zip
+while excluding all the files that end in
+\fB.o\fP.
+The backslash avoids the shell filename substitution, so that the
+name matching is performed by
+.I zip
+at all directory levels.
+.IP
+Also possible:
+.RS
+.IP
+\fCzip -r foo foo -x@exclude.lst\fP
+.RE
+.IP
+which will include the contents of
+.B foo
+in
+.B foo.zip
+while excluding all the files that match the patterns in the file
+\fBexclude.lst\fP.
+.IP
+The long option forms of the above are
+.RS
+.IP
+\fCzip -r foo foo --exclude \\*.o\fP
+.RE
+.IP
+and
+.RS
+.IP
+\fCzip -r foo foo --exclude @exclude.lst\fP
+.RE
+.IP
+Multiple patterns can be specified, as in:
+.RS
+.IP
+\fCzip -r foo foo -x \\*.o \\*.c\fP
+.RE
+.IP
+If there is no space between \fB\-x\fP and
+the pattern, just one value is assumed (no list):
+.RS
+.IP
+\fCzip -r foo foo -x\\*.o\fP
+.RE
+.IP
+.IP
+See \fB-i\fR for more on include and exclude.
+.TP
+.PD 0
+.B \-X
+.TP
+.PD
+.B \-\-no\-extra
+Do not save extra file attributes (Extended Attributes on OS/2, uid/gid
+and file times on Unix).  The zip format uses extra fields to include
+additional information for each entry.  Some extra fields are specific
+to particular systems while others are applicable to all systems.
+Normally when \fIzip\fP reads entries from an existing archive, it
+reads the extra fields it knows, strips the rest, and adds
+the extra fields applicable to that system.  With \fB\-X\fP, \fIzip\fP strips
+all old fields and only includes the Unicode and Zip64 extra fields
+(currently these two extra fields cannot be disabled).
+
+Negating this option, \fB\-X\-\fP, includes all the default extra fields,
+but also copies over any unrecognized extra fields.
+.TP
+.PD 0
+.B \-y
+.TP
+.PD
+.B \-\-symlinks
+For UNIX and VMS (V8.3 and later), store symbolic links as such in the
+.I zip
+archive, instead of compressing and storing the file referred to by
+the link.  This can avoid multiple copies of files being included in
+the archive as \fIzip\fP recurses the directory trees and accesses
+files directly and by links.
+.TP
+.PD 0
+.B \-z
+.TP
+.PD
+.B \-\-archive\-comment
+Prompt for a multi-line comment for the entire
+.I zip
+archive.
+The comment is ended by a line containing just a period,
+or an end of file condition (^D on Unix, ^Z on MSDOS, OS/2, and VMS).
+The comment can be taken from a file:
+.RS
+.IP
+\fCzip -z foo < foowhat\fP
+.RE
+.TP
+.PD 0
+.B \-Z\ \fRcm
+.TP
+.PD
+.B \-\-compression\-method\ \fRcm
+Set the default compression method.  Currently the main methods supported
+by \fIzip\fP are \fBstore\fP and \fBdeflate\fP.  Compression method
+can be set to:
+
+\fBstore\fP \- Setting the compression method to \fBstore\fP forces
+\fIzip\fP to store entries with no compression.  This is generally
+faster than compressing entries, but results in no space savings.
+This is the same as using \fB\-0\fP (compression level zero).
+
+\fBdeflate\fP \- This is the default method for \fIzip\fP.  If \fIzip\fP
+determines that storing is better than deflation, the entry will be
+stored instead.
+
+\fBbzip2\fP \- If \fBbzip2\fP support is compiled in, this compression
+method also becomes available.  Only some modern unzips currently support
+the \fBbzip2\fP compression method, so test the unzip you will be using
+before relying on archives using this method (compression method 12).
+
+For example, to add \fBbar.c\fP to archive \fBfoo\fP using \fBbzip2\fP
+compression:
+.RS
+.IP
+zip -Z bzip2 foo bar.c
+.RE
+.IP
+The compression method can be abbreviated:
+.RS
+.IP
+zip -Zb foo bar.c
+.RE
+.IP
+.TP
+.PD 0
+.BI \-#
+.TP
+.PD
+.B (\-0, \-1, \-2, \-3, \-4, \-5, \-6, \-7, \-8, \-9)
+Regulate the speed of compression using the specified digit
+.BR # ,
+where
+.B \-0
+indicates no compression (store all files),
+.B \-1
+indicates the fastest compression speed (less compression)
+and
+.B \-9
+indicates the slowest compression speed (optimal compression, ignores
+the suffix list). The default compression level is
+.BR \-6.
+
+Though still being worked, the intention is this setting will control
+compression speed for all compression methods.  Currently only
+deflation is controlled.
+.TP
+.PD 0
+.B \-!
+.TP
+.PD
+.B \-\-use\-privileges
+[WIN32] Use priviliges (if granted) to obtain all aspects of WinNT security.
+.TP
+.PD 0
+.B \-@
+.TP
+.PD
+.B \-\-names\-stdin
+Take the list of input files from standard input. Only one filename per line.
+.TP
+.PD 0
+.B \-$
+.TP
+.PD
+.B \-\-volume\-label
+[MSDOS, OS/2, WIN32] Include the volume label for the drive holding
+the first file to be compressed.  If you want to include only the volume
+label or to force a specific drive, use the drive name as first file name,
+as in:
+.RS
+.IP
+\fCzip -$ foo a: c:bar\fP
+.RE
+.IP
+.SH "EXAMPLES"
+The simplest example:
+.IP
+\fCzip stuff *\fP
+.LP
+creates the archive
+.I stuff.zip
+(assuming it does not exist)
+and puts all the files in the current directory in it, in compressed form
+(the
+\fB\&.zip\fP
+suffix is added automatically, unless the archive name contains
+a dot already;
+this allows the explicit specification of other suffixes).
+.LP
+Because of the way the shell on Unix does filename substitution,
+files starting with "." are not included;
+to include these as well:
+.IP
+\fCzip stuff .* *\fP
+.LP
+Even this will not include any subdirectories from the current directory.
+.LP
+To zip up an entire directory, the command:
+.IP
+\fCzip -r foo foo\fP
+.LP
+creates the archive
+.IR foo.zip ,
+containing all the files and directories in the directory
+.I foo
+that is contained within the current directory.
+.LP
+You may want to make a
+.I zip
+archive that contains the files in
+.IR foo ,
+without recording the directory name,
+.IR foo .
+You can use the
+.B \-j
+option to leave off the paths,
+as in:
+.IP
+\fCzip -j foo foo/*\fP
+.LP
+If you are short on disk space,
+you might not have enough room to hold both the original directory
+and the corresponding compressed
+.I zip
+archive.
+In this case, you can create the archive in steps using the
+.B \-m
+option.
+If
+.I foo
+contains the subdirectories
+.IR tom ,
+.IR dick ,
+and
+.IR harry ,
+you can:
+.IP
+\fCzip -rm foo foo/tom\fP
+.br
+\fCzip -rm foo foo/dick\fP
+.br
+\fCzip -rm foo foo/harry\fP
+.LP
+where the first command creates
+.IR foo.zip ,
+and the next two add to it.
+At the completion of each
+.I zip
+command,
+the last created archive is deleted,
+making room for the next
+.I zip
+command to function.
+
+
+
+.LP
+Use \fB\-s\fP to set the split size and create a split archive.  The size is given as
+a number followed optionally by one of k (kB), m (MB), g (GB), or t (TB).
+The command
+.IP
+\fCzip -s 2g -r split.zip foo\fP
+.LP
+creates a split archive of the directory foo with splits no bigger than 2\ GB each.  If
+foo contained 5\ GB of contents and the contents were stored in the split archive without
+compression (to make this example simple), this would create three splits, split.z01 at 2\ GB,
+split.z02 at 2\ GB, and split.zip at a little over 1\ GB.
+.LP
+The \fB\-sp\fP option can be used to pause \fIzip\fP between splits to allow changing
+removable media, for example, but read the descriptions and warnings for both \fB\-s\fP
+and \fB\-sp\fP below.
+.LP
+Though \fIzip\fP does not update split archives, \fIzip\fP provides the new option \fB\-O\fP
+(\fB\-\-output\-file\fP) to allow split archives to be updated and saved in a new archive.  For example,
+.IP
+\fCzip inarchive.zip foo.c bar.c \-\-out outarchive.zip\fP
+.LP
+reads archive \fBinarchive.zip\fP, even if split, adds the files \fBfoo.c\fP and
+\fBbar.c\fP, and writes the resulting archive to \fBoutarchive.zip\fP.  If
+\fBinarchive.zip\fP is split then \fBoutarchive.zip\fP defaults
+to the same split size.  Be aware that \fBoutarchive.zip\fP and any split files
+that are created with it are always overwritten without warning.  This may be changed
+in the future.
+
+
+
+
+.SH "PATTERN MATCHING"
+This section applies only to Unix.
+Watch this space for details on MSDOS and VMS operation.
+However, the special wildcard characters \fB*\fR and \fB[]\fR below apply
+to at least MSDOS also.
+.LP
+The Unix shells (\fIsh\fP, \fIcsh\fP, \fIbash\fP, and others) normally
+do filename substitution (also called "globbing") on command arguments.
+Generally the special characters are:
+.TP
+.B ?
+match any single character
+.TP
+.B *
+match any number of characters (including none)
+.TP
+.B []
+match any character in the range indicated within the brackets
+(example: [a\-f], [0\-9]).  This form of wildcard matching
+allows a user to specify a list of characters between square brackets and
+if any of the characters match the expression matches.  For example:
+.RS
+.IP
+\fCzip archive "*.[hc]"\fP
+.RE
+.IP
+would archive all files in the current directory that end in
+\fB.h\fP or \fB.c\fP.
+
+Ranges of characters are supported:
+.RS
+.IP
+\fCzip archive "[a\-f]*"\fP
+.RE
+.IP
+would add to the archive all files starting with "a" through "f".
+
+Negation is also supported, where any character in that position not in
+the list matches.  Negation is supported by adding \fB!\fP or \fB^\fP
+to the beginning of the list:
+.RS
+.IP
+\fCzip archive "*.[!o]"\fP
+.RE
+.IP
+matches files that don't end in ".o".
+
+On WIN32, [] matching needs to be turned on with the -RE option to avoid
+the confusion that names with [ or ] have caused.
+
+.LP
+When these characters are encountered
+(without being escaped with a backslash or quotes),
+the shell will look for files relative to the current path
+that match the pattern,
+and replace the argument with a list of the names that matched.
+.LP
+The
+.I zip
+program can do the same matching on names that are in the
+.I zip
+archive being modified or,
+in the case of the
+.B \-x
+(exclude) or
+.B \-i
+(include) options, on the list of files to be operated on, by using
+backslashes or quotes to tell the shell not to do the name expansion.
+In general, when
+.I zip
+encounters a name in the list of files to do, it first looks for the name in
+the file system.  If it finds it, it then adds it to the list of files to do.
+If it does not find it, it looks for the name in the
+.I zip
+archive being modified (if it exists), using the pattern matching characters
+described above, if present.  For each match, it will add that name to the
+list of files to be processed, unless this name matches one given
+with the
+.B \-x
+option, or does not match any name given with the
+.B \-i
+option.
+.LP
+The pattern matching includes the path,
+and so patterns like \\*.o match names that end in ".o",
+no matter what the path prefix is.
+Note that the backslash must precede every special character (i.e. ?*[]),
+or the entire argument must be enclosed in double quotes ("").
+.LP
+In general, use backslashes or double quotes for paths
+that have wildcards to make
+.I zip
+do the pattern matching for file paths, and always for
+paths and strings that have spaces or wildcards for
+\fB\-\i\fP, \fB\-x\fP, \fB\-R\fP, \fB\-d\fP, and \fB\-U\fP
+and anywhere \fIzip\fP needs to process the wildcards.
+.SH "ENVIRONMENT"
+.LP
+The following environment variables are read and used by
+.I zip
+as described.
+.TP
+.B ZIPOPT\ \ 
+contains default options that will be used when running
+\fIzip\fR.  The contents of this environment variable will get
+added to the command line just after the \fBzip\fR command.
+.TP
+.B ZIP\ \ \ \ \ 
+[Not on RISC OS and VMS] see ZIPOPT
+.TP
+.B Zip$Options
+[RISC OS] see ZIPOPT
+.TP
+.B Zip$Exts
+[RISC OS] contains extensions separated by a : that will cause
+native filenames with one of the specified extensions to
+be added to the zip file with basename and extension swapped.
+.TP
+.B ZIP_OPTS
+[VMS] see ZIPOPT
+.SH "SEE ALSO"
+compress(1),
+shar(1L),
+tar(1),
+unzip(1L),
+gzip(1L)
+.SH DIAGNOSTICS
+The exit status (or error level) approximates the exit codes defined by PKWARE
+and takes on the following values, except under VMS:
+.RS
+.IP 0
+normal; no errors or warnings detected.
+.IP 2
+unexpected end of zip file.
+.IP 3
+a generic error in the zipfile format was detected.  Processing may have
+completed successfully anyway; some broken zipfiles created by other
+archivers have simple work-arounds.
+.IP 4
+\fIzip\fP was unable to allocate memory for one or more buffers during
+program initialization.
+.IP 5
+a severe error in the zipfile format was detected.  Processing probably
+failed immediately.
+.IP 6
+entry too large to be processed (such as input files larger than 2 GB when
+not using Zip64 or trying to read an existing archive that is too large) or
+entry too large to be split with \fIzipsplit\fP
+.IP 7
+invalid comment format
+.IP 8
+\fIzip\fP -T failed or out of memory
+.IP 9
+the user aborted \fIzip\fP prematurely with control-C (or similar)
+.IP 10
+\fIzip\fP encountered an error while using a temp file
+.IP 11
+read or seek error
+.IP 12
+\fIzip\fP has nothing to do
+.IP 13
+missing or empty zip file
+.IP 14
+error writing to a file
+.IP 15
+\fIzip\fP was unable to create a file to write to
+.IP 16
+bad command line parameters
+.IP 18
+\fIzip\fP could not open a specified file to read
+.IP 19
+\fIzip\fP was compiled with options not supported on this system
+.RE
+.PP
+VMS interprets standard Unix (or PC) return values as other, scarier-looking
+things, so \fIzip\fP instead maps them into VMS-style status codes.  In
+general, \fIzip\fP sets VMS Facility = 1955 (0x07A3), Code = 2* Unix_status,
+and an appropriate Severity (as specified in ziperr.h).  More details are
+included in the VMS-specific documentation.  See [.vms]NOTES.TXT and
+[.vms]vms_msg_gen.c.
+.PD
+.SH BUGS
+.I zip
+3.0 is not compatible with PKUNZIP 1.10. Use
+.I zip
+1.1 to produce
+.I zip
+files which can be extracted by PKUNZIP 1.10.
+.PP
+.I zip
+files produced by
+.I zip
+3.0 must not be
+.I updated
+by
+.I zip
+1.1 or PKZIP 1.10, if they contain
+encrypted members or if they have been produced in a pipe or on a non-seekable
+device. The old versions of
+.I zip
+or PKZIP would create an archive with an incorrect format.
+The old versions can list the contents of the zip file
+but cannot extract it anyway (because of the new compression algorithm).
+If you do not use encryption and use regular disk files, you do
+not have to care about this problem.
+.LP
+Under VMS,
+not all of the odd file formats are treated properly.
+Only stream-LF format
+.I zip
+files are expected to work with
+.IR zip .
+Others can be converted using Rahul Dhesi's BILF program.
+This version of
+.I zip
+handles some of the conversion internally.
+When using Kermit to transfer zip files from VMS to MSDOS, type "set
+file type block" on VMS.  When transfering from MSDOS to VMS, type
+"set file type fixed" on VMS.  In both cases, type "set file type
+binary" on MSDOS.
+.LP
+Under some older VMS versions, \fIzip\fP may hang for file
+specifications that use DECnet syntax
+.I foo::*.*.
+.LP
+On OS/2, zip cannot match some names, such as those including an
+exclamation mark or a hash sign.  This is a bug in OS/2 itself: the
+32-bit DosFindFirst/Next don't find such names.  Other programs such
+as GNU tar are also affected by this bug.
+.LP
+Under OS/2, the amount of Extended Attributes displayed by DIR is (for
+compatibility) the amount returned by the 16-bit version of
+DosQueryPathInfo(). Otherwise OS/2 1.3 and 2.0 would report different
+EA sizes when DIRing a file.
+However, the structure layout returned by the 32-bit DosQueryPathInfo()
+is a bit different, it uses extra padding bytes and link pointers (it's
+a linked list) to have all fields on 4-byte boundaries for portability
+to future RISC OS/2 versions. Therefore the value reported by
+.I zip
+(which uses this 32-bit-mode size) differs from that reported by DIR.
+.I zip
+stores the 32-bit format for portability, even the 16-bit
+MS-C-compiled version running on OS/2 1.3, so even this one shows the
+32-bit-mode size.
+.SH AUTHORS
+Copyright (C) 1997-2008 Info-ZIP.
+.LP
+Currently distributed under the Info-ZIP license.
+.LP
+Copyright (C) 1990-1997 Mark Adler, Richard B. Wales, Jean-loup Gailly,
+Onno van der Linden, Kai Uwe Rommel, Igor Mandrichenko, John Bush and
+Paul Kienitz.
+.LP
+Original copyright:
+.LP
+Permission is granted to any individual or institution to use, copy, or
+redistribute this software so long as all of the original files are included,
+that it is not sold for profit, and that this copyright notice
+is retained.
+.LP
+LIKE ANYTHING ELSE THAT'S FREE, ZIP AND ITS ASSOCIATED UTILITIES ARE
+PROVIDED AS IS AND COME WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR
+IMPLIED. IN NO EVENT WILL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES
+RESULTING FROM THE USE OF THIS SOFTWARE.
+.LP
+Please send bug reports and comments using the web page at:
+.IR www.info-zip.org .
+For bug reports, please include the version of
+.IR zip
+(see \fIzip\ \-h\fR),
+the make options used to compile it (see \fIzip\ \-v\fR),
+the machine and operating system in use,
+and as much additional information as possible.
+.SH ACKNOWLEDGEMENTS
+Thanks to R. P. Byrne for his
+.I Shrink.Pas
+program, which inspired this project,
+and from which the shrink algorithm was stolen;
+to Phil Katz for placing in the public domain the
+.I zip
+file format, compression format, and .ZIP filename extension, and for
+accepting minor changes to the file format; to Steve Burg for
+clarifications on the deflate format; to Haruhiko Okumura and Leonid
+Broukhis for providing some useful ideas for the compression
+algorithm; to Keith Petersen, Rich Wales, Hunter Goatley and Mark
+Adler for providing a mailing list and
+.I ftp
+site for the Info-ZIP group to use; and most importantly, to the
+Info-ZIP group itself (listed in the file
+.IR infozip.who )
+without whose tireless testing and bug-fixing efforts a portable
+.I zip
+would not have been possible.
+Finally we should thank (blame) the first Info-ZIP moderator,
+David Kirschbaum,
+for getting us into this mess in the first place.
+The manual page was rewritten for Unix by R. P. C. Rodgers and
+updated by E. Gordon for \fIzip\fR 3.0.
+.\" end of file
diff --git a/man/zipcloak.1 b/man/zipcloak.1
new file mode 100644 (file)
index 0000000..8260b98
--- /dev/null
@@ -0,0 +1,111 @@
+.TH zipcloak 1 "v3.0 of 8 May 2008"
+.SH NAME
+zipcloak \- encrypt entries in a zipfile
+
+.SH SYNOPSIS
+.I zipcloak
+.RB [ \-d ]
+.RB [ \-b\ path ]
+.RB [ \-h ]
+.RB [ \-v ]
+.RB [ \-L ]
+zipfile
+
+.SH ARGUMENTS
+.in +13
+.ti -13
+zipfile  Zipfile to encrypt entries in
+
+.SH OPTIONS
+.TP
+.PD 0
+.B \-b\ \fPpath
+.TP
+.PD
+.B \-\-temp\-path \fPpath
+Use the directory given by path for the temporary zip file.
+
+.TP
+.PD 0
+.B \-d
+.TP
+.PD
+.B \-\-decrypt
+Decrypt encrypted entries (copy if given wrong password).
+
+.TP
+.PD 0
+.B \-h
+.TP
+.PD
+.B \-\-help\ 
+Show a short help.
+
+.TP
+.PD 0
+.B \-L
+.TP
+.PD
+.B \-\-license
+Show software license.
+
+.TP
+.PD 0
+.B \-O\ \fPpath
+.TP
+.PD
+.B \-\-output\-file\ \fPzipfile
+Write output to new archive zipfile, leaving original archive as is.
+
+.TP
+.PD 0
+.B \-q
+.TP
+.PD
+.B \-\-quiet
+Quiet operation.  Suppresses some informational messages.
+
+.TP
+.PD 0
+.B \-v
+.TP
+.PD
+.B \-\-version
+Show version information.
+
+.SH DESCRIPTION
+.I zipcloak
+encrypts all unencrypted entries in the zipfile.  This is the default action.
+
+.TP
+The \-d option is used to decrypt encrypted entries in the zipfile.
+
+.TP
+\fIzipcloak \fBuses original zip encryption which is considered weak.
+
+.TP
+Note:
+The encryption code of this program is not copyrighted and is put in
+the public domain.  It was originally written in Europe and can be freely
+distributed from any country including the U.S.A.  (Previously if this
+program was imported into the U.S.A, it could not be re-exported from
+the U.S.A to another country.)  See the file README.CR included in the
+source distribution for more on this.  Otherwise, the Info-ZIP license
+applies.
+
+.SH EXAMPLES
+To be added.
+
+.SH BUGS
+Large files (> 2 GB) and large archives not yet supported.
+
+Split archives not yet supported.  A work around is to convert the
+split archive to a single-file archive using \fIzip\fP and then
+use \fIzipcloak\fP on the single-file archive.  If needed, the
+resulting archive can then be split again using \fIzip\fP.
+
+
+.SH SEE ALSO
+zip(1), unzip(1)
+.SH AUTHOR
+Info-ZIP
diff --git a/man/zipnote.1 b/man/zipnote.1
new file mode 100644 (file)
index 0000000..fb4d18b
--- /dev/null
@@ -0,0 +1,85 @@
+.TH zipnote 1 "v3.0 of 8 May 2008"
+.SH NAME
+zipnote \- write the comments in zipfile to stdout, edit comments and rename files in zipfile
+
+.SH SYNOPSIS
+.I zipnote
+.RB [ \-w ]
+.RB [ \-b\ path ]
+.RB [ \-h ]
+.RB [ \-v ]
+.RB [ \-L ]
+zipfile
+
+.SH ARGUMENTS
+.in +13
+.ti -13
+zipfile  Zipfile to read comments from or edit.
+
+.SH OPTIONS
+.TP
+.BI \-w
+Write comments to a zipfile from stdin (see below).
+.TP
+.BI \-b\ \fRpath
+Use path for the temporary zip file.
+.TP
+.BI \-h
+Show a short help.
+.TP
+.BI \-v
+Show version information.
+.TP
+.BI \-L
+Show software license.
+
+.SH DESCRIPTION
+.I zipnote
+writes the comments in a zipfile to stdout.  This is the default mode.  A second mode
+allows updating the comments in a zipfile as well as allows changing the names
+of the files in the zipfile.  These modes are described below.
+
+.SH EXAMPLES
+To write all comments in a zipfile to stdout use for example
+.LP
+.nf
+     zipnote foo.zip > foo.tmp
+.fi
+.LP
+This writes all comments in the zipfile
+.I foo.zip
+to the file
+.I foo.tmp
+in a specific format.
+
+.LP
+If desired, this file can then be edited to change the comments and then used
+to update the zipfile.
+.LP
+.nf
+     zipnote -w foo.zip < foo.tmp
+.fi
+.LP
+The names of the files in the zipfile can also be changed in this way.  This is done by
+following lines like
+.nf
+     "@ name"
+.fi
+in the created temporary file (called
+.I foo.tmp
+here) with lines like
+.nf
+     "@=newname"
+.fi
+and then using the -w option as above.
+
+.SH BUGS
+The temporary file format is rather specific and zipnote is rather picky about it.
+It should be easier to change file names in a script.
+
+Does not yet support large (> 2 GB) or split archives.
+
+.SH SEE ALSO
+zip(1), unzip(1)
+.SH AUTHOR
+Info-ZIP
diff --git a/man/zipsplit.1 b/man/zipsplit.1
new file mode 100644 (file)
index 0000000..4a4de64
--- /dev/null
@@ -0,0 +1,69 @@
+.TH zipnote 1 "v3.0 of 8 May 2008"
+.SH NAME
+zipsplit \- split a zipfile into smaller zipfiles
+
+.SH SYNOPSIS
+.I zipsplit
+.RB [ \-t ]
+.RB [ \-i ]
+.RB [ \-p ]
+.RB [ \-s ]
+.RB [ \-n\ size ]
+.RB [ \-r\ room ]
+.RB [ \-b\ path ]
+.RB [ \-h ]
+.RB [ \-v ]
+.RB [ \-L ]
+zipfile
+
+.SH ARGUMENTS
+.in +13
+.ti -13
+zipfile  Zipfile to split.
+
+.SH OPTIONS
+.TP
+.BI \-t
+Report how many files it will take, but don't make them.
+.TP
+.BI \-i
+Make index (zipsplit.idx) and count its size against first zip file.
+.TP
+.BI \-n\ \fRsize
+Make zip files no larger than "size" (default = 36000).
+.TP
+.BI \-r\ \fRroom
+Leave room for "room" bytes on the first disk (default = 0).
+.TP
+.BI \-b\ \fRpath
+Use path for the output zip files.
+.TP
+.BI \-p
+Pause between output zip files.
+.TP
+.BI \-s
+Do a sequential split even if it takes more zip files.
+.TP
+.BI \-h
+Show a short help.
+.TP
+.BI \-v
+Show version information.
+.TP
+.BI \-L
+Show software license.
+
+.SH DESCRIPTION
+.I zipsplit
+reads a zipfile and splits it into smaller zipfiles.
+
+.SH EXAMPLES
+To be filled in.
+
+.SH BUGS
+Does not yet support large (> 2 GB) or split archives.
+
+.SH SEE ALSO
+zip(1), unzip(1)
+.SH AUTHOR
+Info-ZIP
diff --git a/match.S b/match.S
new file mode 100644 (file)
index 0000000..eb8f735
--- /dev/null
+++ b/match.S
@@ -0,0 +1,407 @@
+/*
+  Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2004-May-22 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/*
+ * match.s by Jean-loup Gailly. Translated to 32 bit code by Kai Uwe Rommel.
+ * The 68020 version has been written by Francesco Potorti` <pot@cnuce.cnr.it>
+ * with adaptations by Carsten Steger <stegerc@informatik.tu-muenchen.de>,
+ * Andreas Schwab <schwab@lamothe.informatik.uni-dortmund.de> and
+ * Kristoffer Eriksson <ske@pkmab.se>
+ */
+
+/* This file is NOT used in conjunction with zlib. */
+#ifndef USE_ZLIB
+
+/* Preprocess with -DNO_UNDERLINE if your C compiler does not prefix
+ * external symbols with an underline character '_'.
+ */
+#if defined(NO_UNDERLINE) || defined(__ELF__)
+#  define _prev             prev
+#  define _window           window
+#  define _match_start      match_start
+#  define _prev_length      prev_length
+#  define _good_match       good_match
+#  define _nice_match       nice_match
+#  define _strstart         strstart
+#  define _max_chain_length max_chain_length
+
+#  define _match_init       match_init
+#  define _longest_match    longest_match
+#endif
+
+#ifdef DYN_ALLOC
+  error: DYN_ALLOC not yet supported in match.s
+#endif
+
+/* Use 16-bytes alignment if your assembler supports it. Warning: gas
+ * uses a log(x) parameter (.align 4 means 16-bytes alignment). On SVR4
+ * the parameter is a number of bytes.
+ */
+#ifndef ALIGNMENT
+#  define ALIGNMENT 4
+#endif
+
+
+#ifndef WSIZE
+# define WSIZE          32768
+#endif
+#define MIN_MATCH       3
+#define MAX_MATCH       258
+#define MIN_LOOKAHEAD   (MAX_MATCH + MIN_MATCH + 1)
+#define MAX_DIST        (WSIZE - MIN_LOOKAHEAD)
+
+#if defined(i386) || defined(_I386) || defined(_i386) || defined(__i386)
+
+/* This version is for 386 Unix or OS/2 in 32 bit mode.
+ * Warning: it uses the AT&T syntax: mov source,dest
+ * This file is only optional. If you want to force the C version,
+ * add -DNO_ASM to CFLAGS in Makefile and set OBJA to an empty string.
+ * If you have reduced WSIZE in (g)zip.h, then make sure this is
+ * assembled with an equivalent -DWSIZE=<whatever>.
+ * This version assumes static allocation of the arrays (-DDYN_ALLOC not used).
+ */
+
+        .file   "match.S"
+
+        .globl  _match_init
+        .globl  _longest_match
+
+        .text
+
+_match_init:
+        ret
+
+/*-----------------------------------------------------------------------
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+
+        .align  ALIGNMENT
+
+_longest_match: /* int longest_match(cur_match) */
+
+#define cur_match   20(%esp)
+     /* return address */               /* esp+16 */
+        push    %ebp                    /* esp+12 */
+        push    %edi                    /* esp+8  */
+        push    %esi                    /* esp+4  */
+        push    %ebx                    /* esp    */
+
+/*
+ *      match        equ esi
+ *      scan         equ edi
+ *      chain_length equ ebp
+ *      best_len     equ ebx
+ *      limit        equ edx
+ */
+        mov     cur_match,%esi
+        mov     _strstart,%edx
+        mov     _max_chain_length,%ebp /* chain_length = max_chain_length */
+        mov     %edx,%edi
+        sub     $(MAX_DIST),%edx       /* limit = strstart-MAX_DIST */
+        cld                            /* string ops increment si and di */
+        jae     limit_ok
+        sub     %edx,%edx              /* limit = NIL */
+limit_ok:
+        add     $2+_window,%edi        /* edi = offset(window+strstart+2) */
+        mov     _prev_length,%ebx      /* best_len = prev_length */
+        movw    -2(%edi),%cx           /* cx = scan[0..1] */
+        movw    -3(%ebx,%edi),%ax      /* ax = scan[best_len-1..best_len] */
+        cmp     _good_match,%ebx       /* do we have a good match already? */
+        jb      do_scan
+        shr     $2,%ebp                /* chain_length >>= 2 */
+        jmp     do_scan
+
+        .align  ALIGNMENT
+long_loop:
+/* at this point, edi == scan+2, esi == cur_match */
+        movw    -3(%ebx,%edi),%ax       /* ax = scan[best_len-1..best_len] */
+        movw     -2(%edi),%cx           /* cx = scan[0..1] */
+short_loop:
+/*
+ * at this point, di == scan+2, si == cur_match,
+ * ax = scan[best_len-1..best_len] and cx = scan[0..1]
+ */
+        and     $(WSIZE-1), %esi
+        dec     %ebp                    /* --chain_length */
+        movw    _prev(,%esi,2),%si      /* cur_match = prev[cur_match] */
+                                        /* top word of esi is still 0 */
+        jz      the_end
+        cmp     %edx,%esi               /* cur_match <= limit ? */
+        jbe     the_end
+do_scan:
+        cmpw    _window-1(%ebx,%esi),%ax/* check match at best_len-1 */
+        jne     short_loop
+        cmpw    _window(%esi),%cx       /* check min_match_length match */
+        jne     short_loop
+
+        add     $2+_window,%esi         /* si = match */
+        mov     $((MAX_MATCH>>1)-1),%ecx/* scan for at most MAX_MATCH bytes */
+        mov     %edi,%eax               /* ax = scan+2 */
+        repe;   cmpsw                   /* loop until mismatch */
+        je      maxmatch                /* match of length MAX_MATCH? */
+mismatch:
+        movb    -2(%edi),%cl        /* mismatch on first or second byte? */
+        xchg    %edi,%eax           /* edi = scan+2, eax = end of scan */
+        subb    -2(%esi),%cl        /* cl = 0 if first bytes equal */
+        sub     %edi,%eax           /* eax = len */
+        sub     $2+_window,%esi     /* esi = cur_match + len */
+        sub     %eax,%esi           /* esi = cur_match */
+        subb    $1,%cl              /* set carry if cl == 0 (cannot use DEC) */
+        adc     $0,%eax             /* eax = carry ? len+1 : len */
+        cmp     %ebx,%eax           /* len > best_len ? */
+        jle     long_loop
+        mov     %esi,_match_start       /* match_start = cur_match */
+        mov     %eax,%ebx               /* ebx = best_len = len */
+#ifdef FULL_SEARCH
+        cmp     $(MAX_MATCH),%eax       /* len >= MAX_MATCH ? */
+#else
+        cmp     _nice_match,%eax        /* len >= nice_match ? */
+#endif
+        jl      long_loop
+the_end:
+        mov     %ebx,%eax               /* result = eax = best_len */
+        pop     %ebx
+        pop     %esi
+        pop     %edi
+        pop     %ebp
+        ret
+        .align  ALIGNMENT
+maxmatch:
+        cmpsb
+        jmp     mismatch
+
+#else /* !(i386 || _I386 || _i386 || __i386) */
+
+/* ======================== 680x0 version ================================= */
+
+#if defined(m68k)||defined(mc68k)||defined(__mc68000__)||defined(__MC68000__)
+#  ifndef mc68000
+#    define mc68000
+#  endif
+#endif
+
+#if defined(__mc68020__) || defined(__MC68020__) || defined(sysV68)
+#  ifndef mc68020
+#    define mc68020
+#  endif
+#endif
+
+#if defined(mc68020) || defined(mc68000)
+
+#if (defined(mc68020) || defined(NeXT)) && !defined(UNALIGNED_OK)
+#  define UNALIGNED_OK
+#endif
+
+#ifdef sysV68  /* Try Motorola Delta style */
+
+#  define GLOBAL(symbol)        global  symbol
+#  define TEXT                  text
+#  define FILE(filename)        file    filename
+#  define invert_maybe(src,dst) dst,src
+#  define imm(data)             &data
+#  define reg(register)         %register
+
+#  define addl                  add.l
+#  define addql                 addq.l
+#  define blos                  blo.b
+#  define bhis                  bhi.b
+#  define bras                  bra.b
+#  define clrl                  clr.l
+#  define cmpmb                 cmpm.b
+#  define cmpw                  cmp.w
+#  define cmpl                  cmp.l
+#  define lslw                  lsl.w
+#  define lsrl                  lsr.l
+#  define movel                 move.l
+#  define movew                 move.w
+#  define moveb                 move.b
+#  define moveml                movem.l
+#  define subl                  sub.l
+#  define subw                  sub.w
+#  define subql                 subq.l
+
+#  define IndBase(bd,An)        (bd,An)
+#  define IndBaseNdxl(bd,An,Xn) (bd,An,Xn.l)
+#  define IndBaseNdxw(bd,An,Xn) (bd,An,Xn.w)
+#  define predec(An)            -(An)
+#  define postinc(An)           (An)+
+
+#else /* default style (Sun 3, NeXT, Amiga, Atari) */
+
+#  define GLOBAL(symbol)        .globl  symbol
+#  define TEXT                  .text
+#  define FILE(filename)        .even
+#  define invert_maybe(src,dst) src,dst
+#  if defined(sun) || defined(mc68k)
+#    define imm(data)           #data
+#  else
+#    define imm(data)           \#data
+#  endif
+#  define reg(register)         register
+
+#  define blos                  bcss
+#  if defined(sun) || defined(mc68k)
+#    define movel               movl
+#    define movew               movw
+#    define moveb               movb
+#  endif
+#  define IndBase(bd,An)        An@(bd)
+#  define IndBaseNdxl(bd,An,Xn) An@(bd,Xn:l)
+#  define IndBaseNdxw(bd,An,Xn) An@(bd,Xn:w)
+#  define predec(An)            An@-
+#  define postinc(An)           An@+
+
+#endif  /* styles */
+
+#define Best_Len        reg(d0)         /* unsigned */
+#define Cur_Match       reg(d1)         /* Ipos */
+#define Loop_Counter    reg(d2)         /* int */
+#define Scan_Start      reg(d3)         /* unsigned short */
+#define Scan_End        reg(d4)         /* unsigned short */
+#define Limit           reg(d5)         /* IPos */
+#define Chain_Length    reg(d6)         /* unsigned */
+#define Scan_Test       reg(d7)
+#define Scan            reg(a0)         /* *uch */
+#define Match           reg(a1)         /* *uch */
+#define Prev_Address    reg(a2)         /* *Pos */
+#define Scan_Ini        reg(a3)         /* *uch */
+#define Match_Ini       reg(a4)         /* *uch */
+#define Stack_Pointer   reg(sp)
+
+        GLOBAL  (_match_init)
+        GLOBAL  (_longest_match)
+
+        TEXT
+
+        FILE    ("match.S")
+
+_match_init:
+        rts
+
+/*-----------------------------------------------------------------------
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+
+/* int longest_match (cur_match) */
+
+#ifdef UNALIGNED_OK
+#  define pushreg       15928           /* d2-d6/a2-a4 */
+#  define popreg        7292
+#else
+#  define pushreg       16184           /* d2-d7/a2-a4 */
+#  define popreg        7420
+#endif
+
+_longest_match:
+        movel   IndBase(4,Stack_Pointer),Cur_Match
+        moveml  imm(pushreg),predec(Stack_Pointer)
+        movel   _max_chain_length,Chain_Length
+        movel   _prev_length,Best_Len
+        movel   imm(_prev),Prev_Address
+        movel   imm(_window+MIN_MATCH),Match_Ini
+        movel   _strstart,Limit
+        movel   Match_Ini,Scan_Ini
+        addl    Limit,Scan_Ini
+        subw    imm(MAX_DIST),Limit
+        bhis    L__limit_ok
+        clrl    Limit
+L__limit_ok:
+        cmpl    invert_maybe(_good_match,Best_Len)
+        blos    L__length_ok
+        lsrl    imm(2),Chain_Length
+L__length_ok:
+        subql   imm(1),Chain_Length
+#ifdef UNALIGNED_OK
+        movew   IndBase(-MIN_MATCH,Scan_Ini),Scan_Start
+        movew   IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+#else
+        moveb   IndBase(-MIN_MATCH,Scan_Ini),Scan_Start
+        lslw    imm(8),Scan_Start
+        moveb   IndBase(-MIN_MATCH+1,Scan_Ini),Scan_Start
+        moveb   IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+        lslw    imm(8),Scan_End
+        moveb   IndBaseNdxw(-MIN_MATCH,Scan_Ini,Best_Len),Scan_End
+#endif
+        bras    L__do_scan
+
+L__long_loop:
+#ifdef UNALIGNED_OK
+        movew   IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+#else
+        moveb   IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+        lslw    imm(8),Scan_End
+        moveb   IndBaseNdxw(-MIN_MATCH,Scan_Ini,Best_Len),Scan_End
+#endif
+
+L__short_loop:
+        lslw    imm(1),Cur_Match
+        movew   IndBaseNdxl(0,Prev_Address,Cur_Match),Cur_Match
+        cmpw    invert_maybe(Limit,Cur_Match)
+        dbls    Chain_Length,L__do_scan
+        bras    L__return
+
+L__do_scan:
+        movel   Match_Ini,Match
+        addl    Cur_Match,Match
+#ifdef UNALIGNED_OK
+        cmpw    invert_maybe(IndBaseNdxw(-MIN_MATCH-1,Match,Best_Len),Scan_End)
+        bne     L__short_loop
+        cmpw    invert_maybe(IndBase(-MIN_MATCH,Match),Scan_Start)
+        bne     L__short_loop
+#else
+        moveb   IndBaseNdxw(-MIN_MATCH-1,Match,Best_Len),Scan_Test
+        lslw    imm(8),Scan_Test
+        moveb   IndBaseNdxw(-MIN_MATCH,Match,Best_Len),Scan_Test
+        cmpw    invert_maybe(Scan_Test,Scan_End)
+        bne     L__short_loop
+        moveb   IndBase(-MIN_MATCH,Match),Scan_Test
+        lslw    imm(8),Scan_Test
+        moveb   IndBase(-MIN_MATCH+1,Match),Scan_Test
+        cmpw    invert_maybe(Scan_Test,Scan_Start)
+        bne     L__short_loop
+#endif
+
+        movew   imm((MAX_MATCH-MIN_MATCH+1)-1),Loop_Counter
+        movel   Scan_Ini,Scan
+L__scan_loop:
+        cmpmb   postinc(Match),postinc(Scan)
+        dbne    Loop_Counter,L__scan_loop
+
+        subl    Scan_Ini,Scan
+        addql   imm(MIN_MATCH-1),Scan
+        cmpl    invert_maybe(Best_Len,Scan)
+        bls     L__short_loop
+        movel   Scan,Best_Len
+        movel   Cur_Match,_match_start
+#ifdef FULL_SEARCH
+        cmpl    invert_maybe(imm(MAX_MATCH),Best_Len)
+#else
+        cmpl    invert_maybe(_nice_match,Best_Len)
+#endif
+        blos    L__long_loop
+L__return:
+        moveml  postinc(Stack_Pointer),imm(popreg)
+        rts
+
+#else
+ error: this asm version is for 386 or 680x0 only
+#endif /* mc68000 || mc68020 */
+#endif /* i386 || _I386 || _i386 || __i386  */
+
+#endif /* !USE_ZLIB */
diff --git a/msdos/README.DOS b/msdos/README.DOS
new file mode 100644 (file)
index 0000000..0b9a57b
--- /dev/null
@@ -0,0 +1,132 @@
+README.DOS
+
+Some notes about the supplied MSDOS executables and their compilers:
+
+A) The 32-bit DOS executables "zip.exe" and the auxilary utilities
+   "zipnote.exe", "zipsplit.exe", "zipcloak.exe" (crypt-enabled distribution
+   only) were compiled with DJGPP v 2.03, using gcc 2.95.3 as compiler.
+   They require a DPMI server to run, e.g.: a DOS command prompt window
+   under WINDOWS 3.x or Windows 9x.  To use this program under plain DOS,
+   you should install the free (GPL'ed) DPMI server CWSDPMI.EXE.  Look
+   for "csdpmi5b.zip" under "simtelnet/gnu/djgpp/v2misc/" on the SimTelNet
+   home site "ftp.cdrom.com" or any mirror site of the SimtelNet archive.
+
+   We have decided to provide 32-bit rather than 16-bit executables of
+   the auxilary tools for the following reasons:
+   - Nowadays, it has become quite unlikely to find PC computers "in action"
+     that do not at least have an i386 CPU.
+   - the 32-bit versions do not impose additional archive handling limits
+     beyond those defined by the Zip archive format
+   - the 32-bit DJGPP executables can handle long filenames on systems running
+     Windows 95/98/Me and Windows 2K/XP.
+
+B) There are two 16-bit MSDOS executables provided in zcr2?x.zip:
+     zip16.exe     regular Zip program, requires ca. 455 KBytes of contiguous
+                   free DOS memory or more.
+     zip16-sm.exe  a variant that was compiled with the SMALL_MEM option
+                   for minimal memory consumption; requires at minimum
+                   322 KBytes of contiguous free DOS memory.
+
+   The SMALL_MEM variant requires much less space for the compression
+   buffers, but at the cost of some compression efficiency.
+   Therefore, we recommend to use the "SMALL_MEM" 16-bit "zip16-sm.exe" only
+   in case of "out of memory" problems (DOS memory is low and/or very large
+   number of archive entries), when the 32-bit program cannot be used for
+   some reason (286 or older; no DPMI server; ...).
+
+C) Hard limits of the Zip archive format:
+   Number of entries in Zip archive:            64 k (2^16 - 1 entries)
+   Compressed size of archive entry:            4 GByte (2^32 - 1 Bytes)
+   Uncompressed size of entry:                  4 GByte (2^32 - 1 Bytes)
+   Size of single-volume Zip archive:           4 GByte (2^32 - 1 Bytes)
+   Per-volume size of multi-volume archives:    4 GByte (2^32 - 1 Bytes)
+   Number of parts for multi-volume archives:   64 k (1^16 - 1 parts)
+   Total size of multi-volume archive:          256 TByte (4G * 64k)
+
+   The number of archive entries and of multivolume parts are limited by
+   the structure of the "end-of-central-directory" record, where the these
+   numbers are stored in 2-Byte fields.
+   Some Zip and/or UnZip implementations (for example Info-ZIP's) allow
+   handling of archives with more than 64k entries.  (The information
+   from "number of entries" field in the "end-of-central-directory" record
+   is not really neccessary to retrieve the contents of a Zip archive;
+   it should rather be used for consistency checks.)
+
+   Length of an archive entry name:             64 kByte (2^16 - 1)
+   Length of archive member comment:            64 kByte (2^16 - 1)
+   Total length of "extra field":               64 kByte (2^16 - 1)
+   Length of a single e.f. block:               64 kByte (2^16 - 1)
+   Length of archive comment:                   64 KByte (2^16 - 1)
+
+   Additional limitation claimed by PKWARE:
+     Size of local-header structure (fixed fields of 30 Bytes + filename
+      local extra field):                     < 64 kByte
+     Size of central-directory structure (46 Bytes + filename +
+      central extra field + member comment):  < 64 kByte
+
+D) Implementation limits of the Zip executables:
+
+ 1. Size limits caused by file I/O and compression handling:
+   Size of Zip archive:                 2 GByte (2^31 - 1 Bytes)
+   Compressed size of archive entry:    2 GByte (2^31 - 1 Bytes)
+   Uncompressed size of entry:          2 GByte (2^31 - 1 Bytes),
+                                        (could/should be 4 GBytes...)
+   Multi-volume archive creation is not supported.
+
+ 2. Limits caused by handling of archive contents lists
+
+ 2.1. Number of archive entries (freshen, update, delete)
+     a) 16-bit executable:              64k (2^16 -1) or 32k (2^15 - 1),
+                                        (unsigned vs. signed type of size_t)
+     a1) 16-bit executable:             <16k ((2^16)/4)
+         (The smaller limit a1) results from the array size limit of
+         the "qsort()" function.)
+         32-bit executables             <1G ((2^32)/4)
+         (usual system limit of the "qsort()" function on 32-bit systems)
+
+     b) stack space needed by qsort to sort list of archive entries
+
+     NOTE: In the current executables, overflows of limits a) and b) are NOT
+           checked!
+
+     c) amount of free memory to hold "central directory information" of
+        all archive entries; one entry needs:
+        96 bytes (32-bit) resp. 80 bytes (16-bit)
+        + 3 * length of entry name
+        + length of zip entry comment (when present)
+        + length of extra field(s) (when present, e.g.: UT needs 9 bytes)
+        + some bytes for book-keeping of memory allocation
+
+   Conclusion:
+     For systems with limited memory space (MSDOS, small AMIGAs, other
+     environments without virtual memory), the number of archive entries
+     is most often limited by condition c).
+     For example, with approx. 100 kBytes of free memory after loading and
+     initializing the program, a 16-bit DOS Zip cannot process more than 600
+     to 1000 (+) archive entries.  (For the 16-bit Windows DLL or the 16-bit
+     OS/2 port, limit c) is less important because Windows or OS/2 executables
+     are not restricted to the 1024k area of real mode memory.  These 16-bit
+     ports are limited by conditions a1) and b), say: at maximum approx.
+     16000 entries!)
+
+
+ 2.2. Number of "new" entries (add operation)
+     In addition to the restrictions above (2.1.), the following limits
+     caused by the handling of the "new files" list apply:
+
+     a) 16-bit executable:              <16k ((2^64)/4)
+
+     b) stack size required for "qsort" operation on "new entries" list.
+
+     NOTE: In the current executables, the overflow checks for these limits
+           are missing!
+
+     c) amount of free memory to hold the directory info list for new entries;
+        one entry needs:
+        24 bytes (32-bit) resp. 22 bytes (16-bit)
+        + 3 * length of filename
+
+
+Please report any problems to:  Zip-Bugs@lists.wku.edu
+
+Last updated:  07 July 2001
diff --git a/msdos/crc_i86.asm b/msdos/crc_i86.asm
new file mode 100644 (file)
index 0000000..3ad0349
--- /dev/null
@@ -0,0 +1,497 @@
+;===========================================================================
+; Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 2000-Apr-09 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+; Created by Christian Spieler, last modified 07 Jan 2007.
+;
+        TITLE   crc_i86.asm
+        NAME    crc_i86
+;
+; Optimized 8086 assembler version of the CRC32 calculation loop, intended
+; for real mode Info-ZIP programs (Zip 2.1, UnZip 5.2, and later versions).
+; Supported compilers are Microsoft C (DOS real mode) and Borland C(++)
+; (Turbo C). Watcom C (16bit) should also work.
+; This module was inspired by a similar module for the Amiga (Paul Kienitz).
+;
+; It replaces the `ulg crc32(ulg crc, ZCONST uch *buf, extent len)' function
+; in crc32.c.
+;
+; In March/April 1997, the code has been revised to incorporate Rodney Brown's
+; ideas for optimized access to the data buffer. For 8086 real mode code,
+; the data buffer is now accessed by aligned word-wide read operations.
+; This new optimization may be turned off by defining the macro switch
+; NO_16_BIT_LOADS.
+;
+; In December 1998, the loop branch commands were changed from "loop dest"
+; into "dec cx; jnz dest". On modern systems (486 and newer), the latter
+; code is usually much faster (e.g. 1 clock cycle compared to 5 for "loop"
+; on Pentium MMX). For the 286, the penalty of "dec cx; jnz" is one clock
+; cycle (12 vs. 11 cycles); on an 8088 the cycle counts are 22 (dec cx; jnz)
+; vs. 18 (loop). I decided to optimize for newer CPU models by default, because
+; I expect that old 80286 or 8088 dinosaurier machines may be rarely used
+; nowadays. In case you want optimum performance for these old CPU models
+; you should define the OPTIMIZE_286_88 macro switch on the assembler's
+; command line.
+; Likewise, "jcxz" was replaced by "jz", because the latter is faster on
+; 486 and newer CPUs (without any penalty on 80286 and older CPU models).
+;
+; In January 2007, the "hand-made" memory model setup section has been guarded
+; against redefinition of @CodeSize and @DataSize symbols, to work around a
+; problem with current Open Watcom (version 1.6) wasm assembler.
+;
+; The code in this module should work with all kinds of C memory models
+; (except Borland's __HUGE__ model), as long as the following
+; restrictions are not violated:
+;
+; - The implementation assumes that the char buffer is confined to a
+;   64k segment. The pointer `s' to the buffer must be in a format that
+;   all bytes can be accessed by manipulating the offset part, only.
+;   This means:
+;   + no huge pointers
+;   + char buffer size < 64 kByte
+;
+; - Since the buffer size argument `n' is of type `size_t' (= unsigned short)
+;   for this routine, the char buffer size is limited to less than 64 kByte,
+;   anyway. So, the assumption above should be easily fulfilled.
+;
+;==============================================================================
+;
+; Do NOT assemble this source if external crc32 routine from zlib gets used,
+; or only the precomputed CRC_32_Table is needed.
+;
+ifndef USE_ZLIB
+ifndef CRC_TABLE_ONLY
+;
+; Setup of amount of assemble time informational messages:
+;
+ifdef     DEBUG
+  VERBOSE_INFO EQU 1
+else
+  ifdef _AS_MSG_
+    VERBOSE_INFO EQU 1
+  else
+    VERBOSE_INFO EQU 0
+  endif
+endif
+;
+; Selection of memory model, and initialization of memory model
+; related macros:
+;
+ifndef __SMALL__
+  ifndef __COMPACT__
+    ifndef __MEDIUM__
+      ifndef __LARGE__
+        ifndef __HUGE__
+;         __SMALL__ EQU 1
+        endif
+      endif
+    endif
+  endif
+endif
+
+ifdef __HUGE__
+; .MODEL Huge
+   ifndef @CodeSize
+    @CodeSize  EQU 1
+   endif
+   ifndef @DataSize
+    @DataSize  EQU 1
+   endif
+   Save_DS    EQU 1
+   if VERBOSE_INFO
+    if1
+      %out Assembling for C, Huge memory model
+    endif
+   endif
+else
+   ifdef __LARGE__
+;      .MODEL Large
+      ifndef @CodeSize
+       @CodeSize  EQU 1
+      endif
+      ifndef @DataSize
+       @DataSize  EQU 1
+      endif
+      if VERBOSE_INFO
+       if1
+         %out Assembling for C, Large memory model
+       endif
+      endif
+   else
+      ifdef __COMPACT__
+;         .MODEL Compact
+         ifndef @CodeSize
+          @CodeSize  EQU 0
+         endif
+         ifndef @DataSize
+          @DataSize  EQU 1
+         endif
+         if VERBOSE_INFO
+          if1
+            %out Assembling for C, Compact memory model
+          endif
+         endif
+      else
+         ifdef __MEDIUM__
+;            .MODEL Medium
+            ifndef @CodeSize
+             @CodeSize  EQU 1
+            endif
+            ifndef @DataSize
+             @DataSize  EQU 0
+            endif
+            if VERBOSE_INFO
+             if1
+               %out Assembling for C, Medium memory model
+             endif
+            endif
+         else
+;            .MODEL Small
+            ifndef @CodeSize
+             @CodeSize  EQU 0
+            endif
+            ifndef @DataSize
+             @DataSize  EQU 0
+            endif
+            if VERBOSE_INFO
+             if1
+               %out Assembling for C, Small memory model
+             endif
+            endif
+         endif
+      endif
+   endif
+endif
+
+if @CodeSize
+        LCOD_OFS        EQU     2
+else
+        LCOD_OFS        EQU     0
+endif
+
+IF @DataSize
+        LDAT_OFS        EQU     2
+else
+        LDAT_OFS        EQU     0
+endif
+
+ifdef Save_DS
+;                       (di,si,ds)+(size, return address)
+        SAVE_REGS       EQU     6+(4+LCOD_OFS)
+else
+;                       (di,si)+(size, return address)
+        SAVE_REGS       EQU     4+(4+LCOD_OFS)
+endif
+
+;
+; Selection of the supported CPU instruction set and initialization
+; of CPU type related macros:
+;
+ifdef __686
+        Use_286_code    EQU     1
+        Align_Size      EQU     4       ; dword alignment on Pentium II/III/IV
+        Alig_PARA       EQU     1       ; paragraph aligned code segment
+else
+ifdef __586
+        Use_286_code    EQU     1
+        Align_Size      EQU     4       ; dword alignment on Pentium
+        Alig_PARA       EQU     1       ; paragraph aligned code segment
+else
+ifdef __486
+        Use_286_code     EQU    1
+        Align_Size       EQU    4       ; dword alignment on 32 bit processors
+        Alig_PARA        EQU    1       ; paragraph aligned code segment
+else
+ifdef __386
+        Use_286_code    EQU     1
+        Align_Size      EQU     4       ; dword alignment on 32 bit processors
+        Alig_PARA       EQU     1       ; paragraph aligned code segment
+else
+ifdef __286
+        Use_286_code    EQU     1
+        Align_Size      EQU     2       ; word alignment on 16 bit processors
+        Alig_PARA       EQU     0       ; word aligned code segment
+else
+ifdef __186
+        Use_186_code    EQU     1
+        Align_Size      EQU     2       ; word alignment on 16 bit processors
+        Alig_PARA       EQU     0       ; word aligned code segment
+else
+        Align_Size      EQU     2       ; word alignment on 16 bit processors
+        Alig_PARA       EQU     0       ; word aligned code segment
+endif   ;?__186
+endif   ;?__286
+endif   ;?__386
+endif   ;?__486
+endif   ;?__586
+endif   ;?__686
+
+ifdef Use_286_code
+        .286
+        Have_80x86      EQU     1
+else
+ifdef Use_186_code
+        .186
+        Have_80x86      EQU     1
+else
+        .8086
+        Have_80x86      EQU     0
+endif   ;?Use_186_code
+endif   ;?Use_286_code
+
+;
+; Declare the segments used in this module:
+;
+if @CodeSize
+if Alig_PARA
+CRC32_TEXT      SEGMENT  PARA PUBLIC 'CODE'
+else
+CRC32_TEXT      SEGMENT  WORD PUBLIC 'CODE'
+endif
+CRC32_TEXT      ENDS
+else    ;!@CodeSize
+if Alig_PARA
+_TEXT   SEGMENT  PARA PUBLIC 'CODE'
+else
+_TEXT   SEGMENT  WORD PUBLIC 'CODE'
+endif
+_TEXT   ENDS
+endif   ;?@CodeSize
+_DATA   SEGMENT  WORD PUBLIC 'DATA'
+_DATA   ENDS
+_BSS    SEGMENT  WORD PUBLIC 'BSS'
+_BSS    ENDS
+DGROUP  GROUP   _BSS, _DATA
+if @DataSize
+        ASSUME  DS: nothing, SS: DGROUP
+else
+        ASSUME  DS: DGROUP, SS: DGROUP
+endif
+
+if @CodeSize
+EXTRN   _get_crc_table:FAR
+else
+EXTRN   _get_crc_table:NEAR
+endif
+
+
+Do_CRC  MACRO
+        mov     bl,al
+        sub     bh,bh
+if Have_80x86
+        shl     bx,2
+else
+        shl     bx,1
+        shl     bx,1
+endif
+        mov     al,ah
+        mov     ah,dl
+        mov     dl,dh
+        sub     dh,dh
+        xor     ax,WORD PTR [bx][si]
+        xor     dx,WORD PTR [bx+2][si]
+        ENDM
+;
+Do_1    MACRO
+if @DataSize
+        xor     al,BYTE PTR es:[di]
+else
+        xor     al,BYTE PTR [di]
+endif
+        inc     di
+        Do_CRC
+        ENDM
+;
+Do_2    MACRO
+ifndef NO_16_BIT_LOADS
+if @DataSize
+        xor     ax,WORD PTR es:[di]
+else
+        xor     ax,WORD PTR [di]
+endif
+        add     di,2
+        Do_CRC
+        Do_CRC
+else
+        Do_1
+        Do_1
+endif
+        ENDM
+;
+Do_4    MACRO
+        Do_2
+        Do_2
+        ENDM
+;
+
+IF @CodeSize
+CRC32_TEXT      SEGMENT
+        ASSUME  CS: CRC32_TEXT
+else
+_TEXT   SEGMENT
+        ASSUME  CS: _TEXT
+endif
+; Line 37
+
+;
+;ulg crc32(ulg crc,
+;    ZCONST uch *buf,
+;    extent len)
+;
+        PUBLIC  _crc32
+if @CodeSize
+_crc32  PROC FAR
+else
+_crc32  PROC NEAR
+endif
+if Have_80x86
+        enter   WORD PTR 0,0
+else
+        push    bp
+        mov     bp,sp
+endif
+        push    di
+        push    si
+if @DataSize
+;       crc = 4+LCOD_OFS        DWORD (unsigned long)
+;       buf = 8+LCOD_OFS        DWORD PTR BYTE (uch *)
+;       len = 12+LCOD_OFS       WORD (unsigned int)
+else
+;       crc = 4+LCOD_OFS        DWORD (unsigned long)
+;       buf = 8+LCOD_OFS        WORD PTR BYTE (uch *)
+;       len = 10+LCOD_OFS       WORD (unsigned int)
+endif
+;
+if @DataSize
+        mov     ax,WORD PTR [bp+8+LCOD_OFS]     ; buf
+        or      ax,WORD PTR [bp+10+LCOD_OFS]    ;     == NULL ?
+else
+        cmp     WORD PTR [bp+8+LCOD_OFS],0      ; buf == NULL ?
+endif
+        jne     crc_update
+        sub     ax,ax                           ; crc = 0
+        cwd
+ifndef NO_UNROLLED_LOOPS
+        jmp     fine
+else
+        jmp     SHORT fine
+endif
+;
+crc_update:
+        call     _get_crc_table
+;  When used with compilers that conform to the Microsoft/Borland standard
+;  C calling convention, model-dependent handling is not needed, because
+;   _get_crc_table returns NEAR pointer.
+;  But Watcom C is different and does not allow one to assume DS pointing to
+;  DGROUP. So, we load DS with DGROUP, to be safe.
+;if @DataSize
+;       push    ds
+;       mov     ds,dx
+;       ASSUME  DS: nothing
+;endif
+        mov     si,ax                           ;crc_table
+if @DataSize
+        push    ds
+        mov     ax,SEG DGROUP
+        mov     ds,ax
+        ASSUME  DS: DGROUP
+endif
+;
+        mov     ax,WORD PTR [bp+4+LCOD_OFS]     ;crc
+        mov     dx,WORD PTR [bp+6+LCOD_OFS]
+        not     ax
+        not     dx
+if @DataSize
+        les     di,DWORD PTR [bp+8+LCOD_OFS]    ;buf
+        mov     cx,WORD PTR [bp+12+LCOD_OFS]    ;len
+else
+        mov     di,WORD PTR [bp+8+LCOD_OFS]     ;buf
+        mov     cx,WORD PTR [bp+10+LCOD_OFS]    ;len
+endif
+;
+ifndef NO_UNROLLED_LOOPS
+ifndef NO_16_BIT_LOADS
+        test    cx,cx
+        jnz     start
+        jmp     done
+start:  test    di,1
+        jz      is_wordaligned
+        dec     cx
+        Do_1
+        mov     WORD PTR [bp+10+LDAT_OFS+LCOD_OFS],cx
+is_wordaligned:
+endif ; !NO_16_BIT_LOADS
+if Have_80x86
+        shr     cx,2
+else
+        shr     cx,1
+        shr     cx,1
+endif
+        jz      No_Fours
+;
+        align   Align_Size              ; align destination of branch
+Next_Four:
+        Do_4
+ifndef OPTIMIZE_286_88
+        dec     cx                      ; on 286, "loop Next_Four" needs 11
+        jnz     Next_Four               ;  clocks, one less than this code
+else
+        loop    Next_Four
+endif
+;
+No_Fours:
+if @DataSize
+        mov     cx,WORD PTR [bp+12+LCOD_OFS]    ;len
+else
+        mov     cx,WORD PTR [bp+10+LCOD_OFS]    ;len
+endif
+        and     cx,00003H
+endif ; !NO_UNROLLED_LOOPS
+        jz      done
+;
+        align   Align_Size              ; align destination of branch
+Next_Byte:
+        Do_1
+ifndef OPTIMIZE_286_88
+        dec     cx                      ; on 286, "loop Next_Four" needs 11
+        jnz     Next_Byte               ;  clocks, one less than this code
+else
+        loop    Next_Four
+endif
+;
+done:
+if @DataSize
+        pop     ds
+;       ASSUME  DS: DGROUP
+        ASSUME  DS: nothing
+endif
+        not     ax
+        not     dx
+;
+fine:
+        pop     si
+        pop     di
+if Have_80x86
+        leave
+else
+        mov     sp,bp
+        pop     bp
+endif
+        ret
+
+_crc32  ENDP
+
+if @CodeSize
+CRC32_TEXT      ENDS
+else
+_TEXT   ENDS
+endif
+;
+endif ;!CRC_TABLE_ONLY
+endif ;!USE_ZLIB
+;
+END
diff --git a/msdos/makebz2.dj2 b/msdos/makebz2.dj2
new file mode 100644 (file)
index 0000000..161f1e3
--- /dev/null
@@ -0,0 +1,148 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# djgpp 2.x
+#
+# This simple modified version of makefile.dj2 adds bzip2 support
+# to Zip for djgpp 2.x and was donated by Robert Riebisch.
+#
+# Given standard djgpp 2.x and bzip2 installations, this should create a
+# version of Zip 3.0 with bzip2 support.  Additional information is in
+# bzip2/install.txt.
+#
+# 27 June 2008
+
+VPATH=.;msdos
+# ------------- djgpp -------------
+CPPFLAGS=-I. -DDOS -DASM_CRC -DBZIP2_SUPPORT $(LOCAL_ZIP)
+ASFLAGS=$(CPPFLAGS)
+CFLAGS=-Wall -O2 $(CPPFLAGS)
+UTILFLAGS=-c -DUTIL $(CFLAGS) -o
+CC=gcc
+LD=gcc
+LDFLAGS=-s
+
+# ------------- file packer --------
+# Laszlo Molnar who wrote DJ Packer and Markus F. X. J. Oberhumer who wrote
+# the compression library used by the DJ Packer have collaborated on the
+# Ultimate Packer for eXecutables, which has recently been released.  Look
+# for upx???d.zip at     http://upx.sourceforge.net
+# As an alternative, look for "djp.exe", now two years old, in the archive
+# mlp107[b,s].zip, found in the same location as csdpmi?[b,s].zip (see below).
+# If you have got an executable packer in your PATH, you may reduce the
+# size of the disk image of the zip*.exe's by uncommenting the lines
+# containing $(DJP) below where the exe's are built.
+#DJP=djp -q
+DJP=upx -qq --best
+
+# variables
+
+#set CRC32 to crc_gcc.o or nothing, depending on whether ASM_CRC is defined:
+CRCA_O = crc_gcc.o
+
+OBJZ = zip.o crypt.o ttyio.o zipfile.o zipup.o fileio.o util.o \
+       crc32.o $(CRCA_O) globals.o
+OBJI = deflate.o trees.o match.o msdos.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o msdos_.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o crc32_.o crypt_.o ttyio.o $(OBJU)
+OBJS = zipsplit.o $(OBJU)
+LIBS = -lbz2
+
+ZIP_H = zip.h ziperr.h tailor.h msdos/osdep.h
+
+# rules
+
+.SUFFIXES:    # Delete make's default suffix list
+.SUFFIXES:    .exe .out .a .ln .o .c .cc .C .p .f .F .y .l .s .S .h
+
+.c.o:
+       $(CC) -c $(CFLAGS) $< -o $@
+
+zips:  zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip.o:       zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+
+zipfile.o:    zipfile.c $(ZIP_H) crc32.h
+
+zipup.o:      zipup.c $(ZIP_H) revision.h crc32.h crypt.h msdos/zipup.h
+
+fileio.o:     fileio.c $(ZIP_H) crc32.h
+
+util.o:       util.c $(ZIP_H)
+
+globals.o:    globals.c $(ZIP_H)
+
+deflate.o:    deflate.c $(ZIP_H)
+
+trees.o:      trees.c $(ZIP_H)
+
+crc_gcc.o:    crc_i386.S
+       $(CC) $(ASFLAGS) -x assembler-with-cpp -c -o $@ crc_i386.S
+
+crc32.o:      crc32.c $(ZIP_H) crc32.h
+
+crypt.o:      crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+
+ttyio.o:      ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+msdos.o:      msdos/msdos.c $(ZIP_H)
+
+zipcloak.o:   zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+
+zipnote.o:    zipnote.c $(ZIP_H) revision.h
+
+zipsplit.o:   zipsplit.c $(ZIP_H) revision.h
+
+zipfile_.o:   zipfile.c $(ZIP_H) crc32.h
+       $(CC) $(UTILFLAGS) $@ zipfile.c
+
+fileio_.o:    fileio.c $(ZIP_H) crc32.h
+       $(CC) $(UTILFLAGS) $@ fileio.c
+
+util_.o:      util.c $(ZIP_H)
+       $(CC) $(UTILFLAGS) $@ util.c
+
+crc32_.o:     crc32.c $(ZIP_H) crc32.h
+       $(CC) $(UTILFLAGS) $@ crc32.c
+
+crypt_.o:     crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) $(UTILFLAGS) $@ crypt.c
+
+msdos_.o:     msdos/msdos.c $(ZIP_H)
+       $(CC) $(UTILFLAGS) $@ msdos/msdos.c
+
+
+match.o:      match.S
+       $(CC) $(ASFLAGS) -x assembler-with-cpp -c -o $@ match.S
+
+zip.exe: $(OBJZ) $(OBJI)
+       echo $(OBJZ) > zip.rsp
+       echo $(OBJI) >> zip.rsp
+       echo $(LIBS) >> zip.rsp
+       $(LD) $(LDFLAGS) -o $@ @zip.rsp
+       del zip.rsp
+#      stubedit $@ dpmi=cwsdpmi.exe
+#      $(DJP) $@
+
+zipcloak.exe: $(OBJC)
+       $(LD) $(LDFLAGS) $(OBJC) -o $@
+#      stubedit $@ dpmi=cwsdpmi.exe
+#      $(DJP) $@
+
+zipnote.exe: $(OBJN)
+       $(LD) $(LDFLAGS) $(OBJN) -o $@
+#      stubedit $@ dpmi=cwsdpmi.exe
+#      $(DJP) $@
+
+zipsplit.exe: $(OBJS)
+       $(LD) $(LDFLAGS) $(OBJS) -o $@
+#      stubedit $@ dpmi=cwsdpmi.exe
+#      $(DJP) $@
+
+# These stand alone executables require dpmi services to run.  When
+# running in a DOS window under windows 3.1 or later, the dpmi server
+# is automatically present.  Under DOS, if a dpmi server is not installed,
+# by default the program will look for "cwsdpmi.exe." If found, it will
+# be loaded for the duration of the program.
+# cwsdpmi is a "free" dpmi server written by Charles W. Sandmann
+# (sandman@clio.rice.edu).  It may be found, among other sites, on SimTel
+# and its mirrors in the .../vendors/djgpp/v2misc directory.
diff --git a/msdos/makefile.bor b/msdos/makefile.bor
new file mode 100644 (file)
index 0000000..88ecde4
--- /dev/null
@@ -0,0 +1,197 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# Borland (Turbo) C++ 1.0 or 2.0.
+# Warning: this file is not suitable for Turbo C 2.0. Use makefile.tc instead.
+
+# To use, do "make -fmakefile.bor"
+
+# WARNING: the small model is not supported.
+# Add -DSMALL_MEM or -DMEDIUM_MEM to the LOC macro if you wish to reduce
+# the memory requirements.
+# Add -DNO_ASM to CFLAGS and comment out the ASMOBJS definition if
+# you do not have tasm.
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = -DDOS -DNO_SECURE_TESTS $(LOCAL_ZIP)
+
+# Zip requires compact or large memory model.
+# with 2.1, compact model exceeds 64k code segment; use large model
+ZIPMODEL=l     # large model for Zip and ZipUtils
+
+# name of Flag to select memory model for assembler compiles, supported
+# values are __SMALL__ , __MEDIUM__ , __COMPACT__ , __LARGE__ :
+ASMODEL=__LARGE__              # keep in sync with ZIPMODEL definition !!
+
+# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc.
+CPU_TYP = 0
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+CRCA_O = crc_i86.obj
+ASMOBJS = match.obj $(CRCA_O)
+
+ASCPUFLAG = __$(CPU_TYP)86
+!if $(CPU_TYP) != 0
+CC_CPUFLG = -$(CPU_TYP)
+!endif
+
+VPATH=.;msdos
+# ------------- Turbo C++, Borland C++ -------------
+!if $(CC_REV) == 1
+CC = tcc
+!else
+! if !$(CC_REV)
+CC_REV = 3
+! endif
+CC = bcc
+!endif
+
+MODEL=-m$(ZIPMODEL)
+!if $(CC_REV) == 1
+CFLAGS=-w -w-eff -w-def -w-sig -w-cln -a -d -G -O -Z $(CC_CPUFLG) $(MODEL) $(LOC)
+!else
+CFLAGS=-w -w-cln -O2 -Z $(CC_CPUFLG) $(MODEL) $(LOC)
+!endif
+UTILFLAGS=-DUTIL $(CFLAGS) -o
+# for Turbo C++ 1.0, replace bcc with tcc and use the upper version of CFLAGS
+
+AS=tasm
+ASFLAGS=-ml -t -m2 -DDYN_ALLOC -DSS_NEQ_DS -D$(ASCPUFLAG) -D$(ASMODEL) $(LOC)
+
+LD=$(CC)
+LDFLAGS=$(MODEL)
+
+# ------------- Common declarations:
+STRIP=@rem
+#    If you don't have UPX, LZEXE, or PKLITE, get one of them. Then define:
+#    (NOTE: upx needs a 386 or higher system to run the exe compressor)
+#STRIP=upx --8086 --best
+#    or
+#STRIP=lzexe
+#    or (if you've registered PKLITE)
+#STRIP=pklite
+#    This makes a big difference in .exe size (and possibly load time)
+
+# ------------- Used by install rule
+# set BIN to the directory you want to install the executables to
+BIN = c:\util
+
+# variables
+OBJZ = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+       crc32.obj globals.obj
+
+OBJI = deflate.obj trees.obj $(ASMOBJS) msdos.obj
+
+OBJU = zipfile_.obj fileio_.obj util_.obj globals.obj msdos_.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj crc32_.obj crypt_.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h msdos/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips:  $(ZIPS)
+
+zip.obj:       zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipfile.obj:   zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipup.obj:     zipup.c $(ZIP_H) revision.h crc32.h crypt.h msdos/zipup.h
+       $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj:    fileio.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+util.obj:      util.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+globals.obj:   globals.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj:   deflate.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+trees.obj:     trees.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj:     crc32.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj:     crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj:     ttyio.c $(ZIP_H) crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+msdos.obj:     msdos/msdos.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) msdos/$*.c
+
+zipcloak.obj:  zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipnote.obj:   zipnote.c $(ZIP_H) revision.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipsplit.obj:  zipsplit.c $(ZIP_H) revision.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipfile_.obj:  zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS)$* zipfile.c
+
+fileio_.obj:   fileio.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS)$* fileio.c
+
+util_.obj:     util.c $(ZIP_H)
+       $(CC) -c $(UTILFLAGS)$* util.c
+
+crc32_.obj:    crc32.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS) crc32.c
+
+crypt_.obj:    crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c $(UTILFLAGS)$* crypt.c
+
+msdos_.obj:    msdos/msdos.c $(ZIP_H)
+       $(CC) -c $(UTILFLAGS)$* msdos/msdos.c
+
+crc_i86.obj:   msdos/crc_i86.asm
+       $(AS) $(ASFLAGS) msdos\crc_i86.asm ;
+
+match.obj:     msdos/match.asm
+       $(AS) $(ASFLAGS) msdos\match.asm ;
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zip.exe: $(OBJZ) $(OBJI)
+       echo $(OBJZ) > zip.rsp
+       echo $(OBJI) >> zip.rsp
+       $(LD) $(LDFLAGS) @zip.rsp
+       del zip.rsp
+       $(STRIP) zip.exe
+
+zipcloak.exe: $(OBJC)
+       echo $(OBJC) > zipc.rsp
+       $(LD) $(LDFLAGS) @zipc.rsp
+       del zipc.rsp
+       $(STRIP) zipcloak.exe
+
+zipnote.exe: $(OBJN)
+       echo $(OBJN) > zipn.rsp
+       $(LD) $(LDFLAGS) @zipn.rsp
+       del zipn.rsp
+       $(STRIP) zipnote.exe
+
+zipsplit.exe: $(OBJS)
+       echo $(OBJS) > zips.rsp
+       $(LD) $(LDFLAGS) @zips.rsp
+       del zips.rsp
+       $(STRIP) zipsplit.exe
+
+install:       $(ZIPS)
+       copy /b *.exe $(BIN)
+
+clean:
+       del *.obj
+       del *.exe
diff --git a/msdos/makefile.dj1 b/msdos/makefile.dj1
new file mode 100644 (file)
index 0000000..05137cc
--- /dev/null
@@ -0,0 +1,126 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# djgpp 1.x
+VPATH=.;msdos
+# ------------- djgpp -------------
+CPPFLAGS=-I. -DDOS -DASM_CRC $(LOCAL_ZIP)
+ASFLAGS=$(CPPFLAGS)
+CFLAGS=-Wall -O2 -m486 $(CPPFLAGS)
+UTILFLAGS=-c -DUTIL $(CFLAGS) -o
+CC=gcc
+LD=gcc
+LDFLAGS=-s
+
+STRIP=strip
+
+# Change the STUBIFY definition to the upper version if you want to create
+# executables which can be used without any external extender file.
+# >>> NOTE: Either copy the go32 extender into your build directory, or
+# >>>       edit the STUBIFY macro and add the correct path to "go32.exe".
+#STUBIFY=coff2exe -s go32.exe
+STUBIFY=coff2exe
+
+# variables
+
+#set CRCA_O to crc_gcc.o or nothing, depending on whether ASM_CRC is defined:
+CRCA_O = crc_gcc.o
+
+OBJZ = zip.o crypt.o ttyio.o zipfile.o zipup.o fileio.o util.o \
+       crc32.o $(CRCA_O) globals.o
+OBJI = deflate.o trees.o match.o msdos.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o msdos_.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o crc32_.o crypt_.o ttyio.o $(OBJU)
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h msdos/osdep.h
+
+# rules
+
+.SUFFIXES:    # Delete make's default suffix list
+.SUFFIXES:    .exe .out .a .ln .o .c .cc .C .p .f .F .y .l .s .S .h
+
+.c.o:
+       $(CC) -c $(CFLAGS) $< -o $@
+
+zips:  zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip.o:       zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+
+zipfile.o:    zipfile.c $(ZIP_H) crc32.h
+
+zipup.o:      zipup.c $(ZIP_H) revision.h crc32.h crypt.h msdos/zipup.h
+
+fileio.o:     fileio.c $(ZIP_H)
+
+util.o:       util.c $(ZIP_H)
+
+globals.o:    globals.c $(ZIP_H)
+
+deflate.o:    deflate.c $(ZIP_H)
+
+trees.o:      trees.c $(ZIP_H)
+
+crc_gcc.o:    crc_i386.S
+       $(CC) $(ASFLAGS) -x assembler-with-cpp -c -o $@ crc_i386.S
+
+crc32.o:      crc32.c $(ZIP_H) crc32.h
+
+crypt.o:      crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+
+ttyio.o:      ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+msdos.o:      msdos/msdos.c $(ZIP_H)
+
+zipcloak.o:   zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+
+zipnote.o:    zipnote.c $(ZIP_H) revision.h
+
+zipsplit.o:   zipsplit.c $(ZIP_H) revision.h
+
+zipfile_.o:   zipfile.c $(ZIP_H) crc32.h
+       $(CC) $(UTILFLAGS) $@ zipfile.c
+
+fileio_.o:    fileio.c $(ZIP_H) crc32.h
+       $(CC) $(UTILFLAGS) $@ fileio.c
+
+util_.o:      util.c $(ZIP_H)
+       $(CC) $(UTILFLAGS) $@ util.c
+
+crc32_.o:     crc32.c $(ZIP_H) crc32.h
+       $(CC) $(UTILFLAGS) $@ crc32.c
+
+crypt_.o:     crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) $(UTILFLAGS) $@ crypt.c
+
+msdos_.o:     msdos/msdos.c $(ZIP_H)
+       $(CC) $(UTILFLAGS) $@ msdos/msdos.c
+
+match.o:      match.S
+       $(CC) $(ASFLAGS) -x assembler-with-cpp -c -o $@ match.S
+
+zip.exe: $(OBJZ) $(OBJI)
+       echo $(OBJZ) > zip.rsp
+       echo $(OBJI) >> zip.rsp
+       $(LD) $(LDFLAGS) -o zip @zip.rsp
+       del zip.rsp
+       $(STRIP) zip
+       $(STUBIFY) zip
+       del zip
+
+zipcloak.exe: $(OBJC)
+       $(LD) $(LDFLAGS) $(OBJC) -o zipcloak
+       $(STRIP) zipcloak
+       $(STUBIFY) zipcloak
+       del zipcloak
+
+zipnote.exe: $(OBJN)
+       $(LD) $(LDFLAGS) $(OBJN) -o zipnote
+       $(STRIP) zipnote
+       $(STUBIFY) zipnote
+       del zipnote
+
+zipsplit.exe: $(OBJS)
+       $(LD) $(LDFLAGS) $(OBJS) -o zipsplit
+       $(STRIP) zipsplit
+       $(STUBIFY) zipsplit
+       del zipsplit
diff --git a/msdos/makefile.dj2 b/msdos/makefile.dj2
new file mode 100644 (file)
index 0000000..39192ee
--- /dev/null
@@ -0,0 +1,136 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# djgpp 2.x
+VPATH=.;msdos
+# ------------- djgpp -------------
+CPPFLAGS=-I. -DDOS -DASM_CRC $(LOCAL_ZIP)
+ASFLAGS=$(CPPFLAGS)
+CFLAGS=-Wall -O2 $(CPPFLAGS)
+UTILFLAGS=-c -DUTIL $(CFLAGS) -o
+CC=gcc
+LD=gcc
+LDFLAGS=-s
+
+# ------------- file packer --------
+# Laszlo Molnar who wrote DJ Packer and Markus F. X. J. Oberhumer who wrote
+# the compression library used by the DJ Packer have collaborated on the
+# Ultimate Packer for eXecutables, which has recently been released.  Look
+# for upx???d.zip at     http://upx.sourceforge.net
+# As an alternative, look for "djp.exe", now two years old, in the archive
+# mlp107[b,s].zip, found in the same location as csdpmi?[b,s].zip (see below).
+# If you have got an executable packer in your PATH, you may reduce the
+# size of the disk image of the zip*.exe's by uncommenting the lines
+# containing $(DJP) below where the exe's are built.
+#DJP=djp -q
+DJP=upx -qq --best
+
+# variables
+
+#set CRC32 to crc_gcc.o or nothing, depending on whether ASM_CRC is defined:
+CRCA_O = crc_gcc.o
+
+OBJZ = zip.o crypt.o ttyio.o zipfile.o zipup.o fileio.o util.o \
+       crc32.o $(CRCA_O) globals.o
+OBJI = deflate.o trees.o match.o msdos.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o msdos_.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o crc32_.o crypt_.o ttyio.o $(OBJU)
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h msdos/osdep.h
+
+# rules
+
+.SUFFIXES:    # Delete make's default suffix list
+.SUFFIXES:    .exe .out .a .ln .o .c .cc .C .p .f .F .y .l .s .S .h
+
+.c.o:
+       $(CC) -c $(CFLAGS) $< -o $@
+
+zips:  zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip.o:       zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+
+zipfile.o:    zipfile.c $(ZIP_H) crc32.h
+
+zipup.o:      zipup.c $(ZIP_H) revision.h crc32.h crypt.h msdos/zipup.h
+
+fileio.o:     fileio.c $(ZIP_H) crc32.h
+
+util.o:       util.c $(ZIP_H)
+
+globals.o:    globals.c $(ZIP_H)
+
+deflate.o:    deflate.c $(ZIP_H)
+
+trees.o:      trees.c $(ZIP_H)
+
+crc_gcc.o:    crc_i386.S
+       $(CC) $(ASFLAGS) -x assembler-with-cpp -c -o $@ crc_i386.S
+
+crc32.o:      crc32.c $(ZIP_H) crc32.h
+
+crypt.o:      crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+
+ttyio.o:      ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+msdos.o:      msdos/msdos.c $(ZIP_H)
+
+zipcloak.o:   zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+
+zipnote.o:    zipnote.c $(ZIP_H) revision.h
+
+zipsplit.o:   zipsplit.c $(ZIP_H) revision.h
+
+zipfile_.o:   zipfile.c $(ZIP_H) crc32.h
+       $(CC) $(UTILFLAGS) $@ zipfile.c
+
+fileio_.o:    fileio.c $(ZIP_H) crc32.h
+       $(CC) $(UTILFLAGS) $@ fileio.c
+
+util_.o:      util.c $(ZIP_H)
+       $(CC) $(UTILFLAGS) $@ util.c
+
+crc32_.o:     crc32.c $(ZIP_H) crc32.h
+       $(CC) $(UTILFLAGS) $@ crc32.c
+
+crypt_.o:     crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) $(UTILFLAGS) $@ crypt.c
+
+msdos_.o:     msdos/msdos.c $(ZIP_H)
+       $(CC) $(UTILFLAGS) $@ msdos/msdos.c
+
+
+match.o:      match.S
+       $(CC) $(ASFLAGS) -x assembler-with-cpp -c -o $@ match.S
+
+zip.exe: $(OBJZ) $(OBJI)
+       echo $(OBJZ) > zip.rsp
+       echo $(OBJI) >> zip.rsp
+       $(LD) $(LDFLAGS) -o $@ @zip.rsp
+       del zip.rsp
+#      stubedit $@ dpmi=cwsdpmi.exe
+#      $(DJP) $@
+
+zipcloak.exe: $(OBJC)
+       $(LD) $(LDFLAGS) $(OBJC) -o $@
+#      stubedit $@ dpmi=cwsdpmi.exe
+#      $(DJP) $@
+
+zipnote.exe: $(OBJN)
+       $(LD) $(LDFLAGS) $(OBJN) -o $@
+#      stubedit $@ dpmi=cwsdpmi.exe
+#      $(DJP) $@
+
+zipsplit.exe: $(OBJS)
+       $(LD) $(LDFLAGS) $(OBJS) -o $@
+#      stubedit $@ dpmi=cwsdpmi.exe
+#      $(DJP) $@
+
+# These stand alone executables require dpmi services to run.  When
+# running in a DOS window under windows 3.1 or later, the dpmi server
+# is automatically present.  Under DOS, if a dpmi server is not installed,
+# by default the program will look for "cwsdpmi.exe." If found, it will
+# be loaded for the duration of the program.
+# cwsdpmi is a "free" dpmi server written by Charles W. Sandmann
+# (sandman@clio.rice.edu).  It may be found, among other sites, on SimTel
+# and its mirrors in the .../vendors/djgpp/v2misc directory.
diff --git a/msdos/makefile.emx b/msdos/makefile.emx
new file mode 100644 (file)
index 0000000..3a50b5b
--- /dev/null
@@ -0,0 +1,169 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit
+# using emx 0.9c for DOS.
+# By Kai-Uwe Rommel, Chr. Spieler, E-Yen Tan (and others).
+# Last updated 7th January 2007.
+#
+# This Makefile is a stripped down version of win32/Makefile.emx that
+# builds executables applying the default MSDOS emx setup.  For variant
+# targets (using zlib), and cross-compilation for WIN32 or OS/2, take a
+# look into "win32/makefile.emx" resp. "os2/makefile.os2".
+#
+# Supported Make utilities:
+# - Microsoft/IBM nmake (e.g. from MSC 6.0 or newer)
+# - dmake 3.8 or higher
+# - GNU make, at least version 3.68 (GNUish 16-bit port, RSXNT Make 3.75 in a
+#   Win95/WinNT DOS box, DJGPP v1.12 Make 3.71, some versions of DJGPP v2.x
+#   32-bit Make; current DJGPP v2.01 Make 3.76.1 does NOT work)
+# - NOT watcom make
+# The "smart" Make utilities mentioned below are Christian Spieler's
+# enhanced version of GNUish 16-bit Make (3.74) and his adaption of these
+# GNU Make sources to EMX (32-bit).
+
+# Supported 32-bit C Compilers for MSDOS:
+# - GNU gcc (emx kit 0.9c or newer, 32-bit)
+
+# Supported Assemblers:
+# - GNU as with GNU gcc
+
+
+# To use, enter "make/nmake/dmake -f msdos/makefile.emx"
+# (this makefile depends on its name being "msdos/makefile.emx").
+
+# emx 0.9c, gcc, a.out format, for MS-DOS
+CC=gcc -O2 -m486 -Wall
+CFLAGS=-DDOS -DMSDOS -DASM_CRC
+AS=gcc
+ASFLAGS=-Di386
+LDFLAGS=-o ./
+LDFLAGS2=-s -Zsmall-conv
+OUT=-o
+OBJ=.o
+CRCA_O=crc_gcc.o
+OBJA=matchgcc.o
+OBJZS=msdos.o
+OBJUS=msdos_.o
+OSDEP_H=msdos/osdep.h
+ZIPUP_H=msdos/zipup.h
+
+#default settings for target dependent macros:
+DIRSEP = /
+AS_DIRSEP = /
+RM = del
+LOCAL_OPTS = $(LOCAL_ZIP)
+CCFLAGS = $(CFLAGS) $(LOCAL_OPTS)
+
+
+OBJZ1 = zip$(OBJ) zipfile$(OBJ) zipup$(OBJ) fileio$(OBJ) util$(OBJ) \
+       crc32$(OBJ) $(CRCA_O)
+OBJZ2 = globals$(OBJ) deflate$(OBJ) trees$(OBJ) crypt$(OBJ) \
+       ttyio$(OBJ)
+OBJZ  = $(OBJZ1) $(OBJZ2) $(OBJZS) $(OBJA)
+
+OBJU1 = zipfile_$(OBJ) fileio_$(OBJ) util_$(OBJ) globals$(OBJ)
+OBJU  = $(OBJU1) $(OBJUS)
+
+OBJN  = zipnote$(OBJ) $(OBJU)
+OBJS  = zipsplit$(OBJ) $(OBJU)
+OBJC1 = zipcloak$(OBJ) crc32_$(OBJ) crypt_$(OBJ) ttyio$(OBJ)
+OBJC  = $(OBJC1) $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h $(OSDEP_H)
+
+# rules
+
+.SUFFIXES: .c $(OBJ)
+
+.c$(OBJ):
+       $(CC) -c -I. $(CCFLAGS) $(OUT)$@ $<
+
+# targets
+
+all:    zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip$(OBJ):      zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipfile$(OBJ):  zipfile.c $(ZIP_H) crc32.h
+zipup$(OBJ):    zipup.c $(ZIP_H) revision.h crc32.h crypt.h $(ZIPUP_H)
+fileio$(OBJ):   fileio.c $(ZIP_H) crc32.h
+util$(OBJ):     util.c $(ZIP_H)
+globals$(OBJ):  globals.c $(ZIP_H)
+deflate$(OBJ):  deflate.c $(ZIP_H)
+trees$(OBJ):    trees.c $(ZIP_H)
+crc32$(OBJ):    crc32.c $(ZIP_H) crc32.h
+crypt$(OBJ):    crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio$(OBJ):    ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+msdos$(OBJ):    msdos/msdos.c $(ZIP_H)
+       $(CC) -c -I. $(CCFLAGS) msdos$(DIRSEP)msdos.c
+
+win32zip$(OBJ): win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+       $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)win32zip.c
+
+win32$(OBJ):    win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)win32.c
+
+nt$(OBJ):       win32/nt.c $(ZIP_H) win32/nt.h
+       $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)nt.c
+
+crc_gcc$(OBJ):  crc_i386.S                                      # 32bit, GNU AS
+       $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o $@ crc_i386.S
+
+matchgcc$(OBJ): match.S
+       $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o $@ match.S
+
+zipcloak$(OBJ): zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipnote$(OBJ):  zipnote.c $(ZIP_H) revision.h
+zipsplit$(OBJ): zipsplit.c $(ZIP_H) revision.h
+
+zipfile_$(OBJ): zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ zipfile.c
+
+fileio_$(OBJ):  fileio.c $(ZIP_H) crc32.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ fileio.c
+
+util_$(OBJ):    util.c $(ZIP_H)
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ util.c
+
+crc32_$(OBJ):   crc32.c $(ZIP_H) crc32.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ crc32.c
+
+crypt_$(OBJ):   crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ crypt.c
+
+msdos_$(OBJ):   msdos/msdos.c $(ZIP_H)
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ msdos$(DIRSEP)msdos.c
+
+win32_$(OBJ):   win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ win32$(DIRSEP)win32.c
+
+# This next bit is nasty, but is needed to overcome the MS-DOS command
+# line limit as response files for emx's gcc seem to only work if each
+# file is on a different line. DJGPP doesn't do this (if you are at all
+# interested).
+
+zip.exe: $(OBJZ)
+# for DUMB make utilities, uncomment the following commands:
+       -@$(RM) zip.rsp
+       @for %%f in ($(OBJZ1)) do echo %%f >> zip.rsp
+       @for %%f in ($(OBJZ2)) do echo %%f >> zip.rsp
+       @for %%f in ($(OBJZS) $(OBJA)) do echo %%f >> zip.rsp
+       $(CC) $(LDFLAGS)$@ @zip.rsp $(LDFLAGS2)
+       @$(RM) zip.rsp
+# smart make utilities (like well done ports of GNU Make) can use this:
+#      $(CC) $(LDFLAGS)$@ $(OBJZ) $(LDFLAGS2)
+
+zipcloak.exe: $(OBJC)
+# for DUMB make utilities, uncomment the following commands:
+       -@$(RM) zipcloak.rsp
+       @for %%f in ($(OBJC1)) do echo %%f >> zipcloak.rsp
+       @for %%f in ($(OBJU1)) do echo %%f >> zipcloak.rsp
+       @for %%f in ($(OBJUS)) do echo %%f >> zipcloak.rsp
+       $(CC) $(LDFLAGS)$@ @zipcloak.rsp $(LDFLAGS2)
+       @$(RM) zipcloak.rsp
+# smart make utilities (like well done ports of GNU Make) can use this:
+#      $(CC) $(LDFLAGS)$@ $(OBJC) $(LDFLAGS2)
+
+zipnote.exe: $(OBJN)
+       $(CC) $(LDFLAGS)$@ $(OBJN) $(LDFLAGS2)
+
+zipsplit.exe: $(OBJS)
+       $(CC) $(LDFLAGS)$@ $(OBJS) $(LDFLAGS2)
diff --git a/msdos/makefile.msc b/msdos/makefile.msc
new file mode 100644 (file)
index 0000000..a7ec9c9
--- /dev/null
@@ -0,0 +1,209 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# Microsoft C 5.1 and above.
+
+# To use, do "make makefile.msc"
+
+# Add -DSMALL_MEM or -DMEDIUM_MEM to the LOC macro if you wish to reduce
+# the memory requirements.
+# Add -DNO_ASM to CFLAGS and comment out the ASMOBJS definition if
+# you do not have masm.
+#
+# If you want link Zip against zlib to replace the built-in deflate routines,
+# the following changes are required:
+# - in the definition of "LOC", add "-DUSE_ZLIB" and remove "-DNO_SECURE_TESTS"
+# - comment out the "ASMOBJS" symbol definition
+# - modify the linking command blocks for zip and zipcloak according to
+#   the following scheme:
+#   add a command line "echo ,,,zlib_$(ZIPMODEL); >> zip[c].rsp" just
+#   before the "$(LD)..." line; and remove the semicolon character from the
+#   "echo ..." line immediately preceding the just inserted command
+
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = -DDOS -DDYN_ALLOC -DNO_SECURE_TESTS $(LOCAL_ZIP)
+
+# Zip requires compact or large memory model.
+# with 2.1, compact model exceeds 64k code segment; use large model
+ZIPMODEL=L     # large model for Zip and ZipUtils
+
+# name of Flag to select memory model for assembler compiles, supported
+# values are __SMALL__ , __MEDIUM__ , __COMPACT__ , __LARGE__ :
+ASMODEL=__LARGE__              # keep in sync with ZIPMODEL definition !!
+
+# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc.
+CPU_TYP = 0
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+ASMOBJS = match.obj crc_i86.obj
+
+ASCPUFLAG = __$(CPU_TYP)86
+
+# ------------- Microsoft C 5.1, 6.0, 7.0 and VC++ Pro 1.0 -------------
+CC=cl
+MODEL=-A$(ZIPMODEL)
+FP=
+# With the feature additions of Zip 3, the default data segment gets occupied
+# with too much initialized data to fit into 64k. As a workaround, for some
+# source files with large amount of message strings, -Gt<num> is used to
+# force data items of size <num> or larger into their own data segments.
+COMMON_CFLAGS=-nologo -I. $(MODEL) $(FP) -DMSC $(LOC) -W3 -G$(CPU_TYP)
+CFLAGS=$(COMMON_CFLAGS) -Ox
+SPECFLAGS=$(COMMON_CFLAGS) -Oaict -Gs
+# For MSC/C++ 7.0 and VC++ no special flags are needed:
+# SPECFLAGS=$(CFLAGS)
+UTILFLAGS=-DUTIL $(CFLAGS) -Fo
+
+AS=masm
+ASFLAGS=-ml -t -D$(ASCPUFLAG) -D$(ASMODEL) $(LOC)
+#     For MSC 6.0, use:
+#AS=ml
+#ASFLAGS=-c -D$(ASCPUFLAG) -D$(ASMODEL) $(LOC)
+# Supress -DDYN_ALLOC in ASFLAGS if you have suppressed it in CFLAGS
+
+LD=link
+LDFLAGS=/noi/farcall/packcode/e/st:0x1400/m
+#     If you use an exe packer as recommended below, remove /e from LDFLAGS
+
+# ------------- Common declarations:
+STRIP=rem
+#    If you don't have UPX, LZEXE, or PKLITE, get one of them. Then define:
+#    (NOTE: upx needs a 386 or higher system to run the exe compressor)
+#STRIP=upx --8086 --best
+#    or
+#STRIP=lzexe
+#    or (if you've registered PKLITE)
+#STRIP=pklite
+#    and remove /e from LDFLAGS.
+#    This makes a big difference in .exe size (and possibly load time)
+
+# ------------- Used by install rule
+# set BIN to the directory you want to install the executables to
+BIN = c:\util
+
+# variables
+OBJZ = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+       crc32.obj globals.obj
+
+OBJI = deflate.obj trees.obj $(ASMOBJS) msdos.obj
+
+OBJU = zipfile_.obj fileio_.obj util_.obj globals.obj msdos_.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj crc32_.obj crypt_.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h msdos/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips:  $(ZIPS)
+
+zip.obj:       zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) -Gt65 $*.c
+
+# MSC 5.1 generates bad code on zipfile with -Ox
+zipfile.obj:   zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c $(SPECFLAGS) $*.c
+
+zipup.obj:     zipup.c $(ZIP_H) revision.h crc32.h crypt.h msdos/zipup.h
+       $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj:    fileio.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+util.obj:      util.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+globals.obj:   globals.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj:   deflate.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+trees.obj:     trees.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj:     crc32.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj:     crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj:     ttyio.c $(ZIP_H) crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+msdos.obj:     msdos/msdos.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) msdos/$*.c
+
+zipcloak.obj:  zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipnote.obj:   zipnote.c $(ZIP_H) revision.h
+       $(CC) -c $(CFLAGS) $*.c
+
+# MSC 5.1 dies on zipsplit with -Ox
+zipsplit.obj:  zipsplit.c $(ZIP_H) revision.h
+       $(CC) -c $(SPECFLAGS) $*.c
+
+# MSC 5.1 generates bad code on zipfile with -Ox
+zipfile_.obj:  zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c $(SPECFLAGS) -DUTIL -Fo$@ zipfile.c
+
+fileio_.obj:   fileio.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS)$@ fileio.c
+
+util_.obj:     util.c $(ZIP_H)
+       $(CC) -c $(UTILFLAGS)$@ util.c
+
+crc32_.obj:    crc32.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS)$@ crc32.c
+
+crypt_.obj:    crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c $(UTILFLAGS)$@ crypt.c
+
+msdos_.obj:    msdos/msdos.c $(ZIP_H)
+       $(CC) -c $(UTILFLAGS)$@ msdos/msdos.c
+
+crc_i86.obj:   msdos/crc_i86.asm
+       $(AS) $(ASFLAGS) msdos\crc_i86.asm ;
+
+match.obj:     msdos/match.asm
+       $(AS) $(ASFLAGS) msdos\match.asm ;
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zip.exe: $(OBJZ) $(OBJI)
+       echo $(OBJZ)+ > zip.rsp
+       echo $(OBJI); >> zip.rsp
+       $(LD) $(LDFLAGS) @zip.rsp
+       del zip.rsp
+       $(STRIP) zip.exe
+
+zipcloak.exe: $(OBJC)
+       echo $(OBJC); > zipc.rsp
+       $(LD) $(LDFLAGS) @zipc.rsp
+       del zipc.rsp
+       $(STRIP) zipcloak.exe
+
+zipnote.exe: $(OBJN)
+       echo $(OBJN); > zipn.rsp
+       $(LD) $(LDFLAGS) @zipn.rsp
+       del zipn.rsp
+       $(STRIP) zipnote.exe
+
+zipsplit.exe: $(OBJS)
+       echo $(OBJS); > zips.rsp
+       $(LD) $(LDFLAGS) @zips.rsp
+       del zips.rsp
+       $(STRIP) zipsplit.exe
+
+# No `install' and `clean' target possible as long as MSC's old MAKE utility
+# is supported (MSC 5.1 Make always tries to update ALL targets. The result
+# is that install and clean are always executed, unless an error occured.)
+#install:      $(ZIPS)
+#      copy /b *.exe $(BIN)
+#
+#clean:
+#      del *.obj
+#      del *.exe
diff --git a/msdos/makefile.tc b/msdos/makefile.tc
new file mode 100644 (file)
index 0000000..9ce3e32
--- /dev/null
@@ -0,0 +1,177 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# Turbo C 2.0. (Thanks to Andrew Cadach <kadach@isi.itfs.nsk.su>)
+
+# To use, do "make -fmakefile.tc"
+
+# WARNING: the small model is not supported. You must use the large model.
+# Add -DSMALL_MEM or -DMEDIUM_MEM to the LOC macro if you wish to reduce
+# the memory requirements.
+# Add -DNO_ASM to CFLAGS and comment out the ASMOBJS definition if
+# you do not have tasm.
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = -DDOS -DNO_SECURE_TESTS $(LOCAL_ZIP)
+
+# Zip requires compact or large memory model.
+# with 2.1, compact model exceeds 64k code segment; use large model
+ZIPMODEL=l     # large model for Zip and ZipUtils
+
+# name of Flag to select memory model for assembler compiles, supported
+# values are __SMALL__ , __MEDIUM__ , __COMPACT__ , __LARGE__ :
+ASMODEL=__LARGE__              # keep in sync with ZIPMODEL definition !!
+
+# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc.
+CPU_TYP = 0
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+ASMOBJS = match.obj crc_i86.obj
+
+ASCPUFLAG = __$(CPU_TYP)86
+
+# ------------- Turbo C 2.0 -------------
+MODEL=-m$(ZIPMODEL)
+CFLAGS=-w -w-eff -w-def -w-sig -w-cln -a -d -G -O -Z $(MODEL) $(LOC)
+UTILFLAGS=-DUTIL $(CFLAGS) -o
+CC=tcc
+
+# Old versions of tasm (prior to 2.01) may not like the "-m2" option...
+AS=tasm
+ASFLAGS=-ml -t -m2 -DDYN_ALLOC -DSS_NEQ_DS -D$(ASCPUFLAG) -D$(ASMODEL) $(LOC)
+
+LD=tcc
+LDFLAGS=$(MODEL)
+
+# ------------- Common declarations:
+STRIP=rem
+#    If you don't have UPX, LZEXE, or PKLITE, get one of them. Then define:
+#    (NOTE: upx needs a 386 or higher system to run the exe compressor)
+#STRIP=upx --8086 --best
+#    or
+#STRIP=lzexe
+#    or (if you've registered PKLITE)
+#STRIP=pklite
+#    This makes a big difference in .exe size (and possibly load time)
+
+# ------------- Used by install rule
+# set BIN to the directory you want to install the executables to
+BIN = c:\util
+
+# variables
+OBJZ = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+       crc32.obj globals.obj
+
+OBJI = deflate.obj trees.obj $(ASMOBJS) msdos.obj
+
+OBJU = _zipfile.obj _fileio.obj _util.obj globals.obj _msdos.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj _crc32.obj _crypt.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h msdos/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips:  $(ZIPS)
+
+zip.obj:       zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipfile.obj:   zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipup.obj:     zipup.c $(ZIP_H) revision.h crc32.h crypt.h msdos/zipup.h
+       $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj:    fileio.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+util.obj:      util.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+globals.obj:   globals.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj:   deflate.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+trees.obj:     trees.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj:     crc32.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj:     crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj:     ttyio.c $(ZIP_H) crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+msdos.obj:     msdos/msdos.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) msdos/$*.c
+
+zipcloak.obj:  zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) -o$* $*.c
+
+zipnote.obj:   zipnote.c $(ZIP_H) revision.h
+       $(CC) -c $(CFLAGS) -o$* $*.c
+
+zipsplit.obj:  zipsplit.c $(ZIP_H) revision.h
+       $(CC) -c $(CFLAGS) -o$* $*.c
+
+_zipfile.obj:  zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS)$* zipfile.c
+
+_fileio.obj:   fileio.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS)$* fileio.c
+
+_util.obj:     util.c $(ZIP_H)
+       $(CC) -c $(UTILFLAGS)$* util.c
+
+_crc32.obj:    crc32.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS)$* crc32.c
+
+_crypt.obj:    crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c $(UTILFLAGS)$* crypt.c
+
+_msdos.obj:    msdos/msdos.c $(ZIP_H)
+       $(CC) -c $(UTILFLAGS)$* msdos/msdos.c
+
+crc_i86.obj:   msdos/crc_i86.asm
+       $(AS) $(ASFLAGS) msdos\crc_i86.asm ;
+
+match.obj:     msdos/match.asm
+       $(AS) $(ASFLAGS) msdos\match.asm ;
+
+# make sure the command line fits in the MS/DOS 128 byte limit:
+zip.exe: $(OBJZ) $(OBJI)
+       rem   ignore any warnings in the following renaming commands:
+       ren _*.obj _*.ob
+       ren zipcloak.obj *.ob
+       ren zipnote.obj *.ob
+       ren zipsplit.obj *.ob
+       $(LD) $(LDFLAGS) -ezip.exe *.obj
+       ren _*.ob _*.obj
+       ren zip???*.ob *.obj
+       $(STRIP) zip.exe
+
+zipcloak.exe: $(OBJC)
+       $(LD) $(LDFLAGS) -ezipcloak.exe $(OBJC)
+       $(STRIP) zipcloak.exe
+
+zipnote.exe: $(OBJN)
+       $(LD) $(LDFLAGS) -ezipnote.exe $(OBJN)
+       $(STRIP) zipnote.exe
+
+zipsplit.exe: $(OBJS)
+       $(LD) $(LDFLAGS) -ezipsplit.exe $(OBJS)
+       $(STRIP) zipsplit.exe
+
+install:        $(ZIPS)
+       copy /b *.exe $(BIN)
+
+clean:
+       del *.obj
+       del *.exe
diff --git a/msdos/makefile.wat b/msdos/makefile.wat
new file mode 100644 (file)
index 0000000..dd4d8cd
--- /dev/null
@@ -0,0 +1,256 @@
+# WMAKE makefile for 16 bit MSDOS or 32 bit DOS extender (PMODE/W or DOS/4GW)
+# using Watcom C/C++ v11.0+, by Paul Kienitz, last revised 07 Aug 2005.
+# Makes Zip.exe, ZipNote.exe, ZipCloak.exe, and ZipSplit.exe.
+#
+# Invoke from Zip source dir with "WMAKE -F MSDOS\MAKEFILE.WAT [targets]"
+# To build with debug info use "WMAKE DEBUG=1 ..."
+# To build with no assembly modules use "WMAKE NOASM=1 ..."
+# To make the PMODE/W version use "WMAKE PM=1 ..."
+# To make the DOS/4GW version use "WMAKE GW=1 ..." (overrides PM=1)
+#   Note: specifying PM or GW without NOASM requires that the win32 source
+#   directory be present, so it can access the 32 bit assembly sources.
+#   PMODE/W is recommended over DOS/4GW for best performance.
+# To create a low memory usage version of Zip, use "WMAKE WSIZE=8192 ..."
+#   (or whatever power of two less than 32768 you wish) -- this also causes
+#   SMALL_MEM to be defined.  Compression performance will be reduced.
+#   This currently is not supported with PM=1 or GW=1.
+#
+# Other options to be fed to the compiler and assembler can be specified in
+# an environment variable called LOCAL_ZIP.
+
+variation = $(%LOCAL_ZIP)
+
+# Stifle annoying "Delete this file?" questions when errors occur:
+.ERASE
+
+.EXTENSIONS:
+.EXTENSIONS: .exe .obj .c .h .asm
+
+# We maintain multiple sets of object files in different directories so that
+# we can compile msdos, dos/4gw or pmode/w, and win32 versions of Zip without
+# their object files interacting.  The following var must be a directory name
+# ending with a backslash.  All object file names must include this macro
+# at the beginning, for example "$(O)foo.obj".
+
+!ifdef GW
+PM = 1      # both protected mode formats use the same object files
+!endif
+
+!ifdef DEBUG
+!  ifdef PM
+OBDIR = od32d
+!  else
+!    ifdef WSIZE
+OBDIR = od16l
+size = -DWSIZE=$(WSIZE) -DSMALL_MEM
+!    else
+OBDIR = od16d
+size = -DMEDIUM_MEM
+!    endif
+!  endif
+!else
+!  ifdef PM
+OBDIR = ob32d
+!  else
+!    ifdef WSIZE
+OBDIR = ob16l
+size = -DWSIZE=$(WSIZE) -DSMALL_MEM
+!    else
+OBDIR = ob16d
+size = -DMEDIUM_MEM
+!    endif
+!  endif
+!endif
+O = $(OBDIR)\   # comment here so backslash won't continue the line
+
+# The assembly hot-spot code in crc_i[3]86.asm and match[32].asm is
+# optional.  This section controls its usage.
+
+!ifdef NOASM
+  # C source
+asmob =
+cvars = $+$(cvars)$- -DDYN_ALLOC -DNO_ASM   # or ASM_CRC might default on!
+# "$+$(foo)$-" means expand foo as it has been defined up to now; normally,
+# this make defers inner expansion until the outer macro is expanded.
+!else  # !NOASM
+asmob = $(O)crc.obj $(O)match.obj
+!  ifdef PM
+cvars = $+$(cvars)$- -DASM_CRC -DASMV       # no DYN_ALLOC with match32.asm
+crc_s = win32\crc_i386.asm   # requires that the win32 directory be present
+mat_s = win32\match32.asm    # ditto
+!  else
+cvars = $+$(cvars)$- -DDYN_ALLOC -DASM_CRC -DASMV
+avars = $+$(avars)$- -DDYN_ALLOC
+crc_s = msdos\crc_i86.asm
+mat_s = msdos\match.asm
+!  endif
+!endif
+
+# Now we have to pick out the proper compiler and options for it.  This gets
+# pretty complicated with the PM, GW, DEBUG, and NOASM options...
+
+link   = wlink
+asm    = wasm
+
+!ifdef PM
+cc     = wcc386
+# Use Pentium Pro timings, register args, static strings in code:
+cflags = -bt=DOS -mf -6r -zt -zq
+aflags = -bt=DOS -mf -3 -zq
+cvars  = $+$(cvars)$- -DDOS $(variation)
+avars  = $+$(avars)$- -DWATCOM_DSEG $(variation)
+
+!  ifdef GW
+lflags = sys DOS4G
+!  else
+# THIS REQUIRES THAT PMODEW.EXE BE FINDABLE IN THE COMMAND PATH.
+# It does NOT require you to add a pmodew entry to wlink.lnk or wlsystem.lnk.
+defaultlibs = libpath %WATCOM%\lib386 libpath %WATCOM%\lib386\dos
+lflags = format os2 le op osname='PMODE/W' op stub=pmodew.exe $(defaultlibs)
+!  endif
+
+!else   # plain 16-bit DOS:
+
+cc     = wcc
+# Use plain 8086 instructions, large memory model, static strings in code:
+cflags = -bt=DOS -ml -0 -zt -zq
+aflags = -bt=DOS -ml -0 -zq
+cvars  = $+$(cvars)$- -DDOS $(size) $(variation)
+avars  = $+$(avars)$- $(size) $(variation)
+lflags = sys DOS
+!endif  # !PM
+
+# Specify optimizations, or a nonoptimized debugging version:
+
+!ifdef DEBUG
+cdebug = -od -d2
+ldebug = d w all op symf
+!else
+!  ifdef PM
+cdebug = -s -obhikl+rt -oe=100 -zp8
+# -oa helps slightly but might be dangerous.
+!  else
+cdebug = -s -oehiklrt
+!  endif
+ldebug = op el
+!endif
+
+# How to compile most sources:
+.c.obj:
+       $(cc) $(cdebug) $(cflags) $(cvars) $[@ -fo=$@
+
+# Our object files.  OBJZ is for Zip, OBJC is for ZipCloak, OBJN is for
+# ZipNote, and OBJS is for ZipSplit:
+
+OBJZ2 = $(O)zip.obj $(O)crypt.obj $(O)ttyio.obj $(O)zipfile.obj $(O)zipup.obj
+OBJZA = $(OBJZ2) $(O)util.obj $(O)fileio.obj $(O)deflate.obj
+OBJZB = $(O)trees.obj $(O)globals.obj $(O)crc32.obj $(asmob) $(O)msdos.obj
+
+OBJU2 = $(O)zipfile_.obj $(O)fileio_.obj $(O)util_.obj $(O)globals.obj
+OBJ_U = $(OBJU2) $(O)msdos_.obj
+
+OBJC  = $(O)zipcloak.obj $(O)crc32_.obj $(O)crypt_.obj $(O)ttyio.obj $(OBJ_U)
+
+OBJN  = $(O)zipnote.obj $(OBJ_U)
+
+OBJS  = $(O)zipsplit.obj $(OBJ_U)
+
+# Common header files included by all C sources:
+
+ZIP_H = zip.h ziperr.h tailor.h msdos\osdep.h
+
+
+# HERE WE GO!  By default, make all targets:
+all: Zip.exe ZipNote.exe ZipCloak.exe ZipSplit.exe
+
+# Convenient shorthand options for single targets:
+z:   Zip.exe       .SYMBOLIC
+n:   ZipNote.exe   .SYMBOLIC
+c:   ZipCloak.exe  .SYMBOLIC
+s:   ZipSplit.exe  .SYMBOLIC
+
+Zip.exe:       $(OBDIR) $(OBJZA) $(OBJZB) $(OBJV)
+       set WLK_VA=file {$(OBJZA)}
+       set WLK_VB=file {$(OBJZB) $(OBJV)}
+       $(link) $(lflags) $(ldebug) name $@ @WLK_VA @WLK_VB
+       set WLK_VA=
+       set WLK_VB=
+# We use WLK_VA and WLK_VB to keep the size of each command under 256 chars.
+
+ZipNote.exe:   $(OBDIR) $(OBJN)
+       set WLK_VAR=file {$(OBJN)}
+       $(link) $(lflags) $(ldebug) name $@ @WLK_VAR
+       set WLK_VAR=
+
+ZipCloak.exe:  $(OBDIR) $(OBJC)
+       set WLK_VAR=file {$(OBJC)}
+       $(link) $(lflags) $(ldebug) name $@ @WLK_VAR
+       set WLK_VAR=
+
+ZipSplit.exe:  $(OBDIR) $(OBJS)
+       set WLK_VAR=file {$(OBJS)}
+       $(link) $(lflags) $(ldebug) name $@ @WLK_VAR
+       set WLK_VAR=
+
+# Source dependencies:
+
+$(O)crc32.obj:    crc32.c $(ZIP_H) crc32.h
+$(O)crypt.obj:    crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+$(O)deflate.obj:  deflate.c $(ZIP_H)
+$(O)fileio.obj:   fileio.c $(ZIP_H) crc32.h
+$(O)globals.obj:  globals.c $(ZIP_H)
+$(O)trees.obj:    trees.c $(ZIP_H)
+$(O)ttyio.obj:    ttyio.c $(ZIP_H) crypt.h ttyio.h
+$(O)util.obj:     util.c $(ZIP_H)
+$(O)zip.obj:      zip.c $(ZIP_H) crc32.h crypt.h revision.h ttyio.h
+$(O)zipfile.obj:  zipfile.c $(ZIP_H) crc32.h
+$(O)zipup.obj:    zipup.c $(ZIP_H) revision.h crc32.h crypt.h msdos\zipup.h
+$(O)zipnote.obj:  zipnote.c $(ZIP_H) revision.h
+$(O)zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+$(O)zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+
+# Special case object files:
+
+$(O)msdos.obj:    msdos\msdos.c $(ZIP_H)
+       $(cc) $(cdebug) $(cflags) $(cvars) msdos\msdos.c -fo=$@
+
+$(O)match.obj:    $(mat_s)
+       $(asm) $(aflags) $(avars) $(mat_s) -fo=$@
+
+$(O)crc.obj:      $(crc_s)
+       $(asm) $(aflags) $(avars) $(crc_s) -fo=$@
+
+# Variant object files for ZipNote, ZipCloak, and ZipSplit:
+
+$(O)zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL zipfile.c -fo=$@
+
+$(O)fileio_.obj:  fileio.c $(ZIP_H) crc32.h
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL fileio.c -fo=$@
+
+$(O)util_.obj:    util.c $(ZIP_H)
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL util.c -fo=$@
+
+$(O)crc32_.obj:   crc32.c $(ZIP_H) crc32.h
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL crc32.c -fo=$@
+
+$(O)crypt_.obj:   crypt.c $(ZIP_H) crc32.h crypt.h ttyio.h
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL crypt.c -fo=$@
+
+$(O)msdos_.obj:   msdos\msdos.c $(ZIP_H)
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL msdos\msdos.c -fo=$@
+
+# Creation of subdirectory for intermediate files
+$(OBDIR):
+       -mkdir $@
+
+# Unwanted file removal:
+
+clean:     .SYMBOLIC
+       del $(O)*.obj
+
+cleaner:   clean  .SYMBOLIC
+       del Zip.exe
+       del ZipNote.exe
+       del ZipCloak.exe
+       del ZipSplit.exe
diff --git a/msdos/match.asm b/msdos/match.asm
new file mode 100644 (file)
index 0000000..998881e
--- /dev/null
@@ -0,0 +1,477 @@
+;===========================================================================
+; Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 2007-Mar-04 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+;
+; match.asm by Jean-loup Gailly.
+
+; match.asm, optimized version of longest_match() in deflate.c
+; Must be assembled with masm -ml. To be used only with C compact model
+; or large model. (For large model, assemble with -D__LARGE__).
+; This file is only optional. If you don't have masm or tasm, use the
+; C version (add -DNO_ASM to CFLAGS in makefile.msc and remove match.obj
+; from OBJI). If you have reduced WSIZE in zip.h, then make sure this is
+; assembled with an equivalent -DWSIZE=<whatever>.
+;
+; The code has been prepared for two different C compiler calling conventions
+; and contains some support for dynamically allocated working space.
+; The different environments are selected by two conditional flags:
+;   DYN_ALLOC  : select support for malloc'ed working space
+;   SS_NEQ_DS  : relaxes assumption that stack and default data segments
+;                are identical
+; When SS_NEQ_DS is defined, the code segment is used to store some
+; local variables. This (bad) coding practice is very likely to break any
+; `segment protection scheme', it will most probably only work for real
+; mode programs.
+;
+; Turbo C 2.0 does not support static allocation of more than 64K bytes per
+; file, and does not have SS == DS. So TC and BC++ users must use:
+;   tasm -ml -DDYN_ALLOC -DSS_NEQ_DS match;
+;
+; To simplify the code, the option -DDYN_ALLOC is supported for OS/2
+; only if the arrays are guaranteed to have zero offset (allocated by
+; halloc). We also require SS==DS. This is satisfied for MSC but not Turbo C.
+;
+; Per default, test code is included to check if the above requirements are
+; fulfilled. This test code can be disabled by defining the compile time
+; option flag NO_SECURE_TESTS when compiling for a production executable.
+; This shortens the code size (but the performance gain is neglectable).
+; The security tests should remain enabled, when a new C compiler
+; and/or a new set of compilation options is tried.
+
+        name    match
+
+; Do NOT assemble this source if external crc32 routine from zlib gets used.
+;
+ifndef USE_ZLIB
+
+ifdef     DEBUG
+  VERBOSE_INFO EQU 1
+else
+  ifdef _AS_MSG_
+    VERBOSE_INFO EQU 1
+  else
+    VERBOSE_INFO EQU 0
+  endif
+endif
+
+ifndef __SMALL__
+  ifndef __COMPACT__
+    ifndef __MEDIUM__
+      ifndef __LARGE__
+        ifndef __HUGE__
+;         __SMALL__ EQU 1
+        endif
+      endif
+    endif
+  endif
+endif
+
+ifdef __HUGE__
+; .MODEL Huge
+   ifndef @CodeSize
+    @CodeSize  EQU 1
+   endif
+   ifndef @DataSize
+    @DataSize  EQU 1
+   endif
+   Save_DS    EQU 1
+   if VERBOSE_INFO
+    if1
+      %out Assembling for C, Huge memory model
+    endif
+   endif
+else
+   ifdef __LARGE__
+;      .MODEL Large
+      ifndef @CodeSize
+       @CodeSize  EQU 1
+      endif
+      ifndef @DataSize
+       @DataSize  EQU 1
+      endif
+      if VERBOSE_INFO
+       if1
+         %out Assembling for C, Large memory model
+       endif
+      endif
+   else
+      ifdef __COMPACT__
+;         .MODEL Compact
+         ifndef @CodeSize
+          @CodeSize  EQU 0
+         endif
+         ifndef @DataSize
+          @DataSize  EQU 1
+         endif
+         if VERBOSE_INFO
+          if1
+            %out Assembling for C, Compact memory model
+          endif
+         endif
+      else
+         ifdef __MEDIUM__
+;            .MODEL Medium
+            ifndef @CodeSize
+             @CodeSize  EQU 1
+            endif
+            ifndef @DataSize
+             @DataSize  EQU 0
+            endif
+            if VERBOSE_INFO
+             if1
+               %out Assembling for C, Medium memory model
+             endif
+            endif
+         else
+;            .MODEL Small
+            ifndef @CodeSize
+             @CodeSize  EQU 0
+            endif
+            ifndef @DataSize
+             @DataSize  EQU 0
+            endif
+            if VERBOSE_INFO
+             if1
+               %out Assembling for C, Small memory model
+             endif
+            endif
+         endif
+      endif
+   endif
+endif
+
+if @CodeSize
+        LCOD_OFS        EQU     2
+else
+        LCOD_OFS        EQU     0
+endif
+
+IF @DataSize
+        LDAT_OFS        EQU     2
+else
+        LDAT_OFS        EQU     0
+endif
+
+ifdef Save_DS
+;                       (di,si,ds)+(size, return address)
+        SAVE_REGS       EQU     6+(4+LCOD_OFS)
+else
+;                       (di,si)+(size, return address)
+        SAVE_REGS       EQU     4+(4+LCOD_OFS)
+endif
+
+;
+; Selection of the supported CPU instruction set and initialization
+; of CPU type related macros:
+;
+ifdef __586
+        Use_286_code    EQU     1
+        Align_Size      EQU     16      ; paragraph alignment on Pentium
+        Alig_PARA       EQU     1       ; paragraph aligned code segment
+else
+ifdef __486
+        Use_286_code    EQU     1
+        Align_Size      EQU     4       ; dword alignment on 32 bit processors
+        Alig_PARA       EQU     1       ; paragraph aligned code segment
+else
+ifdef __386
+        Use_286_code    EQU     1
+        Align_Size      EQU     4       ; dword alignment on 32 bit processors
+        Alig_PARA       EQU     1       ; paragraph aligned code segment
+else
+ifdef __286
+        Use_286_code    EQU     1
+        Align_Size      EQU     2       ; word alignment on 16 bit processors
+        Alig_PARA       EQU     0       ; word aligned code segment
+else
+ifdef __186
+        Use_186_code    EQU     1
+        Align_Size      EQU     2       ; word alignment on 16 bit processors
+        Alig_PARA       EQU     0       ; word aligned code segment
+else
+        Align_Size      EQU     2       ; word alignment on 16 bit processors
+        Alig_PARA       EQU     0       ; word aligned code segment
+endif   ;?__186
+endif   ;?__286
+endif   ;?__386
+endif   ;?__486
+endif   ;?__586
+
+ifdef Use_286_code
+        .286
+        Have_80x86      EQU     1
+else
+ifdef Use_186_code
+        .186
+        Have_80x86      EQU     1
+else
+        .8086
+        Have_80x86      EQU     0
+endif   ;?Use_186_code
+endif   ;?Use_286_code
+
+ifndef DYN_ALLOC
+        extrn   _prev         : word
+        extrn   _window       : byte
+        prev    equ  _prev    ; offset part
+        window  equ  _window
+endif
+
+_DATA    segment  word public 'DATA'
+        extrn   _nice_match   : word
+        extrn   _match_start  : word
+        extrn   _prev_length  : word
+        extrn   _good_match   : word
+        extrn   _strstart     : word
+        extrn   _max_chain_length : word
+ifdef DYN_ALLOC
+        extrn   _prev         : word
+        extrn   _window       : word
+        prev    equ 0         ; offset forced to zero
+        window  equ 0
+        window_seg equ _window[2]
+        window_off equ 0
+else
+        wseg    dw seg _window
+        window_seg equ wseg
+        window_off equ offset _window
+endif
+_DATA    ends
+
+DGROUP  group _DATA
+
+if @CodeSize
+if Alig_PARA
+MATCH_TEXT      SEGMENT  PARA PUBLIC 'CODE'
+else
+MATCH_TEXT      SEGMENT  WORD PUBLIC 'CODE'
+endif
+        assume  cs: MATCH_TEXT, ds: DGROUP
+else    ;!@CodeSize
+if Alig_PARA
+_TEXT   segment para public 'CODE'
+else
+_TEXT   segment word public 'CODE'
+endif
+        assume  cs: _TEXT, ds: DGROUP
+endif   ;?@CodeSize
+
+        public  _match_init
+        public  _longest_match
+
+ifndef      WSIZE
+        WSIZE         equ 32768         ; keep in sync with zip.h !
+endif
+        MIN_MATCH     equ 3
+        MAX_MATCH     equ 258
+        MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
+        MAX_DIST      equ (WSIZE-MIN_LOOKAHEAD)
+
+ifdef DYN_ALLOC
+  ifdef SS_NEQ_DS
+    prev_ptr    dw  seg _prev           ; pointer to the prev array
+  endif
+else
+    prev_ptr    dw  seg _prev           ; pointer to the prev array
+endif
+ifdef SS_NEQ_DS
+    match_start dw  0                   ; copy of _match_start if SS != DS
+    nice_match  dw  0                   ; copy of _nice_match  if SS != DS
+endif
+
+; initialize or check the variables used in match.asm.
+
+if @CodeSize
+_match_init proc far                    ; 'proc far' for large model
+else
+_match_init proc near                   ; 'proc near' for compact model
+endif
+ifdef SS_NEQ_DS
+        ma_start equ cs:match_start     ; does not work on OS/2
+        nice     equ cs:nice_match
+else
+        assume ss: DGROUP
+        ma_start equ ss:_match_start
+        nice     equ ss:_nice_match
+  ifndef NO_SECURE_TESTS
+        mov     ax,ds
+        mov     bx,ss
+        cmp     ax,bx                   ; SS == DS?
+        jne     fatal_err
+  endif
+endif
+ifdef DYN_ALLOC
+  ifndef NO_SECURE_TESTS
+        cmp     _prev[0],0              ; verify zero offset
+        jne     fatal_err
+        cmp     _window[0],0
+        jne     fatal_err
+  endif
+  ifdef SS_NEQ_DS
+        mov     ax,_prev[2]             ; segment value
+        mov     cs:prev_ptr,ax          ; ugly write to code, crash on OS/2
+        prev_seg  equ cs:prev_ptr
+  else
+        prev_seg  equ ss:_prev[2]       ; works on OS/2 if SS == DS
+  endif
+else
+        prev_seg  equ cs:prev_ptr
+endif
+        ret
+ifndef NO_SECURE_TESTS
+if @CodeSize
+        extrn   _exit : far             ; 'far' for large model
+else
+        extrn   _exit : near            ; 'near' for compact model
+endif
+fatal_err:                              ; (quiet) emergency stop:
+        call    _exit                   ; incompatible "global vars interface"
+endif
+
+_match_init endp
+
+; -----------------------------------------------------------------------
+; Set match_start to the longest match starting at the given string and
+; return its length. Matches shorter or equal to prev_length are discarded,
+; in which case the result is equal to prev_length and match_start is
+; garbage.
+; IN assertions: cur_match is the head of the hash chain for the current
+;   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+
+; int longest_match(cur_match)
+
+        align   Align_Size
+
+if @CodeSize
+_longest_match  proc far                 ; 'proc far' for large model
+else
+_longest_match  proc near                ; 'proc near' for compact model
+endif
+        push    bp
+        mov     bp,sp
+        push    di
+        push    si
+        push    ds
+
+if @CodeSize
+        cur_match    equ word ptr [bp+6] ; [bp+6] for large model
+else
+        cur_match    equ word ptr [bp+4] ; [bp+4] for compact model
+endif
+
+;       window       equ es:window (es:0 for DYN_ALLOC)
+;       prev         equ ds:prev
+;       match        equ es:si
+;       scan         equ es:di
+;       chain_length equ bp
+;       best_len     equ bx
+;       limit        equ dx
+
+        mov     si,cur_match            ; use bp before it is destroyed
+ifdef SS_NEQ_DS
+        mov     ax,_nice_match
+        mov     nice,ax                 ; ugly write to code, crash on OS/2
+endif
+        mov     dx,_strstart
+        mov     bp,_max_chain_length    ; chain_length = max_chain_length
+        mov     di,dx
+        sub     dx,MAX_DIST             ; limit = strstart-MAX_DIST
+        cld                             ; string ops increment si and di
+        jae     limit_ok
+        sub     dx,dx                   ; limit = NIL
+limit_ok:
+        add     di,2+window_off         ; di = offset(window + strstart + 2)
+        mov     bx,_prev_length         ; best_len = prev_length
+        mov     es,window_seg
+        mov     ax,es:[bx+di-3]         ; ax = scan[best_len-1..best_len]
+        mov     cx,es:[di-2]            ; cx = scan[0..1]
+        cmp     bx,_good_match          ; do we have a good match already?
+        mov     ds,prev_seg             ; (does not destroy the flags)
+        assume  ds: nothing
+        jb      do_scan                 ; good match?
+if Have_80x86
+        shr     bp,2                    ; chain_length >>= 2
+else
+        shr     bp,1                    ; chain_length >>= 2
+        shr     bp,1
+endif
+        jmp     short do_scan
+
+        align   Align_Size              ; align destination of branch
+long_loop:
+; at this point, ds:di == scan+2, ds:si == cur_match
+        mov     ax,[bx+di-3]            ; ax = scan[best_len-1..best_len]
+        mov     cx,[di-2]               ; cx = scan[0..1]
+        mov     ds,prev_seg             ; reset ds to address the prev array
+short_loop:
+; at this point, di == scan+2, si = cur_match,
+; ax = scan[best_len-1..best_len] and cx = scan[0..1]
+if (WSIZE-32768)
+        and     si,WSIZE-1              ; not needed if WSIZE=32768
+endif
+        shl     si,1                    ; cur_match as word index
+        dec     bp                      ; --chain_length
+        mov     si,prev[si]             ; cur_match = prev[cur_match]
+        jz      the_end
+        cmp     si,dx                   ; cur_match <= limit ?
+        jbe     the_end
+do_scan:
+        cmp     ax,word ptr es:window[bx+si-1] ; check match at best_len-1
+        jne     short_loop
+        cmp     cx,word ptr es:window[si]      ; check min_match_length match
+        jne     short_loop
+
+        mov     cx,es
+        add     si,2+window_off         ; si = match
+        mov     ds,cx                   ; ds = es = window
+        mov     cx,(MAX_MATCH-2)/2      ; scan for at most MAX_MATCH bytes
+        mov     ax,di                   ; ax = scan+2
+        repe    cmpsw                   ; loop until mismatch
+        je      maxmatch                ; match of length MAX_MATCH?
+mismatch:
+        mov     cl,[di-2]               ; mismatch on first or second byte?
+        xchg    ax,di                   ; di = scan+2, ax = end of scan
+        sub     cl,[si-2]               ; cl = 0 if first bytes equal
+        sub     ax,di                   ; ax = len
+        sub     si,2+window_off         ; si = cur_match + len
+        sub     si,ax                   ; si = cur_match
+        sub     cl,1                    ; set carry if cl == 0 (can't use DEC)
+        adc     ax,0                    ; ax = carry ? len+1 : len
+        cmp     ax,bx                   ; len > best_len ?
+        jle     long_loop
+        mov     ma_start,si             ; match_start = cur_match
+        mov     bx,ax                   ; bx = best_len = len
+        cmp     ax,nice                 ; len >= nice_match ?
+        jl      long_loop
+the_end:
+        pop     ds
+        assume  ds: DGROUP
+ifdef SS_NEQ_DS
+        mov     ax,ma_start             ; garbage if no match found
+        mov     ds:_match_start,ax
+endif
+        pop     si
+        pop     di
+        pop     bp
+        mov     ax,bx                   ; result = ax = best_len
+        ret
+maxmatch:                               ; come here if maximum match
+        cmpsb                           ; increment si and di
+        jmp     mismatch                ; force match_length = MAX_LENGTH
+
+_longest_match  endp
+
+if @CodeSize
+MATCH_TEXT      ENDS
+else
+_TEXT   ENDS
+endif
+;
+endif ;!USE_ZLIB
+;
+end
diff --git a/msdos/msdos.c b/msdos/msdos.c
new file mode 100644 (file)
index 0000000..4f71397
--- /dev/null
@@ -0,0 +1,1126 @@
+/*
+  Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2005-Feb-10 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#ifndef UTIL    /* little or no material in this file is used by UTIL */
+
+#include <dos.h>
+#include <time.h>
+
+
+#if defined(__GO32__) || defined(__TURBOC__)
+#  include <dir.h> /* prototypes of find*() */
+   typedef struct ffblk   ff_dir;
+#  define FATTR (hidden_files ? FA_HIDDEN+FA_SYSTEM+FA_DIREC : FA_DIREC)
+#  define FFIRST(n,d,a)   findfirst(n,(struct ffblk *)d,a)
+#  define FNEXT(d)        findnext((struct ffblk *)d)
+#  if (defined(__TURBOC__) || (defined(__DJGPP__) && (__DJGPP__ >=2)))
+#    if (defined(__DJGPP__) && (__DJGPP__ == 2) && (__DJGPP_MINOR__ == 0))
+#      include <libc/dosio.h>
+#    endif
+#    define GetFileMode(name) _chmod(name, 0)
+#    define SetFileMode(name, attr) _chmod(name, 1, attr)
+#  else /* DJGPP v1.x */
+#    define GetFileMode(name) bdosptr(0x43, (name), 0)
+#  endif
+#endif /* __GO32__ || __TURBOC__ */
+
+#if defined(MSC) || defined(__WATCOMC__)
+   typedef struct find_t  ff_dir;
+#  define FATTR (hidden_files ? _A_HIDDEN+_A_SYSTEM+_A_SUBDIR : _A_SUBDIR)
+#  ifndef FA_LABEL
+#    define FA_LABEL      _A_VOLID
+#  endif
+#  define FFIRST(n,d,a)   _dos_findfirst(n,a,(struct find_t *)d)
+#  define FNEXT(d)        _dos_findnext((struct find_t *)d)
+#  define ff_name         name
+#  define ff_fdate        wr_date
+#  define ff_ftime        wr_time
+#  define ff_attrib       attrib
+#endif /* MSC || __WATCOMC__ */
+
+#ifdef __EMX__
+#  ifdef EMX_OBSOLETE           /* emx 0.9b or earlier */
+#    define size_t xxx_size_t
+#    define wchar_t xxx_wchar_t
+#    define tm xxx_tm
+#    include <sys/emx.h>
+#    undef size_t
+#    undef wchar_t
+#    undef tm
+#  else /* !EMX_OBSOLETE */     /* emx 0.9c or newer */
+#    include <emx/syscalls.h>
+#  endif /* ?EMX_OBSOLETE */
+   typedef struct _find   ff_dir;
+#  define FATTR (hidden_files ? _A_HIDDEN+_A_SYSTEM+_A_SUBDIR : _A_SUBDIR)
+#  define FA_LABEL        _A_VOLID
+#  define FFIRST(n,d,a)   __findfirst(n,a,d)
+#  define FNEXT(d)        __findnext(d)
+#  define ff_name         name
+#  define ff_fdate        date
+#  define ff_ftime        time
+#  define ff_attrib       attr
+#  define GetFileMode(name) __chmod(name, 0, 0)
+#  define SetFileMode(name, attr) __chmod(name, 1, attr)
+#endif /* __EMX__ */
+
+#ifndef SetFileMode
+#  define SetFileMode(name, attr) _dos_setfileattr(name, attr)
+#endif
+
+
+#define PAD  0
+#define PATH_END '/'
+
+/* Library functions not in (most) header files */
+int rmdir OF((const char *));
+int utime OF((char *, ztimbuf *));
+
+/* Local functions */
+#ifndef GetFileMode
+int GetFileMode OF((char *name));
+#endif /* !GetFileMode */
+
+local int  initDirSearch OF((char *name, ff_dir *ff_context_p));
+local char *getVolumeLabel OF((int, ulg *, ulg *, time_t *));
+local int  wild_recurse OF((char *, char *));
+local int procname_dos OF((char *n, int caseflag, unsigned attribs));
+local int is_running_on_windows OF((void));
+
+#define MSDOS_INVALID_ATTR      0xFF
+#define getDirEntryAttr(d)      ((d)->ff_attrib)
+
+/* Module level variables */
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Module level constants */
+local ZCONST char wild_match_all[] = "*.*";
+
+
+#ifndef GetFileMode
+int GetFileMode(char *name)
+{
+  unsigned int attr = 0;
+  return (_dos_getfileattr(name, &attr) ? -1 : attr);
+}
+#endif /* !GetFileMode */
+
+local int initDirSearch(name, ff_context_p)
+  char *name;                   /* name of directory to scan */
+  ff_dir *ff_context_p;         /* pointer to FFIRST/FNEXT context structure */
+{
+  int r;                        /* FFIRST return value */
+  char *p, *q;                  /* temporary copy of name, and aux pointer */
+
+  if ((p = malloc(strlen(name) + (2 + sizeof(wild_match_all)))) == NULL)
+    return ZE_MEM;
+
+  strcpy(p, name);
+  q = p + strlen(p);
+  if (q[-1] == ':')
+    *q++ = '.';
+  if ((q - p) > 0 && *(q - 1) != '/')
+    *q++ = '/';
+  strcpy(q, wild_match_all);
+  r = FFIRST(p, ff_context_p, FATTR);
+  free((zvoid *)p);
+
+  return (r ? ZE_MISS : ZE_OK);
+}
+
+local char *getVolumeLabel(drive, vtime, vmode, vutim)
+  int drive;    /* drive name: 'A' .. 'Z' or '\0' for current drive */
+  ulg *vtime;   /* volume label creation time (DOS format) */
+  ulg *vmode;   /* volume label file mode */
+  time_t *vutim;/* volume label creation time (UNIX format) */
+
+/* If a volume label exists for the given drive, return its name and
+   set its time and mode. The returned name must be static data. */
+{
+  static char vol[14];
+  ff_dir d;
+  char *p;
+
+  if (drive) {
+    vol[0] = (char)drive;
+    strcpy(vol+1, ":/");
+  } else {
+    strcpy(vol, "/");
+  }
+  strcat(vol, wild_match_all);
+  if (FFIRST(vol, &d, FA_LABEL) == 0) {
+    strncpy(vol, d.ff_name, sizeof(vol)-1);
+    vol[sizeof(vol)-1] = '\0';   /* just in case */
+    if ((p = strchr(vol, '.')) != NULL) /* remove dot, though PKZIP doesn't */
+      strcpy(p, p + 1);
+    *vtime = ((ulg)d.ff_fdate << 16) | ((ulg)d.ff_ftime & 0xffff);
+    *vmode = (ulg)d.ff_attrib;
+    *vutim = dos2unixtime(*vtime);
+    return vol;
+  }
+  return NULL;
+}
+
+
+#ifdef MSDOS16
+#define ONENAMELEN 12   /* no 16-bit compilers supports LFN */
+#else
+#define ONENAMELEN 255
+#endif
+
+/* whole is a pathname with wildcards, wildtail points somewhere in the  */
+/* middle of it.  All wildcards to be expanded must come AFTER wildtail. */
+
+local int wild_recurse(whole, wildtail)
+char *whole;
+char *wildtail;
+{
+    ff_dir dir;
+    char *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
+    ush newlen, amatch = 0;
+    int e = ZE_MISS;
+
+    if (!isshexp(wildtail)) {
+        struct stat s;                          /* dummy buffer for stat() */
+
+        if (!LSSTAT(whole, &s))                 /* file exists ? */
+            return procname(whole, 0);
+        else
+            return ZE_MISS;                     /* woops, no wildcards! */
+    }
+
+    /* back up thru path components till existing dir found */
+    do {
+        name = wildtail + strlen(wildtail) - 1;
+        for (;;)
+            if (name-- <= wildtail || *name == PATH_END) {
+                subwild = name + 1;
+                plug2 = *subwild;
+                *subwild = 0;
+                break;
+            }
+        if (glue)
+            *glue = plug;
+        glue = subwild;
+        plug = plug2;
+        e = initDirSearch(whole, &dir);
+    } while (e == ZE_MISS && subwild > wildtail);
+    wildtail = subwild;                 /* skip past non-wild components */
+    if (e != ZE_OK) {
+        if (glue)
+            *glue = plug;
+        goto ohforgetit;
+    }
+    subwild = strchr(wildtail + 1, PATH_END);
+    /* this "+ 1" dodges the  ^^^ hole left by *glue == 0 */
+    if (subwild != NULL) {
+        *(subwild++) = 0;               /* wildtail = one component pattern */
+        newlen = strlen(whole) + strlen(subwild) + (ONENAMELEN + 2);
+    } else
+        newlen = strlen(whole) + (ONENAMELEN + 1);
+    if ((newwhole = malloc(newlen)) == NULL) {
+        if (glue)
+            *glue = plug;
+        e = ZE_MEM;
+        goto ohforgetit;
+    }
+    strcpy(newwhole, whole);
+    newlen = strlen(newwhole);
+    if (glue)
+        *glue = plug;                           /* repair damage to whole */
+    if (!isshexp(wildtail)) {
+        e = ZE_MISS;                            /* non-wild name not found */
+        goto ohforgetit;
+    }
+
+    do {
+        if (strcmp(dir.ff_name, ".") && strcmp(dir.ff_name, "..")
+                                  && MATCH(wildtail, dir.ff_name, 0)) {
+            strcpy(newwhole + newlen, dir.ff_name);
+            if (subwild) {
+                name = newwhole + strlen(newwhole);
+                *(name++) = PATH_END;
+                strcpy(name, subwild);
+                e = wild_recurse(newwhole, name);
+            } else
+                e = procname_dos(newwhole, 0, getDirEntryAttr(&dir));
+            newwhole[newlen] = 0;
+            if (e == ZE_OK)
+                amatch = 1;
+            else if (e != ZE_MISS)
+                break;
+        }
+    } while (FNEXT(&dir) == 0);
+
+  ohforgetit:
+    if (subwild)
+        *--subwild = PATH_END;
+    if (newwhole)
+        free(newwhole);
+    if (e == ZE_MISS && amatch)
+        e = ZE_OK;
+    return e;
+}
+
+int wild(w)
+char *w;                /* path/pattern to match */
+/* If not in exclude mode, expand the pattern based on the contents of the
+   file system.  Return an error code in the ZE_ class. */
+{
+    char *p;            /* path */
+    char *q;            /* diskless path */
+    int e;              /* result */
+
+    if (volume_label == 1) {
+      volume_label = 2;
+      label = getVolumeLabel((w != NULL && w[1] == ':') ? to_up(w[0]) : '\0',
+                             &label_time, &label_mode, &label_utim);
+      if (label != NULL)
+        (void)newname(label, 0, 0);
+      if (w == NULL || (w[1] == ':' && w[2] == '\0')) return ZE_OK;
+      /* "zip -$ foo a:" can be used to force drive name */
+    }
+    /* special handling of stdin request */
+    if (strcmp(w, "-") == 0)   /* if compressing stdin */
+        return newname(w, 0, 0);
+
+    /* Allocate and copy pattern, leaving room to add "." if needed */
+    if ((p = malloc(strlen(w) + 2)) == NULL)
+        return ZE_MEM;
+    strcpy(p, w);
+
+    /* Normalize path delimiter as '/' */
+    for (q = p; *q; q++)                  /* use / consistently */
+        if (*q == '\\')
+            *q = '/';
+
+    /* Separate the disk part of the path */
+    q = strchr(p, ':');
+    if (q != NULL) {
+        if (strchr(++q, ':'))     /* sanity check for safety of wild_recurse */
+            return ZE_MISS;
+    } else
+        q = p;
+
+    /* Normalize bare disk names */
+    if (q > p && !*q)
+        strcpy(q, ".");
+
+    /* Here we go */
+    e = wild_recurse(p, q);
+    free((zvoid *)p);
+    return e;
+}
+
+local int procname_dos(n, caseflag, attribs)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+unsigned attribs;       /* file attributes, if available */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  ff_dir *d;            /* control structure for FFIRST/FNEXT */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  int ff_status;        /* return value of FFIRST/FNEXT */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (n == NULL)        /* volume_label request in freshen|delete mode ?? */
+    return ZE_OK;
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (*n == '\0') return ZE_MISS;
+  else if (attribs != MSDOS_INVALID_ATTR)
+  {
+    /* Avoid calling stat() for performance reasons when it is already known
+       (from a previous directory scan) that the passed name corresponds to
+       a "real existing" file.  The only information needed further down in
+       this function is the distinction between directory entries and other
+       (typically normal file) entries.  This distinction can be derived from
+       the file's attributes that the directory lookup has already provided
+       "for free".
+     */
+    s.st_mode = ((attribs & MSDOS_DIR_ATTR) ? S_IFDIR : S_IFREG);
+  }
+  else if (LSSTAT(n, &s)
+#ifdef __TURBOC__
+           /* For this compiler, stat() succeeds on wild card names! */
+           || isshexp(n)
+#endif
+          )
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    if (caseflag) {
+      p = malloc(strlen(n) + 1);
+      if (p != NULL)
+        strcpy(p, n);
+    } else
+      p = ex2in(n, 0, (int *)NULL);     /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (z->mark) z->dosflag = 1;    /* force DOS attribs for incl. names */
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  for (p = n; *p; p++)          /* use / consistently */
+    if (*p == '\\')
+      *p = '/';
+  if ((s.st_mode & S_IFDIR) == 0)
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0, caseflag)) != ZE_OK)
+      return m;
+  } else {
+    /* Add trailing / to the directory name */
+    if ((p = malloc(strlen(n)+2)) == NULL)
+      return ZE_MEM;
+    if (strcmp(n, ".") == 0 || strcmp(n, "/.") == 0) {
+      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      strcpy(p, n);
+      a = p + strlen(p);
+      if (a[-1] != '/')
+        strcpy(a, "/");
+      if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+        free((zvoid *)p);
+        return m;
+      }
+    }
+    /* recurse into directory */
+    if (recurse)
+    {
+      if ((d = malloc(sizeof(ff_dir))) == NULL ||
+          (m = initDirSearch(n, d)) == ZE_MEM)
+      {
+        if (d != NULL)
+          free((zvoid *)d);
+        free((zvoid *)p);
+        return ZE_MEM;
+      }
+      for (e = d->ff_name, ff_status = m;
+           ff_status == 0;
+           ff_status = FNEXT(d))
+      {
+        if (strcmp(e, ".") && strcmp(e, ".."))
+        {
+          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+          {
+            free((zvoid *)d);
+            free((zvoid *)p);
+            return ZE_MEM;
+          }
+          strcat(strcpy(a, p), e);
+          if ((m = procname_dos(a, caseflag, getDirEntryAttr(d)))
+              != ZE_OK)         /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", a);
+            else
+              ziperr(m, a);
+          }
+          free((zvoid *)a);
+        }
+      }
+      free((zvoid *)d);
+    }
+    free((zvoid *)p);
+  } /* (s.st_mode & S_IFDIR) == 0) */
+  return ZE_OK;
+}
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+{
+  return procname_dos(n, caseflag, MSDOS_INVALID_ATTR);
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t;              /* shortened name */
+  int dosflag;
+
+  dosflag = 1;
+
+  /* Find starting point in name before doing malloc */
+  /* Strip drive specification */
+  t = *x && *(x + 1) == ':' ? x + 2 : x;
+  /* Strip "//host/share/" part of a UNC name */
+  if ((!strncmp(x,"//",2) || !strncmp(x,"\\\\",2)) &&
+      (x[2] != '\0' && x[2] != '/' && x[2] != '\\')) {
+    n = x + 2;
+    while (*n != '\0' && *n != '/' && *n != '\\')
+      n++;              /* strip host name */
+    if (*n != '\0') {
+      n++;
+      while (*n != '\0' && *n != '/' && *n != '\\')
+        n++;            /* strip `share' name */
+    }
+    if (*n != '\0')
+      t = n + 1;
+  }
+  /* Strip leading "/" to convert an absolute path into a relative path */
+  while (*t == '/' || *t == '\\')
+    t++;
+  /* Skip leading "./" as well */
+  while (*t == '.' && (t[1] == '/' || t[1] == '\\'))
+    t += 2;
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+  for (n = t; *n; n++)
+    if (*n == '\\')
+      *n = '/';
+
+  if (!pathput)
+    t = last(t, PATH_END);
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL)
+    return NULL;
+  strcpy(n, t);
+
+  if (isdir == 42) return n;      /* avoid warning on unused variable */
+
+  if (dosify)
+    msname(n);
+  else
+#if defined(__DJGPP__) && __DJGPP__ >= 2
+    if (_USE_LFN == 0)
+#endif
+      strlwr(n);
+  if (pdosflag)
+    *pdosflag = dosflag;
+  return n;
+}
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+      return NULL;
+  strcpy(x, n);
+
+  return x;
+}
+
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+#if defined(__TURBOC__) || defined(__GO32__)
+  int h;                /* file handle */
+
+  if ((h = open(f, 0)) != -1)
+  {
+    setftime(h, (struct ftime *)(void *)&d);
+    close(h);
+  }
+#else /* !__TURBOC__ && !__GO32__ */
+  ztimbuf u;            /* argument for utime() */
+
+  /* Convert DOS time to time_t format in u.actime and u.modtime */
+  u.actime = u.modtime = dos2unixtime(d);
+
+  /* Set updated and accessed times of f */
+  utime(f, &u);
+#endif /* ?(__TURBOC__ || __GO32__) */
+}
+
+ulg filetime(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  /* convert FNMAX to malloc - 11/8/04 EG */
+  char *name;
+  int len = strlen(f);
+  int isstdin = !strcmp(f, "-");
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+
+  if (isstdin) {
+    if (fstat(fileno(stdin), &s) != 0) {
+      free(name);
+      error("fstat(stdin)");
+    }
+    time((time_t *)&s.st_mtime);       /* some fstat()s return time zero */
+  } else if (LSSTAT(name, &s) != 0) {
+             /* Accept about any file kind including directories
+              * (stored with trailing / with -r option)
+              */
+    free(name);
+    return 0;
+  }
+
+  if (a != NULL) {
+    *a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)GetFileMode(name));
+#if (S_IFREG != 0x8000)
+    /* kludge to work around non-standard S_IFREG flag used in DJGPP V2.x */
+    if ((s.st_mode & S_IFMT) == S_IFREG) *a |= 0x80000000L;
+#endif
+  }
+  free(name);
+  if (n != NULL)
+    *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = s.st_ctime;
+  }
+
+  return unix2dostime((time_t *)&s.st_mtime);
+}
+
+int deletedir(d)
+char *d;                /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+   Return the result of rmdir(), delete(), or system().
+ */
+{
+    return rmdir(d);
+}
+
+int set_extra_field(z, z_utim)
+  struct zlist far *z;
+  iztimes *z_utim;
+  /* create extra field and change z->att if desired */
+{
+#ifdef USE_EF_UT_TIME
+#ifdef IZ_CHECK_TZ
+  if (!zp_tz_is_valid) return ZE_OK;    /* skip silently if no valid TZ info */
+#endif
+
+  if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
+    return ZE_MEM;
+
+  z->extra[0]  = 'U';
+  z->extra[1]  = 'T';
+  z->extra[2]  = EB_UT_LEN(1);          /* length of data part of e.f. */
+  z->extra[3]  = 0;
+  z->extra[4]  = EB_UT_FL_MTIME;
+  z->extra[5]  = (char)(z_utim->mtime);
+  z->extra[6]  = (char)(z_utim->mtime >> 8);
+  z->extra[7]  = (char)(z_utim->mtime >> 16);
+  z->extra[8]  = (char)(z_utim->mtime >> 24);
+
+  z->cext = z->ext = (EB_HEADSIZE+EB_UT_LEN(1));
+  z->cextra = z->extra;
+
+  return ZE_OK;
+#else /* !USE_EF_UT_TIME */
+  return (int)(z-z);
+#endif /* ?USE_EF_UT_TIME */
+}
+
+
+#ifdef MY_ZCALLOC       /* Special zcalloc function for MEMORY16 (MSDOS/OS2) */
+
+#if defined(__TURBOC__) && !defined(OS2)
+/* Small and medium model are for now limited to near allocation with
+ * reduced MAX_WBITS and MAX_MEM_LEVEL
+ */
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+    zvoid far *org_ptr;
+    zvoid far *new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+zvoid far *zcalloc (unsigned items, unsigned size)
+{
+    zvoid far *buf;
+    ulg bsize = (ulg)items*size;
+
+    if (bsize < (65536L-16L)) {
+        buf = farmalloc(bsize);
+        if (*(ush*)&buf != 0) return buf;
+    } else {
+        buf = farmalloc(bsize + 16L);
+    }
+    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+    table[next_ptr].org_ptr = buf;
+
+    /* Normalize the pointer to seg:0 */
+    *((ush*)&buf+1) += ((ush)((uch*)buf-NULL) + 15) >> 4;
+    *(ush*)&buf = 0;
+    table[next_ptr++].new_ptr = buf;
+    return buf;
+}
+
+zvoid zcfree (zvoid far *ptr)
+{
+    int n;
+    if (*(ush*)&ptr != 0) { /* object < 64K */
+        farfree(ptr);
+        return;
+    }
+    /* Find the original pointer */
+    for (n = next_ptr - 1; n >= 0; n--) {
+        if (ptr != table[n].new_ptr) continue;
+
+        farfree(table[n].org_ptr);
+        while (++n < next_ptr) {
+            table[n-1] = table[n];
+        }
+        next_ptr--;
+        return;
+    }
+    ziperr(ZE_MEM, "zcfree: ptr not found");
+}
+#endif /* __TURBOC__ */
+
+#if defined(MSC) || defined(__WATCOMC__)
+#if (!defined(_MSC_VER) || (_MSC_VER < 700))
+#  define _halloc  halloc
+#  define _hfree   hfree
+#endif
+
+zvoid far *zcalloc (unsigned items, unsigned size)
+{
+    return (zvoid far *)_halloc((long)items, size);
+}
+
+zvoid zcfree (zvoid far *ptr)
+{
+    _hfree((void huge *)ptr);
+}
+#endif /* MSC || __WATCOMC__ */
+
+#endif /* MY_ZCALLOC */
+
+#if (defined(__WATCOMC__) && defined(ASMV) && !defined(__386__))
+/* This is a hack to connect "call _exit" in match.asm to exit() */
+#pragma aux xit "_exit" parm caller []
+void xit(void)
+{
+    exit(20);
+}
+#endif
+
+local int is_running_on_windows(void)
+{
+    char * var = getenv("OS");
+
+    /* if the OS env.var says 'Windows_NT' then */
+    /* we're likely running on a variant of WinNT */
+
+    if ((NULL != var) && (0 == strcmp("Windows_NT", var)))
+    {
+        return 1;
+    }
+
+    /* if the windir env.var is non-null then */
+    /* we're likely running on a variant of Win9x */
+    /* DOS mode of Win9x doesn't define windir, only winbootdir */
+    /* NT's command.com can't see lowercase env. vars */
+
+    var = getenv("windir");
+    if ((NULL != var) && (0 != var[0]))
+    {
+        return 1;
+    }
+
+    return 0;
+}
+
+void check_for_windows(char *app)
+{
+    /* Print a warning for users running under Windows */
+    /* to reduce bug reports due to running DOS version */
+    /* under Windows, when Windows version usually works correctly */
+
+    /* This is only called from the DOS version */
+
+    if (is_running_on_windows())
+    {
+        printf("\nzip warning:  You are running MSDOS %s on Windows.\n"
+               "Try the Windows version before reporting any problems.\n",
+               app);
+    }
+}
+
+#endif /* !UTIL */
+
+
+#ifndef WINDLL
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s.\n\n";
+                        /* At module level to keep Turbo C++ 1.0 happy !! */
+
+void version_local()
+{
+#if defined(__DJGPP__) || defined(__WATCOMC__) || \
+    (defined(_MSC_VER) && (_MSC_VER != 800))
+    char buf[80];
+#endif
+
+/* Define the compiler name and version strings */
+#if defined(__GNUC__)
+#  if defined(__DJGPP__)
+    sprintf(buf, "djgpp v%d.%02d / gcc ", __DJGPP__, __DJGPP_MINOR__);
+#    define COMPILER_NAME1      buf
+#  elif defined(__GO32__)         /* __GO32__ is defined as "1" only (sigh) */
+#    define COMPILER_NAME1      "djgpp v1.x / gcc "
+#  elif defined(__EMX__)          /* ...so is __EMX__ (double sigh) */
+#    define COMPILER_NAME1      "emx+gcc "
+#  else
+#    define COMPILER_NAME1      "gcc "
+#  endif
+#  define COMPILER_NAME2        __VERSION__
+#elif defined(__WATCOMC__)
+#  if (__WATCOMC__ % 10 > 0)
+/* We do this silly test because __WATCOMC__ gives two digits for the  */
+/* minor version, but Watcom packaging prefers to show only one digit. */
+    sprintf(buf, "Watcom C/C++ %d.%02d", __WATCOMC__ / 100,
+            __WATCOMC__ % 100);
+#  else
+    sprintf(buf, "Watcom C/C++ %d.%d", __WATCOMC__ / 100,
+            (__WATCOMC__ % 100) / 10);
+#  endif
+#  define COMPILER_NAME1        buf
+#  define COMPILER_NAME2        ""
+#elif defined(__TURBOC__)
+#  ifdef __BORLANDC__
+#    define COMPILER_NAME1      "Borland C++"
+#    if (__BORLANDC__ < 0x0200)
+#      define COMPILER_NAME2    " 1.0"
+#    elif (__BORLANDC__ == 0x0200)   /* James:  __TURBOC__ = 0x0297 */
+#      define COMPILER_NAME2    " 2.0"
+#    elif (__BORLANDC__ == 0x0400)
+#      define COMPILER_NAME2    " 3.0"
+#    elif (__BORLANDC__ == 0x0410)   /* __BCPLUSPLUS__ = 0x0310 */
+#      define COMPILER_NAME2    " 3.1"
+#    elif (__BORLANDC__ == 0x0452)   /* __BCPLUSPLUS__ = 0x0320 */
+#      define COMPILER_NAME2    " 4.0 or 4.02"
+#    elif (__BORLANDC__ == 0x0460)   /* __BCPLUSPLUS__ = 0x0340 */
+#      define COMPILER_NAME2    " 4.5"
+#    elif (__BORLANDC__ == 0x0500)   /* __TURBOC__ = 0x0500 */
+#      define COMPILER_NAME2    " 5.0"
+#    else
+#      define COMPILER_NAME2    " later than 5.0"
+#    endif
+#  else
+#    define COMPILER_NAME1      "Turbo C"
+#    if (__TURBOC__ > 0x0401)
+#      define COMPILER_NAME2    "++ later than 3.0"
+#    elif (__TURBOC__ == 0x0401)     /* Kevin:  3.0 -> 0x0401 */
+#      define COMPILER_NAME2    "++ 3.0"
+#    elif (__TURBOC__ == 0x0296)     /* [662] checked by SPC */
+#      define COMPILER_NAME2    "++ 1.01"
+#    elif (__TURBOC__ == 0x0295)     /* [661] vfy'd by Kevin */
+#      define COMPILER_NAME2    "++ 1.0"
+#    elif (__TURBOC__ == 0x0201)     /* Brian:  2.01 -> 0x0201 */
+#      define COMPILER_NAME2    " 2.01"
+#    elif ((__TURBOC__ >= 0x018d) && (__TURBOC__ <= 0x0200)) /* James: 0x0200 */
+#      define COMPILER_NAME2    " 2.0"
+#    elif (__TURBOC__ > 0x0100)
+#      define COMPILER_NAME2    " 1.5"          /* James:  0x0105? */
+#    else
+#      define COMPILER_NAME2    " 1.0"          /* James:  0x0100 */
+#    endif
+#  endif
+#elif defined(MSC)
+#  if defined(_QC) && !defined(_MSC_VER)
+#    define COMPILER_NAME1      "Microsoft Quick C"
+#    define COMPILER_NAME2      ""      /* _QC is defined as 1 */
+#  else
+#    define COMPILER_NAME1      "Microsoft C "
+#    ifdef _MSC_VER
+#      if (_MSC_VER == 800)
+#        define COMPILER_NAME2  "8.0/8.0c (Visual C++ 1.0/1.5)"
+#      else
+#        define COMPILER_NAME2 \
+           (sprintf(buf, "%d.%02d", _MSC_VER/100, _MSC_VER%100), buf)
+#      endif
+#    else
+#      define COMPILER_NAME2    "5.1 or earlier"
+#    endif
+#  endif
+#else
+#    define COMPILER_NAME1      "unknown compiler"
+#    define COMPILER_NAME2      ""
+#endif
+
+/* Define the OS name and memory environment strings */
+#if defined(__WATCOMC__) || defined(__TURBOC__) || defined(MSC) || \
+    defined(__GNUC__)
+#  define OS_NAME1      "\nMS-DOS"
+#else
+#  define OS_NAME1      "MS-DOS"
+#endif
+
+#if (defined(__GNUC__) || (defined(__WATCOMC__) && defined(__386__)))
+#  define OS_NAME2      " (32-bit)"
+#elif defined(M_I86HM) || defined(__HUGE__)
+#  define OS_NAME2      " (16-bit, huge)"
+#elif defined(M_I86LM) || defined(__LARGE__)
+#  define OS_NAME2      " (16-bit, large)"
+#elif defined(M_I86MM) || defined(__MEDIUM__)
+#  define OS_NAME2      " (16-bit, medium)"
+#elif defined(M_I86CM) || defined(__COMPACT__)
+#  define OS_NAME2      " (16-bit, compact)"
+#elif defined(M_I86SM) || defined(__SMALL__)
+#  define OS_NAME2      " (16-bit, small)"
+#elif defined(M_I86TM) || defined(__TINY__)
+#  define OS_NAME2      " (16-bit, tiny)"
+#else
+#  define OS_NAME2      " (16-bit)"
+#endif
+
+/* Define the compile date string */
+#ifdef __DATE__
+#  define COMPILE_DATE " on " __DATE__
+#else
+#  define COMPILE_DATE ""
+#endif
+
+    printf(CompiledWith, COMPILER_NAME1, COMPILER_NAME2,
+           OS_NAME1, OS_NAME2, COMPILE_DATE);
+
+} /* end function version_local() */
+#endif /* !WINDLL */
+
+
+#if 0 /* inserted here for future use (clearing of archive bits) */
+#if (defined(__GO32__) && (!defined(__DJGPP__) || (__DJGPP__ < 2)))
+
+#include <errno.h>
+int volatile _doserrno;
+
+unsigned _dos_setfileattr(char *name, unsigned attr)
+{
+#if 0   /* stripping of trailing '/' is not needed for zip-internal use */
+    unsigned namlen = strlen(name);
+    char *i_name = alloca(namlen + 1);
+
+    strcpy(i_name, name);
+    if (namlen > 1 && i_name[namlen-1] == '/' && i_name[namlen-2] != ':')
+        i_name[namlen-1] = '\0';
+    asm("movl %0, %%edx": : "g" (i_name));
+#else
+    asm("movl %0, %%edx": : "g" (name));
+#endif
+    asm("movl %0, %%ecx": : "g" (attr));
+    asm("movl $0x4301, %eax");
+    asm("int $0x21": : : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi");
+    _doserrno = 0;
+    asm("jnc 1f");
+    asm("movl %%eax, %0": "=m" (_doserrno));
+    switch (_doserrno) {
+    case 2:
+    case 3:
+           errno = ENOENT;
+           break;
+    case 5:
+           errno = EACCES;
+           break;
+    }
+    asm("1:");
+    return (unsigned)_doserrno;
+}
+
+#endif /* DJGPP v1.x */
+#endif /* never (not yet used) */
+
+
+#if (defined(__DJGPP__) && (__DJGPP__ >= 2))
+
+/* Disable determination of "x" bit in st_mode field for [f]stat() calls. */
+int _is_executable (const char *path, int fhandle, const char *ext)
+{
+    return 0;
+}
+
+/* Prevent globbing of filenames.  This gives the same functionality as
+ * "stubedit <program> globbing=no" did with DJGPP v1.
+ */
+#ifndef USE_DJGPP_GLOB
+char **__crt0_glob_function(char *_arg)
+{
+    return NULL;
+}
+#endif
+
+/* Reduce the size of the executable and remove the functionality to read
+ * the program's environment from whatever $DJGPP points to.
+ */
+#if !defined(USE_DJGPP_ENV) || defined(UTIL)
+void __crt0_load_environment_file(char *_app_name)
+{
+}
+#endif
+
+#endif /* __DJGPP__ >= 2 */
+
+
+#if defined(_MSC_VER) && _MSC_VER == 700
+
+/*
+ * ARGH.  MSC 7.0 libraries think times are based on 1899 Dec 31 00:00, not
+ *  1970 Jan 1 00:00.  So we have to diddle time_t's appropriately:  add
+ *  70 years' worth of seconds for localtime() wrapper function;
+ *  (70*365 regular days + 17 leap days + 1 1899 day) * 86400 ==
+ *  (25550 + 17 + 1) * 86400 == 2209075200 seconds.
+ *  Let time() and stat() return seconds since 1970 by using our own
+ *  _dtoxtime() which is the routine that is called by these two functions.
+ */
+
+
+#ifdef UTIL
+#  include <time.h>
+#endif
+
+#ifndef UTIL
+#undef localtime
+struct tm *localtime(const time_t *);
+
+struct tm *msc7_localtime(const time_t *clock)
+{
+   time_t t = *clock;
+
+   t += 2209075200L;
+   return localtime(&t);
+}
+#endif /* !UTIL */
+
+
+void __tzset(void);
+int _isindst(struct tm *);
+
+extern int _days[];
+
+/* Nonzero if `y' is a leap year, else zero. */
+#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
+
+/* Number of leap years from 1970 to `y' (not including `y' itself). */
+#define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
+
+time_t _dtoxtime(year, month, mday, hour, min, sec)
+int year, month, mday, year, hour, min, sec;
+{
+   struct tm tm;
+   time_t t;
+   int days;
+
+   days = _days[month - 1] + mday;
+   year += 1980;
+   if (leap(year) && month > 2)
+     ++days;
+   tm.tm_yday = days;
+   tm.tm_mon = month - 1;
+   tm.tm_year = year - 1900;
+   tm.tm_hour = hour;
+   __tzset();
+   days += 365 * (year - 1970) + nleap (year);
+   t = 86400L * days + 3600L * hour + 60 * min + sec + _timezone;
+   if (_daylight && _isindst(&tm))
+      t -= 3600;
+   return t;
+}
+
+#endif /* _MSC_VER && _MSC_VER == 700 */
+
+
+#ifdef __WATCOMC__
+
+/* This papers over a bug in Watcom 10.6's standard library... sigh */
+/* Apparently it applies to both the DOS and Win32 stat()s.         */
+
+int stat_bandaid(const char *path, struct stat *buf)
+{
+  char newname[4];
+  if (!stat(path, buf))
+    return 0;
+  else if (!strcmp(path, ".") || (path[0] && !strcmp(path + 1, ":."))) {
+    strcpy(newname, path);
+    newname[strlen(path) - 1] = '\\';   /* stat(".") fails for root! */
+    return stat(newname, buf);
+  } else
+    return -1;
+}
+
+#endif
diff --git a/msdos/osdep.h b/msdos/osdep.h
new file mode 100644 (file)
index 0000000..0e0f23f
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* The symbol DOS is used throughout the Zip source to identify code portions
+ * specific to the MSDOS port.
+ * Just to make sure, we check that it is set.
+ * (Currently, this should should not be neccessary, since currently it has
+ * to be set on the compiler command line to get this file read in.)
+ */
+#ifndef DOS
+#  define DOS
+#endif
+
+/* The symbol MSDOS is consistently used in the generic source files
+ * to identify code to support for MSDOS (and MSDOS related) stuff.
+ * e.g: FAT or (FAT like) file systems,
+ *      '\\' as directory separator in paths,
+ *      "\r\n" as record (line) terminator in text files, ...
+ *
+ * IMPORTANT Note:
+ *  This symbol is not unique for the MSDOS port !!!!!!
+ *  It is also defined by ports to some other OS which are (to some extend)
+ *  considered DOS compatible.
+ *  Examples are: OS/2 (OS2), Windows NT and Windows 95 (WIN32).
+ *
+ */
+#ifndef MSDOS
+#  define MSDOS
+#endif
+
+/* Power C is similar to Turbo C */
+#ifdef __POWERC
+#  define __TURBOC__
+#endif /* __POWERC */
+
+/* Automatic setting of the common Microsoft C idenfifier MSC.
+ * NOTE: Watcom also defines M_I*86 !
+ */
+#if defined(_MSC_VER) || (defined(M_I86) && !defined(__WATCOMC__))
+#  ifndef MSC
+#    define MSC                 /* This should work for older MSC, too!  */
+#  endif
+#endif
+
+#if !defined(__GO32__) && !defined(__EMX__)
+#  define NO_UNISTD_H
+#endif
+
+#if defined(__WATCOMC__) && defined(__386__)
+#  define WATCOMC_386
+#endif
+
+#ifdef WINDLL
+#  define MSWIN
+#  define MEMORY16
+#endif
+
+
+#if !defined(__EMX__) && !defined(__GO32__) && !defined(WATCOMC_386)
+#if !defined(WINDLL)
+#  define MSDOS16 /* 16 bit MSDOS only */
+#  define MEMORY16
+#endif
+#endif
+
+#if !defined(NO_ASM) && !defined(ASMV)
+#  define ASMV
+#endif
+
+/* enable creation of UTC time fields unless explicitely suppressed */
+#if !defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME)
+#  define USE_EF_UT_TIME
+#endif
+
+/* check that TZ environment variable is defined before using UTC times */
+#if (!defined(NO_IZ_CHECK_TZ) && !defined(IZ_CHECK_TZ))
+#  define IZ_CHECK_TZ
+#endif
+
+#ifdef MEMORY16
+#  ifndef NO_ASM
+#    define ASM_CRC 1
+#  endif /* ?NO_ASM */
+#  ifdef __TURBOC__
+#    include <alloc.h>
+#    if defined(__COMPACT__) || defined(__LARGE__) || defined(__HUGE__)
+#      if defined(DYNAMIC_CRC_TABLE) && defined(DYNALLOC_CRCTAB)
+        error: No dynamic CRC table allocation with Borland C far data models.
+#      endif /* DYNAMIC_CRC_TABLE */
+#    endif /* Turbo/Borland C far data memory models */
+#    define nearmalloc malloc
+#    define nearfree   free
+#    define DYN_ALLOC
+#  else /* !__TURBOC__ */
+#    include <malloc.h>
+#    define nearmalloc _nmalloc
+#    define nearfree   _nfree
+#    define farmalloc  _fmalloc
+#    define farfree    _ffree
+#  endif /* ?__TURBOC__ */
+#  define MY_ZCALLOC 1
+#  ifdef SMALL_MEM
+#    define CBSZ 2048
+#    define ZBSZ 2048
+#  endif
+#  ifdef MEDIUM_MEM
+#    define CBSZ 4096
+#    define ZBSZ 4096
+#  endif
+#  ifndef CBSZ
+#    define CBSZ 8192
+#    define ZBSZ 8192
+#  endif
+#endif /* MEMORY16 */
+
+
+/* Symbolic links are not supported, but some compilers may define S_IFLNK. */
+#ifndef NO_SYMLINKS
+# define NO_SYMLINKS
+#endif
+
+#ifdef MATCH
+#  undef MATCH
+#endif
+#define MATCH dosmatch          /* use DOS style wildcard matching */
+
+#define USE_CASE_MAP
+
+#define ROUNDED_TIME(time)  (((time) + 1) & (~1))
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+                     procname(n, 1))
+
+#define FOPR "rb"
+#define FOPM "r+b"
+#define FOPW "wb"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <io.h>
+
+#ifdef ZCRYPT_INTERNAL
+#  ifdef WINDLL
+#    define ZCR_SEED2     (unsigned)3141592654L /* use PI as seed pattern */
+#  else
+#    ifndef __GO32__
+#      include <process.h>      /* getpid() declaration for srand seed */
+#    endif
+#  endif
+#endif
+
+/*
+ * djgpp 1.x did not declare these
+ */
+#if defined(__GO32__) && !defined(__DJGPP__)
+char *strlwr(char *);
+int setmode(int, int);
+#endif
+
+#ifdef __WATCOMC__
+#  define NO_MKTEMP
+#  define HAS_OPENDIR
+#  define SSTAT stat_bandaid
+   int stat_bandaid(const char *path, struct stat *buf);
+
+/* Get asm routines to link properly without using "__cdecl": */
+#  ifdef __386__
+#    ifdef ASMV
+#      pragma aux match_init    "_*" parm caller [] modify []
+#      pragma aux longest_match "_*" parm caller [] value [eax] \
+                                      modify [eax ecx edx]
+#    endif
+#    ifndef USE_ZLIB
+#      pragma aux crc32         "_*" parm caller [] value [eax] modify [eax]
+#      pragma aux get_crc_table "_*" parm caller [] value [eax] \
+                                      modify [eax ecx edx]
+#    endif /* !USE_ZLIB */
+#  else /* !__386__ */
+#    ifdef ASMV
+#      pragma aux match_init    "_*" parm caller [] loadds modify [ax bx]
+#      pragma aux longest_match "_*" parm caller [] loadds value [ax] \
+                                      modify [ax bx cx dx es]
+#    endif /* ASMV */
+#    ifndef USE_ZLIB
+#      pragma aux crc32         "_*" parm caller [] value [ax dx] \
+                                      modify [ax bx cx dx es]
+#      pragma aux get_crc_table "_*" parm caller [] value [ax] \
+                                      modify [ax bx cx dx]
+#    endif /* !USE_ZLIB */
+#  endif /* ?__386__ */
+#endif /* __WATCOMC__ */
+
+/*
+ * Wrapper function to get around the MSC7 00:00:00 31 Dec 1899 time base,
+ * see msdos.c for more info
+ */
+
+#if defined(_MSC_VER) && _MSC_VER == 700
+#  define localtime(t) msc7_localtime(t)
+#endif
+
+#ifdef __TURBOC__
+#  ifdef __FILEIO_C
+#    include <dir.h>    /* supplies mktemp() prototype */
+#  endif
+#endif
+
+#if (defined(__TURBOC__) && !defined(__BORLANDC__) && __TURBOC__ <= 0x0201)
+#  ifndef NO_MKTIME
+#    define NO_MKTIME           /* TC 2.01 and earlier do not supply mktime() */
+#  endif
+#endif
+
+void check_for_windows(char *app);
diff --git a/msdos/zipup.h b/msdos/zipup.h
new file mode 100644 (file)
index 0000000..78b428a
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define fhow         (O_RDONLY|O_BINARY)
+#define fbad         (-1)
+typedef int          ftype;
+#define zopen(n,p)   open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f)    close(f)
+#define zerr(f)      (k == (extent)(-1L))
+#define zstdin       0
diff --git a/novell/MAKEINIT b/novell/MAKEINIT
new file mode 100644 (file)
index 0000000..f9929e7
--- /dev/null
@@ -0,0 +1,71 @@
+#
+#   makeinit file for makefiles created with QMK386
+#
+#   Novell's NetWare SDK - Release 15
+#
+#   Directories for both the WATCOM and NOVELL tools
+#
+wat386loc = e:\watcom\
+nlm386loc = c:\novell\ndk\nwsdk\
+nlm386hdr = $(nlm386loc)INCLUDE\NLM;$(nlm386loc)INCLUDE;.
+nlm386imp = $(nlm386loc)IMPORTS
+nlm386lib = $(wat386loc)LIB386;$(wat386loc)LIB386\NETWARE
+#
+#   Define this macro with your copyright statement
+#
+#copyright = (C) Copyright 199x NONAME, INC.  All Rights Reserved
+#
+#   Macros that point to various tools we'll need to compile
+#
+wcc386r = WCC386                            # location of 386 real mode compiler
+wcc386p = WCC386P                           # protected compiler (last avail on Watcom v9.5
+wcc386 = $(wcc386r)                         # version we want to use
+linkr = WLINK                               # location of real mode linker
+linkp = WLINKP                              # protected linker (last avail on Watcom v9.5
+linker = $(linkr)                           # version we want to use
+nlmlinkr = $(nlm386loc)TOOLS\NLMLINKR       # location of real mode Novell linker
+nlmlinkp = $(nlm386loc)TOOLS\NLMLINKX       # location of protected Novell linker
+nlmlinker = $(nlmlinkr)                     # version we want to use
+nlmpackr = $(nlm386loc)TOOLS\NLMPACK        # location of real mode NLM compression utility
+nlmpackp = $(nlm386loc)TOOLS\NLMPACKP       # location of protected NLM compression utility
+nlmpack = $(nlmpackr)                       # location of NLM compression utility
+inc_386 = $(nlm386hdr)
+lib_386 = $(nlm386lib)
+code_386 = $(wat386loc)BIN\386WCGL.EXE      # code generator (last avail on Watcom v9.01
+librarian = $(wat386loc)BINB\WLIB           # location of librarian
+#
+#   NLM Import Files
+#
+startup = $(nlm386imp)\PRELUDE.OBJ          # other option is nwpre.obj
+allimp = $(nlm386imp)\ALL.IMP               # import to include all imports
+clibimp = $(nlm386imp)\CLIB.IMP             # the clib import file
+tliimp = $(nlm386imp)\TLI.IMP               # the tli import file
+aioimp = $(nlm386imp)\AIO.IMP               # the aio import file
+socklibimp = $(nlm386imp)\SOCKLIB.IMP       # the socket import file
+mathlibimp = $(nlm386imp)\MATHLIB.IMP       # the math library import file
+dsapiimp = $(nlm386imp)\DSAPI.IMP           # the NDS import file
+nutimp = $(nlm386imp)\NWSNUT.IMP            # the NWSNUT import file
+appleimp = $(nlm386imp)\APPLTLK.IMP         # the AppleTalk import file
+nitimp = $(nlm386imp)\NIT.IMP               # the legacy NLM import file
+nlmlibimp = $(nlm386imp)\NLMLIB.IMP         # the NLM-specific import file
+requesterimp = $(nlm386imp)\REQUESTR.IMP    # the Requester import file
+fpsmimp = $(nlm386imp)\FPSM.IMP             # floating point support import file
+threadsimp = $(nlm386imp)\THREADS.IMP       # the threads import file
+dseventimp = $(nlm386imp)\DSEVENT.IMP       # DS Events import file
+psrvimp = $(nlm386imp)\NWPSRV.IMP           # print services import file
+psrv3ximp = $(nlm386imp)\NWPSRV3X.IMP       # 3.x print services import file
+streamsimp = $(nlm386imp)\STREAMS.IMP       # streams import file
+unicodeimp = $(nlm386imp)\UNICODE.IMP       # unicode import file
+agentimp = $(nlm386imp)\agent.imp           # SNMP Agent import file
+smileimp = $(nlm386imp)\smile.imp           # SMILE (SNMP) import file
+#
+#   Cross-platform Import Files
+#
+audnlm32imp = $(nlm386imp)\AUDNLM32.IMP     # auditing import file
+calnlm32imp = $(nlm386imp)\CALNLM32.IMP     # NWCALLS import file
+clxnlm32imp = $(nlm386imp)\CLXNLM32.IMP     # NWCLIENT import file
+locnlm32imp = $(nlm386imp)\LOCNLM32.IMP     # NWLOCALE import file
+netnlm32imp = $(nlm386imp)\NETNLM32.IMP     # NWNET import file
diff --git a/novell/Makefile b/novell/Makefile
new file mode 100644 (file)
index 0000000..c88bf86
--- /dev/null
@@ -0,0 +1,142 @@
+#
+# This makefile was generated by QMK386 v2.14
+#
+# Program:  unzip.NLM
+#           This makefile rebuilds the zip NetWare Loadable Module
+#
+# Created:  Sun Jan 03 03:54:03 1999
+#
+# MAKEINIT defines many of the macros used herein
+# The following macros can be set via your environment:
+#   CCF386 : Set compile options
+#   QMKVER : Set to 'd' or 'p' to define VERSION
+#   SILENT : If defined, .SILENT will be set
+#
+# The following macros are defined for your program:
+#   vMAJ : Major version number
+#   vMIN : Minor version number
+#   vREV : Revision number
+
+!ifdef %SILENT
+.silent
+!endif
+
+program = zip
+
+pvmaj = 1           # major version number
+pvmin = 00          # minor version number
+pvrev = 3           # revision number e.g. 0,1,2, ...
+
+!ifndef %qmkver
+!   define version p                # use 'd' or 'p' here
+!else
+!   define version $(%qmkver)
+!endif
+!ifeq version d
+!   define lversion DEBUG
+!   define debug /dDEBUG
+!else
+!   define lversion PRODUCTION
+!   define debug
+!endif
+
+nlm_TYPE = Form Novell NLM '$(program)'
+nlm_NAME = Name $^&
+nlm_SCREEN = Op ScreenName '$(program)'
+nlm_THREAD = Op ThreadName '$^&__P '
+nlm_STACK = Op Stack = 8k
+nlm_NLMVER = Op Version = $(pvmaj).$(pvmin).$(pvrev)
+nlm_COPYRIGHT = Op Copyright '$(copyright)'
+linkop = $+$(linkop)$- Caseexact
+linkop = $+$(linkop)$- Nod
+!ifeq version d
+!   define linkop $+$(linkop)$- Map
+!   define linkop $+$(linkop)$- Verbose
+!   define ldebug debug all debug novell
+!endif
+
+objlst = BITS.OBJ
+objlst = $+$(objlst)$- CRC32.OBJ
+objlst = $+$(objlst)$- CRYPT.OBJ
+objlst = $+$(objlst)$- DEFLATE.OBJ
+objlst = $+$(objlst)$- FILEIO.OBJ
+objlst = $+$(objlst)$- GLOBALS.OBJ
+objlst = $+$(objlst)$- MKTIME.OBJ
+objlst = $+$(objlst)$- NETWARE.OBJ
+objlst = $+$(objlst)$- SIGNAL.OBJ
+objlst = $+$(objlst)$- TREES.OBJ
+objlst = $+$(objlst)$- TTYIO.OBJ
+objlst = $+$(objlst)$- UTIL.OBJ
+objlst = $+$(objlst)$- ZIP.OBJ
+objlst = $+$(objlst)$- ZIPFILE.OBJ
+objlst = $+$(objlst)$- ZIPUP.OBJ
+objlst = $+$(objlst)$- $(startup)
+
+import = $(allimp)
+
+module = CLib
+
+build_msg = Building a $(lversion) version of $(program)
+
+pgm_ver = /dvMAJ="$(pvmaj)" /dvMIN="$(pvmin)" /dvREV="$(pvrev)"
+
+!ifndef %ccf386
+!   define  d_wcc386opt /ms /w4 /e99 /zp1 /3s /ot /d2 /dN_PLAT_NLM /d_FIND_OLD_HEADERS -dNO_ASM -dNLM $(debug)
+!   define  p_wcc386opt /ms /w4 /s /zp1 /3s /oaxt /dN_PLAT_NLM /d_FIND_OLD_HEADERS -dNO_ASM -dNLM
+!   define  x_wcc386opt $($(version)_wcc386opt) $(pgm_ver)
+!else
+!   define  x_wcc386opt $(%ccf386)
+!endif
+
+compiler_cmd = $(wcc386) $(x_wcc386opt) $[*.c
+
+.BEFORE
+    echo $(build_msg)
+    set inc386=$(inc_386)
+    set lib386=$(lib_386)
+    set wcg386=$(code_386)
+
+.c.obj:
+        $(compiler_cmd)
+
+zip.nlm : $(objlst) zip.LNK
+        $(linker) @zip
+
+zip.LNK : MAKEFILE
+  if exist $^&.LNK del $^&.LNK
+  %append $^&.LNK $(nlm_TYPE)
+  %append $^&.LNK $(nlm_NAME)
+  %append $^&.LNK $(nlm_SCREEN)
+  %append $^&.LNK $(nlm_THREAD)
+  %append $^&.LNK $(nlm_STACK)
+  %append $^&.LNK $(nlm_NLMVER)
+!ifdef copyright
+  %append $^&.LNK $(nlm_COPYRIGHT)
+!endif
+!ifdef ldebug
+  %append $^&.LNK $(ldebug)
+!endif
+  for %i in ($(linkop)) do %append $^&.LNK Op %i
+  for %i in ($(objlst)) do %append $^&.LNK File %i
+  for %i in ($(import)) do %append $^&.LNK Import @%i
+  for %i in ($(export)) do %append $^&.LNK Export @%i
+  for %i in ($(module)) do %append $^&.LNK Module %i
+  for %i in ($(library)) do %append $^&.LNK Library %i
+
+clean : .symbolic
+    del *.MAP
+    del *.OBJ
+    del *.ERR
+    del *.LNK
+    del *.NLM
+
+zip : .symbolic
+    -pkzip -u zip MAKEFILE *.c *.h
+
+unzip : .symbolic
+    -pkunzip -n -d zip
+
+save : .symbolic
+    %make zip
+    %make clean
+
diff --git a/novell/Netware.c b/novell/Netware.c
new file mode 100644 (file)
index 0000000..20efa16
--- /dev/null
@@ -0,0 +1,970 @@
+#include <stdio.h> 
+#include <stdlib.h> 
+#include <string.h>
+#include <ntypes.h>
+#include <nwconio.h> 
+#include <ctype.h>
+#include <unistd.h>
+#include <nit\nwdir.h>
+#include <dirent.h>
+#include <nwnamspc.h> 
+#include <locale.h>
+#include <nwlocale.h>
+#include <time.h>
+
+extern void UseAccurateCaseForPaths(int);
+
+#include "zip.h"
+
+   /*------------------------------------------------------------------
+   **   Global Variables
+   */
+
+#define   skipspace( x )  while( isspace( *x ) ) ++x
+#define   nextspace( x )  while( *x && !isspace( *x ) ) ++x
+#define   CWS     0
+#define   CWV     1
+#define   CWP     2
+#define   ALL     99
+
+/* Globals */
+extern      char   *GetWorkArea(void);
+extern      char   *next_arg(char *);
+extern         int NLM_exiting;
+char        fid[100];
+static      breakkey = FALSE;
+
+#define MATCH shmatch
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+#define PAD 0
+#define PATH_END '/'
+
+local char *readd(d)
+DIR *d;                 /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+   no more entries or an error occurs. */
+{
+  struct dirent *e;
+
+  e = readdir(d);
+  return e == NULL ? (char *) NULL : e->d_name;
+}
+
+void findzip(char *s)
+{
+   dowhereis(s);
+} 
+
+void dowhereis(char *s)
+{
+   char    dir[_MAX_PATH];
+   char    fsv[_MAX_SERVER+_MAX_VOLUME+1];
+   char    fdir[_MAX_PATH];
+   char    fname[_MAX_FNAME],fext[_MAX_EXT], both[_MAX_FNAME+_MAX_EXT];
+   char    *p = next_arg(s); /* point at argument */
+
+   if(!*p)
+   {
+      printf("No filename specified!");
+      return;
+   }
+
+   //setlocale (LC_ALL, "NORWAY");
+   NWLsetlocale (LC_ALL, "NORWAY");
+
+   strcpy(dir,GetWorkArea());
+
+   /* get the file name specification */
+   _splitpath(p,fsv,fdir,fname,fext);
+
+   //printf ("p %s, fsv %s, fdir %s, fname %s, fext %s\n", p,fsv,fdir,fname,fext);
+   //getch();
+   
+   sprintf(both,"%s%s",strupr(fname),strupr(fext));
+
+   breakkey = FALSE;
+
+   /* startup the recursive file find operation */
+   chdir(fsv);
+   UseAccurateCaseForPaths(1);
+   SetCurrentNameSpace (NW_NS_LONG);
+   chdir(fdir);
+   findit(both);
+}
+
+char *GetWorkArea(void)
+{
+   static  char   cwd[_MAX_PATH];
+   static  char   serverName[_MAX_SERVER];
+   static  char   volumeName[_MAX_VOLUME + 1];
+   static  char   dirName[_MAX_DIR];
+
+   if(getcwd(cwd,_MAX_PATH) == NULL) 
+      return NULL;
+
+   ParsePath(cwd,serverName,volumeName,dirName);   /* shouldn't fail! */
+
+   return cwd;
+}
+
+char *next_arg(char *s)
+{
+   char    *p;
+
+   skipspace(s);     /* ignore white */
+   p = s;
+   nextspace(s);     /* find next blank */
+   *s = NULL;
+   return(p);
+}
+
+static void findit(char *what)
+{
+   char dir[_MAX_PATH];
+   char zipdir[_MAX_PATH];
+   char szzipfile[_MAX_PATH];
+   char *psz;
+   DIR *dirStructPtr;
+   DIR *dirStructPtrSave;
+   int r;
+
+   getcwd(dir,_MAX_PATH);
+
+   psz = dir;
+
+         while (*psz)
+         {
+                 if (*psz == ':')
+                 {
+                         strcpy (zipdir, psz + 1);
+                         break;
+                 }
+                 psz++;
+         }
+
+   dirStructPtrSave = dirStructPtr = opendir(what);
+
+       /*
+       _A_NORMAL Normal file; read/write permitted 
+       _A_RDONLY Read-only file 
+       _A_HIDDEN Hidden file 
+       _A_SYSTEM System file 
+       _A_VOLID Volume ID entry 
+       _A_SUBDIR Subdirectory 
+       _A_ARCH Archive file 
+       */
+
+   if (hidden_files)
+         SetReaddirAttribute (dirStructPtr, _A_NORMAL | _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH);
+   else
+         SetReaddirAttribute (dirStructPtr, _A_NORMAL | _A_ARCH);
+
+   //while(dirStructPtr && !breakkey)
+   while(dirStructPtr && !NLM_exiting)
+   {
+         //printf ("\n NLM_exiting test Line 167.... \n");
+          
+      dirStructPtr = readdir(dirStructPtr);
+      if((dirStructPtr == NULL) || (dirStructPtr == -1))
+         break;
+      
+         /* Filen er funnet */
+      if(dirStructPtr->d_attr & _A_SUBDIR)
+               continue;
+
+         strcpy (szzipfile, zipdir);
+         strcat (szzipfile, "/");
+         strcat (szzipfile, dirStructPtr->d_name);
+         procnamehho (szzipfile);
+
+         //ThreadSwitchWithDelay();
+
+      //if(kbhit() && getch() == 3) 
+        // printf("^C\n",breakkey = TRUE);
+   }
+
+   if(dirStructPtrSave) 
+      closedir(dirStructPtrSave);
+
+   if (!recurse)
+          return;
+
+   /*  Now traverse the directories in this path */
+
+   dirStructPtrSave = dirStructPtr = opendir("*.*");
+   if(dirStructPtr == NULL) 
+      return;
+
+   if (hidden_files)
+               SetReaddirAttribute (dirStructPtr, _A_NORMAL | _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH | _A_SUBDIR);
+        else
+               SetReaddirAttribute (dirStructPtr, _A_NORMAL | _A_ARCH | _A_SUBDIR);
+
+   //ThreadSwitchWithDelay();
+
+   while(!NLM_exiting)
+   {
+         //printf ("\n NLM_exiting test Line 204.... \n"); getch ();
+
+      dirStructPtr = readdir(dirStructPtr);
+      if((dirStructPtr == NULL) || (dirStructPtr == -1))
+         break;
+      
+      if(dirStructPtr->d_attr & _A_SUBDIR)
+      {
+                strcpy (szzipfile, zipdir);
+                strcat (szzipfile, "/");
+                strcat (szzipfile, dirStructPtr->d_name);
+                procnamehho (szzipfile);
+
+         chdir(dirStructPtr->d_name);
+         findit(what);                
+         chdir("..");
+      }
+
+      //if(kbhit() && getch() == 3) 
+        // printf("^C\n",breakkey = TRUE);
+   }
+
+   if(dirStructPtrSave) 
+      closedir(dirStructPtrSave);
+} 
+
+
+int wild(w)
+char *w;                /* path/pattern to match */
+/* If not in exclude mode, expand the pattern based on the contents of the
+   file system.  Return an error code in the ZE_ class. */
+{
+  DIR *d;               /* stream for reading directory */
+  char *e;              /* name found in directory */
+  int r;                /* temporary variable */
+  char *n;              /* constructed name from directory */
+  int f;                /* true if there was a match */
+  char *a;              /* alloc'ed space for name */
+  //char *p;              /* path */
+  char *q;              /* name */
+  char v[5];            /* space for device current directory */
+
+
+  char    dir[_MAX_PATH];
+  char    fsv[_MAX_SERVER+_MAX_VOLUME+1];
+  char    fdir[_MAX_PATH];
+  char    fname[_MAX_FNAME],fext[_MAX_EXT], both[_MAX_FNAME+_MAX_EXT];
+  char    *p; /* point at argument */
+
+  p = w;
+
+
+  /* Test HHO */
+  findzip(p);
+
+  return ZE_OK;
+
+
+  strcpy(dir,GetWorkArea());
+
+   /* get the file name specification */
+
+   _splitpath(p,fsv,fdir,fname,fext);
+   sprintf(both,"%s%s",strupr(fname),strupr(fext));
+
+   /* startup the recursive file find operation */
+
+   chdir(fsv);
+   
+  /* Search that level for matching names */
+  if ((d = opendir(both)) == NULL)
+  {
+    free((zvoid *)a);
+    return ZE_MISS;
+  }
+  
+  f = 0;
+  while ((e = readd(d)) != NULL) {
+    if (strcmp(e, ".") && strcmp(e, "..") && MATCH(q, e))
+    {
+      f = 1;
+      if (strcmp(p, ".") == 0) {                /* path is . */
+        r = procname(e);                        /* name is name */
+        if (r) {
+           f = 0;
+           break;
+        }
+      } else
+      {
+        if ((n = malloc(strlen(p) + strlen(e) + 2)) == NULL)
+        {
+          free((zvoid *)a);
+          closedir(d);
+          return ZE_MEM;
+        }
+        n = strcpy(n, p);
+        if (n[r = strlen(n) - 1] != '/' && n[r] != ':')
+          strcat(n, "/");
+        r = procname(strcat(n, e));             /* name is path/name */
+        free((zvoid *)n);
+        if (r) {
+          f = 0;
+          break;
+        }
+      }
+    }
+  }
+  closedir(d);
+
+  /* Done */
+  free((zvoid *)a);
+  return f ? ZE_OK : ZE_MISS;
+}
+
+int procnamehho (char *n)
+{
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  char *a;
+
+  if (n == NULL)        /* volume_label request in freshen|delete mode ?? */
+    return ZE_OK;
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0);
+  else if (stat(n, &s)
+#if defined(__TURBOC__) || defined(__WATCOMC__)
+           /* For these 2 compilers, stat() succeeds on wild card names! */
+           || isshexp(n)
+#endif
+          )
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname))
+      {
+        z->mark = pcount ? filter(z->zname) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  for (p = n; *p; p++)          /* use / consistently */
+    if (*p == '\\')
+      *p = '/';
+
+  //printf ("\nHHO %s\n", n);
+  if ((s.st_mode & S_IFDIR) == 0)
+  {
+       //printf ("\nHHO1 %s\n", n);
+    /* add or remove name of file */
+       //printf ("\nAdding name %s to list.\n", n);
+    if ((m = newname(n, 0)) != ZE_OK)
+      return m;
+  } else {
+    
+       /* Add trailing / to the directory name */
+    if ((p = malloc(strlen(n)+2)) == NULL)
+     return ZE_MEM;
+    if (strcmp(n, ".") == 0 || strcmp(n, "/.") == 0) {
+      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      strcpy(p, n);
+      a = p + strlen(p);
+      if (a[-1] != '/')
+        strcpy(a, "/");
+    //if (dirnames && (m = newname(p, 1)) != ZE_OK) {
+         if ((m = newname(p, 1)) != ZE_OK) {
+        free((zvoid *)p);
+        return m;
+      }
+         free ((zvoid *)p);
+    }
+      
+       return ZE_OK;
+  }
+  return ZE_OK;
+}
+
+int procname(n)
+char *n;                /* name to process */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  DIR *d;               /* directory stream from opendir() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (n == NULL)        /* volume_label request in freshen|delete mode ?? */
+    return ZE_OK;
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0);
+  else if (stat(n, &s)
+#if defined(__TURBOC__) || defined(__WATCOMC__)
+           /* For these 2 compilers, stat() succeeds on wild card names! */
+           || isshexp(n)
+#endif
+          )
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname))
+      {
+        z->mark = pcount ? filter(z->zname) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  for (p = n; *p; p++)          /* use / consistently */
+    if (*p == '\\')
+      *p = '/';
+  if ((s.st_mode & S_IFDIR) == 0)
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0)) != ZE_OK)
+      return m;
+  } else {
+    /* Add trailing / to the directory name */
+    if ((p = malloc(strlen(n)+2)) == NULL)
+      return ZE_MEM;
+    if (strcmp(n, ".") == 0 || strcmp(n, "/.") == 0) {
+      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      strcpy(p, n);
+      a = p + strlen(p);
+      if (a[-1] != '/')
+        strcpy(a, "/");
+      if (dirnames && (m = newname(p, 1)) != ZE_OK) {
+        free((zvoid *)p);
+        return m;
+      }
+    }
+    /* recurse into directory */
+    if (recurse && (d = opendir(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if (strcmp(e, ".") && strcmp(e, ".."))
+        {
+          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+          {
+            closedir(d);
+            free((zvoid *)p);
+            return ZE_MEM;
+          }
+          strcat(strcpy(a, p), e);
+          if ((m = procname(a)) != ZE_OK)   /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", a);
+            else
+              ziperr(m, a);
+          }
+          free((zvoid *)a);
+        }
+      }
+      closedir(d);
+    }
+    free((zvoid *)p);
+  } /* (s.st_mode & S_IFDIR) == 0) */
+  return ZE_OK;
+}
+
+char *szRelativParameter;
+char szRelativ[512];
+int    iRelativOK = FALSE;
+int    iRelativPakking = FALSE;
+
+int fixRelativpath ()
+{
+       char *szp;
+       
+       szp = szRelativParameter;
+
+       if (szRelativParameter[0] == '/' || szRelativParameter[0] == '\\')
+               szp++;
+
+       while (*szp) {
+               if (*szp == '\\')
+                       *szp = '/';
+               szp++;
+       }
+
+       szp = szRelativParameter;
+       if (szRelativParameter[0] == '/')
+               szp++;
+
+       strcpy (szRelativ, szp);
+
+       if (strlen(szp) == 0) {
+               szRelativ[0] = '\0';
+               return FALSE;
+       }
+       return TRUE;
+}
+
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t;              /* shortened name */
+  int dosflag;
+  char *sztUpper;
+  
+  
+  /* Find starting point in name before doing malloc */
+  t = *x && *(x + 1) == ':' ? x + 2 : x;
+  while (*t == '/' || *t == '\\')
+    t++;
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+  for (n = t; *n; n++)
+    if (*n == '\\')
+      *n = '/';
+       
+  if (iRelativPakking) {
+         //printf ("\n LINE 516  *ex2ex Internt navn %s external name %s.\n", t, x); getch ();
+         if (!iRelativOK) {
+                 if (!fixRelativpath()) {
+                       iRelativOK = FALSE;
+                       iRelativPakking = FALSE;
+                 }
+                 else {
+                       sztUpper = malloc (strlen(t) + 10);
+                       strcpy (sztUpper, t);
+                       NWLstrupr (sztUpper);
+                       NWLstrupr (szRelativ);
+                       if (strncmp (sztUpper, szRelativ, strlen(szRelativ)) == 0) {
+                               t = t + strlen(szRelativ);
+                               iRelativPakking = TRUE;
+                               iRelativOK = TRUE;
+                       }
+                       else {
+                               iRelativOK = FALSE;
+                               iRelativPakking = FALSE;
+                       }
+                       free (sztUpper);
+                 }
+         }
+         else 
+         {
+               t = t + strlen(szRelativ);
+         }
+  }
+  
+  if (!pathput)
+    t = last(t, PATH_END);
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL)
+    return NULL;
+  strcpy(n, t);
+
+  if (dosify)
+    msname(n);
+
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+
+  return n;
+}
+
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+    return NULL;
+  strcpy(x, n);
+
+  //if ( !IsFileNameValid(x) )
+    //ChangeNameForFAT(x);
+
+  //printf ("\n *in2ex Internt navn %s external name %s.\n", n, x); getch ();
+
+  return x;
+}
+
+
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+  //SetFileTime(f, d);
+}
+
+ulg filetime(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  /* convert FNMAX to malloc - 11/8/04 EG */
+  char *name;
+  int len = strlen(f);
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+  if (strcmp(f, "-") == 0) {
+    if (fstat(fileno(stdin), &s) != 0)
+      error("fstat(stdin)");
+  }
+  else if (stat(name, &s) != 0) {
+    /* Accept about any file kind including directories
+     * (stored with trailing / with -r option)
+     */
+    free(name);
+    return 0;
+  }
+  free(name);
+
+  if (a != NULL) {
+         *a = s.st_attr; // << 16) | !(s.st_mode & S_IWRITE);
+    //*a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+    //if ((s.st_mode & S_IFMT) == S_IFDIR) {
+    //*a |= MSDOS_DIR_ATTR;
+    //}
+  }
+  if (n != NULL)
+         *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+           
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = t->mtime;   /* best guess, (s.st_ctime: last status change!!) */
+  }
+  return unix2dostime(&s.st_mtime);
+}
+
+
+ulg filetimeHHO(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  char *name;
+  int len = strlen(f), isstdin = !strcmp(f, "-");
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetimeHHO");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+
+  if (isstdin) {
+    /* it is common for some PC based compilers to 
+       fail with fstat() on devices or pipes */
+    if (fstat(fileno(stdin), &s) != 0) {
+      s.st_mode = S_IFREG; s.st_size = -1L;
+    }
+    time(&s.st_ctime);
+    s.st_atime = s.st_mtime = s.st_ctime;
+  } else if (stat(name, &s) != 0) {
+             /* Accept about any file kind including directories
+              * (stored with trailing / with -r option)
+              */
+    free(name);
+    return 0;
+  }
+
+  if (a != NULL) {
+    //*a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)GetFileMode(name));
+       //*a = (ulg)s.st_mode;
+         *a = s.st_attr;
+  }
+
+  printf ("\nDette er en test LINE : 721 \n"); getch();
+
+  if (n != NULL)
+    *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+#ifdef __WATCOMC__
+  /* of course, Watcom always has to make an exception */
+  if (s.st_atime == 312764400)
+    s.st_atime = s.st_mtime;
+  if (s.st_ctime == 312764400)
+    s.st_ctime = s.st_mtime;
+#endif
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = s.st_ctime;
+  }
+
+  printf ("\nDette er en test LINE : 735 \n"); getch();
+
+  //return GetFileTime(name);
+  free(name);
+  return t->atime;
+}
+
+int deletedir(d)
+char *d;                /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+   Return the result of rmdir(), delete(), or system().
+ */
+{
+    return rmdir(d);
+}
+
+int set_extra_field(z, z_utim)
+  struct zlist far *z;
+  iztimes *z_utim;
+  /* create extra field and change z->att if desired */
+{
+#ifdef USE_EF_UT_TIME
+  if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
+    return ZE_MEM;
+
+  z->extra[0]  = 'U';
+  z->extra[1]  = 'T';
+  z->extra[2]  = EB_UT_LEN(1);          /* length of data part of e.f. */
+  z->extra[3]  = 0;
+  z->extra[4]  = EB_UT_FL_MTIME;
+  z->extra[5]  = (char)(z_utim->mtime);
+  z->extra[6]  = (char)(z_utim->mtime >> 8);
+  z->extra[7]  = (char)(z_utim->mtime >> 16);
+  z->extra[8]  = (char)(z_utim->mtime >> 24);
+
+  z->cext = z->ext = (EB_HEADSIZE+EB_UT_LEN(1));
+  z->cextra = z->extra;
+
+  return ZE_OK;
+#else /* !USE_EF_UT_TIME */
+  return (int)(z-z);
+#endif /* ?USE_EF_UT_TIME */
+}
+
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+                        /* At module level to keep Turbo C++ 1.0 happy !! */
+
+void version_local()
+{
+#if defined(__DJGPP__) || defined(__WATCOMC__) || \
+    (defined(_MSC_VER) && (_MSC_VER != 800))
+    char buf[80];
+#endif
+
+    printf(CompiledWith,
+
+#ifdef __GNUC__
+#  if defined(__DJGPP__)
+      (sprintf(buf, "djgpp v%d / gcc ", __DJGPP__), buf),
+#  elif defined(__GO32__)
+      "djgpp v1.x / gcc ",
+#  elif defined(__EMX__)            /* ...so is __EMX__ (double sigh) */
+      "emx+gcc ",
+#  else
+      "gcc ",
+#  endif
+      __VERSION__,
+#elif defined(__WATCOMC__)
+#  if (__WATCOMC__ % 10 > 0)
+/* We do this silly test because __WATCOMC__ gives two digits for the  */
+/* minor version, but Watcom packaging prefers to show only one digit. */
+      (sprintf(buf, "Watcom C/C++ %d.%02d", __WATCOMC__ / 100,
+               __WATCOMC__ % 100), buf), "",
+#  else
+      (sprintf(buf, "Watcom C/C++ %d.%d", __WATCOMC__ / 100,
+               (__WATCOMC__ % 100) / 10), buf), "",
+#  endif
+#elif defined(__TURBOC__)
+#  ifdef __BORLANDC__
+      "Borland C++",
+#    if (__BORLANDC__ < 0x0200)
+        " 1.0",
+#    elif (__BORLANDC__ == 0x0200)   /* James:  __TURBOC__ = 0x0297 */
+        " 2.0",
+#    elif (__BORLANDC__ == 0x0400)
+        " 3.0",
+#    elif (__BORLANDC__ == 0x0410)   /* __BCPLUSPLUS__ = 0x0310 */
+        " 3.1",
+#    elif (__BORLANDC__ == 0x0452)   /* __BCPLUSPLUS__ = 0x0320 */
+        " 4.0 or 4.02",
+#    elif (__BORLANDC__ == 0x0460)   /* __BCPLUSPLUS__ = 0x0340 */
+        " 4.5",
+#    elif (__BORLANDC__ == 0x0500)   /* __TURBOC__ = 0x0500 */
+        " 5.0",
+#    else
+        " later than 5.0",
+#    endif
+#  else
+      "Turbo C",
+#    if (__TURBOC__ > 0x0401)
+        "++ later than 3.0"
+#    elif (__TURBOC__ == 0x0401)     /* Kevin:  3.0 -> 0x0401 */
+        "++ 3.0",
+#    elif (__TURBOC__ == 0x0295)     /* [661] vfy'd by Kevin */
+        "++ 1.0",
+#    elif ((__TURBOC__ >= 0x018d) && (__TURBOC__ <= 0x0200)) /* James: 0x0200 */
+        " 2.0",
+#    elif (__TURBOC__ > 0x0100)
+        " 1.5",                    /* James:  0x0105? */
+#    else
+        " 1.0",                    /* James:  0x0100 */
+#    endif
+#  endif
+#elif defined(MSC)
+      "Microsoft C ",
+#  ifdef _MSC_VER
+#    if (_MSC_VER == 800)
+        "(Visual C++ v1.1)",
+#    elif (_MSC_VER == 850)
+        "(Windows NT v3.5 SDK)",
+#    elif (_MSC_VER == 900)
+        "(Visual C++ v2.0/v2.1)",
+#    elif (_MSC_VER > 900)
+        (sprintf(buf2, "(Visual C++ v%d.%d)", _MSC_VER/100 - 6,
+          _MSC_VER%100/10), buf2),
+#    else
+        (sprintf(buf, "%d.%02d", _MSC_VER/100, _MSC_VER%100), buf),
+#    endif
+#  else
+      "5.1 or earlier",
+#  endif
+#else
+      "unknown compiler", "",
+#endif
+
+      "MS-DOS",
+
+#if (defined(__GNUC__) || (defined(__WATCOMC__) && defined(__386__)))
+      " (32-bit)",
+#elif defined(M_I86HM) || defined(__HUGE__)
+      " (16-bit, huge)",
+#elif defined(M_I86LM) || defined(__LARGE__)
+      " (16-bit, large)",
+#elif defined(M_I86MM) || defined(__MEDIUM__)
+      " (16-bit, medium)",
+#elif defined(M_I86CM) || defined(__COMPACT__)
+      " (16-bit, compact)",
+#elif defined(M_I86SM) || defined(__SMALL__)
+      " (16-bit, small)",
+#elif defined(M_I86TM) || defined(__TINY__)
+      " (16-bit, tiny)",
+#else
+      " (16-bit)",
+#endif
+
+#ifdef __DATE__
+      " on ", __DATE__
+#else
+      "", ""
+#endif
+    );
+
+} /* end function version_local() */
+
+
+#ifdef __WATCOMC__
+
+/* This papers over a bug in Watcom 10.6's standard library... sigh */
+/* Apparently it applies to both the DOS and Win32 stat()s.         */
+
+int stat_bandaid(const char *path, struct stat *buf)
+{
+  char newname[4];
+  if (!stat(path, buf))
+    return 0;
+  else if (!strcmp(path, ".") || (path[0] && !strcmp(path + 1, ":."))) {
+    strcpy(newname, path);
+    newname[strlen(path) - 1] = '\\';   /* stat(".") fails for root! */
+    return stat(newname, buf);
+  } else
+    return -1;
+}
+
+#endif
+
+
diff --git a/novell/README b/novell/README
new file mode 100644 (file)
index 0000000..a620c1b
--- /dev/null
@@ -0,0 +1,9 @@
+Unfinished integration into zip 2.4 of novell port to zip 2.2.
+
+TODO:
+
+Too much novell specific stuff via ifdef into the main sourcecode,
+use atexit() and setjmp()/longjmp() constructions instead.
+
+If a function doesn't exist (e.g. isatty), just write a wrapper
+and put it in Netware.c
diff --git a/novell/m.cmd b/novell/m.cmd
new file mode 100644 (file)
index 0000000..04084b3
--- /dev/null
@@ -0,0 +1,9 @@
+wmake
+
+copy zip.nlm f:
+
+attrib -r -h -s g:\hho\*.* /s
+del g:\hho\Attrib\*.*
+del g:\hho\Attrib\*.*
+rmdir g:\hho\Attrib
+
diff --git a/novell/osdep.h b/novell/osdep.h
new file mode 100644 (file)
index 0000000..f7b463c
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/* The symbol DOS is used throughout the Zip source to identify code portions
+ * specific to the MSDOS port.
+ * Just to make sure, we check that it is set.
+ * (Currently, this should should not be neccessary, since currently it has
+ * to be set on the compiler command line to get this file read in.)
+ */
+#ifndef DOS
+#  define DOS
+#endif
+
+/* The symbol MSDOS is consistently used in the generic source files
+ * to identify code to support for MSDOS (and MSDOS related) stuff.
+ * e.g: FAT or (FAT like) file systems,
+ *      '\\' as directory separator in paths,
+ *      "\r\n" as record (line) terminator in text files, ...
+ *
+ * IMPORTANT Note:
+ *  This symbol is not unique for the MSDOS port !!!!!!
+ *  It is also defined by ports to some other OS which are (to some extend)
+ *  considered DOS compatible.
+ *  Examples are: OS/2 (OS2), Windows NT and Windows 95 (WIN32).
+ *
+ */
+#ifndef MSDOS
+#  define MSDOS
+#endif
+
+/* Power C is similar to Turbo C */
+#ifdef __POWERC
+#  define __TURBOC__
+#endif /* __POWERC */
+
+/* Automatic setting of the common Microsoft C idenfifier MSC.
+ * NOTE: Watcom also defines M_I*86 !
+ */
+#if defined(_MSC_VER) || (defined(M_I86) && !defined(__WATCOMC__))
+#  ifndef MSC
+#    define MSC                 /* This should work for older MSC, too!  */
+#  endif
+#endif
+
+#if !defined(__GO32__) && !defined(__EMX__)
+#  define NO_UNISTD_H
+#endif
+
+#if defined(__WATCOMC__) && defined(__386__)
+#  define WATCOMC_386
+#endif
+
+#ifdef WINDLL
+#  define MSWIN
+#  define MEMORY16
+#endif
+
+
+#if !defined(__EMX__) && !defined(__GO32__) && !defined(WATCOMC_386)
+#if !defined(WINDLL)
+#  define MSDOS16 /* 16 bit MSDOS only */
+#  define MEMORY16
+#endif
+#endif
+
+#if !defined(NO_ASM) && !defined(ASMV)
+#  define ASMV
+#endif
+
+/* enable creation of UTC time fields unless explicitely suppressed */
+#if !defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME)
+#  define USE_EF_UT_TIME
+#endif
+
+/* check that TZ environment variable is defined before using UTC times */
+#if (!defined(NO_IZ_CHECK_TZ) && !defined(IZ_CHECK_TZ))
+#  define IZ_CHECK_TZ
+#endif
+
+#ifdef MEMORY16
+#  ifndef NO_ASM
+#    define ASM_CRC 1
+#  endif /* ?NO_ASM */
+#  ifdef __TURBOC__
+#    include <alloc.h>
+#    if defined(__COMPACT__) || defined(__LARGE__) || defined(__HUGE__)
+#      if defined(DYNAMIC_CRC_TABLE) && defined(DYNALLOC_CRCTAB)
+        error: No dynamic CRC table allocation with Borland C far data models.
+#      endif /* DYNAMIC_CRC_TABLE */
+#    endif /* Turbo/Borland C far data memory models */
+#    define nearmalloc malloc
+#    define nearfree   free
+#    define DYN_ALLOC
+#  else /* !__TURBOC__ */
+#    include <malloc.h>
+#    define nearmalloc _nmalloc
+#    define nearfree   _nfree
+#    define farmalloc  _fmalloc
+#    define farfree    _ffree
+#  endif /* ?__TURBOC__ */
+#  define MY_ZCALLOC 1
+#  ifdef SMALL_MEM
+#    define CBSZ 2048
+#    define ZBSZ 2048
+#  endif
+#  ifdef MEDIUM_MEM
+#    define CBSZ 4096
+#    define ZBSZ 4096
+#  endif
+#  ifndef CBSZ
+#    define CBSZ 8192
+#    define ZBSZ 8192
+#  endif
+#endif /* MEMORY16 */
+
+
+#ifdef MATCH
+#  undef MATCH
+#endif
+#define MATCH dosmatch          /* use DOS style wildcard matching */
+
+#define USE_CASE_MAP
+
+#define ROUNDED_TIME(time)  (((time) + 1) & (~1))
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+                     procname(n, 1))
+
+#define FOPR "rb"
+#define FOPM "r+b"
+#define FOPW "wb"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <io.h>
+
+#ifdef ZCRYPT_INTERNAL
+#  ifdef WINDLL
+#    define ZCR_SEED2     (unsigned)3141592654L /* use PI as seed pattern */
+#  else
+#    ifndef __GO32__
+#      include <process.h>      /* getpid() declaration for srand seed */
+#    endif
+#  endif
+#endif
+
+/*
+ * djgpp 1.x did not declare these
+ */
+#if defined(__GO32__) && !defined(__DJGPP__)
+char *strlwr(char *);
+int setmode(int, int);
+#endif
+
+#ifdef __WATCOMC__
+#  define NO_MKTEMP
+#  define HAS_OPENDIR
+#  define SSTAT stat_bandaid
+   int stat_bandaid(const char *path, struct stat *buf);
+
+/* Get asm routines to link properly without using "__cdecl": */
+#  ifdef __386__
+#    ifdef ASMV
+#      pragma aux match_init    "_*" parm caller [] modify []
+#      pragma aux longest_match "_*" parm caller [] value [eax] \
+                                      modify [eax ecx edx]
+#    endif
+#    ifndef USE_ZLIB
+#      pragma aux crc32         "_*" parm caller [] value [eax] modify [eax]
+#      pragma aux get_crc_table "_*" parm caller [] value [eax] \
+                                      modify [eax ecx edx]
+#    endif /* !USE_ZLIB */
+#  else /* !__386__ */
+#    ifdef ASMV
+#      pragma aux match_init    "_*" parm caller [] loadds modify [ax bx]
+#      pragma aux longest_match "_*" parm caller [] loadds value [ax] \
+                                      modify [ax bx cx dx es]
+#    endif /* ASMV */
+#    ifndef USE_ZLIB
+#      pragma aux crc32         "_*" parm caller [] value [ax dx] \
+                                      modify [ax bx cx dx es]
+#      pragma aux get_crc_table "_*" parm caller [] value [ax] \
+                                      modify [ax bx cx dx]
+#    endif /* !USE_ZLIB */
+#  endif /* ?__386__ */
+#endif /* __WATCOMC__ */
+
+/*
+ * Wrapper function to get around the MSC7 00:00:00 31 Dec 1899 time base,
+ * see msdos.c for more info
+ */
+
+#if defined(_MSC_VER) && _MSC_VER == 700
+#  define localtime(t) msc7_localtime(t)
+#endif
+
+#if (defined(__TURBOC__) && !defined(__BORLANDC__) && __TURBOC__ <= 0x0201)
+#  ifndef NO_MKTIME
+#    define NO_MKTIME           /* TC 2.01 and earlier do not supply mktime() */
+#  endif
+#endif
diff --git a/novell/signal.c b/novell/signal.c
new file mode 100644 (file)
index 0000000..a092bd3
--- /dev/null
@@ -0,0 +1,49 @@
+#include <nwthread.h>
+#include <nwerrno.h>
+
+/*******************************/
+/*  Interupt handler              */
+/*******************************/
+
+int NLM_mainThreadGroupID;
+int NLM_threadCnt = 0;
+int NLM_exiting = FALSE;
+
+#pragma off(unreferenced);
+void NLM_SignalHandler(int sig)
+#pragma on(unreferenced);
+{
+       int handlerThreadGroupID;
+
+       switch(sig)
+       {
+       case SIGTERM:
+               NLM_exiting = TRUE;
+               handlerThreadGroupID = GetThreadGroupID();
+               SetThreadGroupID(NLM_mainThreadGroupID);
+
+               /* NLM SDK functions may be called here */
+
+               while (NLM_threadCnt != 0) 
+                       ThreadSwitchWithDelay();
+               SetThreadGroupID(handlerThreadGroupID);
+               break;
+       case SIGINT:
+               signal(SIGINT, NLM_SignalHandler);
+               break;
+       }
+       return;
+}
+
+void NLMsignals(void)
+{
+    ++NLM_threadCnt;
+    NLM_mainThreadGroupID = GetThreadGroupID();
+    signal(SIGTERM, NLM_SignalHandler);
+    signal(SIGINT, NLM_SignalHandler);
+}
+
+void NLMexit(void)
+{
+   --NLM_threadCnt;
+}
diff --git a/novell/zip.lnk b/novell/zip.lnk
new file mode 100644 (file)
index 0000000..19626c7
--- /dev/null
@@ -0,0 +1,25 @@
+Form Novell NLM 'zip'
+Name zip
+Op ScreenName 'zip'
+Op ThreadName 'zip__P '
+Op Stack = 8k
+Op Version = 1.00.3
+Op Caseexact
+Op Nod
+File BITS.OBJ
+File CRC_i386.OBJ
+File CRYPT.OBJ
+File DEFLATE.OBJ
+File FILEIO.OBJ
+File GLOBALS.OBJ
+File MKTIME.OBJ
+File NETWARE.OBJ
+File TREES.OBJ
+File TTYIO.OBJ
+File UTIL.OBJ
+File ZIP.OBJ
+File ZIPFILE.OBJ
+File ZIPUP.OBJ
+File c:\novell\ndk\nwsdk\IMPORTS\PRELUDE.OBJ
+Import @c:\novell\ndk\nwsdk\IMPORTS\ALL.IMP
+Module CLib
diff --git a/novell/zipup.h b/novell/zipup.h
new file mode 100644 (file)
index 0000000..78b428a
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define fhow         (O_RDONLY|O_BINARY)
+#define fbad         (-1)
+typedef int          ftype;
+#define zopen(n,p)   open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f)    close(f)
+#define zerr(f)      (k == (extent)(-1L))
+#define zstdin       0
diff --git a/os2/makefile.os2 b/os2/makefile.os2
new file mode 100644 (file)
index 0000000..a008ea5
--- /dev/null
@@ -0,0 +1,563 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit
+
+# Supported Make utilities:
+# - Microsoft/IBM nmake
+# - dmake 3.8 or higher
+# - GNU make, at least version 3.68
+# - NOT watcom make
+# For Microsoft and Watcom C, better use NMAKE,
+# otherwise it doesn't matter.
+
+# Supported 16-bit C Compilers (created programs run under OS/2 1.x and 2.x):
+# - Microsoft C 6.00A
+# - Watcom C/C++ 16-bit
+
+# Supported 32-bit C Compilers (created programs run under OS/2 2.x only):
+# - GNU gcc (emx kit 0.9c or newer)
+# - IBM C Set/2 or C Set++   - does not yet work with ASM code
+# - Watcom C/C++ 32-bit      - does not yet work with ASM code
+# - Borland C++              - no ASM code yet
+# - MetaWare High C/C++      - no ASM code yet
+
+# Supported Cross-Compilers for MS-DOS:
+# - Microsoft C 6.00A (16-bit)
+# - Watcom C/C++ (16- and 32-bit)
+# - GNU gcc (emx kit 0.9c or newer, 32-bit)
+
+# Supported Cross-Compilers for Win32 (WinNT/Win95):
+# - GNU gcc (emx kit 0.9c or newer, with RSXNT 1.4 or newer)
+
+# Supported Assemblers:
+# - Microsoft MASM 6.00 with Microsoft C, IBM C
+# - Watcom WASM with Watcom C/C++
+# - GNU as with GNU gcc
+
+# To use MASM 5.x instead of MASM 6.00:
+# - set AS="masm -T -Ml"
+# - set ASEOL=";"
+
+
+# To use, enter "make/nmake/dmake -f os2/makefile.os2"
+# (this makefile depends on its name being "os2/makefile.os2").
+
+# Add -DNO_ASM to CFLAGS and define OBJA to `nothing' if you do not have
+# masm or ml.
+# Add -DDYN_ALLOC to ASFLAGS if you have defined it in tailor.h or CFLAGS
+
+# Note: assembly language modules are really only supported for
+# Microsoft 16-bit and GNU gcc 32-bit compilation.
+
+# Notes on 16-bit (Microsoft C 6.00) compilation:
+
+#   The resulting programs can be used under OS/2 protected mode only.
+#   A larger stack has to be used for OS/2 because system calls
+#   use more stack than under DOS, 8k is recommended by Microsoft.
+#   Note that __STDC__ has to be defined explicitly with C 6.00 when -Ze
+#   is given, because Microsoft disables __STDC__ when their extensions
+#   are enabled. This is different from the C 5.10 behaviour.
+
+# Notes on 32-bit OS/2 compilation:
+
+#   The resulting programs can be used under OS/2 protected
+#   mode of OS/2 2.x only, not under 1.x and not under DOS.
+#   It makes no difference if __STDC__ is defined or not.
+#   Borland C++ works with DYN_ALLOC only.
+
+# Special Notes on IBM C/C++ compilation:
+
+#   The older C compiler (C Set/2) breaks, while optimizing, on deflate.c
+#   and trees.c (generates incorrect code). The newer C++ compiler (C Set++)
+#   doesn't but instead breaks on crypt.c in the initial version and up to
+#   CSD level 003. Starting with CSD level 004, it doesn't break any longer.
+
+# Notes on Watcom C/C++ compilation for DOS with the PMODE/W extender:
+#
+#   You need to add the following section to your \watcom\binb\wlsystem.lnk
+#   file and also need to copy pmodew.exe to the same directory:
+#
+#   system begin pmodew
+#       option osname='PMODE/W'
+#       libpath %WATCOM%\lib386
+#       libpath %WATCOM%\lib386\dos
+#       op stub=pmodew.exe
+#       format os2 le
+#   end
+#
+#   PMODE/W 1.16 or higher is required.
+
+
+default:
+       @echo "Enter $(MAKE) -f os2/makefile.os2 target"
+       @echo "where target is one of:"
+       @echo "   msc mscdos ibm ibmdyn ibmdebug ibmprof metaware borland"
+       @echo "   gcc gccdyn gcczlib gccdebug gccdos gccwin32 gccw32dyn"
+       @echo "   watcom watcom16 watcomdos watcom16dos pmodew"
+
+# MS C 6.00 for OS/2, 16-bit
+msc:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="cl -nologo -AL -Ocegit -Gs $(FP)" \
+       CFLAGS="-W1 -Zep -J -G2 -D__STDC__ -DOS2 -DASM_CRC" \
+       AS="ml -nologo -c -Zm -Cp" \
+       ASFLAGS="-D__LARGE__ -D__286" \
+       LDFLAGS="-F 2000 -Lp -Fe" \
+       LDFLAGS2="-link /noe /pm:vio" \
+       OUT="-Fo" \
+       OBJ=".obj" \
+       CRCA_O="crc_i86.obj" \
+       OBJA="match.obj" \
+       DEF="os2\zip.def"
+
+# MS C 6.00 for OS/2, 16-bit, debug
+mscdebug:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="cl -nologo -AL -Zi -Od $(FP)" \
+       CFLAGS="-W1 -Zep -J -G2 -D__STDC__ -DOS2 -DASM_CRC" \
+       AS="ml -nologo -c -Zim -Cp" \
+       ASFLAGS="-D__LARGE__ -D__286" \
+       LDFLAGS="-F 2000 -Lp -Fe" \
+       LDFLAGS2="-link /noe /pm:vio" \
+       OUT="-Fo" \
+       OBJ=".obj" \
+       CRCA_O="crc_i86.obj" \
+       OBJA="match.obj" \
+       DEF="os2\zip.def"
+
+# crosscompilation for MS-DOS with MS C 6.00
+mscdos:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="cl -nologo -AL -Ocegit -Gs $(FP)" \
+       CFLAGS="-W1 -Zep -J -D__STDC__ -DDOS -DASM_CRC -DDYN_ALLOC" \
+       AS="ml -nologo -c -Zm -Cp" \
+       ASFLAGS="-D__LARGE__ -DDYN_ALLOC" \
+       LDFLAGS="-F 2000 -Lr -Fe" \
+       LDFLAGS2="-link /noe /exe" \
+       OUT="-Fo" \
+       OBJ=".obj" \
+       CRCA_O="crc_i86.obj" \
+       OBJA="match.obj" \
+       OBJ2="msdos.obj" OBJU2="msdos_.obj" \
+       OSDEP_H="msdos/osdep.h" ZIPUP_H="msdos/zipup.h"
+
+
+# IBM C Set/2, statically linked runtime
+ibm:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="icc -Q -O -Gs" \
+       CFLAGS="-Sm -Sp1 -DOS2 -DNO_ASM" \
+       AS="ml -nologo -c -Zm -Cp" \
+       ASFLAGS="" \
+       LDFLAGS="-B/ST:0x50000 -Fe" \
+       LDFLAGS2="" \
+       OUT="-Fo" \
+       OBJ=".obj" \
+       OBJA="" \
+       DEF="os2/zip.def"
+
+# IBM C Set/2, dynamically linked runtime
+ibmdyn:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="icc -Q -O -Gd -Gs" \
+       CFLAGS="-Sm -Sp1 -DOS2 -DNO_ASM" \
+       AS="ml -nologo -c -Zm -Cp" \
+       ASFLAGS="" \
+       LDFLAGS="-B/ST:0x50000 -Fe" \
+       LDFLAGS2="" \
+       OUT="-Fo" \
+       OBJ=".obj" \
+       OBJA="" \
+       DEF="os2/zip.def"
+
+# IBM C Set/2, debug version
+ibmdebug:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="icc -Q -Ti" \
+       CFLAGS="-Sm -Sp1 -DOS2 -DNO_ASM -Tm" \
+       AS="ml -nologo -c -Zim -Cp" \
+       ASFLAGS="" \
+       LDFLAGS="-B/ST:0x50000 -Fe" \
+       LDFLAGS2="" \
+       OUT="-Fo" \
+       OBJ=".obj" \
+       OBJA="" \
+       DEF="os2/zip.def"
+
+# IBM C Set/2, profiling version for PROFIT
+ibmprof:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="icc -Q -O -Gs -Gh -Ti" \
+       CFLAGS="-Sm -Sp1 -DOS2 -DNO_ASM" \
+       AS="ml -nologo -c -Zm -Cp" \
+       ASFLAGS="" \
+       LDFLAGS="-B/ST:0x50000 -Fe" \
+       LDFLAGS2="profit.obj" \
+       OUT="-Fo" \
+       OBJ=".obj" \
+       OBJA="" \
+       DEF="os2/zip.def"
+
+# Watcom C/386 9.0 or higher
+watcom:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="wcl386 -bt=os2v2 -zq -Ox -s" \
+       CFLAGS="-Zp1 -DOS2 -DNO_ASM" \
+       AS="wasm -zq -bt=os2v2 -3p" \
+       ASFLAGS="" \
+       LDFLAGS="-k0x50000 -x -l=os2v2 -Fe=" \
+       LDFLAGS2="" \
+       OUT="-Fo" \
+       OBJ=".obj" \
+       OBJA="" \
+       DIRSEP="\\" \
+       AS_DIRSEP="\\"
+
+# Watcom C/286 9.0 or higher
+watcom16:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="wcl -bt=os2 -zq -ml -Ox -s" \
+       CFLAGS="-Zp1 -DOS2 -DNO_ASM" \
+       AS="wasm -zq -bt=os2 -2p -ml" \
+       ASFLAGS="" \
+       LDFLAGS="/\"option newfiles\" -k0x3000 -x -l=os2 -Fe=" \
+       LDFLAGS2="" \
+       OUT="-Fo" \
+       OBJ=".obj" \
+       OBJA="" \
+       DIRSEP="\\" \
+       AS_DIRSEP="\\"
+
+# Watcom C/386 9.0 or higher, crosscompilation for DOS, DOS4GW extender
+watcomdos:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="wcl386 -bt=dos4g -zq -Ox -s" \
+       CFLAGS="-Zp1 -DDOS -DMSDOS -DASM_CRC" \
+       AS="wasm -zq -bt=dos4g -3p" \
+       ASFLAGS="-DWATCOM_DSEG" \
+       LDFLAGS="-k0x50000 -x -l=dos4g -Fe=" \
+       LDFLAGS2="" \
+       OUT="-Fo" \
+       OBJ=".obj" \
+       CRCA_O="crc_i386.obj" \
+       OBJA="match32.obj" \
+       OBJ2="msdos.obj" \
+       OBJU2="msdos_.obj" \
+       OSDEP_H="msdos/osdep.h" \
+       ZIPUP_H="msdos/zipup.h" \
+       DIRSEP="\\" \
+       AS_DIRSEP="\\"
+
+# Watcom C/386 9.0 or higher, crosscompilation for DOS, PMODE/W extender
+pmodew:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="wcl386 -bt=dos4g -zq -Ox -s" \
+       CFLAGS="-Zp1 -DDOS -DMSDOS -DASM_CRC" \
+       AS="wasm -zq -bt=dos4g -3p" \
+       ASFLAGS="-DWATCOM_DSEG" \
+       LDFLAGS="-k0x50000 -x -l=pmodew -Fe=" \
+       LDFLAGS2="" \
+       OUT="-Fo" \
+       OBJ=".obj" \
+       CRCA_O="crc_i386.obj" \
+       OBJA="match32.obj" \
+       OBJ2="msdos.obj" \
+       OBJU2="msdos_.obj" \
+       OSDEP_H="msdos/osdep.h" \
+       ZIPUP_H="msdos/zipup.h" \
+       DIRSEP="\\" \
+       AS_DIRSEP="\\"
+
+# Watcom C/286 9.0 or higher, crosscompilation for DOS
+watcom16dos:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="wcl -bt=dos -zq -ml -Ox -s" \
+       CFLAGS="-Zp1 -DDOS -DMSDOS -DDYN_ALLOC -DNO_ASM" \
+       AS="wasm -zq -bt=dos -2 -ml" \
+       ASFLAGS="-DDYN_ALLOC" \
+       LDFLAGS="-k0x2000 -x -l=dos -Fe=" \
+       LDFLAGS2="" \
+       OUT="-Fo" \
+       OBJ=".obj" \
+       OBJA="" \
+       OBJ2="msdos.obj" \
+       OBJU2="msdos_.obj" \
+       OSDEP_H="msdos/osdep.h" \
+       ZIPUP_H="msdos/zipup.h" \
+       DIRSEP="\\" \
+       AS_DIRSEP="\\"
+
+# MetaWare High C/C++ 3.2
+metaware:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="hc -O2" \
+       CFLAGS="-D__32BIT__ -DOS2 -DNO_ASM" \
+       AS="ml -nologo -c -Zm -Cp" \
+       ASFLAGS="" \
+       LDFLAGS="-o " \
+       LDFLAGS2="" \
+       OUT="-o ./" \
+       OBJ=".obj" \
+       DEF="-Hdef=os2/zip.def"
+
+# Borland C++
+borland:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="bcc -O" \
+       CFLAGS="-w- -DOS2 -DDYN_ALLOC -DNO_ASM" \
+       AS="ml -nologo -c -Zm -Cp" \
+       ASFLAGS="" \
+       LDFLAGS="-e" \
+       LDFLAGS2="" \
+       OUT="-o" \
+       OBJ=".obj" \
+       OBJA="" \
+       DEF="-sDos2/zip.def"
+
+# emx 0.9c, gcc, OMF format, statically linked C runtime and emx
+gcc:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="gcc -Zomf -O -Wimplicit" \
+       CFLAGS="-DOS2 -DASM_CRC" \
+       AS="gcc -Zomf" \
+       ASFLAGS="-Di386" \
+       LDFLAGS="-o ./" \
+       LDFLAGS2="-Zsys -Zstack 320 -s -Zsmall-conv" \
+       OUT="-o" \
+       OBJ=".obj" \
+       CRCA_O="crc_gcc.obj" \
+       OBJA="matchgcc.obj" \
+       DEF="os2/zip.def"
+
+# emx 0.9c, gcc, OMF format, dynamically linked C runtime and emx
+gccdyn:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="gcc -Zomf -O -Wimplicit" \
+       CFLAGS="-DOS2 -DASM_CRC" \
+       AS="gcc -Zomf" \
+       ASFLAGS="-Di386" \
+       LDFLAGS="-o ./" \
+       LDFLAGS2="-Zcrtdll -Zstack 320 -s" \
+       OUT="-o" \
+       OBJ=".obj" \
+       CRCA_O="crc_gcc.obj" \
+       OBJA="matchgcc.obj" \
+       DEF="os2/zip.def"
+
+# emx 0.9c, gcc, OMF format, statically linked zlib, C runtime, and emx
+gcczlib:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="gcc -Zomf -O -Wimplicit" \
+       CFLAGS="-DOS2 -DUSE_ZLIB" \
+       AS="gcc -Zomf" \
+       ASFLAGS="-Di386 -DUSE_ZLIB" \
+       LDFLAGS="-o ./" \
+       LDFLAGS2="-L. -lzlib -Zsys -Zstack 320 -s -Zsmall-conv" \
+       OUT="-o" \
+       OBJ=".obj" \
+       CRCA_O="" \
+       OBJA="" \
+       DEF="os2/zip.def"
+
+# emx 0.9c, gcc, a.out format, with debug info for gdb
+gccdebug:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="gcc -g -Wimplicit" \
+       CFLAGS="-DOS2 -DASM_CRC" \
+       AS="gcc" \
+       ASFLAGS="-Di386" \
+       LDFLAGS="-o ./" \
+       LDFLAGS2="" \
+       OUT="-o" \
+       OBJ=".o" \
+       CRCA_O="crc_gcc.o" \
+       OBJA="matchgcc.o" \
+       DEF="os2/zip.def"
+
+# emx 0.9c, gcc, a.out format, for MS-DOS
+gccdos:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="gcc -O -Wimplicit" \
+       CFLAGS="-DDOS -DMSDOS -DASM_CRC" \
+       AS="gcc" \
+       ASFLAGS="-Di386" \
+       LDFLAGS="-o ./" \
+       LDFLAGS2="-s -Zsmall-conv" \
+       OUT="-o" \
+       OBJ=".o" \
+       CRCA_O="crc_gcc.o" \
+       OBJA="matchgcc.o" \
+       OBJ2="msdos.o" \
+       OBJU2="msdos_.o" \
+       OSDEP_H="msdos/osdep.h" \
+       ZIPUP_H="msdos/zipup.h"
+
+# emx 0.9c, gcc, RSXNT 1.4, cross-compilation for Win32
+gccwin32:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="gcc -Zwin32 -O -m486 -Wall" \
+       CFLAGS="-DWIN32 -DASM_CRC" \
+       AS="gcc -Zwin32" \
+       ASFLAGS="-Di386" \
+       LDFLAGS="-o ./" \
+       LDFLAGS2="-ladvapi32 -Zsys -Zsmall-conv -s" \
+       OUT="-o" \
+       OBJ=".o" \
+       CRCA_O="crc_gcc.o" \
+       OBJA="matchgcc.o" \
+       OBJ2="win32zip.o win32.o nt.o" \
+       OBJU2="win32_.o" \
+       OSDEP_H="win32/osdep.h" \
+       ZIPUP_H="win32/zipup.h" \
+       DEF="win32/zip.def"
+
+# emx 0.9c, gcc, RSXNT 1.4, cross-compilation for Win32, use emx C rtl DLL
+gccw32dyn:
+       $(MAKE) -f os2/makefile.os2 zips \
+       CC="gcc -Zwin32 -Zcrtdll=crtrsxnt -O -m486 -Wall" \
+       CFLAGS="-DWIN32 -DASM_CRC" \
+       AS="gcc -Zwin32" \
+       ASFLAGS="-Di386" \
+       LDFLAGS="-o ./" \
+       LDFLAGS2="-ladvapi32 -s" \
+       OUT="-o" \
+       OBJ=".o" \
+       CRCA_O="crc_gcc.o" \
+       OBJA="matchgcc.o" \
+       OBJ2="win32zip.o win32.o nt.o" \
+       OBJU2="win32_.o" \
+       OSDEP_H="win32/osdep.h" \
+       ZIPUP_H="win32/zipup.h" \
+       DEF="win32/zip.def"
+
+# VPATH = .;os2
+
+# variables
+
+#default settings for target dependent macros:
+DIRSEP = /
+AS_DIRSEP = /
+# LOCAL_OPTS =
+CCFLAGS = $(CFLAGS) $(LOCAL_OPTS)
+
+OSDEP_H = os2/osdep.h
+ZIPUP_H = os2/os2zip.h os2/zipup.h
+CRCA_O  =
+
+
+OBJZ =  zip$(OBJ) zipfile$(OBJ) zipup$(OBJ) fileio$(OBJ) util$(OBJ) \
+        crc32$(OBJ) $(CRCA_O) globals$(OBJ) \
+       deflate$(OBJ) trees$(OBJ) crypt$(OBJ) ttyio$(OBJ)
+OBJ2 = os2zip$(OBJ) os2$(OBJ) os2acl$(OBJ)
+
+OBJU =  zipfile_$(OBJ) fileio_$(OBJ) util_$(OBJ) globals$(OBJ)
+OBJU2 = os2zip_$(OBJ)
+
+OBJN =  zipnote$(OBJ) $(OBJU) $(OBJU2)
+OBJS =  zipsplit$(OBJ) $(OBJU) $(OBJU2)
+OBJC =  zipcloak$(OBJ) crc32_$(OBJ) crypt_$(OBJ) ttyio$(OBJ) $(OBJU) $(OBJU2)
+
+ZIP_H = zip.h ziperr.h tailor.h $(OSDEP_H)
+
+# rules
+
+.SUFFIXES: .c $(OBJ)
+
+.c$(OBJ):
+       $(CC) -c -I. $(CCFLAGS) $<
+
+.asm$(OBJ):
+       $(AS) $(ASFLAGS) $< $(ASEOL)
+
+# targets
+
+zips:  zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip$(OBJ):     zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipfile$(OBJ): zipfile.c $(ZIP_H) crc32.h
+zipup$(OBJ):   zipup.c $(ZIP_H) revision.h crc32.h crypt.h $(ZIPUP_H)
+fileio$(OBJ):  fileio.c $(ZIP_H) crc32.h
+util$(OBJ):    util.c $(ZIP_H)
+globals$(OBJ): globals.c $(ZIP_H)
+deflate$(OBJ): deflate.c $(ZIP_H)
+trees$(OBJ):   trees.c $(ZIP_H)
+crc32$(OBJ):   crc32.c $(ZIP_H) crc32.h
+crypt$(OBJ):   crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio$(OBJ):   ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+os2zip$(OBJ):  os2/os2zip.c $(ZIP_H) os2/os2zip.h os2/os2acl.h
+       $(CC) -c -I. $(CCFLAGS) os2$(DIRSEP)os2zip.c
+
+os2$(OBJ):     os2/os2.c $(ZIP_H) os2/os2zip.h
+       $(CC) -c -I. $(CCFLAGS) os2$(DIRSEP)os2.c
+
+os2acl$(OBJ):  os2/os2acl.c os2/os2acl.h
+       $(CC) -c -I. $(CCFLAGS) os2$(DIRSEP)os2acl.c
+
+msdos$(OBJ):   msdos/msdos.c $(ZIP_H)
+       $(CC) -c -I. $(CCFLAGS) msdos$(DIRSEP)msdos.c
+
+win32zip$(OBJ):        win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+       $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)win32zip.c
+
+win32$(OBJ):   win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)win32.c
+
+nt$(OBJ):      win32/nt.c win32/nt.h
+       $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)nt.c
+
+crc_i86$(OBJ): msdos/crc_i86.asm                               # 16bit only
+       $(AS) $(ASFLAGS) msdos$(AS_DIRSEP)crc_i86.asm $(ASEOL)
+
+crc_i386$(OBJ):        win32/crc_i386.asm                              # 32bit, MASM
+       $(AS) $(ASFLAGS) win32$(AS_DIRSEP)crc_i386.asm $(ASEOL)
+
+crc_gcc$(OBJ): crc_i386.S                                      # 32bit, GNU AS
+       $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o $@ crc_i386.S
+
+match$(OBJ):   msdos/match.asm
+       $(AS) $(ASFLAGS) msdos$(AS_DIRSEP)match.asm $(ASEOL)
+
+match32$(OBJ): win32/match32.asm
+       $(AS) $(ASFLAGS) win32$(AS_DIRSEP)match32.asm
+
+matchgcc$(OBJ):        match.S
+       $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o $@ match.S
+
+zipcloak$(OBJ):        zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipnote$(OBJ): zipnote.c $(ZIP_H) revision.h
+zipsplit$(OBJ): zipsplit.c $(ZIP_H) revision.h
+
+zipfile_$(OBJ):        zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ zipfile.c
+
+fileio_$(OBJ): fileio.c $(ZIP_H) crc32.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ fileio.c
+
+util_$(OBJ):   util.c $(ZIP_H) os2/os2zip.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ util.c
+
+crc32_$(OBJ):  crc32.c $(ZIP_H) crc32.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ crc32.c
+
+crypt_$(OBJ):  crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ crypt.c
+
+os2zip_$(OBJ): os2/os2zip.c $(ZIP_H) os2/os2zip.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ os2$(DIRSEP)os2zip.c
+
+msdos_$(OBJ):  msdos/msdos.c $(ZIP_H)
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ msdos$(DIRSEP)msdos.c
+
+win32_$(OBJ):  win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ win32$(DIRSEP)win32.c
+
+zip.exe: $(OBJZ) $(OBJ2) $(OBJA)
+       $(CC) $(LDFLAGS)$@ $(DEF) $(OBJZ) $(OBJ2) $(OBJA) $(LDFLAGS2)
+
+zipcloak.exe: $(OBJC)
+       $(CC) $(LDFLAGS)$@ $(DEF) $(OBJC) $(LDFLAGS2)
+
+zipnote.exe: $(OBJN)
+       $(CC) $(LDFLAGS)$@ $(DEF) $(OBJN) $(LDFLAGS2)
+
+zipsplit.exe: $(OBJS)
+       $(CC) $(LDFLAGS)$@ $(DEF) $(OBJS) $(LDFLAGS2)
diff --git a/os2/match32.asm b/os2/match32.asm
new file mode 100644 (file)
index 0000000..4797a73
--- /dev/null
@@ -0,0 +1,175 @@
+;===========================================================================
+; Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 2005-Feb-10 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+;
+; match32.asm by Jean-loup Gailly.
+
+; match32.asm, optimized version of longest_match() in deflate.c
+; To be used only with 32 bit flat model. To simplify the code, the option
+; -DDYN_ALLOC is not supported.
+; This file is only optional. If you don't have an assembler, use the
+; C version (add -DNO_ASM to CFLAGS in makefile and remove match.o
+; from OBJI). If you have reduced WSIZE in zip.h, then make sure this is
+; assembled with an equivalent -DWSIZE=<whatever>.
+
+; Caution: this module works for IBM's C/C++ compiler versions 2 and 3
+; and for Watcom's 32-bit C/C++ compiler. Both pass the first (and only)
+; argument for longest_match in the EAX register, not on the stack, with
+; the default calling conventions (_System would use the stack).
+;
+;==============================================================================
+;
+; Do NOT assemble this source if external crc32 routine from zlib gets used.
+;
+    IFNDEF USE_ZLIB
+;
+        .386
+
+        name    match
+
+BSS32   segment  dword USE32 public 'BSS'
+        extrn   window       : byte
+        extrn   prev         : word
+        extrn   prev_length  : dword
+        extrn   strstart     : dword
+        extrn   match_start  : dword
+        extrn   max_chain_length : dword
+        extrn   good_match   : dword
+        extrn   nice_match   : dword
+BSS32   ends
+
+CODE32  segment dword USE32 public 'CODE'
+        assume cs:CODE32, ds:FLAT, ss:FLAT
+
+        public  match_init
+        public  longest_match
+
+    ifndef      WSIZE
+        WSIZE         equ 32768         ; keep in sync with zip.h !
+    endif
+        MIN_MATCH     equ 3
+        MAX_MATCH     equ 258
+        MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
+        MAX_DIST      equ (WSIZE-MIN_LOOKAHEAD)
+
+; initialize or check the variables used in match.asm.
+
+match_init proc near
+        ret
+match_init endp
+
+; -----------------------------------------------------------------------
+; Set match_start to the longest match starting at the given string and
+; return its length. Matches shorter or equal to prev_length are discarded,
+; in which case the result is equal to prev_length and match_start is
+; garbage.
+; IN assertions: cur_match is the head of the hash chain for the current
+;   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+
+; int longest_match(cur_match)
+
+longest_match proc near
+
+        ; return address                ; esp+16
+        push    ebp                     ; esp+12
+        push    edi                     ; esp+8
+        push    esi                     ; esp+4
+
+        lea     ebx,window
+        add     ebx,2
+        window_off equ dword ptr [esp]
+        push    ebx                     ; esp
+
+;       match        equ esi
+;       scan         equ edi
+;       chain_length equ ebp
+;       best_len     equ ebx
+;       limit        equ edx
+
+        mov     esi,eax                 ; cur_match
+        mov     edx,strstart
+        mov     ebp,max_chain_length    ; chain_length = max_chain_length
+        mov     edi,edx
+        sub     edx,MAX_DIST            ; limit = strstart-MAX_DIST
+        cld                             ; string ops increment esi and edi
+        jae     short limit_ok
+        sub     edx,edx                 ; limit = NIL
+limit_ok:
+        add     edi,window_off          ; edi = offset(window + strstart + 2)
+        mov     ebx,prev_length         ; best_len = prev_length
+        mov     cx,[edi-2]              ; cx = scan[0..1]
+        mov     ax,[ebx+edi-3]          ; ax = scan[best_len-1..best_len]
+        cmp     ebx,good_match          ; do we have a good match already?
+        jb      do_scan
+        shr     ebp,2                   ; chain_length >>= 2
+        jmp     short do_scan
+
+        align   4                       ; align destination of branch
+long_loop:
+; at this point, edi == scan+2, esi == cur_match
+        mov     ax,[ebx+edi-3]          ; ax = scan[best_len-1..best_len]
+        mov     cx,[edi-2]              ; cx = scan[0..1]
+short_loop:
+; at this point, edi == scan+2, esi == cur_match,
+; ax = scan[best_len-1..best_len] and cx = scan[0..1]
+        and     esi,WSIZE-1             ; not needed if WSIZE=32768
+        dec     ebp                     ; --chain_length
+        shl     esi,1                   ; cur_match as word index
+        mov     si,prev[esi]            ; cur_match = prev[cur_match]
+                                        ; top word of esi is still 0
+        jz      the_end
+        cmp     esi,edx                 ; cur_match <= limit ?
+        jbe     short the_end
+do_scan:
+        cmp     ax,word ptr window[ebx+esi-1]   ; check match at best_len-1
+        jne     short_loop
+        cmp     cx,word ptr window[esi]         ; check min_match_length match
+        jne     short_loop
+
+        add     esi,window_off          ; esi = match
+        mov     ecx,(MAX_MATCH-2)/2     ; scan for at most MAX_MATCH bytes
+        mov     eax,edi                 ; eax = scan+2
+        repe    cmpsw                   ; loop until mismatch
+        je      maxmatch                ; match of length MAX_MATCH?
+mismatch:
+        mov     cl,[edi-2]              ; mismatch on first or second byte?
+        xchg    eax,edi                 ; edi = scan+2, eax = end of scan
+        sub     cl,[esi-2]              ; cl = 0 if first bytes equal
+        sub     eax,edi                 ; eax = len
+        sub     esi,window_off          ; esi = match - (2 + offset(window))
+        sub     esi,eax                 ; esi = cur_match (= match - len)
+        sub     cl,1                    ; set carry if cl == 0 (can't use DEC)
+        adc     eax,0                   ; eax = carry ? len+1 : len
+        cmp     eax,ebx                 ; len > best_len ?
+        jle     long_loop
+        mov     match_start,esi         ; match_start = cur_match
+        mov     ebx,eax                 ; ebx = best_len = len
+    ifdef FULL_SEARCH
+        cmp     eax,MAX_MATCH           ; len >= MAX_MATCH ?
+    else
+        cmp     eax,nice_match          ; len >= nice_match ?
+    endif
+        jl      long_loop
+the_end:
+        mov     eax,ebx                 ; result = eax = best_len
+        pop     ebx
+        pop     esi
+        pop     edi
+        pop     ebp
+        ret
+maxmatch:                               ; come here if maximum match
+        cmpsb                           ; increment esi and edi
+        jmp     mismatch                ; force match_length = MAX_LENGTH
+
+longest_match endp
+
+CODE32  ends
+;
+    ENDIF ; !USE_ZLIB
+;
+        end
diff --git a/os2/os2.c b/os2/os2.c
new file mode 100644 (file)
index 0000000..b44fe2e
--- /dev/null
+++ b/os2/os2.c
@@ -0,0 +1,481 @@
+/*
+  Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2005-Feb-10 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#ifndef UTIL    /* the companion #endif is a bit of ways down ... */
+
+#include <time.h>
+#if defined(__IBMC__) || defined(MSC)
+#include <direct.h>
+#endif
+
+/* Extra malloc() space in names for cutpath() */
+#define PAD 0
+#define PATH_END '/'
+
+
+#include "os2zip.h"
+
+/* Library functions not in (most) header files */
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Local functions */
+local char *readd OF((DIR *));
+
+
+local char *readd(d)
+DIR *d;                 /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+   no more entries or an error occurs. */
+{
+  struct dirent *e;
+
+  e = readdir(d);
+  return e == NULL ? (char *) NULL : e->d_name;
+}
+
+int wild(w)
+char *w;                /* path/pattern to match */
+/* If not in exclude mode, expand the pattern based on the contents of the
+   file system.  Return an error code in the ZE_ class. */
+{
+  DIR *d;               /* stream for reading directory */
+  char *e;              /* name found in directory */
+  int r;                /* temporary variable */
+  char *n;              /* constructed name from directory */
+  int f;                /* true if there was a match */
+  char *a;              /* alloc'ed space for name */
+  char *p;              /* path */
+  char *q;              /* name */
+  char v[5];            /* space for device current directory */
+
+  if (volume_label == 1) {
+    volume_label = 2;
+    label = getVolumeLabel((w != NULL && w[1] == ':') ? to_up(w[0]) : '\0',
+                           &label_time, &label_mode, &label_utim);
+    if (label != NULL) {
+       newname(label, 0, 0);
+    }
+    if (w == NULL || (w[1] == ':' && w[2] == '\0')) return ZE_OK;
+    /* "zip -$ foo a:" can be used to force drive name */
+  }
+
+  if (w == NULL)
+    return ZE_OK;
+
+  /* special handling of stdin request */
+  if (strcmp(w, "-") == 0)   /* if compressing stdin */
+    return newname(w, 0, 0);
+
+  /* Allocate and copy pattern */
+  if ((p = a = malloc(strlen(w) + 1)) == NULL)
+    return ZE_MEM;
+  strcpy(p, w);
+
+  /* catch special case: treat "*.*" as "*" for DOS-impaired people */
+  r = strlen(p);
+  if (strcmp(p + r - 3, "*.*") == 0)
+    p[r - 2] = '\0';
+
+  /* Normalize path delimiter as '/'. */
+  for (q = p; *q; q++)                  /* use / consistently */
+    if (*q == '\\')
+      *q = '/';
+
+  /* Only name can have special matching characters */
+  if ((q = isshexp(p)) != NULL &&
+      (strrchr(q, '/') != NULL || strrchr(q, ':') != NULL))
+  {
+    free((zvoid *)a);
+    return ZE_PARMS;
+  }
+
+  /* Separate path and name into p and q */
+  if ((q = strrchr(p, '/')) != NULL && (q == p || q[-1] != ':'))
+  {
+    *q++ = '\0';                        /* path/name -> path, name */
+    if (*p == '\0')                     /* path is just / */
+      p = strcpy(v, "/.");
+  }
+  else if ((q = strrchr(p, ':')) != NULL)
+  {                                     /* has device and no or root path */
+    *q++ = '\0';
+    p = strcat(strcpy(v, p), ":");      /* copy device as path */
+    if (*q == '/')                      /* -> device:/., name */
+    {
+      strcat(p, "/");
+      q++;
+    }
+    strcat(p, ".");
+  }
+  else if (recurse && (strcmp(p, ".") == 0 ||  strcmp(p, "..") == 0))
+  {                                    /* current or parent directory */
+    /* I can't understand Mark's code so I am adding a hack here to get
+     * "zip -r foo ." to work. Allow the dubious "zip -r foo .." but
+     * reject "zip -rm foo ..".
+     */
+    if (dispose && strcmp(p, "..") == 0)
+       ziperr(ZE_PARMS, "cannot remove parent directory");
+    q = "*";
+  }
+  else                                  /* no path or device */
+  {
+    q = p;
+    p = strcpy(v, ".");
+  }
+  if (recurse && *q == '\0') {
+    q = "*";
+  }
+  /* Search that level for matching names */
+  if ((d = opendir(p)) == NULL)
+  {
+    free((zvoid *)a);
+    return ZE_MISS;
+  }
+  if ((r = strlen(p)) > 1 &&
+      (strcmp(p + r - 2, ":.") == 0 || strcmp(p + r - 2, "/.") == 0))
+    *(p + r - 1) = '\0';
+  f = 0;
+  while ((e = readd(d)) != NULL) {
+    if (strcmp(e, ".") && strcmp(e, "..") && MATCH(q, e, 0))
+    {
+      f = 1;
+      if (strcmp(p, ".") == 0) {                /* path is . */
+        r = procname(e, 0);                     /* name is name */
+        if (r) {
+           f = 0;
+           break;
+        }
+      } else
+      {
+        if ((n = malloc(strlen(p) + strlen(e) + 2)) == NULL)
+        {
+          free((zvoid *)a);
+          closedir(d);
+          return ZE_MEM;
+        }
+        n = strcpy(n, p);
+        if (n[r = strlen(n) - 1] != '/' && n[r] != ':')
+          strcat(n, "/");
+        r = procname(strcat(n, e), 0);          /* name is path/name */
+        free((zvoid *)n);
+        if (r) {
+          f = 0;
+          break;
+        }
+      }
+    }
+  }
+  closedir(d);
+
+  /* Done */
+  free((zvoid *)a);
+  return f ? ZE_OK : ZE_MISS;
+}
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  DIR *d;               /* directory stream from opendir() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (n == NULL)        /* volume_label request in freshen|delete mode ?? */
+    return ZE_OK;
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (LSSTAT(n, &s)
+#if defined(__TURBOC__) || defined(__WATCOMC__)
+           /* For these 2 compilers, stat() succeeds on wild card names! */
+           || isshexp(n)
+#endif
+          )
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  for (p = n; *p; p++)          /* use / consistently */
+    if (*p == '\\')
+      *p = '/';
+  if ((s.st_mode & S_IFDIR) == 0)
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0, caseflag)) != ZE_OK)
+      return m;
+  } else {
+    /* Add trailing / to the directory name */
+    if ((p = malloc(strlen(n)+2)) == NULL)
+      return ZE_MEM;
+    if (strcmp(n, ".") == 0 || strcmp(n, "/.") == 0) {
+      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      strcpy(p, n);
+      a = p + strlen(p);
+      if (a[-1] != '/')
+        strcpy(a, "/");
+      if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+        free((zvoid *)p);
+        return m;
+      }
+    }
+    /* recurse into directory */
+    if (recurse && (d = opendir(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if (strcmp(e, ".") && strcmp(e, ".."))
+        {
+          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+          {
+            closedir(d);
+            free((zvoid *)p);
+            return ZE_MEM;
+          }
+          strcat(strcpy(a, p), e);
+          if ((m = procname(a, caseflag)) != ZE_OK)   /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", a);
+            else
+              ziperr(m, a);
+          }
+          free((zvoid *)a);
+        }
+      }
+      closedir(d);
+    }
+    free((zvoid *)p);
+  } /* (s.st_mode & S_IFDIR) == 0) */
+  return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t;              /* shortened name */
+  int dosflag;
+
+  dosflag = dosify || IsFileSystemFAT(x) || (x == label);
+  if (!dosify && use_longname_ea && (t = GetLongPathEA(x)) != NULL)
+  {
+    x = t;
+    dosflag = 0;
+  }
+
+  /* Find starting point in name before doing malloc */
+  /* Strip drive specification */
+  t = *x && *(x + 1) == ':' ? x + 2 : x;
+  /* Strip "//host/share/" part of a UNC name */
+  if ((!strncmp(x,"//",2) || !strncmp(x,"\\\\",2)) &&
+      (x[2] != '\0' && x[2] != '/' && x[2] != '\\')) {
+    n = x + 2;
+    while (*n != '\0' && *n != '/' && *n != '\\')
+      n++;              /* strip host name */
+    if (*n != '\0') {
+      n++;
+      while (*n != '\0' && *n != '/' && *n != '\\')
+        n++;            /* strip `share' name */
+    }
+    if (*n != '\0')
+      t = n + 1;
+  }
+  /* Strip leading "/" to convert an absolute path into a relative path */
+  while (*t == '/' || *t == '\\')
+    t++;
+  /* Strip leading "./" as well as drive letter */
+  while (*t == '.' && (t[1] == '/' || t[1] == '\\'))
+    t += 2;
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+  for (n = t; *n; n++)
+    if (*n == '\\')
+      *n = '/';
+
+  if (!pathput)
+    t = last(t, PATH_END);
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL)
+    return NULL;
+  strcpy(n, t);
+
+  if (dosify)
+    msname(n);
+
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+  return n;
+}
+
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+    return NULL;
+  strcpy(x, n);
+
+  return x;
+}
+
+
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+  SetFileTime(f, d);
+}
+
+ulg filetime(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  char *name;
+  ulg r;
+  unsigned int len = strlen(f);
+  int isstdin = !strcmp(f, "-");
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+
+  if (isstdin) {
+    /* it is common for some PC based compilers to
+       fail with fstat() on devices or pipes */
+    if (fstat(fileno(stdin), &s) != 0) {
+      s.st_mode = S_IFREG; s.st_size = -1L;
+    }
+    time(&s.st_ctime);
+    s.st_atime = s.st_mtime = s.st_ctime;
+  } else if (LSSTAT(name, &s) != 0) {
+             /* Accept about any file kind including directories
+              * (stored with trailing / with -r option)
+              */
+    free(name);
+    return 0;
+  }
+
+  if (a != NULL) {
+    *a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)GetFileMode(name));
+  }
+  if (n != NULL)
+    *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+#ifdef __WATCOMC__
+  /* of course, Watcom always has to make an exception */
+  if (s.st_atime == 312764400)
+    s.st_atime = s.st_mtime;
+  if (s.st_ctime == 312764400)
+    s.st_ctime = s.st_mtime;
+#endif
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = s.st_ctime;
+  }
+
+  r = GetFileTime(name);
+  free(name);
+
+  return r;
+}
+
+int deletedir(d)
+char *d;                /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+   Return the result of rmdir(), delete(), or system().
+ */
+{
+    return rmdir(d);
+}
+
+
+#if defined MY_ZCALLOC /* Special zcalloc function for MEMORY16 (MSDOS/OS2) */
+
+#ifdef MSC  /* Microsoft C */
+
+zvoid far *zcalloc (unsigned items, unsigned size)
+{
+    return (zvoid far *)halloc((long)items, size);
+}
+
+zvoid zcfree (zvoid far *ptr)
+{
+    hfree((void huge *)ptr);
+}
+
+#endif /* MSC */
+
+#endif /* MY_ZCALLOC */
+
+#endif /* !UTIL */
diff --git a/os2/os2acl.c b/os2/os2acl.c
new file mode 100644 (file)
index 0000000..4f88643
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* os2acl.c - access to OS/2 (LAN Server) ACLs
+ *
+ * Author:  Kai Uwe Rommel <rommel@ars.de>
+ * Created: Mon Aug 08 1994
+ *
+ */
+
+/*
+ * supported 32-bit compilers:
+ * - emx+gcc
+ * - IBM C Set++ 2.1 or newer
+ * - Watcom C/C++ 10.0 or newer
+ *
+ * supported 16-bit compilers:
+ * - MS C 6.00A
+ * - Watcom C/C++ 10.0 or newer
+ *
+ * supported OS/2 LAN environments:
+ * - IBM LAN Server/Requester 3.0, 4.0 and 5.0 (Warp Server)
+ * - IBM Peer 1.0 (Warp Connect)
+ */
+
+#ifdef KUR
+   static char *rcsid =
+   "$Id: os2acl.c,v 1.3 1996/04/03 19:18:27 rommel Exp rommel $";
+   static char *rcsrev = "$Revision: 1.3 $";
+#endif
+
+/*
+ * $Log: os2acl.c,v $
+ * Revision 1.3  1996/04/03 19:18:27  rommel
+ * minor fixes
+ *
+ * Revision 1.2  1996/03/30 22:03:52  rommel
+ * avoid frequent dynamic allocation for every call
+ * streamlined code
+ *
+ * Revision 1.1  1996/03/30 09:35:00  rommel
+ * Initial revision
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <malloc.h>
+
+#define INCL_NOPM
+#define INCL_DOS
+#define INCL_DOSERRORS
+#include <os2.h>
+
+#include "os2/os2acl.h"
+
+#define UNLEN 20
+
+#if defined(__WATCOMC__) && defined(__386__) && !defined(__32BIT__)
+#define __32BIT__
+#endif
+
+#ifdef __32BIT__
+typedef ULONG U_INT;
+#ifdef __EMX__
+#define PSTR16 _far16ptr
+#define PTR16(x) _emx_32to16(x)
+#else /* other 32-bit */
+#define PSTR16 PCHAR16
+#define PTR16(x) ((PCHAR16)(x))
+#endif
+#else /* 16-bit */
+typedef USHORT U_INT;
+#define PSTR16 PSZ
+#define PTR16(x) (x)
+#endif
+
+typedef struct access_list
+{
+  char acl_ugname[UNLEN+1];
+  char acl_pad;
+  USHORT acl_access;
+}
+ACCLIST;
+
+typedef struct access_info
+{
+  PSTR16 acc_resource_name;
+  USHORT acc_attr;
+  USHORT acc_count;
+}
+ACCINFO;
+
+static ACCINFO *ai;
+static char *path, *data;
+
+#ifdef __32BIT__
+
+#ifdef __EMX__
+
+static USHORT (APIENTRY *_NetAccessGetInfo)(PSZ pszServer, PSZ pszResource,
+  USHORT sLevel, PVOID pbBuffer, USHORT cbBuffer, PUSHORT pcbTotalAvail);
+static USHORT (APIENTRY *_NetAccessSetInfo)(PSZ pszServer, PSZ pszResource,
+  USHORT sLevel, PVOID pbBuffer, USHORT cbBuffer, USHORT sParmNum);
+static USHORT (APIENTRY *_NetAccessAdd)(PSZ pszServer,
+  USHORT sLevel, PVOID pbBuffer, USHORT cbBuffer);
+
+USHORT NetAccessGetInfo(PSZ pszServer, PSZ pszResource, USHORT sLevel,
+                        PVOID pbBuffer, USHORT cbBuffer, PUSHORT pcbTotalAvail)
+{
+  return (USHORT)
+          (_THUNK_PROLOG (4+4+2+4+2+4);
+           _THUNK_FLAT (pszServer);
+           _THUNK_FLAT (pszResource);
+           _THUNK_SHORT (sLevel);
+           _THUNK_FLAT (pbBuffer);
+           _THUNK_SHORT (cbBuffer);
+           _THUNK_FLAT (pcbTotalAvail);
+           _THUNK_CALLI (_emx_32to16(_NetAccessGetInfo)));
+}
+
+USHORT NetAccessSetInfo(PSZ pszServer, PSZ pszResource, USHORT sLevel,
+                        PVOID pbBuffer, USHORT cbBuffer, USHORT sParmNum)
+{
+  return (USHORT)
+          (_THUNK_PROLOG (4+4+2+4+2+2);
+           _THUNK_FLAT (pszServer);
+           _THUNK_FLAT (pszResource);
+           _THUNK_SHORT (sLevel);
+           _THUNK_FLAT (pbBuffer);
+           _THUNK_SHORT (cbBuffer);
+           _THUNK_SHORT (sParmNum);
+           _THUNK_CALLI (_emx_32to16(_NetAccessSetInfo)));
+}
+
+USHORT NetAccessAdd(PSZ pszServer, USHORT sLevel,
+                    PVOID pbBuffer, USHORT cbBuffer)
+{
+  return (USHORT)
+          (_THUNK_PROLOG (4+2+4+2);
+           _THUNK_FLAT (pszServer);
+           _THUNK_SHORT (sLevel);
+           _THUNK_FLAT (pbBuffer);
+           _THUNK_SHORT (cbBuffer);
+           _THUNK_CALLI (_emx_32to16(_NetAccessAdd)));
+}
+
+#else /* other 32-bit */
+
+APIRET16 (* APIENTRY16 NetAccessGetInfo)(PCHAR16 pszServer, PCHAR16 pszResource,
+  USHORT sLevel, PVOID16 pbBuffer, USHORT cbBuffer, PVOID16 pcbTotalAvail);
+APIRET16 (* APIENTRY16 NetAccessSetInfo)(PCHAR16 pszServer, PCHAR16 pszResource,
+  USHORT sLevel, PVOID16 pbBuffer, USHORT cbBuffer, USHORT sParmNum);
+APIRET16 (* APIENTRY16 NetAccessAdd)(PCHAR16 pszServer,
+  USHORT sLevel, PVOID16 pbBuffer, USHORT cbBuffer);
+
+#define _NetAccessGetInfo NetAccessGetInfo
+#define _NetAccessSetInfo NetAccessSetInfo
+#define _NetAccessAdd NetAccessAdd
+
+#if !defined(__IBMC__) || !defined(__TILED__)
+#define _tmalloc malloc
+#define _tfree free
+#endif
+
+#endif
+#else /* 16-bit */
+
+USHORT (APIENTRY *NetAccessGetInfo)(PSZ pszServer, PSZ pszResource,
+  USHORT sLevel, PVOID pbBuffer, USHORT cbBuffer, PUSHORT pcbTotalAvail);
+USHORT (APIENTRY *NetAccessSetInfo)(PSZ pszServer, PSZ pszResource,
+  USHORT sLevel, PVOID pbBuffer, USHORT cbBuffer, USHORT sParmNum);
+USHORT (APIENTRY *NetAccessAdd)(PSZ pszServer,
+  USHORT sLevel, PVOID pbBuffer, USHORT cbBuffer);
+
+#define _NetAccessGetInfo NetAccessGetInfo
+#define _NetAccessSetInfo NetAccessSetInfo
+#define _NetAccessAdd NetAccessAdd
+
+#define _tmalloc malloc
+#define _tfree free
+
+#define DosQueryProcAddr(handle, ord, name, funcptr) \
+        DosGetProcAddr(handle, name, funcptr)
+#define DosQueryCurrentDir DosQCurDir
+#define DosQueryCurrentDisk DosQCurDisk
+
+#endif
+
+
+static BOOL acl_init(void)
+{
+  static BOOL initialized, netapi_avail;
+  HMODULE netapi;
+  char buf[256];
+
+  if (initialized)
+    return netapi_avail;
+
+  initialized = TRUE;
+
+  if (DosLoadModule(buf, sizeof(buf), "NETAPI", &netapi))
+    return FALSE;
+
+  if (DosQueryProcAddr(netapi, 0, "NETACCESSGETINFO", (PFN *) &_NetAccessGetInfo) ||
+      DosQueryProcAddr(netapi, 0, "NETACCESSSETINFO", (PFN *) &_NetAccessSetInfo) ||
+      DosQueryProcAddr(netapi, 0, "NETACCESSADD", (PFN *) &_NetAccessAdd))
+    return FALSE;
+
+#if defined(__WATCOMC__) && defined(__386__)
+  NetAccessGetInfo = (PVOID) (ULONG) (PVOID16) NetAccessGetInfo;
+  NetAccessSetInfo = (PVOID) (ULONG) (PVOID16) NetAccessSetInfo;
+  NetAccessAdd     = (PVOID) (ULONG) (PVOID16) NetAccessAdd;
+#endif
+
+  if ((path = _tmalloc(CCHMAXPATH)) == NULL)
+    return FALSE;
+  if ((data = _tmalloc(ACL_BUFFERSIZE)) == NULL)
+    return FALSE;
+  if ((ai = _tmalloc(sizeof(ACCINFO))) == NULL)
+    return -1;
+
+  netapi_avail = TRUE;
+
+  return netapi_avail;
+}
+
+static void acl_mkpath(char *buffer, const char *source)
+{
+  char *ptr;
+  static char cwd[CCHMAXPATH];
+  static U_INT cwdlen;
+  U_INT cdrive;
+  ULONG drivemap;
+
+  if (isalpha((int)source[0]) && source[1] == ':')
+    buffer[0] = 0; /* fully qualified names */
+  else
+  {
+    if (cwd[0] == 0)
+    {
+      DosQueryCurrentDisk(&cdrive, &drivemap);
+      cwd[0] = (char)(cdrive + '@');
+      cwd[1] = ':';
+      cwd[2] = '\\';
+      cwdlen = sizeof(cwd) - 3;
+      DosQueryCurrentDir(0, cwd + 3, &cwdlen);
+      cwdlen = strlen(cwd);
+    }
+
+    if (source[0] == '/' || source[0] == '\\')
+    {
+      if (source[1] == '/' || source[1] == '\\')
+        buffer[0] = 0; /* UNC names */
+      else
+      {
+        strncpy(buffer, cwd, 2);
+        buffer[2] = 0;
+      }
+    }
+    else
+    {
+      strcpy(buffer, cwd);
+      if (cwd[cwdlen - 1] != '\\' && cwd[cwdlen - 1] != '/')
+        strcat(buffer, "/");
+    }
+  }
+
+  strcat(buffer, source);
+
+  for (ptr = buffer; *ptr; ptr++)
+    if (*ptr == '/')
+      *ptr = '\\';
+
+  if (ptr[-1] == '\\')
+    ptr[-1] = 0;
+
+  strupr(buffer);
+}
+
+static int acl_bin2text(char *data, char *text)
+{
+  ACCINFO *ai;
+  ACCLIST *al;
+  U_INT cnt, offs;
+
+  ai = (ACCINFO *) data;
+  al = (ACCLIST *) (data + sizeof(ACCINFO));
+
+  offs = sprintf(text, "ACL1:%X,%d\n",
+                 ai -> acc_attr, ai -> acc_count);
+
+  for (cnt = 0; cnt < ai -> acc_count; cnt++)
+    offs += sprintf(text + offs, "%s,%X\n",
+                    al[cnt].acl_ugname, al[cnt].acl_access);
+
+  return strlen(text);
+}
+
+int acl_get(char *server, const char *resource, char *buffer)
+{
+  USHORT datalen;
+  PSZ srv = NULL;
+  int rc;
+
+  if (!acl_init())
+    return -1;
+
+  if (server)
+    srv = server;
+
+  acl_mkpath(path, resource);
+  datalen = 0;
+
+  rc = NetAccessGetInfo(srv, path, 1, data, ACL_BUFFERSIZE, &datalen);
+
+  if (rc == 0)
+    acl_bin2text(data, buffer);
+
+  return rc;
+}
+
+static int acl_text2bin(char *data, char *text, char *path)
+{
+  ACCINFO *ai;
+  ACCLIST *al;
+  char *ptr, *ptr2;
+  U_INT cnt;
+
+  ai = (ACCINFO *) data;
+  ai -> acc_resource_name = PTR16(path);
+
+  if (sscanf(text, "ACL1:%hX,%hd",
+             &ai -> acc_attr, &ai -> acc_count) != 2)
+    return ERROR_INVALID_PARAMETER;
+
+  al = (ACCLIST *) (data + sizeof(ACCINFO));
+  ptr = strchr(text, '\n') + 1;
+
+  for (cnt = 0; cnt < ai -> acc_count; cnt++)
+  {
+    ptr2 = strchr(ptr, ',');
+    strncpy(al[cnt].acl_ugname, ptr, ptr2 - ptr);
+    al[cnt].acl_ugname[ptr2 - ptr] = 0;
+    sscanf(ptr2 + 1, "%hx", &al[cnt].acl_access);
+    ptr = strchr(ptr, '\n') + 1;
+  }
+
+  return sizeof(ACCINFO) + ai -> acc_count * sizeof(ACCLIST);
+}
+
+int acl_set(char *server, const char *resource, char *buffer)
+{
+  USHORT datalen;
+  PSZ srv = NULL;
+
+  if (!acl_init())
+    return -1;
+
+  if (server)
+    srv = server;
+
+  acl_mkpath(path, resource);
+
+  ai -> acc_resource_name = PTR16(path);
+  ai -> acc_attr = 0;
+  ai -> acc_count = 0;
+
+  NetAccessAdd(srv, 1, ai, sizeof(ACCINFO));
+  /* Ignore any errors, most probably because ACL already exists. */
+  /* In any such case, try updating the existing ACL. */
+
+  datalen = acl_text2bin(data, buffer, path);
+
+  return NetAccessSetInfo(srv, path, 1, data, datalen, 0);
+}
+
+/* end of os2acl.c */
diff --git a/os2/os2acl.h b/os2/os2acl.h
new file mode 100644 (file)
index 0000000..03bb8a2
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* os2acl.h
+ *
+ * Author:  Kai Uwe Rommel <rommel@ars.de>
+ * Created: Fri Mar 29 1996
+ */
+
+/* $Id: os2acl.h,v 1.1 1996/03/30 09:35:00 rommel Exp rommel $ */
+
+/*
+ * $Log: os2acl.h,v $
+ * Revision 1.1  1996/03/30 09:35:00  rommel
+ * Initial revision
+ *
+ */
+
+#ifndef _OS2ACL_H
+#define _OS2ACL_H
+
+#define ACL_BUFFERSIZE 4096
+
+int acl_get(char *server, const char *resource, char *buffer);
+int acl_set(char *server, const char *resource, char *buffer);
+
+#endif /* _OS2ACL_H */
+
+/* end of os2acl.h */
diff --git a/os2/os2zip.c b/os2/os2zip.c
new file mode 100644 (file)
index 0000000..83bc3bc
--- /dev/null
@@ -0,0 +1,1213 @@
+/*
+ * @(#)dir.c 1.4 87/11/06 Public Domain.
+ *
+ *  A public domain implementation of BSD directory routines for
+ *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
+ *  August 1987
+ *
+ *  Ported to OS/2 by Kai Uwe Rommel
+ *  Addition of other OS/2 file system specific code
+ *  Placed into the public domain
+ */
+
+/* does also contain EA access code for use in ZIP */
+
+
+#ifdef OS2
+
+
+#if defined(__EMX__) && !defined(__32BIT__)
+#  define __32BIT__
+#endif
+
+#include "zip.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#ifndef __BORLANDC__
+#include <malloc.h>
+#endif
+
+#define INCL_NOPM
+#define INCL_DOSNLS
+#define INCL_DOSERRORS
+#include <os2.h>
+
+#include "os2zip.h"
+#include "os2acl.h"
+
+
+#ifndef max
+#define max(a, b) ((a) < (b) ? (b) : (a))
+#endif
+
+
+#ifdef __32BIT__
+#define DosFindFirst(p1, p2, p3, p4, p5, p6) \
+        DosFindFirst(p1, p2, p3, p4, p5, p6, 1)
+#else
+#define DosQueryCurrentDisk DosQCurDisk
+#define DosQueryFSAttach(p1, p2, p3, p4, p5) \
+        DosQFSAttach(p1, p2, p3, p4, p5, 0)
+#define DosQueryFSInfo(d, l, b, s) \
+        DosQFSInfo(d, l, b, s)
+#define DosQueryPathInfo(p1, p2, p3, p4) \
+        DosQPathInfo(p1, p2, p3, p4, 0)
+#define DosSetPathInfo(p1, p2, p3, p4, p5) \
+        DosSetPathInfo(p1, p2, p3, p4, p5, 0)
+#define DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7) \
+        DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7, 0)
+#define DosFindFirst(p1, p2, p3, p4, p5, p6) \
+        DosFindFirst(p1, p2, p3, p4, p5, p6, 0)
+#define DosMapCase DosCaseMap
+#endif
+
+
+#ifndef UTIL
+
+extern int noisy;
+
+#ifndef S_IFMT
+#define S_IFMT 0xF000
+#endif
+
+static int attributes = _A_DIR | _A_HIDDEN | _A_SYSTEM;
+
+static char *getdirent(char *);
+static void free_dircontents(struct _dircontents *);
+
+#ifdef __32BIT__
+static HDIR hdir;
+static ULONG count;
+static FILEFINDBUF3 find;
+#else
+static HDIR hdir;
+static USHORT count;
+static FILEFINDBUF find;
+#endif
+
+DIR *opendir(const char *name)
+{
+  struct stat statb;
+  DIR *dirp;
+  char c;
+  char *s;
+  struct _dircontents *dp;
+  char nbuf[MAXPATHLEN + 1];
+  int len;
+
+  attributes = hidden_files ? (_A_DIR | _A_HIDDEN | _A_SYSTEM) : _A_DIR;
+
+  strcpy(nbuf, name);
+  if ((len = strlen(nbuf)) == 0)
+    return NULL;
+
+  if (((c = nbuf[len - 1]) == '\\' || c == '/') && (len > 1))
+  {
+    nbuf[len - 1] = 0;
+    --len;
+
+    if (nbuf[len - 1] == ':')
+    {
+      strcpy(nbuf+len, "\\.");
+      len += 2;
+    }
+  }
+  else
+    if (nbuf[len - 1] == ':')
+    {
+      strcpy(nbuf+len, ".");
+      ++len;
+    }
+
+#ifndef __BORLANDC__
+  /* when will we ever see a Borland compiler that can properly stat !!! */
+  if (stat(nbuf, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
+    return NULL;
+#endif
+
+  if ((dirp = malloc(sizeof(DIR))) == NULL)
+    return NULL;
+
+  if (nbuf[len - 1] == '.' && (len == 1 || nbuf[len - 2] != '.'))
+    strcpy(nbuf+len-1, "*.*");
+  else
+    if (((c = nbuf[len - 1]) == '\\' || c == '/') && (len == 1))
+      strcpy(nbuf+len, "*");
+    else
+      strcpy(nbuf+len, "\\*");
+
+  /* len is no longer correct (but no longer needed) */
+
+  dirp -> dd_loc = 0;
+  dirp -> dd_contents = dirp -> dd_cp = NULL;
+
+  if ((s = getdirent(nbuf)) == NULL)
+    return dirp;
+
+  do
+  {
+    if (((dp = malloc(sizeof(struct _dircontents))) == NULL) ||
+        ((dp -> _d_entry = malloc(strlen(s) + 1)) == NULL)      )
+    {
+      if (dp)
+        free(dp);
+      free_dircontents(dirp -> dd_contents);
+
+      return NULL;
+    }
+
+    if (dirp -> dd_contents)
+    {
+      dirp -> dd_cp -> _d_next = dp;
+      dirp -> dd_cp = dirp -> dd_cp -> _d_next;
+    }
+    else
+      dirp -> dd_contents = dirp -> dd_cp = dp;
+
+    strcpy(dp -> _d_entry, s);
+    dp -> _d_next = NULL;
+
+    dp -> _d_size = find.cbFile;
+    dp -> _d_mode = find.attrFile;
+    dp -> _d_time = *(unsigned *) &(find.ftimeLastWrite);
+    dp -> _d_date = *(unsigned *) &(find.fdateLastWrite);
+  }
+  while ((s = getdirent(NULL)) != NULL);
+
+  dirp -> dd_cp = dirp -> dd_contents;
+
+  return dirp;
+}
+
+void closedir(DIR * dirp)
+{
+  free_dircontents(dirp -> dd_contents);
+  free(dirp);
+}
+
+struct dirent *readdir(DIR * dirp)
+{
+  static struct dirent dp;
+
+  if (dirp -> dd_cp == NULL)
+    return NULL;
+
+  dp.d_namlen = dp.d_reclen =
+    strlen(strcpy(dp.d_name, dirp -> dd_cp -> _d_entry));
+
+  dp.d_ino = 0;
+
+  dp.d_size = dirp -> dd_cp -> _d_size;
+  dp.d_mode = dirp -> dd_cp -> _d_mode;
+  dp.d_time = dirp -> dd_cp -> _d_time;
+  dp.d_date = dirp -> dd_cp -> _d_date;
+
+  dirp -> dd_cp = dirp -> dd_cp -> _d_next;
+  dirp -> dd_loc++;
+
+  return &dp;
+}
+
+void seekdir(DIR * dirp, long off)
+{
+  long i = off;
+  struct _dircontents *dp;
+
+  if (off >= 0)
+  {
+    for (dp = dirp -> dd_contents; --i >= 0 && dp; dp = dp -> _d_next);
+
+    dirp -> dd_loc = off - (i + 1);
+    dirp -> dd_cp = dp;
+  }
+}
+
+long telldir(DIR * dirp)
+{
+  return dirp -> dd_loc;
+}
+
+static void free_dircontents(struct _dircontents * dp)
+{
+  struct _dircontents *odp;
+
+  while (dp)
+  {
+    if (dp -> _d_entry)
+      free(dp -> _d_entry);
+
+    dp = (odp = dp) -> _d_next;
+    free(odp);
+  }
+}
+
+static char *getdirent(char *dir)
+{
+  int done;
+  static int lower;
+
+  if (dir != NULL)
+  {                                    /* get first entry */
+    hdir = HDIR_SYSTEM;
+    count = 1;
+    done = DosFindFirst(dir, &hdir, attributes, &find, sizeof(find), &count);
+    lower = IsFileSystemFAT(dir);
+  }
+  else                                 /* get next entry */
+    done = DosFindNext(hdir, &find, sizeof(find), &count);
+
+  if (done == 0)
+  {
+    if (lower)
+      StringLower(find.achName);
+    return find.achName;
+  }
+  else
+  {
+    DosFindClose(hdir);
+    return NULL;
+  }
+}
+
+/* FAT / HPFS detection */
+
+int IsFileSystemFAT(char *dir)
+{
+  static USHORT nLastDrive = -1, nResult;
+  ULONG lMap;
+  BYTE bData[64];
+  char bName[3];
+#ifdef __32BIT__
+  ULONG nDrive, cbData;
+  PFSQBUFFER2 pData = (PFSQBUFFER2) bData;
+#else
+  USHORT nDrive, cbData;
+  PFSQBUFFER pData = (PFSQBUFFER) bData;
+#endif
+
+  /* We separate FAT and HPFS+other file systems here.
+     at the moment I consider other systems to be similar to HPFS,
+     i.e. support long file names and being case sensitive */
+
+  if (isalpha(dir[0]) && (dir[1] == ':'))
+    nDrive = to_up(dir[0]) - '@';
+  else
+    DosQueryCurrentDisk(&nDrive, &lMap);
+
+  if (nDrive == nLastDrive)
+    return nResult;
+
+  bName[0] = (char) (nDrive + '@');
+  bName[1] = ':';
+  bName[2] = 0;
+
+  nLastDrive = nDrive;
+  cbData = sizeof(bData);
+
+  if (!DosQueryFSAttach(bName, 0, FSAIL_QUERYNAME, (PVOID) pData, &cbData))
+    nResult = !strcmp((char *) pData -> szFSDName + pData -> cbName, "FAT");
+  else
+    nResult = FALSE;
+
+  /* End of this ugly code */
+  return nResult;
+}
+
+/* access mode bits and time stamp */
+
+int GetFileMode(char *name)
+{
+#ifdef __32BIT__
+  FILESTATUS3 fs;
+  return DosQueryPathInfo(name, 1, &fs, sizeof(fs)) ? -1 : fs.attrFile;
+#else
+  USHORT mode;
+  return DosQFileMode(name, &mode, 0L) ? -1 : mode;
+#endif
+}
+
+ulg GetFileTime(char *name)
+{
+#ifdef __32BIT__
+  FILESTATUS3 fs;
+#else
+  FILESTATUS fs;
+#endif
+  USHORT nDate, nTime;
+  DATETIME dtCurrent;
+
+  if (strcmp(name, "-") == 0)
+  {
+    DosGetDateTime(&dtCurrent);
+    fs.fdateLastWrite.day     = dtCurrent.day;
+    fs.fdateLastWrite.month   = dtCurrent.month;
+    fs.fdateLastWrite.year    = dtCurrent.year - 1980;
+    fs.ftimeLastWrite.hours   = dtCurrent.hours;
+    fs.ftimeLastWrite.minutes = dtCurrent.minutes;
+    fs.ftimeLastWrite.twosecs = dtCurrent.seconds / 2;
+  }
+  else
+    if (DosQueryPathInfo(name, 1, (PBYTE) &fs, sizeof(fs)))
+      return -1;
+
+  nDate = * (USHORT *) &fs.fdateLastWrite;
+  nTime = * (USHORT *) &fs.ftimeLastWrite;
+
+  return ((ULONG) nDate) << 16 | nTime;
+}
+
+void SetFileTime(char *path, ulg stamp)
+{
+  FILESTATUS fs;
+  USHORT fd, ft;
+
+  if (DosQueryPathInfo(path, FIL_STANDARD, (PBYTE) &fs, sizeof(fs)))
+    return;
+
+  fd = (USHORT) (stamp >> 16);
+  ft = (USHORT) stamp;
+  fs.fdateLastWrite = fs.fdateCreation = * (FDATE *) &fd;
+  fs.ftimeLastWrite = fs.ftimeCreation = * (FTIME *) &ft;
+
+  DosSetPathInfo(path, FIL_STANDARD, (PBYTE) &fs, sizeof(fs), 0);
+}
+
+/* read volume label */
+
+char *getVolumeLabel(int drive, unsigned long *vtime, unsigned long *vmode,
+                     time_t *utim)
+{
+  static FSINFO fi;
+
+  if (DosQueryFSInfo(drive ? drive - 'A' + 1 : 0,
+                     FSIL_VOLSER, (PBYTE) &fi, sizeof(fi)))
+    return NULL;
+
+  time(utim);
+  *vtime = unix2dostime(utim);
+  *vmode = _A_VOLID | _A_ARCHIVE;
+
+  return (fi.vol.cch > 0) ? fi.vol.szVolLabel : NULL;
+}
+
+/* FAT / HPFS name conversion stuff */
+
+int IsFileNameValid(char *name)
+{
+  HFILE hf;
+#ifdef __32BIT__
+  ULONG uAction;
+#else
+  USHORT uAction;
+#endif
+
+  switch(DosOpen(name, &hf, &uAction, 0, 0, FILE_OPEN,
+                 OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0))
+  {
+  case ERROR_INVALID_NAME:
+  case ERROR_FILENAME_EXCED_RANGE:
+    return FALSE;
+  case NO_ERROR:
+    DosClose(hf);
+  default:
+    return TRUE;
+  }
+}
+
+void ChangeNameForFAT(char *name)
+{
+  char *src, *dst, *next, *ptr, *dot, *start;
+  static char invalid[] = ":;,=+\"[]<>| \t";
+
+  if (isalpha(name[0]) && (name[1] == ':'))
+    start = name + 2;
+  else
+    start = name;
+
+  src = dst = start;
+  if ((*src == '/') || (*src == '\\'))
+    src++, dst++;
+
+  while (*src)
+  {
+    for (next = src; *next && (*next != '/') && (*next != '\\'); next++);
+
+    for (ptr = src, dot = NULL; ptr < next; ptr++)
+      if (*ptr == '.')
+      {
+        dot = ptr; /* remember last dot */
+        *ptr = '_';
+      }
+
+    if (dot == NULL)
+      for (ptr = src; ptr < next; ptr++)
+        if (*ptr == '_')
+          dot = ptr; /* remember last _ as if it were a dot */
+
+    if (dot && (dot > src) &&
+        ((next - dot <= 4) ||
+         ((next - src > 8) && (dot - src > 3))))
+    {
+      if (dot)
+        *dot = '.';
+
+      for (ptr = src; (ptr < dot) && ((ptr - src) < 8); ptr++)
+        *dst++ = *ptr;
+
+      for (ptr = dot; (ptr < next) && ((ptr - dot) < 4); ptr++)
+        *dst++ = *ptr;
+    }
+    else
+    {
+      if (dot && (next - src == 1))
+        *dot = '.';           /* special case: "." as a path component */
+
+      for (ptr = src; (ptr < next) && ((ptr - src) < 8); ptr++)
+        *dst++ = *ptr;
+    }
+
+    *dst++ = *next; /* either '/' or 0 */
+
+    if (*next)
+    {
+      src = next + 1;
+
+      if (*src == 0) /* handle trailing '/' on dirs ! */
+        *dst = 0;
+    }
+    else
+      break;
+  }
+
+  for (src = start; *src != 0; ++src)
+    if ((strchr(invalid, *src) != NULL) || (*src == ' '))
+      *src = '_';
+}
+
+/* .LONGNAME EA code */
+
+typedef struct
+{
+  ULONG cbList;               /* length of value + 22 */
+#ifdef __32BIT__
+  ULONG oNext;
+#endif
+  BYTE fEA;                   /* 0 */
+  BYTE cbName;                /* length of ".LONGNAME" = 9 */
+  USHORT cbValue;             /* length of value + 4 */
+  BYTE szName[10];            /* ".LONGNAME" */
+  USHORT eaType;              /* 0xFFFD for length-preceded ASCII */
+  USHORT eaSize;              /* length of value */
+  BYTE szValue[CCHMAXPATH];
+}
+FEALST;
+
+typedef struct
+{
+  ULONG cbList;
+#ifdef __32BIT__
+  ULONG oNext;
+#endif
+  BYTE cbName;
+  BYTE szName[10];            /* ".LONGNAME" */
+}
+GEALST;
+
+char *GetLongNameEA(const char *name)
+{
+  EAOP eaop;
+  GEALST gealst;
+  static FEALST fealst;
+  char *ptr;
+
+  eaop.fpGEAList = (PGEALIST) &gealst;
+  eaop.fpFEAList = (PFEALIST) &fealst;
+  eaop.oError = 0;
+
+  strcpy((char *) gealst.szName, ".LONGNAME");
+  gealst.cbName  = (BYTE) strlen((char *) gealst.szName);
+#ifdef __32BIT__
+  gealst.oNext   = 0;
+#endif
+
+  gealst.cbList  = sizeof(gealst);
+  fealst.cbList  = sizeof(fealst);
+
+  if (DosQueryPathInfo(name, FIL_QUERYEASFROMLIST,
+                       (PBYTE) &eaop, sizeof(eaop)))
+    return NULL;
+
+  if (fealst.cbValue > 4 && fealst.eaType == 0xFFFD)
+  {
+    fealst.szValue[fealst.eaSize] = 0;
+
+    for (ptr = fealst.szValue; *ptr; ptr++)
+      if (*ptr == '/' || *ptr == '\\')
+        *ptr = '!';
+
+    return (char *) fealst.szValue;
+  }
+
+  return NULL;
+}
+
+char *GetLongPathEA(const char *name)
+{
+  static char nbuf[CCHMAXPATH + 1];
+  char tempbuf[CCHMAXPATH + 1];
+  char *comp, *next, *ea, sep;
+  BOOL bFound = FALSE;
+
+  nbuf[0] = 0;
+  strncpy(tempbuf, name, CCHMAXPATH);
+  tempbuf[CCHMAXPATH] = '\0';
+  next = tempbuf;
+
+  while (*next)
+  {
+    comp = next;
+
+    while (*next != '\\' && *next != '/' && *next != 0)
+      next++;
+
+    sep = *next;
+    *next = 0;
+
+    ea = GetLongNameEA(tempbuf);
+    strcat(nbuf, ea ? ea : comp);
+    bFound = bFound || (ea != NULL);
+
+    if (sep)
+    {
+      strcat(nbuf, "\\");
+      *next++ = sep;
+    }
+  }
+
+  return (nbuf[0] != 0) && bFound ? nbuf : NULL;
+}
+
+/* general EA code */
+
+typedef struct
+{
+  USHORT nID;
+  USHORT nSize;
+  ULONG lSize;
+}
+EFHEADER, *PEFHEADER;
+
+#ifdef __32BIT__
+
+/* Perhaps due to bugs in the current OS/2 2.0 kernel, the success or
+   failure of the DosEnumAttribute() and DosQueryPathInfo() system calls
+   depends on the area where the return buffers are allocated. This
+   differs for the various compilers, for some alloca() works, for some
+   malloc() works, for some, both work. We'll have to live with that. */
+
+/* The use of malloc() is not very convenient, because it requires
+   backtracking (i.e. free()) at error returns. We do that for system
+   calls that may fail, but not for malloc() calls, because they are VERY
+   unlikely to fail. If ever, we just leave some memory allocated
+   over the usually short lifetime of a zip process ... */
+
+#ifdef __GNUC__
+#define alloc(x) alloca(x)
+#define unalloc(x)
+#else
+#define alloc(x) malloc(x)
+#define unalloc(x) free(x)
+#endif
+
+void GetEAs(char *path, char **bufptr, size_t *size,
+                        char **cbufptr, size_t *csize)
+{
+  FILESTATUS4 fs;
+  PDENA2 pDENA, pFound;
+  EAOP2 eaop;
+  PGEA2 pGEA;
+  PGEA2LIST pGEAlist;
+  PFEA2LIST pFEAlist;
+  PEFHEADER pEAblock;
+  ULONG ulAttributes, ulMemoryBlock;
+  ULONG nLength;
+  ULONG nBlock;
+  char szName[CCHMAXPATH];
+
+  *size = *csize = 0;
+
+  strcpy(szName, path);
+  nLength = strlen(szName);
+  if (szName[nLength - 1] == '/')
+    szName[nLength - 1] = 0;
+
+  if (DosQueryPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &fs, sizeof(fs)))
+    return;
+  nBlock = max(fs.cbList, 65535);
+  if ((pDENA = alloc((size_t) nBlock)) == NULL)
+    return;
+
+  ulAttributes = -1;
+
+  if (DosEnumAttribute(ENUMEA_REFTYPE_PATH, szName, 1, pDENA, nBlock,
+                       &ulAttributes, ENUMEA_LEVEL_NO_VALUE)
+    || ulAttributes == 0
+    || (pGEAlist = alloc((size_t) nBlock)) == NULL)
+  {
+    unalloc(pDENA);
+    return;
+  }
+
+  pGEA = pGEAlist -> list;
+  memset(pGEAlist, 0, nBlock);
+  pFound = pDENA;
+
+  while (ulAttributes--)
+  {
+    if (!(strcmp(pFound -> szName, ".LONGNAME") == 0 && use_longname_ea))
+    {
+      pGEA -> cbName = pFound -> cbName;
+      strcpy(pGEA -> szName, pFound -> szName);
+
+      nLength = sizeof(GEA2) + strlen(pGEA -> szName);
+      nLength = ((nLength - 1) / sizeof(ULONG) + 1) * sizeof(ULONG);
+
+      pGEA -> oNextEntryOffset = ulAttributes ? nLength : 0;
+      pGEA   = (PGEA2)  ((PCH) pGEA + nLength);
+    }
+
+    pFound = (PDENA2) ((PCH) pFound + pFound -> oNextEntryOffset);
+  }
+
+  if (pGEA == pGEAlist -> list) /* no attributes to save */
+  {
+    unalloc(pDENA);
+    unalloc(pGEAlist);
+    return;
+  }
+
+  pGEAlist -> cbList = (PCH) pGEA - (PCH) pGEAlist;
+
+  pFEAlist = (PVOID) pDENA;  /* reuse buffer */
+  pFEAlist -> cbList = nBlock;
+
+  eaop.fpGEA2List = pGEAlist;
+  eaop.fpFEA2List = pFEAlist;
+  eaop.oError = 0;
+
+  if (DosQueryPathInfo(szName, FIL_QUERYEASFROMLIST,
+                       (PBYTE) &eaop, sizeof(eaop)))
+  {
+    unalloc(pDENA);
+    unalloc(pGEAlist);
+    return;
+  }
+
+  /* The maximum compressed size is (in case of STORE type) the
+     uncompressed size plus the size of the compression type field
+     plus the size of the CRC field + 2*5 deflate overhead bytes
+     for uncompressable data.
+     (5 bytes per 32Kb block, max compressed size = 2 blocks) */
+
+  ulAttributes = pFEAlist -> cbList;
+  ulMemoryBlock = ulAttributes +
+                  sizeof(USHORT) + sizeof(ULONG) + EB_DEFLAT_EXTRA;
+  pEAblock = (PEFHEADER) malloc(sizeof(EFHEADER) + ulMemoryBlock);
+
+  if (pEAblock == NULL)
+  {
+    unalloc(pDENA);
+    unalloc(pGEAlist);
+    return;
+  }
+
+  *bufptr = (char *) pEAblock;
+  *size = sizeof(EFHEADER);
+
+  pEAblock -> nID = EF_OS2EA;
+  pEAblock -> nSize = sizeof(pEAblock -> lSize);
+  pEAblock -> lSize = ulAttributes; /* uncompressed size */
+
+  nLength = memcompress((char *) (pEAblock + 1), ulMemoryBlock,
+                        (char *) pFEAlist, ulAttributes);
+  *size += nLength;
+  pEAblock -> nSize += nLength;
+
+  if ((pEAblock = (PEFHEADER) malloc(sizeof(EFHEADER))) == NULL)
+  {
+    unalloc(pDENA);
+    unalloc(pGEAlist);
+    return;
+  }
+
+  *cbufptr = (char *) pEAblock;
+  *csize = sizeof(EFHEADER);
+
+  pEAblock -> nID = EF_OS2EA;
+  pEAblock -> nSize = sizeof(pEAblock -> lSize);
+  pEAblock -> lSize = ulAttributes;
+
+  if (noisy)
+    printf(" (%ld bytes EA's)", ulAttributes);
+
+  unalloc(pDENA);
+  unalloc(pGEAlist);
+}
+
+#else /* !__32BIT__ */
+
+typedef struct
+{
+  ULONG oNextEntryOffset;
+  BYTE fEA;
+  BYTE cbName;
+  USHORT cbValue;
+  CHAR szName[1];
+}
+FEA2, *PFEA2;
+
+typedef struct
+{
+  ULONG cbList;
+  FEA2 list[1];
+}
+FEA2LIST, *PFEA2LIST;
+
+void GetEAs(char *path, char **bufptr, size_t *size,
+                        char **cbufptr, size_t *csize)
+{
+  FILESTATUS2 fs;
+  PDENA1 pDENA, pFound;
+  EAOP eaop;
+  PGEALIST pGEAlist;
+  PGEA pGEA;
+  PFEALIST pFEAlist;
+  PFEA pFEA;
+  PFEA2LIST pFEA2list;
+  PFEA2 pFEA2;
+  EFHEADER *pEAblock;
+  ULONG ulAttributes;
+  USHORT nLength, nMaxSize;
+  char szName[CCHMAXPATH];
+
+  *size = *csize = 0;
+
+  strcpy(szName, path);
+  nLength = strlen(szName);
+  if (szName[nLength - 1] == '/')
+    szName[nLength - 1] = 0;
+
+  if (DosQueryPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &fs, sizeof(fs))
+      || fs.cbList <= 2 * sizeof(ULONG))
+    return;
+
+  ulAttributes = -1;
+  nMaxSize = (USHORT) min(fs.cbList * 2, 65520L);
+
+  if ((pDENA = malloc((size_t) nMaxSize)) == NULL)
+    return;
+
+  if (DosEnumAttribute(ENUMEA_REFTYPE_PATH, szName, 1, pDENA, fs.cbList,
+                       &ulAttributes, ENUMEA_LEVEL_NO_VALUE)
+    || ulAttributes == 0
+    || (pGEAlist = malloc(nMaxSize)) == NULL)
+  {
+    free(pDENA);
+    return;
+  }
+
+  pGEA = pGEAlist -> list;
+  pFound = pDENA;
+
+  while (ulAttributes--)
+  {
+    nLength = strlen(pFound -> szName);
+
+    if (!(strcmp(pFound -> szName, ".LONGNAME") == 0 && use_longname_ea))
+    {
+      pGEA -> cbName = pFound -> cbName;
+      strcpy(pGEA -> szName, pFound -> szName);
+
+      pGEA++;
+      pGEA = (PGEA) (((PCH) pGEA) + nLength);
+    }
+
+    pFound++;
+    pFound = (PDENA1) (((PCH) pFound) + nLength);
+  }
+
+  if (pGEA == pGEAlist -> list)
+  {
+    free(pDENA);
+    free(pGEAlist);
+    return;
+  }
+
+  pGEAlist -> cbList = (PCH) pGEA - (PCH) pGEAlist;
+
+  pFEAlist = (PFEALIST) pDENA; /* reuse buffer */
+  pFEAlist -> cbList = fs.cbList;
+  pFEA = pFEAlist -> list;
+
+  eaop.fpGEAList = pGEAlist;
+  eaop.fpFEAList = pFEAlist;
+  eaop.oError = 0;
+
+  if (DosQueryPathInfo(szName, FIL_QUERYEASFROMLIST,
+                       (PBYTE) &eaop, sizeof(eaop)))
+  {
+    free(pDENA);
+    free(pGEAlist);
+    return;
+  }
+
+  /* now convert into new OS/2 2.0 32-bit format */
+
+  pFEA2list = (PFEA2LIST) pGEAlist;  /* reuse buffer */
+  pFEA2 = pFEA2list -> list;
+
+  while ((PCH) pFEA - (PCH) pFEAlist < pFEAlist -> cbList)
+  {
+    nLength = sizeof(FEA) + pFEA -> cbName + 1 + pFEA -> cbValue;
+    memcpy((PCH) pFEA2 + sizeof(pFEA2 -> oNextEntryOffset), pFEA, nLength);
+    memset((PCH) pFEA2 + sizeof(pFEA2 -> oNextEntryOffset) + nLength, 0, 3);
+    pFEA = (PFEA) ((PCH) pFEA + nLength);
+
+    nLength = sizeof(FEA2) + pFEA2 -> cbName + 1 + pFEA2 -> cbValue;
+    nLength = ((nLength - 1) / sizeof(ULONG) + 1) * sizeof(ULONG);
+    /* rounded up to 4-byte boundary */
+    pFEA2 -> oNextEntryOffset =
+      ((PCH) pFEA - (PCH) pFEAlist < pFEAlist -> cbList) ? nLength : 0;
+    pFEA2 = (PFEA2) ((PCH) pFEA2 + nLength);
+  }
+
+  pFEA2list -> cbList = (PCH) pFEA2 - (PCH) pFEA2list;
+  ulAttributes = pFEA2list -> cbList;
+
+  pEAblock = (PEFHEADER) pDENA; /* reuse buffer */
+
+  *bufptr = (char *) pEAblock;
+  *size = sizeof(EFHEADER);
+
+  pEAblock -> nID = EF_OS2EA;
+  pEAblock -> nSize = sizeof(pEAblock -> lSize);
+  pEAblock -> lSize = ulAttributes; /* uncompressed size */
+
+  nLength = (USHORT) memcompress((char *) (pEAblock + 1),
+    nMaxSize - sizeof(EFHEADER), (char *) pFEA2list, ulAttributes);
+
+  *size += nLength;
+  pEAblock -> nSize += nLength;
+
+  pEAblock = (PEFHEADER) pGEAlist;
+
+  *cbufptr = (char *) pEAblock;
+  *csize = sizeof(EFHEADER);
+
+  pEAblock -> nID = EF_OS2EA;
+  pEAblock -> nSize = sizeof(pEAblock -> lSize);
+  pEAblock -> lSize = ulAttributes;
+
+  if (noisy)
+    printf(" (%ld bytes EA's)", ulAttributes);
+}
+
+#endif /* __32BIT__ */
+
+void GetACL(char *path, char **bufptr, size_t *size,
+                        char **cbufptr, size_t *csize)
+{
+  static char *buffer;
+  char *cbuffer;
+  long bytes, cbytes;
+  PEFHEADER pACLblock;
+
+  if (buffer == NULL) /* avoid frequent allocation (for every file) */
+    if ((buffer = malloc(ACL_BUFFERSIZE)) == NULL)
+      return;
+
+  if (acl_get(NULL, path, buffer))
+    return; /* this will be the most likely case */
+
+  bytes = strlen(buffer);
+
+  /* The maximum compressed size is (in case of STORE type) the
+     uncompressed size plus the size of the compression type field
+     plus the size of the CRC field + 2*5 deflate overhead bytes
+     for uncompressable data.
+     (5 bytes per 32Kb block, max compressed size = 2 blocks) */
+
+  cbytes = bytes + sizeof(USHORT) + sizeof(ULONG) + EB_DEFLAT_EXTRA;
+  if ((*bufptr = realloc(*bufptr, *size + sizeof(EFHEADER) + cbytes)) == NULL)
+    return;
+
+  pACLblock = (PEFHEADER) (*bufptr + *size);
+
+  cbuffer = (char *) (pACLblock + 1);
+  cbytes = memcompress(cbuffer, cbytes, buffer, bytes);
+
+  *size += sizeof(EFHEADER) + cbytes;
+
+  pACLblock -> nID = EF_ACL;
+  pACLblock -> nSize = sizeof(pACLblock -> lSize) + cbytes;
+  pACLblock -> lSize = bytes; /* uncompressed size */
+
+  if ((*cbufptr = realloc(*cbufptr, *csize + sizeof(EFHEADER))) == NULL)
+    return;
+
+  pACLblock = (PEFHEADER) (*cbufptr + *csize);
+  *csize += sizeof(EFHEADER);
+
+  pACLblock -> nID = EF_ACL;
+  pACLblock -> nSize = sizeof(pACLblock -> lSize);
+  pACLblock -> lSize = bytes;
+
+  if (noisy)
+    printf(" (%ld bytes ACL)", bytes);
+}
+
+#ifdef USE_EF_UT_TIME
+
+int GetExtraTime(struct zlist far *z, iztimes *z_utim)
+{
+  int eb_c_size = EB_HEADSIZE + EB_UT_LEN(1);
+  int eb_l_size = eb_c_size;
+  char *eb_c_ptr;
+  char *eb_l_ptr;
+  unsigned long ultime;
+
+#ifdef IZ_CHECK_TZ
+  if (!zp_tz_is_valid) return ZE_OK;    /* skip silently no correct tz info */
+#endif
+
+  eb_c_ptr = realloc(z->cextra, (z->cext + eb_c_size));
+  if (eb_c_ptr == NULL)
+    return ZE_MEM;
+  z->cextra = eb_c_ptr;
+  eb_c_ptr += z->cext;
+  z->cext += eb_c_size;
+
+  eb_c_ptr[0]  = 'U';
+  eb_c_ptr[1]  = 'T';
+  eb_c_ptr[2]  = EB_UT_LEN(1);          /* length of data part of e.f. */
+  eb_c_ptr[3]  = 0;
+  eb_c_ptr[4]  = EB_UT_FL_MTIME;
+  ultime = (unsigned long) z_utim->mtime;
+  eb_c_ptr[5]  = (char)(ultime);
+  eb_c_ptr[6]  = (char)(ultime >> 8);
+  eb_c_ptr[7]  = (char)(ultime >> 16);
+  eb_c_ptr[8]  = (char)(ultime >> 24);
+
+  if (z_utim->mtime != z_utim->atime || z_utim->mtime != z_utim->ctime)
+  {
+    eb_c_ptr[4]  = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME;
+    eb_l_size = EB_HEADSIZE + EB_UT_LEN(3); /* only on HPFS they can differ */
+  /* so only then it makes sense to store all three time stamps */
+  }
+
+  eb_l_ptr = realloc(z->extra, (z->ext + eb_l_size));
+  if (eb_l_ptr == NULL)
+    return ZE_MEM;
+  z->extra = eb_l_ptr;
+  eb_l_ptr += z->ext;
+  z->ext += eb_l_size;
+
+  memcpy(eb_l_ptr, eb_c_ptr, eb_c_size);
+
+  if (eb_l_size > eb_c_size)
+  {
+    eb_l_ptr[2]  = EB_UT_LEN(3);
+    ultime = (unsigned long) z_utim->atime;
+    eb_l_ptr[9]  = (char)(ultime);
+    eb_l_ptr[10] = (char)(ultime >> 8);
+    eb_l_ptr[11] = (char)(ultime >> 16);
+    eb_l_ptr[12] = (char)(ultime >> 24);
+    ultime = (unsigned long) z_utim->ctime;
+    eb_l_ptr[13] = (char)(ultime);
+    eb_l_ptr[14] = (char)(ultime >> 8);
+    eb_l_ptr[15] = (char)(ultime >> 16);
+    eb_l_ptr[16] = (char)(ultime >> 24);
+  }
+
+  return ZE_OK;
+}
+
+#endif /* USE_EF_UT_TIME */
+
+int set_extra_field(struct zlist far *z, iztimes *z_utim)
+{
+  /* store EA data in local header, and size only in central headers */
+  GetEAs(z->name, &z->extra, &z->ext, &z->cextra, &z->cext);
+
+  /* store ACL data in local header, and size only in central headers */
+  GetACL(z->name, &z->extra, &z->ext, &z->cextra, &z->cext);
+
+#ifdef USE_EF_UT_TIME
+  /* store extended time stamps in both headers */
+  return GetExtraTime(z, z_utim);
+#else /* !USE_EF_UT_TIME */
+  return ZE_OK;
+#endif /* ?USE_EF_UT_TIME */
+}
+
+#endif /* !UTIL */
+
+/* Initialize the table of uppercase characters including handling of
+   country dependent characters. */
+
+void init_upper()
+{
+  COUNTRYCODE cc;
+  unsigned nCnt, nU;
+
+  for (nCnt = 0; nCnt < sizeof(upper); nCnt++)
+    upper[nCnt] = lower[nCnt] = (unsigned char) nCnt;
+
+  cc.country = cc.codepage = 0;
+  DosMapCase(sizeof(upper), &cc, (PCHAR) upper);
+
+  for (nCnt = 0; nCnt < 256; nCnt++)
+  {
+    nU = upper[nCnt];
+    if (nU != nCnt && lower[nU] == (unsigned char) nU)
+      lower[nU] = (unsigned char) nCnt;
+  }
+
+  for (nCnt = 'A'; nCnt <= 'Z'; nCnt++)
+    lower[nCnt] = (unsigned char) (nCnt - 'A' + 'a');
+}
+
+char *StringLower(char *szArg)
+{
+  unsigned char *szPtr;
+  for (szPtr = (unsigned char *) szArg; *szPtr; szPtr++)
+    *szPtr = lower[*szPtr];
+  return szArg;
+}
+
+#if defined(__IBMC__) && defined(__DEBUG_ALLOC__)
+void DebugMalloc(void)
+{
+  _dump_allocated(0); /* print out debug malloc memory statistics */
+}
+#endif
+
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+void version_local()
+{
+    static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+#if defined(__IBMC__) || defined(__WATCOMC__) || defined(_MSC_VER)
+    char buf[80];
+#endif
+
+    printf(CompiledWith,
+
+#ifdef __GNUC__
+#  ifdef __EMX__  /* __EMX__ is defined as "1" only (sigh) */
+      "emx+gcc ", __VERSION__,
+#  else
+      "gcc/2 ", __VERSION__,
+#  endif
+#elif defined(__IBMC__)
+      "IBM ",
+#  if (__IBMC__ < 200)
+      (sprintf(buf, "C Set/2 %d.%02d", __IBMC__/100,__IBMC__%100), buf),
+#  elif (__IBMC__ < 300)
+      (sprintf(buf, "C Set++ %d.%02d", __IBMC__/100,__IBMC__%100), buf),
+#  else
+      (sprintf(buf, "Visual Age C++ %d.%02d", __IBMC__/100,__IBMC__%100), buf),
+#  endif
+#elif defined(__WATCOMC__)
+      "Watcom C", (sprintf(buf, " (__WATCOMC__ = %d)", __WATCOMC__), buf),
+#elif defined(__TURBOC__)
+#  ifdef __BORLANDC__
+      "Borland C++",
+#    if (__BORLANDC__ < 0x0460)
+        " 1.0",
+#    elif (__BORLANDC__ == 0x0460)
+        " 1.5",
+#    else
+        " 2.0",
+#    endif
+#  else
+      "Turbo C",
+#    if (__TURBOC__ >= 661)
+       "++ 1.0 or later",
+#    elif (__TURBOC__ == 661)
+       " 3.0?",
+#    elif (__TURBOC__ == 397)
+       " 2.0",
+#    else
+       " 1.0 or 1.5?",
+#    endif
+#  endif
+#elif defined(MSC)
+      "Microsoft C ",
+#  ifdef _MSC_VER
+      (sprintf(buf, "%d.%02d", _MSC_VER/100, _MSC_VER%100), buf),
+#  else
+      "5.1 or earlier",
+#  endif
+#else
+      "unknown compiler", "",
+#endif /* __GNUC__ */
+
+      "OS/2",
+
+/* GRR:  does IBM C/2 identify itself as IBM rather than Microsoft? */
+#if (defined(MSC) || (defined(__WATCOMC__) && !defined(__386__)))
+#  if defined(M_I86HM) || defined(__HUGE__)
+      " (16-bit, huge)",
+#  elif defined(M_I86LM) || defined(__LARGE__)
+      " (16-bit, large)",
+#  elif defined(M_I86MM) || defined(__MEDIUM__)
+      " (16-bit, medium)",
+#  elif defined(M_I86CM) || defined(__COMPACT__)
+      " (16-bit, compact)",
+#  elif defined(M_I86SM) || defined(__SMALL__)
+      " (16-bit, small)",
+#  elif defined(M_I86TM) || defined(__TINY__)
+      " (16-bit, tiny)",
+#  else
+      " (16-bit)",
+#  endif
+#else
+      " 2.x/3.x (32-bit)",
+#endif
+
+#ifdef __DATE__
+      " on ", __DATE__
+#else
+      "", ""
+#endif
+    );
+
+    /* temporary debugging code for Borland compilers only */
+#ifdef __TURBOC__
+    printf("\t(__TURBOC__ = 0x%04x = %d)\n", __TURBOC__, __TURBOC__);
+#ifdef __BORLANDC__
+    printf("\t(__BORLANDC__ = 0x%04x)\n",__BORLANDC__);
+#else
+    printf("\tdebug(__BORLANDC__ not defined)\n");
+#endif
+#ifdef __TCPLUSPLUS__
+    printf("\t(__TCPLUSPLUS__ = 0x%04x)\n", __TCPLUSPLUS__);
+#else
+    printf("\tdebug(__TCPLUSPLUS__ not defined)\n");
+#endif
+#ifdef __BCPLUSPLUS__
+    printf("\t(__BCPLUSPLUS__ = 0x%04x)\n\n", __BCPLUSPLUS__);
+#else
+    printf("\tdebug(__BCPLUSPLUS__ not defined)\n\n");
+#endif
+#endif /* __TURBOC__ */
+
+} /* end function version_local() */
+
+#endif /* OS2 */
diff --git a/os2/os2zip.h b/os2/os2zip.h
new file mode 100644 (file)
index 0000000..06d0a02
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * @(#) dir.h 1.4 87/11/06   Public Domain.
+ *
+ *  A public domain implementation of BSD directory routines for
+ *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
+ *  August 1987
+ *
+ *  Ported to OS/2 by Kai Uwe Rommel
+ *  Addition of other OS/2 file system specific code
+ *  Placed into the public domain
+ */
+
+
+#define MAXNAMLEN  256
+#define MAXPATHLEN 256
+
+#define _A_RONLY    0x01
+#define _A_HIDDEN   0x02
+#define _A_SYSTEM   0x04
+#define _A_VOLID    0x08
+#define _A_DIR      0x10
+#define _A_ARCHIVE  0x20
+
+
+struct dirent
+{
+  ino_t    d_ino;                   /* a bit of a farce */
+  int      d_reclen;                /* more farce */
+  int      d_namlen;                /* length of d_name */
+  char     d_name[MAXNAMLEN + 1];   /* null terminated */
+  /* nonstandard fields */
+  long     d_size;                  /* size in bytes */
+  unsigned d_mode;                  /* DOS or OS/2 file attributes */
+  unsigned d_time;
+  unsigned d_date;
+};
+
+/* The fields d_size and d_mode are extensions by me (Kai Uwe Rommel).
+ * The find_first and find_next calls deliver this data without any extra cost.
+ * If this data is needed, these fields save a lot of extra calls to stat()
+ * (each stat() again performs a find_first call !).
+ */
+
+struct _dircontents
+{
+  char *_d_entry;
+  long _d_size;
+  unsigned _d_mode, _d_time, _d_date;
+  struct _dircontents *_d_next;
+};
+
+typedef struct _dirdesc
+{
+  int  dd_id;                   /* uniquely identify each open directory */
+  long dd_loc;                  /* where we are in directory entry is this */
+  struct _dircontents *dd_contents;   /* pointer to contents of dir */
+  struct _dircontents *dd_cp;         /* pointer to current position */
+}
+DIR;
+
+
+extern DIR *opendir(const char *);
+extern struct dirent *readdir(DIR *);
+extern void seekdir(DIR *, long);
+extern long telldir(DIR *);
+extern void closedir(DIR *);
+#define rewinddir(dirp) seekdir(dirp, 0L)
+
+int GetFileMode(char *name);
+ulg GetFileTime(char *name);
+void SetFileTime(char *path, ulg stamp);
+char *getVolumeLabel(int drive, unsigned long *time, unsigned long *mode,
+                     time_t *utim);
+
+int IsFileNameValid(char *name);
+int IsFileSystemFAT(char *dir);
+void ChangeNameForFAT(char *name);
+
+char *GetLongNameEA(const char *name);
+char *GetLongPathEA(const char *name);
+void GetEAs(char *name, char **bufptr, size_t *size,
+                        char **cbufptr, size_t *csize);
+
+char *StringLower(char *);
diff --git a/os2/osdep.h b/os2/osdep.h
new file mode 100644 (file)
index 0000000..ea2c3f9
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#if defined(__OS2__) && !defined(OS2)
+#  define OS2
+#endif
+
+/* Automatic setting of the common Microsoft C idenfifier MSC.
+ * NOTE: Watcom also defines M_I*86 !
+ */
+#if defined(_MSC_VER) || (defined(M_I86) && !defined(__WATCOMC__))
+#  ifndef MSC
+#    define MSC                 /* This should work for older MSC, too!  */
+#  endif
+#endif
+
+#if defined(__WATCOMC__) && defined(__386__)
+#  define WATCOMC_386
+#endif
+
+#if defined(__EMX__) || defined(WATCOMC_386) || defined(__BORLANDC__)
+#  if (defined(OS2) && !defined(__32BIT__))
+#    define __32BIT__
+#  endif
+#endif
+
+#if defined(OS2) && !defined(__32BIT__)
+#  define MEMORY16
+#endif
+
+#ifndef NO_ASM
+#  define ASMV
+/* #  define ASM_CRC */
+#endif
+
+/* enable creation of UTC time fields unless explicitely suppressed */
+#if (!defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME))
+#  define USE_EF_UT_TIME
+#endif
+
+/* check that TZ environment variable is defined before using UTC times */
+#if (!defined(NO_IZ_CHECK_TZ) && !defined(IZ_CHECK_TZ))
+#  define IZ_CHECK_TZ
+#endif
+
+#ifndef ZP_NEED_MEMCOMPR
+#  define ZP_NEED_MEMCOMPR
+#endif
+
+#ifdef MEMORY16
+#  ifdef __TURBOC__
+#    include <alloc.h>
+#    if defined(__COMPACT__) || defined(__LARGE__) || defined(__HUGE__)
+#      if defined(DYNAMIC_CRC_TABLE) && defined(DYNALLOC_CRCTAB)
+        error: No dynamic CRC table allocation with Borland C far data models.
+#      endif /* DYNAMIC_CRC_TABLE */
+#    endif /* Turbo/Borland C far data memory models */
+#    define nearmalloc malloc
+#    define nearfree   free
+#    define DYN_ALLOC
+#  else /* !__TURBOC__ */
+#    include <malloc.h>
+#    define nearmalloc _nmalloc
+#    define nearfree   _nfree
+#    define farmalloc  _fmalloc
+#    define farfree    _ffree
+#  endif /* ?__TURBOC__ */
+#  define MY_ZCALLOC 1
+#endif /* MEMORY16 */
+
+
+/* The symbol MSDOS is consistently used in the generic source files
+ * to identify code to support for MSDOS (and MSDOS related) stuff.
+ * e.g: FAT or (FAT like) file systems,
+ *      '\\' as directory separator in paths,
+ *      "\r\n" as record (line) terminator in text files, ...
+ *
+ * MSDOS is defined anyway with MS C 16-bit. So the block above works.
+ * For the 32-bit compilers, MSDOS must not be defined in the block above.
+ */
+#if (defined(OS2) && !defined(MSDOS))
+#  define MSDOS
+/* inherit MS-DOS file system etc. stuff */
+#endif
+
+#define USE_CASE_MAP
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+                     procname(n, 1))
+
+/* time stamp resolution of file system is 2 seconds */
+#define ROUNDED_TIME(time)  ((time_t)(((unsigned long)(time) + 1) & (~1)))
+
+#define FOPR "rb"
+#define FOPM "r+b"
+#define FOPW "wb"
+
+#ifdef __32BIT__
+#  define CBSZ 0x40000
+#  define ZBSZ 0x40000
+#else
+#  define CBSZ 0xE000
+#  define ZBSZ 0x7F00 /* Some libraries do not allow a buffer size > 32K */
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <io.h>
+
+#ifdef ZCRYPT_INTERNAL
+#  ifndef __GO32__
+#    include <process.h>        /* getpid() declaration for srand seed */
+#  endif
+#endif
+
+/* for some (all ?) versions of IBM C Set/2 and IBM C Set++ */
+#ifndef S_IFMT
+#  define S_IFMT 0xF000
+#endif /* !S_IFMT */
+
+#ifdef MSC
+#  define NO_UNISTD_H
+#endif
+
+#ifdef __WATCOMC__
+#  define NO_MKTEMP
+/* Get asm routines to link properly without using "__cdecl": */
+#  ifdef __386__
+#    ifdef ASMV
+#      pragma aux window "*";
+#      pragma aux prev "*";
+#      pragma aux prev_length "*";
+#      pragma aux strstart "*";
+#      pragma aux match_start "*";
+#      pragma aux max_chain_length "*";
+#      pragma aux good_match "*";
+#      pragma aux nice_match "*";
+#      pragma aux match_init "*";
+#      pragma aux longest_match "*";
+#    endif
+#    ifndef USE_ZLIB
+#      pragma aux crc32         "_*" parm caller [] value [eax] modify [eax]
+#      pragma aux get_crc_table "_*" parm caller [] value [eax] \
+                                      modify [eax ecx edx]
+#    endif /* !USE_ZLIB */
+#  else /* !__386__ */
+#    if defined(ASMV) || defined(ASM_CRC)
+/*#      error 16 bit assembly modules currently DO NOT WORK with Watcom C. */
+#    endif
+#    ifdef ASMV
+#      pragma aux match_init    "_*" parm caller [] loadds modify [ax bx]
+#      pragma aux longest_match "_*" parm caller [] loadds value [ax] \
+                                      modify [ax bx cx dx es]
+#    endif
+#    ifndef USE_ZLIB
+#      pragma aux crc32         "_*" parm caller [] value [ax dx] \
+                                      modify [ax bx cx dx es]
+#      pragma aux get_crc_table "_*" parm caller [] value [ax] \
+                                      modify [ax bx cx dx]
+#    endif /* !USE_ZLIB */
+#  endif /* ?__386__ */
+#endif
+
+#ifdef __IBMC__
+#  define NO_UNISTD_H
+#  define NO_MKTEMP
+#  define timezone _timezone            /* (underscore names work with    */
+#  define tzset _tzset                  /*  all versions of C Set)        */
+#endif
diff --git a/os2/zip.def b/os2/zip.def
new file mode 100644 (file)
index 0000000..7404eee
--- /dev/null
@@ -0,0 +1,3 @@
+NAME WINDOWCOMPAT NEWFILES
+DESCRIPTION 'The world-famous zip utilities from Info-ZIP'
+; STACKSIZE 0x50000
diff --git a/os2/zipup.h b/os2/zipup.h
new file mode 100644 (file)
index 0000000..592cff8
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define fhow (O_RDONLY|O_BINARY)
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/packaging/zip.spec b/packaging/zip.spec
new file mode 100644 (file)
index 0000000..6d71d4b
--- /dev/null
@@ -0,0 +1,53 @@
+Summary: A file compression and packaging utility compatible with PKZIP.
+Name: zip
+Version: 3.0
+Release: 1.0.1
+License: distributable
+Group: Applications/Archiving
+Source:%{name}-%{version}.tar.gz
+URL: http://www.info-zip.org/pub/infozip/Zip.html
+
+%description
+The zip program is a compression and file packaging utility.  Zip is
+analogous to a combination of the UNIX tar and compress commands and
+is compatible with PKZIP (a compression and file packaging utility for
+MS-DOS systems).
+
+Install the zip package if you need to compress files using the zip
+program.
+
+%prep
+%setup -q
+%build
+make -f unix/Makefile prefix=/usr "CFLAGS=$RPM_OPT_FLAGS -I. -DUNIX -D_LARGEFILE64_SOURCE" generic_gcc
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/usr/bin
+mkdir -p $RPM_BULD_ROOT%{_mandir}/man1
+
+make -f unix/Makefile prefix=$RPM_BUILD_ROOT/usr \
+       MANDIR=$RPM_BUILD_ROOT%{_mandir}/man1 install
+
+pushd $RPM_BUILD_ROOT
+for n in zipnote zipsplit zip zipcloak ; do
+    chmod 755 ./usr/bin/$n
+done
+popd
+
+mkdir -p %{buildroot}/usr/share/license
+cp LICENSE %{buildroot}/usr/share/license/%{name}
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%doc README BUGS CHANGES TODO WHATSNEW WHERE LICENSE
+%doc proginfo/algorith.txt
+/usr/bin/zipnote
+/usr/bin/zipsplit
+/usr/bin/zip
+/usr/bin/zipcloak
+%{_mandir}/man1/zip*1*
+/usr/share/license/%{name}
diff --git a/proginfo/3rdparty.bug b/proginfo/3rdparty.bug
new file mode 100644 (file)
index 0000000..32e7823
--- /dev/null
@@ -0,0 +1,114 @@
+Known, current PKZIP bugs/limitations:
+-------------------------------------
+
+ - PKUNZIP 2.04g is reported to corrupt some files when compressing them with
+   the -ex option; when tested, the files fail the CRC check, and comparison
+   with the original file shows bogus data (6K in one case) embedded in the
+   middle.  PKWARE apparently characterized this as a "known problem."
+
+ - PKUNZIP 2.04g considers volume labels valid only if originated on a FAT
+   file system, but other OSes and file systems (e.g., Amiga and OS/2 HPFS)
+   support volume labels, too.
+
+ - PKUNZIP 2.04g can restore volume labels created by Zip 2.x but not by
+   PKZIP 2.04g (OS/2 DOS box only??).
+
+ - PKUNZIP 2.04g gives an error message for stored directory entries created
+   under other OSes (although it creates the directory anyway), and PKZIP -vt
+   does not report the directory attribute bit as being set, even if it is.
+
+ - PKZIP 2.04g mangles unknown extra fields (especially OS/2 extended attri-
+   butes) when adding new files to an existing zipfile [example:  Walnut Creek
+   Hobbes March 1995 CD-ROM, FILE_ID.DIZ additions].
+
+ - PKUNZIP 2.04g is unable to detect or deal with prepended junk in a zipfile,
+   reporting CRC errors in valid compressed data.
+
+ - PKUNZIP 2.04g (registered version) incorrectly updates/freshens the AV extra
+   field in authenticated archives.  The resultant extra block length and total
+   extra field length are inconsistent.
+
+ - [Windows version 2.01] Win95 long filenames (VFAT) are stored OK, but the
+   file system is always listed as ordinary DOS FAT.
+
+ - [Windows version 2.50] NT long filenames (NTFS) are stored OK, but the
+   file system is always listed as ordinary DOS FAT.
+
+ - PKZIP 2.04 for DOS encrypts using the OEM code page for 8-bit passwords,
+   while PKZIP 2.50 for Windows uses Latin-1 (ISO 8859-1).  This means an
+   archive encrypted with an 8-bit password with one of the two PKZIP versions
+   cannot be decrypted with the other version.
+
+ - PKZIP for Windows GUI (v 2.60), PKZIP for Windows command line (v 2.50) and
+   PKZIP for Unix (v 2.51) save the host's native file timestamps, but
+   only in a local extra field. Thus, timestamp-related selections (update
+   or freshen, both in extraction or archiving operations) use the DOS-format
+   localtime records in the Zip archives for comparisons. This may result
+   in wrong decisions of the program when updating archives that were
+   previously created in a different local time zone.
+
+ - PKZIP releases newer than PKZIP for DOS 2.04g (PKZIP for Windows, both
+   GUI v 2.60 and console v 2.50; PKZIP for Unix v 2.51; probably others too)
+   use different code pages for storing filenames in central (OEM Codepage)
+   and local (ANSI / ISO 8859-1 Codepage) headers. When a stored filename
+   contains extended-ASCII characters, the local and central filename fields
+   do not match. As a consequence, Info-ZIP's Zip program considers such
+   archives as being corrupt and does not allow to modify them. Beginning
+   with release 5.41, Info-ZIP's UnZip contains a workaround to list AND
+   extract such archives with the correct filenames.
+   Maybe PKWARE has implemented this "feature" to allow extraction of their
+   "made-by-PKZIP for Unix/Windows" archives using old (v5.2 and earlier)
+   versions of Info-ZIP's UnZip for Unix/WinNT ??? (UnZip versions before
+   v 5.3 assumed that all archive entries were encoded in the codepage of
+   the UnZip program's host system.)
+
+ - PKUNZIP 2.04g is reported to have problems with archives created on and/or
+   copied from Iomega ZIP drives (irony, eh?).
+
+Known, current WinZip bugs/limitations:
+--------------------------------------
+
+ - [16-bit version 6.1a] NT short filenames (FAT) are stored OK, but the
+   file system is always listed as NTFS.
+
+ - WinZip doesn't allow 8-bit passwords, which means it cannot decrypt an
+   archive created with an 8-bit password (by PKZIP or Info-ZIP's Zip).
+
+ - WinZip (at least Versions 6.3 PL1, 7.0 SR1) fails to remove old extra
+   fields when freshening existing archive entries. When updating archives
+   created by Info-ZIP's Zip that contain UT time stamp extra field blocks,
+   UnZip cannot display or restore the updated (DOS) time stamps of the
+   freshened archive members.
+
+Known, current other third-party Zip utils bugs/limitations:
+------------------------------------------------------------
+
+ - Asi's PKZip clones for Macintosh (versions 2.3 and 2.10d) are thoroughly
+   broken. They create invalid Zip archives!
+   a) For the first entry, both compressed size and uncompressed length
+      are recorded as 0, despite the fact that compressed data of non-zero
+      length has been added.
+   b) Their program creates extra fields with an (undocumented) internal
+      structure that violates the requirements of PKWARE's Zip format
+      specification document "appnote.txt": Their extra field seems to
+      contain pure data; the 4-byte block header consisting of block ID
+      and data length is missing.
+
+Possibly current PKZIP bugs:
+---------------------------
+
+ - PKZIP (2.04g?) can silently ignore read errors on network drives, storing
+   the correct CRC and compressed length but an incorrect and inconsistent
+   uncompressed length.
+
+ - PKZIP (2.04g?), when deleting files from within a zipfile on a Novell
+   drive, sometimes only zeros out the data while failing to shrink the
+   zipfile.
+
+Other limitations:
+-----------------
+
+ - PKZIP 1.x and 2.x encryption has been cracked (known-plaintext approach;
+   see http://www.cryptography.com/ for details).
+
+[many other bugs in PKZIP 1.0, 1.1, 1.93a, 2.04c and 2.04e]
diff --git a/proginfo/ZipPorts b/proginfo/ZipPorts
new file mode 100644 (file)
index 0000000..2d946d3
--- /dev/null
@@ -0,0 +1,285 @@
+__________________________________________________________________________
+
+  This is the Info-ZIP file ZipPorts, last updated on 17 February 1996.
+__________________________________________________________________________
+
+
+This document defines a set of rules and guidelines for those who wish to
+contribute patches to Zip and UnZip (or even entire ports to new operating
+systems).  The list below is something between a style sheet and a "Miss
+Manners" etiquette guide.  While Info-ZIP encourages contributions and
+fixes from anyone who finds something worth changing, we are also aware
+of the fact that no two programmers have the programming style and that
+unrestrained changes by a few dozen contributors would result in hideously
+ugly (and unmaintainable) Frankenstein code.  So consider the following an
+attempt by the maintainers to maintain sanity as well as useful code.
+
+(The first version of this document was called either "ZipRules" or the
+"No Feelthy ..." file and was compiled by David Kirschbaum in consulta-
+tion with Mark Adler, Cave McNewt and others.  The current incarnation
+expands upon the original with insights gained from a few more years of
+happy hacking...)
+
+
+Summary:
+
+  (0) The Platinum Rule:  DON'T BREAK EXISTING PORTS
+(0.1) The Golden Rule:    DO UNTO THE CODE AS OTHERS HAVE DONE BEFORE
+(0.2) The Silver Rule:    DO UNTO THE LATEST BETA CODE
+(0.3) The Bronze Rule:    NO FEELTHY PIGGYBACKS
+
+  (1) NO FEELTHY TABS
+  (2) NO FEELTHY CARRIAGE RETURNS
+  (3) NO FEELTHY 8-BIT CHARS
+  (4) NO FEELTHY LEFT-JUSTIFIED DASHES
+  (5) NO FEELTHY FANCY_FILENAMES
+  (6) NO FEELTHY NON-ZIPFILES AND NO FEELTHY E-MAIL BETAS
+  (7) NO FEELTHY E-MAIL BINARIES
+
+
+Explanations:
+
+  (0) The Platinum Rule:  DON'T BREAK EXISTING PORTS
+
+      No doubt about it, this is the one which really pisses us off and
+      pretty much guarantees that your port or patch will be ignored and/
+      or laughed at.  Examples range from the *really* severe cases which
+      "port" by ripping out all of the existing multi-OS code, to more
+      subtle oopers like relying on a local capability which doesn't exist
+      on other OSes or in older compilers (e.g., the use of ANSI "#elif"
+      or "#pragma" or "##" constructs, C++ comments, GNU extensions, etc.).
+      As to the former, use #ifdefs for your new code (see rule 0.3).  And
+      as to the latter, trust us--there are few things we'd like better
+      than to be able to use some of the elegant "new" features out there
+      (many of which have been around for a decade or more).  But our code
+      still compiles on machines dating back even longer, at least in spirit
+      --e.g., the AT&T 3B1 family and Dynix/ptx.  Until we say otherwise,
+      dinosaurs are supported.
+
+
+(0.1) The Golden Rule:  DO UNTO THE CODE AS OTHERS HAVE DONE BEFORE
+
+      In other words, try to fit into the local style of programming--no
+      matter how painful it may be.  This includes cosmetic aspects like
+      indenting the same amount (both in the main C code and in the in-
+      clude files), using braces and comments similarly, NO TABS (see rule
+      #1), etc.; but also more substantive things like (for UnZip) putting
+      character strings into static (far) variables and using the LoadFar-
+      String macros to avoid overflowing limited MS-DOS data segments, and
+      using the ugly Info() macro instead of the more usual *printf()
+      functions so that dynamic-link-library ports are simpler.  NEVER put
+      single-OS code (e.g., OS/2) of more than two or three lines into the
+      main (generic) modules; those are shared by everybody, and nobody else
+      cares about it or wants to see it.
+
+      Note that not only do Zip and UnZip differ in these respects, so do
+      individual parts of each program.  While it would be nice to have
+      global consistency, cosmetic changes are not a high priority; for
+      now we'll settle for local consistency--i.e., don't make things any
+      worse than they already are.
+
+      Exception (BIG exception):  single-letter variable names.  Despite
+      the prevailing practice in much of Zip and parts of UnZip, and de-
+      spite the fact that one-letter variables allow you to pack really
+      cool, compact and complicated expressions onto one line, they also
+      make the code very difficult to maintain and are therefore *strongly*
+      discouraged.  Don't ask us who is responsible in the first place;
+      while this sort of brain damage is not uncommon among former BASIC
+      programmers, it is nevertheless a lifelong embarrassment, and we do
+      try to pity the poor sod (that is, when we're not chasing bugs and
+      cursing him).  :-)
+
+
+(0.2) The Silver Rule:  DO UNTO THE LATEST BETA CODE
+
+      Few things are as annoying as receiving a large patch which obviously
+      represents a lot of time and careful work but which is relative to
+      an old version of Info-ZIP code.  As wonderful as Larry Wall's patch
+      program is at applying context diffs to modified code, we regularly
+      make near-global changes and/or reorganize big chunks of the sources
+      (particularly in UnZip), and "patch" can't work miracles--big changes
+      invariably break any patch which is relative to an old version of the
+      code.
+
+      Bottom line:  contact the Info-ZIP core team FIRST (via the zip-bugs
+      e-mail address) and get up to date with the latest code before begin-
+      ning a big new port.  And try to *stay* up to date while working on
+      your port--at least, as much as possible.
+
+
+(0.3) The Bronze Rule:  NO FEELTHY PIGGYBACKS
+
+      UnZip is currently ported to something like 12 operating systems
+      (a few more or less depending on how one counts), and each of these,
+      with the possible exception of VM/CMS, has a unique macro identifying
+      it:  AMIGA, ATARI_ST, __human68k__, MACOS, MSDOS, MVS, OS2, TOPS20,
+      UNIX, VMS, WIN32.  Zip is moving in the same direction.  New ports
+      should NOT piggyback one of the existing ports unless they are sub-
+      stantially similar--for example, Minix and Coherent are basically Unix
+      and therefore are included in the UNIX macro, but DOS djgpp ports and
+      OS/2 emx ports (both of which use the Unix-originated GNU C compiler
+      and often have "unix" defined by default) are obviously *not* Unix.
+      [The existing MTS port is a special exception; basically only one per-
+      son knows what MTS really is, and he's not telling.  Presumably it's
+      not very close to Unix, but it's not worth arguing about it now.]
+      Along the same lines, neither OS/2 nor Human68K is the same as (or
+      even close to) MS-DOS.  MVS and VM/CMS, on the other hand, are quite
+      similar to each other and are therefore combined in most places.
+
+      Bottom line:  when adding a new port (e.g., QDOS), create a new macro
+      for it ("QDOS"), a new subdirectory ("qdos") and a new source file for
+      OS-specific code ("qdos/qdos.c").  Use #ifdefs to fit any OS-specific
+      changes into the existing code (e.g., unzpriv.h).  If it's close enough
+      to an existing port that piggybacking is a temptation, define a new
+      "combination macro" (e.g., "CMS_MVS") and replace the old macros as
+      required.  (This last applies to UnZip, at least; the old preference
+      in Zip was fewer macros and long #ifdef lines, so talk to Onno or Jean-
+      loup about that.)  See also rule 0.1.
+
+      (Note that, for UnZip, new ports need not attempt to deal with all
+      features.  Among other things, the wildcard-zipfile code in do_wild()
+      may be replaced with a supplied dummy version, since opendir/readdir/
+      closedir() or the equivalent can be difficult to implement.)
+
+
+  (1) NO FEELTHY TABS
+
+      Some editors and e-mail systems either have no capability to use
+      and/or display tab characters (ASCII 9) correctly, or they use non-
+      standard or variable-width tab columns, or other horrors.  Some edi-
+      tors auto-convert spaces to tabs, after which the blind use of "diff
+      -c" results in a huge and mostly useless patch.  Yes, *we* know about
+      diff's "-b" option, but not everyone does.  And yes, we also know this
+      makes the source files bigger, even after compression; so be it.  If
+      we *really* cared that much about the size of the sources, we'd still
+      be writing Unix-only utilities.
+
+      Bottom line:  use spaces, not tabs.
+
+      Exception:  some of the makefiles (the Unix one in particular) require
+      tabs as part of the syntax.
+
+      Related utility programs:
+          Unix, OS/2 and MS-DOS:  expand, unexpand.
+          MS-DOS:  Buerg's TABS; Toad Hall's TOADSOFT.
+          And some editors have the conversion built-in.
+
+
+  (2) NO FEELTHY CARRIAGE RETURNS
+
+      All source, documentation and other text files shall have Unix style
+      line endings (LF only, a.k.a. ctrl-J), not the DOS/OS2/NT CR+LF or Mac
+      CR-only line endings.
+
+      Reason:  "real programmers" in any environment can convert back and
+      forth between Unix and DOS/Mac style.  All PC compilers but a few old
+      Borland versions can use either Unix or MS-DOS end-of-lines.  Buerg's
+      LIST (file-display utility) for MS-DOS can use Unix or MS-DOS EOLs.
+      Both Zip and UnZip can convert line-endings as appropriate.  But Unix
+      utilities like diff and patch die a horrible death (or produce horrible
+      output) if the target files have CRs.
+
+      Related utilities:  flip for Unix, OS/2 and MS-DOS; Unix "tr".
+
+      Exceptions:  documentation in pre-compiled binary distributions should
+      be in the local (target) format.
+
+
+  (3) NO FEELTHY 8-BIT CHARS
+
+      Do all your editing in a plain-text ASCII editor.  No WordPerfect, MS
+      Word, WordStar document mode, or other word processor files, thenkyew.
+      No desktop publishing.  *Especially* no EBCDIC.  No TIFFs, no GIFs, no
+      embedded pictures or dancing ladies (too bad, Cave Newt).  [Sigh... -CN]
+
+      Reason:  compatibility with different consoles.  My old XT clone is
+      the most limited!
+
+      Exceptions:  some Macintosh makefiles apparently require some 8-bit
+      characters; the Human68k port uses 8-bit characters for Kanji or Kana
+      comments (I think); etc.
+
+      Related utilities:  vi, emacs, EDLIN, Turbo C editor, other programmers'
+      editors, various word processor -> text conversion utilities.
+
+
+  (4) NO FEELTHY LEFT-JUSTIFIED DASHES
+
+      Always precede repeated dashes (------) with one or more leading non-
+      dash characters:  spaces, tabs, pound signs (#), comments (/*), what-
+      ever.
+
+      Reason:  sooner or later your source file will be e-mailed through an
+      undigestifier utility, most of which treat leading dashes as end-of-
+      message separators.  We'd rather not have your code broken up into a
+      dozen separate untitled messages, thank you.
+
+
+  (5) NO FEELTHY FANCY_FILENAMES
+
+      Assume the worst:  that someone on a brain-damaged DOS system has to
+      work with everything your magic fingers produced.  Keep the filenames
+      unimaginative and within MS-DOS limits (i.e., ordinary A..Z, 1..9,
+      "-$_!"-type characters, in the 8.3 "filename.ext" format).  Mac and
+      Unix users, giggle all you want, but no spaces or multiple dots.
+
+      Reason:  compatibility with different file systems.  MS-DOS FAT is the
+      most limited, with the exception of CompuServe (6.3, argh).
+
+      Exceptions:  slightly longer names are occasionally acceptable within
+      OS-specific subdirectories, but don't do that unless there's a good
+      reason for it.
+
+
+  (6) NO FEELTHY NON-ZIPFILES AND NO FEELTHY E-MAIL BETAS
+
+      Beta testers and developers are in general expected to have both
+      ftp capability and the ability to deal with zipfiles.  Those without
+      should either find a friend who does or else learn about ftp-mailers.
+
+      Reason:  the core development team barely has time to work on the
+      code, much less prepare oddball formats and/or mail betas out (and
+      the situation is getting worse, sigh).
+
+      Exceptions:  anyone seriously proposing to do a new port will be
+      given special treatment, particularly with respect to UnZip; we
+      obviously realize that bootstrapping a completely new port can be
+      quite difficult and have no desire to make it even harder due to
+      lack of access to the latest code (rule 0.2).
+
+      Public releases of UnZip, on the other hand, will be available in
+      two formats:  .tar.Z (16-bit compress'd tar) and .zip (either "plain"
+      or self-extracting).  Zip sources and executables will generally only
+      be distributed in .zip format, since Zip is pretty much useless without
+      UnZip.
+
+
+  (7) NO FEELTHY E-MAIL BINARIES
+
+      Binary files (e.g., executables, test zipfiles, etc.) should NEVER
+      be mailed raw.  Where possible, they should be uploaded via ftp in
+      BINARY mode; if that's impossible, Mark's "ship" ASCII-encoder should
+      be used; and if that's unavailable, uuencode or xxencode should be
+      used.  Weirdo NeXTmail, mailtool and MIME formats are also Right Out.
+
+      Files larger than 50KB may need to be broken into pieces for mailing
+      (be sure to label them in order!), unless "ship" is used (it can
+      auto-split, label and mail files if told to do so).  If Down Under
+      is involved, files must be broken into under-20KB chunks.
+
+      Reasons:  to prevent sounds of gagging mailers from resounding through-
+      out the land.  To be relatively efficient in the binary->ASCII conver-
+      sion.  (Yeah, yeah, I know, there's better conversions out there.  But
+      not as widely known, and they often break on BITNET gateways.)
+
+      Related utilities:  ship, uuencode, uudecode, uuxfer20, quux, others.
+      Just make sure they don't leave embedded or trailing spaces (that is,
+      they should use the "`" character in place of ASCII 32).  Otherwise
+      mailers are prone to truncate or whatever.
+
+
+Greg Roelofs (a.k.a. Cave Newt)
+Info-ZIP UnZip maintainer
+
+David Kirschbaum
+former Info-ZIP Coordinator
diff --git a/proginfo/algorith.txt b/proginfo/algorith.txt
new file mode 100644 (file)
index 0000000..867e30b
--- /dev/null
@@ -0,0 +1,68 @@
+Zip's deflation algorithm is a variation of LZ77 (Lempel-Ziv 1977, see
+reference below). It finds duplicated strings in the input data.  The
+second occurrence of a string is replaced by a pointer to the previous
+string, in the form of a pair (distance, length).  Distances are
+limited to 32K bytes, and lengths are limited to 258 bytes. When a
+string does not occur anywhere in the previous 32K bytes, it is
+emitted as a sequence of literal bytes.  (In this description,
+'string' must be taken as an arbitrary sequence of bytes, and is not
+restricted to printable characters.)
+
+Literals or match lengths are compressed with one Huffman tree, and
+match distances are compressed with another tree. The trees are stored
+in a compact form at the start of each block. The blocks can have any
+size (except that the compressed data for one block must fit in
+available memory). A block is terminated when zip determines that it
+would be useful to start another block with fresh trees. (This is
+somewhat similar to compress.)
+
+Duplicated strings are found using a hash table. All input strings of
+length 3 are inserted in the hash table. A hash index is computed for
+the next 3 bytes. If the hash chain for this index is not empty, all
+strings in the chain are compared with the current input string, and
+the longest match is selected.
+
+The hash chains are searched starting with the most recent strings, to
+favor small distances and thus take advantage of the Huffman encoding.
+The hash chains are singly linked. There are no deletions from the
+hash chains, the algorithm simply discards matches that are too old.
+
+To avoid a worst-case situation, very long hash chains are arbitrarily
+truncated at a certain length, determined by a runtime option (zip -1
+to -9). So zip does not always find the longest possible match but
+generally finds a match which is long enough.
+
+zip also defers the selection of matches with a lazy evaluation
+mechanism. After a match of length N has been found, zip searches for a
+longer match at the next input byte. If a longer match is found, the
+previous match is truncated to a length of one (thus producing a single
+literal byte) and the longer match is emitted afterwards.  Otherwise,
+the original match is kept, and the next match search is attempted only
+N steps later.
+
+The lazy match evaluation is also subject to a runtime parameter. If
+the current match is long enough, zip reduces the search for a longer
+match, thus speeding up the whole process. If compression ratio is more
+important than speed, zip attempts a complete second search even if
+the first match is already long enough.
+
+The lazy match evaluation is not performed for the fastest compression
+modes (speed options -1 to -3). For these fast modes, new strings
+are inserted in the hash table only when no match was found, or
+when the match is not too long. This degrades the compression ratio
+but saves time since there are both fewer insertions and fewer searches.
+
+Jean-loup Gailly
+jloup@chorus.fr
+
+References:
+
+[LZ77] Ziv J., Lempel A., "A Universal Algorithm for Sequential Data
+Compression", IEEE Transactions on Information Theory", Vol. 23, No. 3,
+pp. 337-343.
+
+APPNOTE.TXT documentation file in PKZIP 1.93a. It is available by
+ftp in ftp.cso.uiuc.edu:/pc/exec-pc/pkz193a.exe [128.174.5.59]
+
+'Deflate' Compressed Data Format Specification:
+ftp://ftp.uu.net/pub/archiving/zip/doc/deflate-1.1.doc
diff --git a/proginfo/ebcdic.msg b/proginfo/ebcdic.msg
new file mode 100644 (file)
index 0000000..1a7bbad
--- /dev/null
@@ -0,0 +1,63 @@
+From dima@mitrah.ru  Mon Nov 10 02:25:38 2003
+Return-Path: <dima@mitrah.ru>
+Received: from b.mx.sonic.net (eth0.b.mx.sonic.net [209.204.159.4])
+       by eth0.a.lds.sonic.net (8.12.10/8.12.9) with ESMTP id hAAAPccT025257
+       for <roelofs@lds.sonic.net>; Mon, 10 Nov 2003 02:25:38 -0800
+Received: from icicle.pobox.com (icicle.pobox.com [207.8.214.2])
+       by b.mx.sonic.net (8.12.10/8.12.7) with ESMTP id hAAAPar9007141
+       for <roelofs@sonic.net>; Mon, 10 Nov 2003 02:25:37 -0800
+Received: from icicle.pobox.com (localhost[127.0.0.1])
+       by icicle.pobox.com (Postfix) with ESMTP id 9BA347A96B
+       for <roelofs@sonic.net>; Sat,  8 Nov 2003 06:15:13 -0500 (EST)
+Delivered-To: newt@pobox.com
+Received: from mail.ropnet.ru (mail.ropnet.ru[212.42.37.90])
+       by icicle.pobox.com (Postfix) with ESMTP id A96817A8F7
+       for <newt@pobox.com>; Sat,  8 Nov 2003 06:15:04 -0500 (EST)
+Received: from d34-67.ropnet.ru (d34-67.ropnet.ru [212.42.34.67])
+       by mail.ropnet.ru (8.11.7/8.11.7) with ESMTP id hA8BEjF76200
+       for <newt@pobox.com>; Sat, 8 Nov 2003 14:14:46 +0300 (MSK)
+Resent-Date: Sat, 8 Nov 2003 14:14:46 +0300 (MSK)
+Resent-Message-Id: <200311081114.hA8BEjF76200@mail.ropnet.ru>
+Date: Sat, 8 Nov 2003 14:18:18 +0300
+From: Dmitri Koulikov <dima@mitrah.ru>
+X-Mailer: The Bat! (v1.62r) Personal
+Reply-To: Dmitri Koulikov <dima@mitrah.ru>
+X-Priority: 3 (Normal)
+Message-ID: <815640011.20031108141818@mitrah.ru>
+To: newt@pobox.com
+Subject: unzip and zip lack NLS - 2
+Resent-From: Dmitri Koulikov <dima@mitrah.ru>
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="----------EB1581C42AB86662"
+Status: R
+
+------------EB1581C42AB86662
+Content-Type: text/plain; charset=us-ascii
+Content-Transfer-Encoding: 7bit
+
+Hello Greg Roelofs,
+
+   By mistake I sent you wrong version of ebcdic.h. Now it is as it
+have to.
+   Additionally I found that zip works with Russian filenames good.
+But fails to process -D switch. So I have to chahge zipfile.c. Most
+probably this is not good but it works.
+
+-- 
+Best regards,
+ Dmitri 
+
+mailto:dima@mitrah.ru
+------------EB1581C42AB86662
+Content-Type: application/octet-stream; name="ebcdic.h"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename="ebcdic.h"
+
+------------EB1581C42AB86662
+Content-Type: application/octet-stream; name="zipfile.c"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename="zipfile.c"
+
+------------EB1581C42AB86662--
+
+
diff --git a/proginfo/extrafld.txt b/proginfo/extrafld.txt
new file mode 100644 (file)
index 0000000..624e05c
--- /dev/null
@@ -0,0 +1,1372 @@
+The following are the known types of zipfile extra fields as of this
+writing.  Extra fields are documented in PKWARE's appnote.txt and are
+intended to allow for backward- and forward-compatible extensions to
+the zipfile format.  Multiple extra-field types may be chained together,
+provided that the total length of all extra-field data is less than 64KB.
+(In fact, PKWARE requires that the total length of the entire file header,
+including timestamp, file attributes, filename, comment, extra field, etc.,
+be no more than 64KB.)
+
+Each extra-field type (or subblock) must contain a four-byte header con-
+sisting of a two-byte header ID and a two-byte length (little-endian) for
+the remaining data in the subblock.  If there are additional subblocks
+within the extra field, the header for each one will appear immediately
+following the data for the previous subblock (i.e., with no padding for
+alignment).
+
+All integer fields in the descriptions below are in little-endian (Intel)
+format unless otherwise specified.  Note that "Short" means two bytes,
+"Long" means four bytes, and "Long-Long" means eight bytes, regardless
+of their native sizes.  Unless specifically noted, all integer fields should
+be interpreted as unsigned (non-negative) numbers.
+
+Christian Spieler, 20010517
+
+Updated to include the Unicode extra fields.  Added new Unix extra field.
+
+Ed Gordon, 20060819, 20070607, 20070909, 20080426, 20080509
+
+                        -------------------------
+
+          Header ID's of 0 thru 31 are reserved for use by PKWARE.
+          The remaining ID's can be used by third party vendors for
+          proprietary usage.
+
+          The current Header ID mappings defined by PKWARE are:
+
+          0x0001        ZIP64 extended information extra field
+          0x0007        AV Info
+          0x0009        OS/2 extended attributes      (also Info-ZIP)
+          0x000a        NTFS (Win9x/WinNT FileTimes)
+          0x000c        OpenVMS                       (also Info-ZIP)
+          0x000d        Unix
+          0x000f        Patch Descriptor
+          0x0014        PKCS#7 Store for X.509 Certificates
+          0x0015        X.509 Certificate ID and Signature for
+                        individual file
+          0x0016        X.509 Certificate ID for Central Directory
+
+          The Header ID mappings defined by Info-ZIP and third parties are:
+
+          0x0065        IBM S/390 attributes - uncompressed
+          0x0066        IBM S/390 attributes - compressed
+          0x07c8        Info-ZIP Macintosh (old, J. Lee)
+          0x2605        ZipIt Macintosh (first version)
+          0x2705        ZipIt Macintosh v 1.3.5 and newer (w/o full filename)
+          0x334d        Info-ZIP Macintosh (new, D. Haase's 'Mac3' field )
+          0x4154        Tandem NSK
+          0x4341        Acorn/SparkFS (David Pilling)
+          0x4453        Windows NT security descriptor (binary ACL)
+          0x4704        VM/CMS
+          0x470f        MVS
+          0x4854        Theos, old inofficial port
+          0x4b46        FWKCS MD5 (see below)
+          0x4c41        OS/2 access control list (text ACL)
+          0x4d49        Info-ZIP OpenVMS (obsolete)
+          0x4d63        Macintosh SmartZIP, by Macro Bambini
+          0x4f4c        Xceed original location extra field
+          0x5356        AOS/VS (binary ACL)
+          0x5455        extended timestamp
+          0x5855        Info-ZIP Unix (original; also OS/2, NT, etc.)
+          0x554e        Xceed unicode extra field
+          0x6375        Info-ZIP Unicode Comment
+          0x6542        BeOS (BeBox, PowerMac, etc.)
+          0x6854        Theos
+          0x7075        Info-ZIP Unicode Path
+          0x756e        ASi Unix
+          0x7855        Info-ZIP Unix (previous new)
+          0x7875        Info-ZIP Unix (new)
+          0xfb4a        SMS/QDOS
+
+The following are detailed descriptions of the known extra-field block types:
+
+         -OS/2 Extended Attributes Extra Field:
+          ====================================
+
+          The following is the layout of the OS/2 extended attributes "extra"
+          block.  (Last Revision 19960922)
+
+          Note: all fields stored in Intel low-byte/high-byte order.
+
+          Local-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (OS/2)  0x0009        Short       tag for this extra block type
+          TSize         Short       total data size for this block
+          BSize         Long        uncompressed EA data size
+          CType         Short       compression type
+          EACRC         Long        CRC value for uncompressed EA data
+          (var.)        variable    compressed EA data
+
+          Central-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (OS/2)  0x0009        Short       tag for this extra block type
+          TSize         Short       total data size for this block (4)
+          BSize         Long        size of uncompressed local EA data
+
+          The value of CType is interpreted according to the "compression
+          method" section above; i.e., 0 for stored, 8 for deflated, etc.
+
+          The OS/2 extended attribute structure (FEA2LIST) is compressed and
+          then stored in its entirety within this structure.  There will only
+          ever be one block of data in the variable-length field.
+
+
+         -OS/2 Access Control List Extra Field:
+          ====================================
+
+          The following is the layout of the OS/2 ACL extra block.
+          (Last Revision 19960922)
+
+          Local-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (ACL)   0x4c41        Short       tag for this extra block type ("AL")
+          TSize         Short       total data size for this block
+          BSize         Long        uncompressed ACL data size
+          CType         Short       compression type
+          EACRC         Long        CRC value for uncompressed ACL data
+          (var.)        variable    compressed ACL data
+
+          Central-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (ACL)   0x4c41        Short       tag for this extra block type ("AL")
+          TSize         Short       total data size for this block (4)
+          BSize         Long        size of uncompressed local ACL data
+
+          The value of CType is interpreted according to the "compression
+          method" section above; i.e., 0 for stored, 8 for deflated, etc.
+
+          The uncompressed ACL data consist of a text header of the form
+          "ACL1:%hX,%hd\n", where the first field is the OS/2 ACCINFO acc_attr
+          member and the second is acc_count, followed by acc_count strings
+          of the form "%s,%hx\n", where the first field is acl_ugname (user
+          group name) and the second acl_access.  This block type will be
+          extended for other operating systems as needed.
+
+
+         -Windows NT Security Descriptor Extra Field:
+          ==========================================
+
+          The following is the layout of the NT Security Descriptor (another
+          type of ACL) extra block.  (Last Revision 19960922)
+
+          Local-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (SD)    0x4453        Short       tag for this extra block type ("SD")
+          TSize         Short       total data size for this block
+          BSize         Long        uncompressed SD data size
+          Version       Byte        version of uncompressed SD data format
+          CType         Short       compression type
+          EACRC         Long        CRC value for uncompressed SD data
+          (var.)        variable    compressed SD data
+
+          Central-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (SD)    0x4453        Short       tag for this extra block type ("SD")
+          TSize         Short       total data size for this block (4)
+          BSize         Long        size of uncompressed local SD data
+
+          The value of CType is interpreted according to the "compression
+          method" section above; i.e., 0 for stored, 8 for deflated, etc.
+          Version specifies how the compressed data are to be interpreted
+          and allows for future expansion of this extra field type.  Currently
+          only version 0 is defined.
+
+          For version 0, the compressed data are to be interpreted as a single
+          valid Windows NT SECURITY_DESCRIPTOR data structure, in self-relative
+          format.
+
+
+         -PKWARE Win95/WinNT Extra Field:
+          ==============================
+
+          The following description covers PKWARE's "NTFS" attributes
+          "extra" block, introduced with the release of PKZIP 2.50 for
+          Windows. (Last Revision 20001118)
+
+          (Note: At this time the Mtime, Atime and Ctime values may
+          be used on any WIN32 system.)
+         [Info-ZIP note: In the current implementations, this field has
+          a fixed total data size of 32 bytes and is only stored as local
+          extra field.]
+
+          Value         Size        Description
+          -----         ----        -----------
+  (NTFS)  0x000a        Short       Tag for this "extra" block type
+          TSize         Short       Total Data Size for this block
+          Reserved      Long        for future use
+          Tag1          Short       NTFS attribute tag value #1
+          Size1         Short       Size of attribute #1, in bytes
+          (var.)        SubSize1    Attribute #1 data
+          .
+          .
+          .
+          TagN          Short       NTFS attribute tag value #N
+          SizeN         Short       Size of attribute #N, in bytes
+          (var.)        SubSize1    Attribute #N data
+
+          For NTFS, values for Tag1 through TagN are as follows:
+          (currently only one set of attributes is defined for NTFS)
+
+          Tag        Size       Description
+          -----      ----       -----------
+          0x0001     2 bytes    Tag for attribute #1
+          Size1      2 bytes    Size of attribute #1, in bytes (24)
+          Mtime      8 bytes    64-bit NTFS file last modification time
+          Atime      8 bytes    64-bit NTFS file last access time
+          Ctime      8 bytes    64-bit NTFS file creation time
+
+          The total length for this block is 28 bytes, resulting in a
+          fixed size value of 32 for the TSize field of the NTFS block.
+
+          The NTFS filetimes are 64-bit unsigned integers, stored in Intel
+          (least significant byte first) byte order. They determine the
+          number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",
+          which is "01-Jan-1601 00:00:00 UTC".
+
+
+         -PKWARE OpenVMS Extra Field:
+          ==========================
+
+          The following is the layout of PKWARE's OpenVMS attributes "extra"
+          block.  (Last Revision 12/17/91)
+
+          Note: all fields stored in Intel low-byte/high-byte order.
+
+          Value         Size        Description
+          -----         ----        -----------
+  (VMS)   0x000c        Short       Tag for this "extra" block type
+          TSize         Short       Total Data Size for this block
+          CRC           Long        32-bit CRC for remainder of the block
+          Tag1          Short       OpenVMS attribute tag value #1
+          Size1         Short       Size of attribute #1, in bytes
+          (var.)        Size1       Attribute #1 data
+          .
+          .
+          .
+          TagN          Short       OpenVMS attribute tage value #N
+          SizeN         Short       Size of attribute #N, in bytes
+          (var.)        SizeN       Attribute #N data
+
+          Rules:
+
+          1. There will be one or more of attributes present, which
+             will each be preceded by the above TagX & SizeX values.
+             These values are identical to the ATR$C_XXXX and
+             ATR$S_XXXX constants which are defined in ATR.H under
+             OpenVMS C.  Neither of these values will ever be zero.
+
+          2. No word alignment or padding is performed.
+
+          3. A well-behaved PKZIP/OpenVMS program should never produce
+             more than one sub-block with the same TagX value.  Also,
+             there will never be more than one "extra" block of type
+             0x000c in a particular directory record.
+
+
+         -Info-ZIP VMS Extra Field:
+          ========================
+
+          The following is the layout of Info-ZIP's VMS attributes extra
+          block for VAX or Alpha AXP.  The local-header and central-header
+          versions are identical.  (Last Revision 19960922)
+
+          Value         Size        Description
+          -----         ----        -----------
+  (VMS2)  0x4d49        Short       tag for this extra block type ("JM")
+          TSize         Short       total data size for this block
+          ID            Long        block ID
+          Flags         Short       info bytes
+          BSize         Short       uncompressed block size
+          Reserved      Long        (reserved)
+          (var.)        variable    compressed VMS file-attributes block
+
+          The block ID is one of the following unterminated strings:
+
+                "VFAB"          struct FAB
+                "VALL"          struct XABALL
+                "VFHC"          struct XABFHC
+                "VDAT"          struct XABDAT
+                "VRDT"          struct XABRDT
+                "VPRO"          struct XABPRO
+                "VKEY"          struct XABKEY
+                "VMSV"          version (e.g., "V6.1"; truncated at hyphen)
+                "VNAM"          reserved
+
+          The lower three bits of Flags indicate the compression method.  The
+          currently defined methods are:
+
+                0       stored (not compressed)
+                1       simple "RLE"
+                2       deflated
+
+          The "RLE" method simply replaces zero-valued bytes with zero-valued
+          bits and non-zero-valued bytes with a "1" bit followed by the byte
+          value.
+
+          The variable-length compressed data contains only the data corre-
+          sponding to the indicated structure or string.  Typically multiple
+          VMS2 extra fields are present (each with a unique block type).
+
+
+         -Info-ZIP Macintosh Extra Field:
+          ==============================
+
+          The following is the layout of the (old) Info-ZIP resource-fork extra
+          block for Macintosh.  The local-header and central-header versions
+          are identical.  (Last Revision 19960922)
+
+          Value         Size        Description
+          -----         ----        -----------
+  (Mac)   0x07c8        Short       tag for this extra block type
+          TSize         Short       total data size for this block
+          "JLEE"        beLong      extra-field signature
+          FInfo         16 bytes    Macintosh FInfo structure
+          CrDat         beLong      HParamBlockRec fileParam.ioFlCrDat
+          MdDat         beLong      HParamBlockRec fileParam.ioFlMdDat
+          Flags         beLong      info bits
+          DirID         beLong      HParamBlockRec fileParam.ioDirID
+          VolName       28 bytes    volume name (optional)
+
+          All fields but the first two are in native Macintosh format
+          (big-endian Motorola order, not little-endian Intel).  The least
+          significant bit of Flags is 1 if the file is a data fork, 0 other-
+          wise.  In addition, if this extra field is present, the filename
+          has an extra 'd' or 'r' appended to indicate data fork or resource
+          fork.  The 28-byte VolName field may be omitted.
+
+
+         -ZipIt Macintosh Extra Field (long):
+          ==================================
+
+          The following is the layout of the ZipIt extra block for Macintosh.
+          The local-header and central-header versions are identical.
+          (Last Revision 19970130)
+
+          Value         Size        Description
+          -----         ----        -----------
+  (Mac2)  0x2605        Short       tag for this extra block type
+          TSize         Short       total data size for this block
+          "ZPIT"        beLong      extra-field signature
+          FnLen         Byte        length of FileName
+          FileName      variable    full Macintosh filename
+          FileType      Byte[4]     four-byte Mac file type string
+          Creator       Byte[4]     four-byte Mac creator string
+
+
+         -ZipIt Macintosh Extra Field (short):
+          ===================================
+
+          The following is the layout of a shortened variant of the
+          ZipIt extra block for Macintosh (without "full name" entry).
+          This variant is used by ZipIt 1.3.5 and newer for entries that
+          do not need a "full Mac filename" record.
+          The local-header and central-header versions are identical.
+          (Last Revision 19980903)
+
+          Value         Size        Description
+          -----         ----        -----------
+  (Mac2b) 0x2705        Short       tag for this extra block type
+          TSize         Short       total data size for this block (12)
+          "ZPIT"        beLong      extra-field signature
+          FileType      Byte[4]     four-byte Mac file type string
+          Creator       Byte[4]     four-byte Mac creator string
+
+
+         -Info-ZIP Macintosh Extra Field (new):
+          ====================================
+
+          The following is the layout of the (new) Info-ZIP extra
+          block for Macintosh, designed by Dirk Haase.
+          All values are in little-endian.
+          (Last Revision 19981005)
+
+          Local-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (Mac3)  0x334d        Short       tag for this extra block type ("M3")
+          TSize         Short       total data size for this block
+          BSize         Long        uncompressed finder attribute data size
+          Flags         Short       info bits
+          fdType        Byte[4]     Type of the File (4-byte string)
+          fdCreator     Byte[4]     Creator of the File (4-byte string)
+          (CType)       Short       compression type
+          (CRC)         Long        CRC value for uncompressed MacOS data
+          Attribs       variable    finder attribute data (see below)
+
+
+          Central-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (Mac3)  0x334d        Short       tag for this extra block type ("M3")
+          TSize         Short       total data size for this block
+          BSize         Long        uncompressed finder attribute data size
+          Flags         Short       info bits
+          fdType        Byte[4]     Type of the File (4-byte string)
+          fdCreator     Byte[4]     Creator of the File (4-byte string)
+
+          The third bit of Flags in both headers indicates whether
+          the LOCAL extra field is uncompressed (and therefore whether CType
+          and CRC are omitted):
+
+          Bits of the Flags:
+              bit 0           if set, file is a data fork; otherwise unset
+              bit 1           if set, filename will be not changed
+              bit 2           if set, Attribs is uncompressed (no CType, CRC)
+              bit 3           if set, date and times are in 64 bit
+                              if zero date and times are in 32 bit.
+              bit 4           if set, timezone offsets fields for the native
+                              Mac times are omitted (UTC support deactivated)
+              bits 5-15       reserved;
+
+
+          Attributes:
+
+          Attribs is a Mac-specific block of data in little-endian format with
+          the following structure (if compressed, uncompress it first):
+
+          Value         Size        Description
+          -----         ----        -----------
+          fdFlags       Short       Finder Flags
+          fdLocation.v  Short       Finder Icon Location
+          fdLocation.h  Short       Finder Icon Location
+          fdFldr        Short       Folder containing file
+
+          FXInfo        16 bytes    Macintosh FXInfo structure
+            FXInfo-Structure:
+                fdIconID        Short
+                fdUnused[3]     Short       unused but reserved 6 bytes
+                fdScript        Byte        Script flag and number
+                fdXFlags        Byte        More flag bits
+                fdComment       Short       Comment ID
+                fdPutAway       Long        Home Dir ID
+
+          FVersNum      Byte        file version number
+                                    may be not used by MacOS
+          ACUser        Byte        directory access rights
+
+          FlCrDat       ULong       date and time of creation
+          FlMdDat       ULong       date and time of last modification
+          FlBkDat       ULong       date and time of last backup
+            These time numbers are original Mac FileTime values (local time!).
+            Currently, date-time width is 32-bit, but future version may
+            support be 64-bit times (see flags)
+
+          CrGMTOffs     Long(signed!)   difference "local Creat. time - UTC"
+          MdGMTOffs     Long(signed!)   difference "local Modif. time - UTC"
+          BkGMTOffs     Long(signed!)   difference "local Backup time - UTC"
+            These "local time - UTC" differences (stored in seconds) may be
+            used to support timestamp adjustment after inter-timezone transfer.
+            These fields are optional; bit 4 of the flags word controls their
+            presence.
+
+          Charset       Short       TextEncodingBase (Charset)
+                                    valid for the following two fields
+
+          FullPath      variable    Path of the current file.
+                                    Zero terminated string (C-String)
+                                    Currently coded in the native Charset.
+
+          Comment       variable    Finder Comment of the current file.
+                                    Zero terminated string (C-String)
+                                    Currently coded in the native Charset.
+
+
+         -SmartZIP Macintosh Extra Field:
+          ====================================
+
+          The following is the layout of the SmartZIP extra
+          block for Macintosh, designed by Marco Bambini.
+
+          Local-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+          0x4d63        Short       tag for this extra block type ("cM")
+          TSize         Short       total data size for this block (64)
+          "dZip"        beLong      extra-field signature
+          fdType        Byte[4]     Type of the File (4-byte string)
+          fdCreator     Byte[4]     Creator of the File (4-byte string)
+          fdFlags       beShort     Finder Flags
+          fdLocation.v  beShort     Finder Icon Location
+          fdLocation.h  beShort     Finder Icon Location
+          fdFldr        beShort     Folder containing file
+          CrDat         beLong      HParamBlockRec fileParam.ioFlCrDat
+          MdDat         beLong      HParamBlockRec fileParam.ioFlMdDat
+          frScroll.v    Byte        vertical pos. of folder's scroll bar
+          fdScript      Byte        Script flag and number
+          frScroll.h    Byte        horizontal pos. of folder's scroll bar
+          fdXFlags      Byte        More flag bits
+          FileName      Byte[32]    full Macintosh filename (pascal string)
+
+          All fields but the first two are in native Macintosh format
+          (big-endian Motorola order, not little-endian Intel).
+          The extra field size is fixed to 64 bytes.
+          The local-header and central-header versions are identical.
+
+
+         -Acorn SparkFS Extra Field:
+          =========================
+
+          The following is the layout of David Pilling's SparkFS extra block
+          for Acorn RISC OS.  The local-header and central-header versions are
+          identical.  (Last Revision 19960922)
+
+          Value         Size        Description
+          -----         ----        -----------
+  (Acorn) 0x4341        Short       tag for this extra block type ("AC")
+          TSize         Short       total data size for this block (20)
+          "ARC0"        Long        extra-field signature
+          LoadAddr      Long        load address or file type
+          ExecAddr      Long        exec address
+          Attr          Long        file permissions
+          Zero          Long        reserved; always zero
+
+          The following bits of Attr are associated with the given file
+          permissions:
+
+                bit 0           user-writable ('W')
+                bit 1           user-readable ('R')
+                bit 2           reserved
+                bit 3           locked ('L')
+                bit 4           publicly writable ('w')
+                bit 5           publicly readable ('r')
+                bit 6           reserved
+                bit 7           reserved
+
+
+         -VM/CMS Extra Field:
+          ==================
+
+          The following is the layout of the file-attributes extra block for
+          VM/CMS.  The local-header and central-header versions are
+          identical.  (Last Revision 19960922)
+
+          Value         Size        Description
+          -----         ----        -----------
+ (VM/CMS) 0x4704        Short       tag for this extra block type
+          TSize         Short       total data size for this block
+          flData        variable    file attributes data
+
+          flData is an uncompressed fldata_t struct.
+
+
+         -MVS Extra Field:
+          ===============
+
+          The following is the layout of the file-attributes extra block for
+          MVS.  The local-header and central-header versions are identical.
+          (Last Revision 19960922)
+
+          Value         Size        Description
+          -----         ----        -----------
+  (MVS)   0x470f        Short       tag for this extra block type
+          TSize         Short       total data size for this block
+          flData        variable    file attributes data
+
+          flData is an uncompressed fldata_t struct.
+
+
+         -PKWARE Unix Extra Field:
+          ========================
+
+          The following is the layout of PKWARE's Unix "extra" block.
+          It was introduced with the release of PKZIP for Unix 2.50.
+          Note: all fields are stored in Intel low-byte/high-byte order.
+          (Last Revision 19980901)
+
+          This field has a minimum data size of 12 bytes and is only stored
+          as local extra field.
+
+          Value         Size        Description
+          -----         ----        -----------
+ (Unix0)  0x000d        Short       Tag for this "extra" block type
+          TSize         Short       Total Data Size for this block
+          AcTime        Long        time of last access (UTC/GMT)
+          ModTime       Long        time of last modification (UTC/GMT)
+          UID           Short       Unix user ID
+          GID           Short       Unix group ID
+          (var)         variable    Variable length data field
+
+          The variable length data field will contain file type
+          specific data.  Currently the only values allowed are
+          the original "linked to" file names for hard or symbolic
+          links, and the major and minor device node numbers for
+          character and block device nodes.  Since device nodes
+          cannot be either symbolic or hard links, only one set of
+          variable length data is stored.  Link files will have the
+          name of the original file stored.  This name is NOT NULL
+          terminated.  Its size can be determined by checking TSize -
+          12.  Device entries will have eight bytes stored as two 4
+          byte entries (in little-endian format).  The first entry
+          will be the major device number, and the second the minor
+          device number.
+
+         [Info-ZIP note: The fixed part of this field has the same layout as
+          Info-ZIP's abandoned "Unix1 timestamps & owner ID info" extra field;
+          only the two tag bytes are different.]
+
+
+         -PATCH Descriptor Extra Field:
+          ============================
+
+          The following is the layout of the Patch Descriptor "extra"
+          block.
+
+          Note: all fields stored in Intel low-byte/high-byte order.
+
+          Value         Size        Description
+          -----         ----        -----------
+  (Patch) 0x000f        Short       Tag for this "extra" block type
+          TSize         Short       Size of the total "extra" block
+          Version       Short       Version of the descriptor
+          Flags         Long        Actions and reactions (see below)
+          OldSize       Long        Size of the file about to be patched
+          OldCRC        Long        32-bit CRC of the file about to be patched
+          NewSize       Long        Size of the resulting file
+          NewCRC        Long        32-bit CRC of the resulting file
+
+
+          Actions and reactions
+
+          Bits          Description
+          ----          ----------------
+          0             Use for autodetection
+          1             Treat as selfpatch
+          2-3           RESERVED
+          4-5           Action (see below)
+          6-7           RESERVED
+          8-9           Reaction (see below) to absent file
+          10-11         Reaction (see below) to newer file
+          12-13         Reaction (see below) to unknown file
+          14-15         RESERVED
+          16-31         RESERVED
+
+          Actions
+
+          Action       Value
+          ------       -----
+          none         0
+          add          1
+          delete       2
+          patch        3
+
+          Reactions
+
+          Reaction     Value
+          --------     -----
+          ask          0
+          skip         1
+          ignore       2
+          fail         3
+
+
+         -PKCS#7 Store for X.509 Certificates:
+          ===================================
+
+          This field is contains the information about each
+          certificate a file is signed with.  This field should only
+          appear in the first central directory record, and will be
+          ignored in any other record.
+
+          Note: all fields stored in Intel low-byte/high-byte order.
+
+          Value         Size        Description
+          -----         ----        -----------
+  (Store) 0x0014        2 bytes     Tag for this "extra" block type
+          SSize         2 bytes     Size of the store data
+          SData         (variable)  Data about the store
+
+          SData
+          Value         Size        Description
+          -----         ----        -----------
+          Version       2 bytes     Version number, 0x0001 for now
+          StoreD        (variable)  Actual store data
+
+          The StoreD member is suitable for passing as the pbData
+          member of a CRYPT_DATA_BLOB to the CertOpenStore() function
+          in Microsoft's CryptoAPI.  The SSize member above will be
+          cbData + 6, where cbData is the cbData member of the same
+          CRYPT_DATA_BLOB.  The encoding type to pass to
+          CertOpenStore() should be
+          PKCS_7_ANS_ENCODING | X509_ASN_ENCODING.
+
+
+         -X.509 Certificate ID and Signature for individual file:
+          ======================================================
+
+          This field contains the information about which certificate
+          in the PKCS#7 Store was used to sign the particular file.
+          It also contains the signature data.  This field can appear
+          multiple times, but can only appear once per certificate.
+
+          Note: all fields stored in Intel low-byte/high-byte order.
+
+          Value         Size        Description
+          -----         ----        -----------
+  (CID)   0x0015        2 bytes     Tag for this "extra" block type
+          CSize         2 bytes     Size of Method
+          Method        (variable)
+
+          Method
+          Value         Size        Description
+          -----         ----        -----------
+          Version       2 bytes     Version number, for now 0x0001
+          AlgID         2 bytes     Algorithm ID used for signing
+          IDSize        2 bytes     Size of Certificate ID data
+          CertID        (variable)  Certificate ID data
+          SigSize       2 bytes     Size of Signature data
+          Sig           (variable)  Signature data
+
+          CertID
+          Value         Size        Description
+          -----         ----        -----------
+          Size1         4 bytes     Size of CertID, should be (IDSize - 4)
+          Size1         4 bytes     A bug in version one causes this value
+                                    to appear twice.
+          IssSize       4 bytes     Issuer data size
+          Issuer        (variable)  Issuer data
+          SerSize       4 bytes     Serial Number size
+          Serial        (variable)  Serial Number data
+
+          The Issuer and IssSize members are suitable for creating a
+          CRYPT_DATA_BLOB to be the Issuer member of a CERT_INFO
+          struct. The Serial and SerSize members would be the
+          SerialNumber member of the same CERT_INFO struct.  This
+          struct would be used to find the certificate in the store
+          the file was signed with.  Those structures are from the MS
+          CryptoAPI.
+
+          Sig and SigSize are the actual signature data and size
+          generated by signing the file with the MS CryptoAPI using a
+          hash created with the given AlgID.
+
+
+         -X.509 Certificate ID and Signature for central directory:
+          ========================================================
+
+          This field contains the information about which certificate
+          in the PKCS#7 Store was used to sign the central directory.
+          It should only appear with the first central directory
+          record, along with the store.  The data structure is the
+          same as the CID, except that SigSize will be 0, and there
+          will be no Sig member.
+
+          This field is also kept after the last central directory
+          record, as the signature data (ID 0x05054b50, it looks like
+          a central directory record of a different type).  This
+          second copy of the data is the Signature Data member of the
+          record, and will have a SigSize that is non-zero, and will
+          have Sig data.
+
+          Note: all fields stored in Intel low-byte/high-byte order.
+
+          Value         Size        Description
+          -----         ----        -----------
+  (CDID)  0x0016        2 bytes     Tag for this "extra" block type
+          CSize         2 bytes     Size of Method
+          Method       (variable)
+
+
+         -ZIP64 Extended Information Extra Field:
+          ======================================
+
+          The following is the layout of the ZIP64 extended
+          information "extra" block. If one of the size or
+          offset fields in the Local or Central directory
+          record is too small to hold the required data,
+          a ZIP64 extended information record is created.
+          The order of the fields in the ZIP64 extended
+          information record is fixed, but the fields will
+          only appear if the corresponding Local or Central
+          directory record field is set to 0xFFFF or 0xFFFFFFFF.
+
+          Note: all fields stored in Intel low-byte/high-byte order.
+
+          Value      Size       Description
+          -----      ----       -----------
+  (ZIP64) 0x0001     2 bytes    Tag for this "extra" block type
+          Size       2 bytes    Size of this "extra" block
+          Original
+          Size       8 bytes    Original uncompresseed file size
+          Compressed
+          Size       8 bytes    Size of compressed data
+          Relative Header
+          Offset     8 bytes    Offset of local header record
+          Disk Start
+          Number     4 bytes    Number of the disk on which
+                                this file starts
+
+          This entry in the Local header must include BOTH original
+          and compressed file sizes.
+
+
+         -Extended Timestamp Extra Field:
+          ==============================
+
+          The following is the layout of the extended-timestamp extra block.
+          (Last Revision 19970118)
+
+          Local-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (time)  0x5455        Short       tag for this extra block type ("UT")
+          TSize         Short       total data size for this block
+          Flags         Byte        info bits
+          (ModTime)     Long        time of last modification (UTC/GMT)
+          (AcTime)      Long        time of last access (UTC/GMT)
+          (CrTime)      Long        time of original creation (UTC/GMT)
+
+          Central-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (time)  0x5455        Short       tag for this extra block type ("UT")
+          TSize         Short       total data size for this block
+          Flags         Byte        info bits (refers to local header!)
+          (ModTime)     Long        time of last modification (UTC/GMT)
+
+          The central-header extra field contains the modification time only,
+          or no timestamp at all.  TSize is used to flag its presence or
+          absence.  But note:
+
+              If "Flags" indicates that Modtime is present in the local header
+              field, it MUST be present in the central header field, too!
+              This correspondence is required because the modification time
+              value may be used to support trans-timezone freshening and
+              updating operations with zip archives.
+
+          The time values are in standard Unix signed-long format, indicating
+          the number of seconds since 1 January 1970 00:00:00.  The times
+          are relative to Coordinated Universal Time (UTC), also sometimes
+          referred to as Greenwich Mean Time (GMT).  To convert to local time,
+          the software must know the local timezone offset from UTC/GMT.
+
+          The lower three bits of Flags in both headers indicate which time-
+          stamps are present in the LOCAL extra field:
+
+                bit 0           if set, modification time is present
+                bit 1           if set, access time is present
+                bit 2           if set, creation time is present
+                bits 3-7        reserved for additional timestamps; not set
+
+          Those times that are present will appear in the order indicated, but
+          any combination of times may be omitted.  (Creation time may be
+          present without access time, for example.)  TSize should equal
+          (1 + 4*(number of set bits in Flags)), as the block is currently
+          defined.  Other timestamps may be added in the future.
+
+
+         -Info-ZIP Unix Extra Field (type 1):
+          ==================================
+
+          The following is the layout of the old Info-ZIP extra block for
+          Unix.  It has been replaced by the extended-timestamp extra block
+          (0x5455) and the Unix type 2 extra block (0x7855).
+          (Last Revision 19970118)
+
+          Local-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (Unix1) 0x5855        Short       tag for this extra block type ("UX")
+          TSize         Short       total data size for this block
+          AcTime        Long        time of last access (UTC/GMT)
+          ModTime       Long        time of last modification (UTC/GMT)
+          UID           Short       Unix user ID (optional)
+          GID           Short       Unix group ID (optional)
+
+          Central-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (Unix1) 0x5855        Short       tag for this extra block type ("UX")
+          TSize         Short       total data size for this block
+          AcTime        Long        time of last access (GMT/UTC)
+          ModTime       Long        time of last modification (GMT/UTC)
+
+          The file access and modification times are in standard Unix signed-
+          long format, indicating the number of seconds since 1 January 1970
+          00:00:00.  The times are relative to Coordinated Universal Time
+          (UTC), also sometimes referred to as Greenwich Mean Time (GMT).  To
+          convert to local time, the software must know the local timezone
+          offset from UTC/GMT.  The modification time may be used by non-Unix
+          systems to support inter-timezone freshening and updating of zip
+          archives.
+
+          The local-header extra block may optionally contain UID and GID
+          info for the file.  The local-header TSize value is the only
+          indication of this.  Note that Unix UIDs and GIDs are usually
+          specific to a particular machine, and they generally require root
+          access to restore.
+
+          This extra field type is obsolete, but it has been in use since
+          mid-1994.  Therefore future archiving software should continue to
+          support it.  Some guidelines:
+
+              An archive member should either contain the old "Unix1"
+              extra field block or the new extra field types "time" and/or
+              "Unix2".
+
+              If both the old "Unix1" block type and one or both of the new
+              block types "time" and "Unix2" are found, the "Unix1" block
+              should be considered invalid and ignored.
+
+              Unarchiving software should recognize both old and new extra
+              field block types, but the info from new types overrides the
+              old "Unix1" field.
+
+              Archiving software should recognize "Unix1" extra fields for
+              timestamp comparison but never create it for updated, freshened
+              or new archive members.  When copying existing members to a new
+              archive, any "Unix1" extra field blocks should be converted to
+              the new "time" and/or "Unix2" types.
+
+
+         -Info-ZIP Unix Extra Field (type 2):
+          ==================================
+
+          The following is the layout of the new Info-ZIP extra block for
+          Unix.  (Last Revision 19960922)
+
+          Local-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (Unix2) 0x7855        Short       tag for this extra block type ("Ux")
+          TSize         Short       total data size for this block (4)
+          UID           Short       Unix user ID
+          GID           Short       Unix group ID
+
+          Central-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (Unix2) 0x7855        Short       tag for this extra block type ("Ux")
+          TSize         Short       total data size for this block (0)
+
+          The data size of the central-header version is zero; it is used
+          solely as a flag that UID/GID info is present in the local-header
+          extra field.  If additional fields are ever added to the local
+          version, the central version may be extended to indicate this.
+
+          Note that Unix UIDs and GIDs are usually specific to a particular
+          machine, and they generally require root access to restore.
+
+
+         -ASi Unix Extra Field:
+          ====================
+
+          The following is the layout of the ASi extra block for Unix.  The
+          local-header and central-header versions are identical.
+          (Last Revision 19960916)
+
+          Value         Size        Description
+          -----         ----        -----------
+  (Unix3) 0x756e        Short       tag for this extra block type ("nu")
+          TSize         Short       total data size for this block
+          CRC           Long        CRC-32 of the remaining data
+          Mode          Short       file permissions
+          SizDev        Long        symlink'd size OR major/minor dev num
+          UID           Short       user ID
+          GID           Short       group ID
+          (var.)        variable    symbolic link filename
+
+          Mode is the standard Unix st_mode field from struct stat, containing
+          user/group/other permissions, setuid/setgid and symlink info, etc.
+
+          If Mode indicates that this file is a symbolic link, SizDev is the
+          size of the file to which the link points.  Otherwise, if the file
+          is a device, SizDev contains the standard Unix st_rdev field from
+          struct stat (includes the major and minor numbers of the device).
+          SizDev is undefined in other cases.
+
+          If Mode indicates that the file is a symbolic link, the final field
+          will be the name of the file to which the link points.  The file-
+          name length can be inferred from TSize.
+
+          [Note that TSize may incorrectly refer to the data size not counting
+           the CRC; i.e., it may be four bytes too small.]
+
+
+         -BeOS Extra Field:
+          ================
+
+          The following is the layout of the file-attributes extra block for
+          BeOS.  (Last Revision 19970531)
+
+          Local-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (BeOS)  0x6542        Short       tag for this extra block type ("Be")
+          TSize         Short       total data size for this block
+          BSize         Long        uncompressed file attribute data size
+          Flags         Byte        info bits
+          (CType)       Short       compression type
+          (CRC)         Long        CRC value for uncompressed file attribs
+          Attribs       variable    file attribute data
+
+          Central-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (BeOS)  0x6542        Short       tag for this extra block type ("Be")
+          TSize         Short       total data size for this block (5)
+          BSize         Long        size of uncompr. local EF block data
+          Flags         Byte        info bits
+
+          The least significant bit of Flags in both headers indicates whether
+          the LOCAL extra field is uncompressed (and therefore whether CType
+          and CRC are omitted):
+
+                bit 0           if set, Attribs is uncompressed (no CType, CRC)
+                bits 1-7        reserved; if set, assume error or unknown data
+
+          Currently the only supported compression types are deflated (type 8)
+          and stored (type 0); the latter is not used by Info-ZIP's Zip but is
+          supported by UnZip.
+
+          Attribs is a BeOS-specific block of data in big-endian format with
+          the following structure (if compressed, uncompress it first):
+
+              Value     Size        Description
+              -----     ----        -----------
+              Name      variable    attribute name (null-terminated string)
+              Type      Long        attribute type (32-bit unsigned integer)
+              Size      Long Long   data size for this sub-block (64 bits)
+              Data      variable    attribute data
+
+          The attribute structure is repeated for every attribute.  The Data
+          field may contain anything--text, flags, bitmaps, etc.
+
+
+         -SMS/QDOS Extra Field:
+          ====================
+
+          The following is the layout of the file-attributes extra block for
+          SMS/QDOS.  The local-header and central-header versions are identical.
+          (Last Revision 19960929)
+
+          Value         Size        Description
+          -----         ----        -----------
+  (QDOS)  0xfb4a        Short       tag for this extra block type
+          TSize         Short       total data size for this block
+          LongID        Long        extra-field signature
+          (ExtraID)     Long        additional signature/flag bytes
+          QDirect       64 bytes    qdirect structure
+
+          LongID may be "QZHD" or "QDOS".  In the latter case, ExtraID will
+          be present.  Its first three bytes are "02\0"; the last byte is
+          currently undefined.
+
+          QDirect contains the file's uncompressed directory info (qdirect
+          struct).  Its elements are in native (big-endian) format:
+
+          d_length      beLong          file length
+          d_access      byte            file access type
+          d_type        byte            file type
+          d_datalen     beLong          data length
+          d_reserved    beLong          unused
+          d_szname      beShort         size of filename
+          d_name        36 bytes        filename
+          d_update      beLong          time of last update
+          d_refdate     beLong          file version number
+          d_backup      beLong          time of last backup (archive date)
+
+
+         -AOS/VS Extra Field:
+          ==================
+
+          The following is the layout of the extra block for Data General
+          AOS/VS.  The local-header and central-header versions are identical.
+          (Last Revision 19961125)
+
+          Value         Size        Description
+          -----         ----        -----------
+  (AOSVS) 0x5356        Short       tag for this extra block type ("VS")
+          TSize         Short       total data size for this block
+          "FCI\0"       Long        extra-field signature
+          Version       Byte        version of AOS/VS extra block (10 = 1.0)
+          Fstat         variable    fstat packet
+          AclBuf        variable    raw ACL data ($MXACL bytes)
+
+          Fstat contains the file's uncompressed fstat packet, which is one of
+          the following:
+
+                normal fstat packet             (P_FSTAT struct)
+                DIR/CPD fstat packet            (P_FSTAT_DIR struct)
+                unit (device) fstat packet      (P_FSTAT_UNIT struct)
+                IPC file fstat packet           (P_FSTAT_IPC struct)
+
+          AclBuf contains the raw ACL data; its length is $MXACL.
+
+
+         -Tandem NSK Extra Field:
+          ======================
+
+          The following is the layout of the file-attributes extra block for
+          Tandem NSK.  The local-header and central-header versions are
+          identical.  (Last Revision 19981221)
+
+          Value         Size        Description
+          -----         ----        -----------
+  (TA)    0x4154        Short       tag for this extra block type ("TA")
+          TSize         Short       total data size for this block (20)
+          NSKattrs      20 Bytes    NSK attributes
+
+
+         -THEOS Extra Field:
+          =================
+
+          The following is the layout of the file-attributes extra block for
+          Theos.  The local-header and central-header versions are identical.
+          (Last Revision 19990206)
+
+          Value         Size        Description
+          -----         ----        -----------
+  (Theos) 0x6854        Short       'Th' signature
+          size          Short       size of extra block
+          flags         Byte        reserved for future use
+          filesize      Long        file size
+          fileorg       Byte        type of file (see below)
+          keylen        Short       key length for indexed and keyed files,
+                                    data segment size for 16 bits programs
+          reclen        Short       record length for indexed,keyed and direct,
+                                    text segment size for 16 bits programs
+          filegrow      Byte        growing factor for indexed,keyed and direct
+          protect       Byte        protections (see below)
+          reserved      Short       reserved for future use
+
+            File types
+            ==========
+
+            0x80  library (keyed access list of files)
+            0x40  directory
+            0x10  stream file
+            0x08  direct file
+            0x04  keyed file
+            0x02  indexed file
+            0x0e  reserved
+            0x01  16 bits real mode program (obsolete)
+            0x21  16 bits protected mode program
+            0x41  32 bits protected mode program
+
+            Protection codes
+            ================
+
+            User protection
+            ---------------
+            0x01  non readable
+            0x02  non writable
+            0x04  non executable
+            0x08  non erasable
+
+            Other protection
+            ----------------
+            0x10  non readable
+            0x20  non writable
+            0x40  non executable Theos before 4.0
+            0x40  modified Theos 4.x
+            0x80  not hidden
+
+
+         -THEOS old inofficial Extra Field:
+          ================================
+
+          The following is the layout of an inoffical former version of a
+          Theos file-attributes extra blocks.  This layout was never published
+          and is no longer created. However, UnZip can optionally support it
+          when compiling with the option flag OLD_THEOS_EXTRA defined.
+          Both the local-header and central-header versions are identical.
+          (Last Revision 19990206)
+
+          Value         Size        Description
+          -----         ----        -----------
+  (THS0)  0x4854        Short       'TH' signature
+          size          Short       size of extra block
+          flags         Short       reserved for future use
+          filesize      Long        file size
+          reclen        Short       record length for indexed,keyed and direct,
+                                    text segment size for 16 bits programs
+          keylen        Short       key length for indexed and keyed files,
+                                    data segment size for 16 bits programs
+          filegrow      Byte        growing factor for indexed,keyed and direct
+          reserved      3 Bytes     reserved for future use
+
+
+         -FWKCS MD5 Extra Field:
+          =====================
+
+          The FWKCS Contents_Signature System, used in automatically
+          identifying files independent of filename, optionally adds
+          and uses an extra field to support the rapid creation of
+          an enhanced contents_signature.
+          There is no local-header version; the following applies
+          only to the central header.  (Last Revision 19961207)
+
+          Central-header version:
+
+          Value         Size        Description
+          -----         ----        -----------
+  (MD5)   0x4b46        Short       tag for this extra block type ("FK")
+          TSize         Short       total data size for this block (19)
+          "MD5"         3 bytes     extra-field signature
+          MD5hash       16 bytes    128-bit MD5 hash of uncompressed data
+                                    (low byte first)
+
+          When FWKCS revises a .ZIP file central directory to add
+          this extra field for a file, it also replaces the
+          central directory entry for that file's uncompressed
+          file length with a measured value.
+
+          FWKCS provides an option to strip this extra field, if
+          present, from a .ZIP file central directory. In adding
+          this extra field, FWKCS preserves .ZIP file Authenticity
+          Verification; if stripping this extra field, FWKCS
+          preserves all versions of AV through PKZIP version 2.04g.
+
+          FWKCS, and FWKCS Contents_Signature System, are
+          trademarks of Frederick W. Kantor.
+
+          (1) R. Rivest, RFC1321.TXT, MIT Laboratory for Computer
+              Science and RSA Data Security, Inc., April 1992.
+              ll.76-77: "The MD5 algorithm is being placed in the
+              public domain for review and possible adoption as a
+              standard."
+
+
+         -Info-ZIP Unicode Path Extra Field:
+          =================================
+
+          Stores the UTF-8 version of the entry path as stored in the
+          local header and central directory header.
+          (Last Revision 20070912)
+
+          Value         Size        Description
+          -----         ----        -----------
+  (UPath) 0x7075        Short       tag for this extra block type ("up")
+          TSize         Short       total data size for this block
+          Version       1 byte      version of this extra field, currently 1
+          NameCRC32     4 bytes     File Name Field CRC32 Checksum
+          UnicodeName   Variable    UTF-8 version of the entry File Name
+
+          Currently Version is set to the number 1.  If there is a need
+          to change this field, the version will be incremented.  Changes
+          may not be backward compatible so this extra field should not be
+          used if the version is not recognized.
+
+          The NameCRC32 is the standard zip CRC32 checksum of the File Name
+          field in the header.  This is used to verify that the header
+          File Name field has not changed since the Unicode Path extra field
+          was created.  This can happen if a utility renames the entry but
+          does not update the UTF-8 path extra field.  If the CRC check fails,
+          this UTF-8 Path Extra Field should be ignored and the File Name field
+          in the header used instead.
+
+          The UnicodeName is the UTF-8 version of the contents of the File Name
+          field in the header.  As UnicodeName is defined to be UTF-8, no UTF-8
+          byte order mark (BOM) is used.  The length of this field is determined
+          by subtracting the size of the previous fields from TSize.  If both
+          the File Name and Comment fields are UTF-8, the new General Purpose
+          Bit Flag, bit 11 (Language encoding flag (EFS)), can be used to
+          indicate that both the header File Name and Comment fields are UTF-8
+          and, in this case, the Unicode Path and Unicode Comment extra fields
+          are not needed and should not be created.  Note that, for backward
+          compatibility, bit 11 should only be used if the native character set
+          of the paths and comments being zipped up are already in UTF-8.  The
+          same method, either bit 11 or extra fields, should be used in both
+          the local and central directory headers.
+
+
+         -Info-ZIP Unicode Comment Extra Field:
+          ====================================
+
+          Stores the UTF-8 version of the entry comment as stored in the
+          central directory header.
+          (Last Revision 20070912)
+
+          Value         Size        Description
+          -----         ----        -----------
+   (UCom) 0x6375        Short       tag for this extra block type ("uc")
+          TSize         Short       total data size for this block
+          Version       1 byte      version of this extra field, currently 1
+          ComCRC32      4 bytes     Comment Field CRC32 Checksum
+          UnicodeCom    Variable    UTF-8 version of the entry comment
+
+          Currently Version is set to the number 1.  If there is a need
+          to change this field, the version will be incremented.  Changes
+          may not be backward compatible so this extra field should not be
+          used if the version is not recognized.
+
+          The ComCRC32 is the standard zip CRC32 checksum of the Comment
+          field in the central directory header.  This is used to verify that
+          the comment field has not changed since the Unicode Comment extra field
+          was created.  This can happen if a utility changes the Comment field
+          but does not update the UTF-8 Comment extra field.  If the CRC check
+          fails, this Unicode Comment extra field should be ignored and the
+          Comment field in the header used.
+
+          The UnicodeCom field is the UTF-8 version of the entry comment field
+          in the header.  As UnicodeCom is defined to be UTF-8, no UTF-8 byte
+          order mark (BOM) is used.  The length of this field is determined by
+          subtracting the size of the previous fields from TSize.  If both the
+          File Name and Comment fields are UTF-8, the new General Purpose Bit
+          Flag, bit 11 (Language encoding flag (EFS)), can be used to indicate
+          both the header File Name and Comment fields are UTF-8 and, in this
+          case, the Unicode Path and Unicode Comment extra fields are not
+          needed and should not be created.  Note that, for backward
+          compatibility, bit 11 should only be used if the native character set
+          of the paths and comments being zipped up are already in UTF-8.  The
+          same method, either bit 11 or extra fields, should be used in both
+          the local and central directory headers.
+
+
+         -Info-ZIP New Unix Extra Field:
+          ====================================
+
+          Currently stores Unix UIDs/GIDs up to 32 bits.
+          (Last Revision 20080509)
+
+          Value         Size        Description
+          -----         ----        -----------
+  (UnixN) 0x7875        Short       tag for this extra block type ("ux")
+          TSize         Short       total data size for this block
+          Version       1 byte      version of this extra field, currently 1
+          UIDSize       1 byte      Size of UID field
+          UID           Variable    UID for this entry
+          GIDSize       1 byte      Size of GID field
+          GID           Variable    GID for this entry
+
+          Currently Version is set to the number 1.  If there is a need
+          to change this field, the version will be incremented.  Changes
+          may not be backward compatible so this extra field should not be
+          used if the version is not recognized.
+
+          UIDSize is the size of the UID field in bytes.  This size should
+          match the size of the UID field on the target OS.
+
+          UID is the UID for this entry in standard little endian format.
+
+          GIDSize is the size of the GID field in bytes.  This size should
+          match the size of the GID field on the target OS.
+
+          GID is the GID for this entry in standard little endian format.
+
+          If both the old 16-bit Unix extra field (tag 0x7855, Info-ZIP Unix)
+          and this extra field are present, the values in this extra field
+          supercede the values in that extra field.
diff --git a/proginfo/fileinfo.cms b/proginfo/fileinfo.cms
new file mode 100644 (file)
index 0000000..9d21935
--- /dev/null
@@ -0,0 +1,231 @@
+[Quoting from a C/370 manual, courtesy of Carl Forde.]
+
+  C/370 supports three types of input and output: text streams, binary
+  streams, and record I/O.  Text and binary streams are both ANSI
+  standards; record I/O is a C/370 extension.
+
+[...]
+
+  Record I/O is a C/370 extension to the ANSI standard.  For files
+  opened in record format, C/370 reads and writes one record at a
+  time.  If you try to write more data to a record than the record
+  can hold, the data is truncated.  For record I/O, C/370 only allows
+  the use of fread() and fwrite() to read and write to the files.  Any
+  other functions (such as fprintf(), fscanf(), getc(), and putc())
+  fail.  For record-orientated files, records do not change size when
+  you update them.  If the new data has fewer characters than the
+  original record, the new data fills the first n characters, where
+  n is the number of characters of the new data.  The record will
+  remain the same size, and the old characters (those after) n are
+  left unchanged.  A subsequent update begins at the next boundary.
+  For example, if you have the string "abcdefgh":
+
+  abcdefgh
+
+  and you overwrite it with the string "1234", the record will look
+  like this:
+
+  1234efgh
+
+  C/370 record I/O is binary.  That is, it does not interpret any of
+  the data in a record file and therefore does not recognize control
+  characters.
+
+
+  The record model consists of:
+
+  * A record, which is the unit of data transmitted to and from a
+    program
+  * A block, which is the unit of data transmitted to and from a
+    device.  Each block may contain one or more records.
+
+  In the record model of I/O, records and blocks have the following
+  attributes:
+
+  RECFM   Specifies the format of the data or how the data is organized
+          on the physical device.
+  LRECL   Specifies the length of logical records (as opposed to
+          physical ones).
+
+  BLKSIZE Specifies the length of physical records (blocks on the
+          physical device).
+
+
+  Opening a File by Filename
+
+  The filename that you specify on the call to fopen() or freopen()
+  must be in the following format:
+
+  >> ----filename---- ----filetype--------------------
+                   |   |             |             |
+                   --.--             -- --filemode--
+                                     |   |
+                                     --.--
+  where
+
+  filename is a 1- to 8-character string of any of the characters,
+  A-Z, a-z, 0-9, and +, -, $, #, @, :, and _.  You can separate it
+  from the filetype with one or more spaces, or with a period.
+  [Further note:  filenames are fully case-sensitive, as in Unix.]
+
+  filetype is a 1- to 8-character string of any of the characters,
+  A-Z, a-z, 0-9, and +, -, $, #, @, :, and _.  You can separate it
+  from the filemode with one or more spaces, or with a period. The
+  separator between filetype and filemode must be the same as the
+  one between filename and filetype.
+
+  filemode is a 1- to 2-character string.  The first must be any of
+  the characters A-Z, a-z, or *.  If you use the asis parameter on
+  the fopen() or freopen() call, the first character of the filemode
+  must be a capital letter or an asterisk.  Otherwise, the function
+  call fails.  The second character of filemode is optional; if you
+  specify it, it must be any of the digits 0-6.  You cannot specify
+  the second character if you have specified * for the first one.
+
+  If you do not use periods as separators, there is no limit to how
+  much whitespace you can have before and after the filename, the
+  filetype, and filemode.
+
+
+  Opening a File without a File Mode Specified
+
+  If you omit the file mode or specify * for it, C/370 does one
+  of the following when you call fopen() or freopen():
+
+  * If you have specified a read mode, C/370 looks for the named file
+    on all the accessed readable disks, in order.  If it does not find
+    the file, the fopen() or freopen() call fails.
+  * If you have specified any of the write modes, C/370 writes the file
+    on the first writable disk you have accessed.  Specifying a write
+    mode on an fopen() or freopen() call that contains the filename of
+    an existing file destroys that file.  If you do not have any
+    writable disks accessed, the call fails.
+
+
+  fopen() and freopen() parameters
+
+  recfm
+     CMS supports only two RECFMs, V and F.  [note that MVS supports
+     27(!) different RECFMs.]  If you do not specify the RECFM for a
+     file, C/370 determines whether is is in fixed or variable format.
+
+  lrecl and blksize
+     For files in fixed format, CMS allows records to be read and
+     written in blocks.  To have a fixed format CMS file treated as a
+     fixed blocked CMS file, you can open the file with recfm=fb and
+     specify the lrecl and blksize.  If you do not specify a recfm on
+     the open, the blksize can be a multiple of the lrecl, and the
+     file is treated as if it were blocked.
+
+     For files in variable format, the CMS LRECL is different from the
+     LRECL for the record model.  In the record model, the LRECL is
+     equal to the data length plus 4 bytes (for the record descriptor
+     word), and the BLKSIZE  is equal to the LRECL plus 4 bytes (for
+     the block descriptor word).  In CMS, BDWs and RDWs do not exist,
+     but because CMS follows the record model, you must still account
+     for them.  When you specify V, you must still allocate the record
+     descriptor word and block descriptor word.  That is, if you want
+     a maximum of n bytes per record, you must specify a minimum LRECL
+     of n+4 and a minimum BLKSIZE of n+8.
+
+     When you are appending to V files, you can enlarge the record size
+     dynamically, but only if you have not specified LRECL or BLKSIZE
+     on the fopen() or freopen() command that opened the file.
+
+  type
+     If you specify this parameter, the only valid value for CMS disk
+     files is type =record. This opens a file for record I/O.
+
+  asis
+     If you use this parameter, you can open files with mixed-case
+     filenames such as JaMeS dAtA or pErCy.FILE.  If you specify this
+     parameter, the file mode that you specify must be a capital letter
+     (if it is not an asterisk); otherwise; the function call fails and
+     the value returned is NULL.
+
+
+  Reading from Record I/O Files
+     fread() is the only interface allowed for reading record I/O files.
+     Each time you call fread() for a record I/O file, fread() reads
+     one record from the system.  If you call fread() with a request for
+     less than a complete record, the requested bytes are copied to your
+     buffer, and the file position is set to the start fo the next
+     record.  If the request is for more bytes that are in the record,
+     one record is read and the position is set to the start of the next
+     record.  C/370 does not strip any blank characters or interpret any
+     data.
+
+     fread() returns the number of items read successfully, so if you
+     pass a size argument equal to 1 and a count argument equal to the
+     maximum expected length of the record, fread() returns the length,
+     in bytes, of the record read.  If you pass a size argument equal
+     to the maximum expected length of the record, and a count argument
+     equal to 1, fread() returns either 0 or 1, indicating whether a
+     record of length size read.  If a record is read successfully but
+     is less than size bytes long, fread() returns 0.
+
+
+  Writing to Record I/O Files
+     fwrite() is the only interface allowed for writing to a file
+     opened for record I/O.  Only one record is written at a time.  If
+     you attempt to write more new data than a full record can hold or
+     try to update a record with more data than it currently has, C/370
+     truncates your output at the record boundary.  When C/370 performs
+     a truncation, it sets errno and raises SIGIOERR, if SIGIOERR is not
+     set to SIG_IGN.
+
+     When you are writing new records to a fixed-record I/O file, if you
+     try to write a short record, C/370 pads the record with nulls out
+     to LRECL.
+
+     At the completion of an fwrite(), the file position is at the start
+     of the next record.  For new data, the block is flushed out to the
+     system as soon as it is full.
+
+
+  fldata() Behavior
+     When you call the fldata() function for an open CMS minidisk file,
+     it returns a data structure that looks like this:
+
+     struct __filedata {
+          unsigned int   __recfmF      : 1, /* fixed length records */
+                         __recfmV      : 1, /* variable length records */
+                         __recfmU      : 1, /* n/a */
+                         __recfmS      : 1, /* n/a */
+                         __recfmBlk    : 1, /* n/a */
+                         __recfmASA    : 1, /* text mode and ASA */
+                         __recfmM      : 1, /* n/a */
+                         __dsorgPO     : 1, /* n/a */
+                         __dsorgPDSmem : 1, /* n/a */
+                         __dsorgPDSdir : 1, /* n/a */
+                         __dsorgPS     : 1, /* sequential data set */
+                         __dsorgConcat : 1, /* n/a */
+                         __dsorgMem    : 1, /* n/a */
+                         __dsorgHiper  : 1, /* n/a */
+                         __dsorgTemp   : 1, /* created with tmpfile() */
+                         __dsorgVSAM   : 1, /* n/a */
+                         __reserve1    : 1, /* n/a */
+                         __openmode    : 2, /* see below 1 */
+                         __modeflag    : 4, /* see below 2 */
+                         __reserve2    : 9, /* n/a */
+
+          char           __device;  __DISK
+          unsigned long  __blksize,         /* see below 3 */
+                         __maxreclen;       /* see below 4 */
+          unsigned short __vsamtype;        /* n/a */
+          unsigned long  __vsamkeylen;      /* n/a */
+          unsigned long  __vsamRKP;         /* n/a */
+          char *         __dsname;          /* fname ftype fmode */
+          unsigned int   __reserve4;        /* n/a */
+
+          /* note 1: values are: __TEXT, __BINARY, __RECORD
+             note 2: values are: __READ, __WRITE, __APPEND, __UPDATE
+                     these values can be added together to determine
+                     the return value; for example, a file opened with
+                     a+ will have the value __READ + __APPEND.
+             note 3: total block size of the file, including ASA
+                     characters as well as RDW information
+             note 4: maximum record length of the data only (includes
+                     ASA characters but excludes RDW information).
+          */
+       };
diff --git a/proginfo/infozip.who b/proginfo/infozip.who
new file mode 100644 (file)
index 0000000..994851c
--- /dev/null
@@ -0,0 +1,242 @@
+These members of the Info-ZIP group contributed to the development and
+testing of portable Zip.  They are responsible for whatever works in
+Zip.  Whatever doesn't work is solely the fault of the authors of Zip
+(Mark Adler, Rich Wales, Jean-loup Gailly, Kai Uwe Rommel, Igor Mandrichenko,
+Onno van der Linden, Christian Spieler, John Bush, Paul Kienitz, Sergio Monesi
+and Karl Davis, but see the license for the latest list).  If you have
+contributed and your name has been forgotten, please send a reminder to us
+using the contact information in the Readme file.  The names are given here
+in alphabetical order, because it's impossible to classify them by importance
+of the contribution.  Some have made a complete port to a new target, some
+have provided a one line fix.  All are to be thanked.
+
+
+Mark Adler              madler@tybalt.caltech.edu       NeXT 2.x, Mac
+                        alan@spri.levels.unisa.edu.au   Linux
+Jeffrey Altman          jaltman@watsun.cc.columbia.edu  fseek bug on NT
+Glenn J. Andrews        oper1%drcv06.decnet@drcvax.af.mil       VAX VMS
+James Van Artsdalen     james@raid.dell.com             bug report
+Eric Backus             ericb@lsid.hp.com               bug report
+Quentin Barnes          qbarnes@urbana.css.mot.com      unix/Makefile mode of
+                                                        installed files
+Elmar Bartel            bartel@informatik.tu-muenchen.de
+Mark E. Becker          mbecker@cs.uml.edu              bug report
+Paul von Behren         Paul_von_Behren@stortek.com     OS/390 port
+Jon Bell                swy@wsdot.wa.gov                Intergraph/CLIX
+Myles Bennett           -                               Initial UnZip 6.0 large
+                                                        files beta
+Michael Bernardi        mike@childsoc.demon.co.uk       RS6000
+Tom Betz                marob!upaya!tbetz@phri.nyu.edu  SCO Xenix 2.3.1
+James Birdsall          jwbirdsa@picarefy.com           AT&T 3B1
+George                  boer@fwi.uva.nl                 OS/2
+Michael Bolton          bolton@vaxc.erim.org            VAX/VMS
+Wim Bonner              27313853@WSUVM1.CSC.WSU.EDU     HP 9000/840a HPUX
+Paul Borman             prb@cray.com                    Cray-X/YMP,2 UNICOS 6-8
+Kurt Van den Branden    kvd2@bipsy.se.bel.alcatel.be    VAX VMS
+Scott Briggs            briggs@nashua.progress.com      Windows NT
+Leslie C. Brown         lbrown@BRL.MIL                  Pyramid MIS-4
+Ralf Brown              ralf@b.gp.cs.cmu.edu            Pyramid MIS-4
+Rodney Brown            rdb@cmutual.com.au              SunOS 4.1.3 DGUX OSF/1
+                                                        HP-UX  CRC optimization
+Jeremy Daniel Buhler    jbuhler@owlnet.rice.edu         BC++
+John Bush               john.bush@east.sun.com          Amiga (SAS/C)
+Pietro Caselli          zaphod@petruz.sublink.org       Minix 1.5.10
+Andrew A. Chernov       ache@astral.msk.su              FreeBSD
+Jeff Coffler            jeffcof@microsoft.com           Windows NT
+David Dachtera          David.Dachtera@advocatehealth.com  VMS
+                                                        link_zip.com bug
+Bill Davidsen           davidsen@crdos1.crd.ge.com      Xenix (on what?)
+Karl Davis              riscman@geko.com.au             Acorn
+Daniel Deimert          daniel@pkmab.se                 zeus3.21 Zilog S8000
+David Denholm           denholm@sotona.physics.southampton.ac.uk   VMS
+Harald Denker           harry@hal.westfalen.de          ATARI
+Matthew J. D'Errico     doc@magna.com                   Bull
+L. Peter Deutsch        ghost@aladdin.com               Linux
+Uwe Doering             gemini@geminix.in-berlin.de     386 Unix
+Jean-Michel Dubois      jmdubois@ibcfrance.fr           Theos support
+James P. Dugal          jpd@usl.edu                     Pyramid 90X OSx4.1
+"Evil Ed"               esaffle@gmuvax2.gmu.edu         Ultrix-32 V3.1 (Rev. 9)
+Patrick Ellis           pellis@aic.mdc.com              VMS zip -h appearance
+Thomas Esken            esken@uni-muenster.de           Acorn fix
+Dwight Estep            estep@dlo10.enet.dec.com        MSDOS
+David A. Feinleib       t-davefe@microsoft.com          Windows NT
+Joshua Felsteiner       joshua@phys1.technion.ac.il     Linux
+Greg Flint              afc@klaatu.cc.purdue.edu        ETA-10P* hybrid Sys V
+Carl Forde              cforde@bcsc02.gov.bc.ca         VM/CMS
+Jeff Foy                jfoy@glia.biostr.washington.edu IRIX Sys V Rel 3.3.1
+Mike Freeman            mikef@pacifier.com              Vax VMS
+Kevin M. Fritz          kmfritz@apgea.army.mil          Turbo C++ 1.0
+                                                        Pyramid
+Jean-loup Gailly        jloup@chorus.fr                 MS-DOS Microsoft C 5.1
+Scott D. Galloway       sgallowa@letterkenn-emh1.army.mil   Sperry 5000 SysV.3
+Rainer Gerling          gerling@faupt101.physik.uni-erlangen.de   HPUX, MSDOS
+Henry Gessau            henryg@kullmar.kullmar.se       Windows NT
+Ed Gordon               -                               Zip 3.0, VB, Unicode,
+                                                        large files, splits, DLLs
+Ian E. Gorman           ian@iosphere.net                ported zip 2.2 to VM/CMS
+Wayne R. Graves         graves@csa2.lbl.gov             Vax VMS
+George Grimes           grimes@netcom.com               Apollo Domain SR10.4
+Hunter Goatley          goathunter@MadGoat.com          VMS (VAX & Alpha),
+                                                        web and ftp sites
+Arnt Gulbrandsen        agulbra@pvv.unit.no             Linux
+David Gundlach          david@rolf.stat.uga.edu         Sun SS1+ SunOS 4.1
+Peter Gutmann           pgut1@cs.aukuni.ac.nz           bug report
+Dirk Haase              d_haase@sitec.de                MacOS port
+Mark Hanning-Lee        markhl@iris-355.jpl.nasa.gov    SGI
+Walter Haidinger        e9225662@student.tuwien.ac.at   Amiga and general fixes
+Charles Hannum          mycroft@ai.mit.edu              bug report
+Greg Hartwig            ghartwig@ix.netcom.com          VM/CMS cleanup
+Tanvir Hassan           tanvir.hassan@autodesk.com      NT
+Bob Hardy               hardy@lucid.com                 Power C on MSDOS
+Zachary Heilig          heilig@plains.nodak.edu         Turbo C++ 3.0
+Chris Herborth          chrish@pobox.com                BeOS port
+Jonathan Hudson         jrhudson@bigfoot.com            QDOS port
+Mark William Jacobs     mark@mensch.stanford.edu        MSDOS
+Aubrey Jaffer           jaffer@martigny.ai.mit.edu      Pixel
+Peter Jones             jones.peter@uqam.ca             MIPS UMIPS 4.0
+                                                        +Onolimit fix for HP-UX
+Kjetil W. J{\o}rgensen  jorgens@lise.unit.no            OSF/1, DJGPP v2
+Bruce Kahn              bkahn@archive.webo.dg.com       MS-DOS Microsoft C 5.1
+Jonathan I. Kamens      jik@pit-manager.mit.edu         ultrix on DECstation
+Dave Kapalko            d.kapalko@att.com               bug report
+Bob Kemp                Robert.V.Kemp@att.com           AT&T 3B2 SysV 3.2v2
+Vivek Khera             khera@cs.duke.edu               SunOS
+Earl Kiech              KIECH@utkvx.utk.edu             VAX VMS V5.4-1A
+Paul Kienitz            Paul.Kienitz@shelter.sf.ca.us   Amiga, Watcom C
+David Kirschbaum        kirsch@usasoc.soc.mil           He got us all in this
+                                                        mess in the first place
+Thomas Klausner         wiz@danbala.tuwien.ac.at        cygwin32 and -k fix
+D. Krumbholz            krumbh00@marvin.informatik.uni-dortmund.de
+                                                        Acorn filetype and
+                                                        timestamp bug report
+
+Bo Kullmar              bk@kullmar.se                   DNIX 5.3, SunOS 4.1
+Baden Kudrenecky        baden@unixg.ubc.ca              OS/2
+Giuseppe La Sala        lasala@mail.esa.esrin.it        VMS
+Jean-Marc Lasgouttes    jean-marc.lasgouttes@inria.fr   Bug report
+Harry Langenbacher      harry@neuron6.Jpl.Nasa.Gov      Sun SS1+ SunOS 4.1
+Michael D. Lawler       mdlawler@gwmicro.com            Mt.Xinu BSD 4.3 on VAX
+                                                        Borland C++ 4.51
+Johnny Lee              johnnyl@microsoft.com           Microsoft C 7.0
+Michael Lemke           michael@io.as.utexas.edu        VMS
+David Lemson            lemson@ux1.cso.uiuc.edu         Sequent Dynix 3.0.17
+Tai-Shan Lin            tlin@snakeyes.eecs.wsu.edu      OS/2
+Onno van der Linden     onno@simplex.nl                 NetBSD, Borland C++,
+                                                        MSC 7.0, DJGPP 2
+
+Michel                  loehden%mv13.decnet@vax.hrz.uni-marburg.de  VMS
+Warner Losh             imp@Solbourne.COM               packing algorithm help
+Dave Lovelace           davel@grex.cyberspace.org       DG AOS/VS
+Erik Luijten            erik@tntnhb3.tn.tudelft.nl      problem report
+John Lundin             lundin@urvax.urich.edu          VAX VMS
+Igor Mandrichenko       mandrichenko@m10.ihep.su        VAX VMS
+Cliff Manis             root@csoftec.csf.com            SCO 2.3.1 (386)
+Fulvio Marino           fulvio@iconet.ico.olivetti.it   X/OS 2.3 & 2.4
+Bill Marsh              bmarsh@cod.nosc.mil             SGI Iris 4D35
+Michael Mauch           mauch@gmx.de                    djgpp LFN attribute fix
+Peter Mauzey            ptm@mtdcr.mt.lucent.com         AT&T 6300, 7300
+Rafal Z. Maszkowski     rzm@mat.torun.edu.pl            Convex
+Robert McBroom (?)      rm3@ornl.gov                    DECsystem 5810
+Tom McConnell           tmcconne@sedona.intel.com       NCR SVR4
+Frank P. McIngvale      frankm@eng.auburn.edu           Bug report
+Conor McMenamin         C.S.McMenamin@sussex.ac.uk      MSDOS
+Will Menninger                                          Win32, MinGW
+John Messenger          jlm@proteon.com                 Bug report
+Michael                 kuch@mailserv.zdv.uni-tuebingen.de SGI
+Dan Mick                dmick@pongo.west.sun.com        Solaris
+Alan Modra              alan@spri.levels.unisa.edu.au   Linux
+Laszlo Molnar           lmolnar@goliat.eik.bme.hu       DJGPP v2
+Jim Mollmann            jmq@nccibm1.bitnet              OS/2 & MVS
+Sergio Monesi           pel0015@cdc8g5.cdc.polimi.it    Acorn
+J. Mukherjee            jmukherj@ringer.cs.utsa.edu     OS/2
+Anthony Naggs           amn@ubik.demon.co.uk            bug report
+Matti Narkia            matti.narkia@ntc.nokia.com      VAX VMS
+Rainer Nausedat                                         Zip 3.0, large files
+Robert E. Newman Jr.    newmanr@ssl.msfc.nasa.gov       bug report
+Robert Nielsen          NielsenRJ@ems.com               2.2 -V VMS bug report
+Christian Michel        cmichel@de.ibm.com              2.2 check_dup OS/2 bug
+                                                        report
+Thomas S. Opheys        opheys@kirk.fmi.uni-passau.de   OS/2
+Humberto Ortiz-Zuazaga  zuazaga@ucunix.san.uc.edu       Linux
+James E. O'Dell         jim@fpr.com                     MacOS
+William O'Shaughnessy   williamo@hpcupt1.cup.hp.com     HPUX
+Neil Parks              neil.parks@pcohio.com           MSDOS
+Enrico Renato Palmerini palmer@vxscaq.cineca.it         UNISYS 7000 Sys 5 r2.3
+Geoff Pennington        Geoff.Pennington@sgcs.co.uk     -q output bug
+Keith Petersen          w8sdz@simtel20.army.mil         Pyramid UCB OSx4.4c
+George Petrov                                           VM/CMS, MVS
+Alan Phillips           postmaster@lancaster.ac.uk      Dynix/ptx 1.3
+Bruno Pillard           bp@chorus.fr                    SunOS 4.1
+Piet W. Plomp           piet@icce.rug.nl                MSC 7.0, SCO 3.2v4.0
+John Poltorak           j.poltorak@bradford.ac.uk       problem report
+Kenneth Porter          72420.2436@compuserve.com       OS/2
+Norbert Pueschel        pueschel@imsdd.meb.uni-bonn.de  Amiga time.lib
+Yuval Rakavy            yuval@cs.huji.ac.il             MSDOS
+David A Rasmussen       dave@convex.csd.uwm.edu         Convex C220 with 9.0 OS
+Eric Raymond            esr@snark.thyrsus.com           Unix
+Jim Read                74312.3103@compuserve.com       OS/2
+Michael Regoli          mr@cica.indiana.edu             Ultrix 3.1 VAX 8650
+                                                        BSD 4.3 IBM RT/125
+                                                        BSD 4.3 MicroVAX 3500
+                                                        SunOS 4.0.3 Sun 4/330
+Jochen Roderburg        roderburg@rrz.uni-koeln.de      Digital Unix with
+                                                        AFS/NFS converter
+Rick Rodgers            rodgers@maxwell.mmwb.ucsf.EDU   Unix man page
+Greg Roelofs            roe2@midway.uchicago.edu        SunOS 4.1.1,4.1.2 Sun 4
+                                                        Unicos 5.1--6.1.5 Cray
+                                                        OS/2 1.3 MS C 6.0
+                                                        Ultrix 4.1,4.2 DEC 5810
+                                                        VMS 5.2, 5.4 VAX 8600
+                                                        Irix 3.3.2, SGI Iris 4D
+                                                        UTS 1.2.4 Amdahl 5880
+Phil Ritzenthaler       phil@cgrg.ohio-state.edu        SYSV
+Kai Uwe Rommel          rommel@ars.de or rommel@leo.org OS/2
+Markus Ruppel           m.ruppel@imperial.ac.uk         OS/2
+Shimazaki Ryo           eririn@ma.mailbank.ne.jp        human68k
+Jon Saxton              jrs@panix.com                   Microsoft C 6.0
+Steve Salisbury         stevesa@msn.com                 Microsoft C 8.0
+Timo Salmi              ts@uwasa.fi                     bug report
+Darren Salt             ds@youmustbejoking.demon.co.uk  RISC OS
+NIIMI Satoshi           a01309@cfi.waseda.ac.jp         Human68K
+Tom Schmidt             tschmidt@micron.com             SCO 286
+Martin Schulz           martin.schulz@isltd.insignia.com Windows NT, Atari
+Steven Schweda                                          VMS, Unix, large files
+Dan Seyb                dseyb@halnet.com                AIX
+Mark Shadley            shadcat@catcher.com             unix fixes
+Timur Shaporev          tim@rd.relcom.msk.su            MSDOS
+W. T. Sidney            sidney@picard.med.ge.com        bug report
+Dave Sisson             daves@vtcosy.cns.vt.edu         AIX 1.1.1 PS/2 & 3090
+Dave Smith              smithdt@bp.com                  Tandem port
+Fred Smith              fredex@fcshome.stoneham.ma.us   Coherent
+Christian Spieler       spieler@ikp.tu-darmstadt.de     VMS, MSDOS, emx, djgpp,
+                                                        WIN32, Linux
+Ron Srodawa             srodawa@vela.acs.oakland.edu    SCO Xenix/386 2.3.3
+Adam Stanley            astanley@winternet.com          MSDOS
+Bertil Stenstr|m        stenis@heron.dafa.se            HP-UX 7.0 HP9000/835
+Carl Streeter           streeter@oshkoshw.bitnet        OS/2
+Reuben Sumner           rasumner@undergrad.math.uwaterloo.ca  Suggestions
+E-Yen Tan               e-yen.tan@brasenose.oxford.ac.uk Borland C++ win32
+Yoshioka Tsuneo         tsuneo-y@is.aist-nara.ac.jp     Multibyte charset
+                                                        support
+Paul Telles             paul@pubnet.com                 SCO Xenix
+Julian Thompson         jrt@oasis.icl.co.uk             bug report
+Christopher C. Tjon     tjon@plains.nodak.edu           bug report
+Robert F Tobler         rft@cs.stanford.edu             bug report
+Eric  Tomio             tomio@acri.fr                   bug report
+Cosmin Truta            cosmint@cs.ubbcluj.ro           win32 gcc based + asm
+Anthony R. Venson       cevens@unix1.sncc.lsu.edu       MSDOS/emx
+Antoine Verheijen       antoine@sysmail.ucs.ualberta.ca envargs fix
+Arjan de Vet            devet@info.win.tue.nl           SunOS 4.1, MSC 5.1
+Santiago Vila Doncel    sanvila@ba.unex.es              MSDOS
+Johan Vromans           jv@mh.nl                        bug report
+Rich Wales              wales@cs.ucla.edu               SunOS 4.0.3 Sun-3/50
+Scott Walton            scottw@io.com                   BSD/386
+Frank J. Wancho         wancho@wsmr-simtel20.army.mil   TOPS-20
+                        oyvind@stavanger.sgp.slb.com    Bug report.
+Takahiro Watanabe       wata@first.tsukuba.ac.jp        fixes for INSTALL
+Mike White              mwhite@pumatech.com             wizzip DLL
+Ray Wickert             wickert@dc-srv.pa-x.dec.com     MSDOS/DJGPP
+Winfried Winkler        willi@wap0109.chem.tu-berlin.de AIX
+Norman J. Wong          as219@freenet.carleton.ca       MSDOS
+Martin Zinser           m.zinser@gsi.de                 VMS 7.x
+
diff --git a/proginfo/ntsd.txt b/proginfo/ntsd.txt
new file mode 100644 (file)
index 0000000..8ac31ba
--- /dev/null
@@ -0,0 +1,111 @@
+Info-ZIP portable Zip/UnZip Windows NT security descriptor support
+==================================================================
+Scott Field (sfield@microsoft.com), 8 October 1996
+
+
+This version of Info-ZIP's Win32 code allows for processing of Windows
+NT security descriptors if they were saved in the .zip file using the
+appropriate Win32 Zip running under Windows NT.  This also requires
+that the file system that Zip/UnZip operates on supports persistent
+Acl storage.  When the operating system is not Windows NT and the
+target file system does not support persistent Acl storage, no security
+descriptor processing takes place.
+
+A Windows NT security descriptor consists of any combination of the
+following components:
+
+       an owner (Sid)
+       a primary group (Sid)
+       a discretionary ACL (Dacl)
+       a system ACL (Sacl)
+       qualifiers for the preceding items
+
+By default, Zip will save all aspects of the security descriptor except
+for the Sacl.  The Sacl contains information pertaining to auditing of
+the file, and requires a security privilege be granted to the calling
+user in addition to being enabled by the calling application.  In order
+to save the Sacl during Zip, the user must specify the -! switch on the
+Zip commandline.  The user must also be granted either the SeBackupPrivilege
+"Backup files and directories" or the SeSystemSecurityPrivilege "Manage
+auditing and security log".
+
+By default, UnZip will not restore any aspects of the security descriptor.
+If the -X option is specified to UnZip, the Dacl is restored to the file.
+The other items in the security descriptor on the new file will receive
+default values.  If the -XX option is specified to UnZip, as many aspects
+of the security descriptor as possible will be restored.  If the calling
+user is granted the SeRestorePrivilege "Restore files and directories",
+all aspects of the security descriptor will be restored.  If the calling
+user is only granted the SeSystemSecurityPrivilege "Manage auditing and
+security log", only the Dacl and Sacl will be restored to the new file.
+
+Note that when operating on files that reside on remote volumes, the
+privileges specified above must be granted to the calling user on that
+remote machine.  Currently, there is no way to directly test what privileges
+are present on a remote machine, so Zip and UnZip make a remote privilege
+determination based on an indirect method.
+
+UnZip considerations
+--------------------
+
+In order for file security to be processed correctly, any directory entries
+that have a security descriptor will be processed at the end of the unzip
+cycle.  This allows for unzip to process files within the newly created
+directory regardless of the security descriptor associated with the directory
+entry.  This also prevents security inheritance problems that can occur as
+a result of creating a new directory and then creating files in that directory
+that will inherit parent directory permissions; such inherited permissions may
+prevent the security descriptor taken from the zip file from being applied
+to the new file.
+
+If directories exist which match directory/extract paths in the .zip file,
+file security is not updated on the target directory.  It is assumed that if
+the target directory already exists, then appropriate security has already
+been applied to that directory.
+
+"unzip -t" will test the integrity of stored security descriptors when
+present and the operating system is Windows NT.
+
+ZipInfo (unzip -Z) will display information on stored security descriptor
+when "unzip -Zv" is specifed.
+
+
+Potential uses
+==============
+
+The obvious use for this new support is to better support backup and restore
+operations in a Windows NT environment where NTFS file security is utilized.
+This allows individuals and organizations to archive files in a portable
+fashion and transport these files across the organization.
+
+Another potential use of this support is setup and installation.  This
+allows for distribution of Windows NT based applications that have preset
+security on files and directories.  For example, prior to creation of the
+.zip file, the user can set file security via File Manager or Explorer on
+the files to be contained in the .zip file.  In many cases, it is appropriate
+to only grant Everyone Read access to .exe and .dll files, while granting
+Administrators Full control.  Using this support in conjunction with the
+unzipsfx.exe self-extractor stub can yield a useful and powerful way to
+install software with preset security (note that -X or -XX should be
+specified on the self-extractor commandline).
+
+When creating .zip files with security which are intended for transport
+across systems, it is important to take into account the relevance of
+access control entries and the associated Sid of each entry.  For example,
+if a .zip file is created on a Windows NT workstation, and file security
+references local workstation user accounts (like an account named Fred),
+this access entry will not be relevant if the .zip file is transported to
+another machine.  Where possible, take advantage of the built-in well-known
+groups, like Administrators, Everyone, Network, Guests, etc.  These groups
+have the same meaning on any Windows NT machine.  Note that the names of
+these groups may differ depending on the language of the installed Windows
+NT, but this isn't a problem since each name has well-known ID that, upon
+restore, translates to the correct group name regardless of locale.
+
+When access control entries contain Sid entries that reference Domain
+accounts, these entries will only be relevant on systems that recognize
+the referenced domain.  Generally speaking, the only side effects of
+irrelevant access control entries is wasted space in the stored security
+descriptor and loss of complete intended access control.  Such irrelevant
+access control entries will show up as "Account Unknown" when viewing file
+security with File Manager or Explorer.
diff --git a/proginfo/perform.dos b/proginfo/perform.dos
new file mode 100644 (file)
index 0000000..98744ee
--- /dev/null
@@ -0,0 +1,183 @@
+Date: Wed, 27 Mar 1996 01:31:50 CET +0100
+From: Christian Spieler (IKDA, THD, D-64289 Darmstadt)
+Subject: More detailed comparison of MSDOS Info-ZIP programs' performance
+
+Hello all,
+
+In response to some additional questions and requests concerning
+my previous message about DOS performance of 16/32-bit Info-ZIP programs,
+I have produced a more detailed comparison:
+
+System:
+Cx486DX-40, VL-bus, 8MB; IDE hard disk;
+DOS 6.2, HIMEM, EMM386 NOEMS NOVCPI, SMARTDRV 3MB, write back.
+
+I have used the main directory of UnZip 5.20p as source, including the
+objects and executable of an EMX compile for unzip.exe (to supply some
+binary test files).
+
+Tested programs were (my current updated sources!) Zip 2.0w and UnZip 5.20p
+- 16-bit MSC 5.1, compressed with LZEXE 0.91e
+- 32-bit Watcom C 10.5, as supplied by Kai Uwe Rommel (PMODE 1.22)
+- 32-bit EMX 0.9b
+- 32-bit DJGPP v2
+- 32-bit DJGPP v1.12m4
+
+The EMX and DJ1 (GO32) executables were bound with the full extender, to
+create standalone executables.
+
+A) Tests of Zip
+  Command :  "<system>\zip.exe -q<#> tes.zip unz/*"  (unz/*.* for Watcom!!)
+             where <#> was: 0, 1, 6, 9.
+             The test archive "tes.zip" was never deleted, this test
+             measured "time to update archive".
+
+  The following table contains average execution seconds (averaged over
+  at least 3 runs, with the first run discarted to fill disk cache);
+  numbers in parenteses specify the standard deviation of the last
+  digits.
+
+  cmpr level|      0     |      1     |      6     |      9
+ ===============================================================
+  EMX win95 |   7.77     |   7.97     |  12.82     |  22.31
+ ---------------------------------------------------------------
+  EMX       |   7.15(40) |   8.00(6)  |  12.52(25) |  20.93
+  DJ2       |  13.50(32) |  14.20(7)  |  19.05     |  28.48(9)
+  DJ1       |  13.56(30) |  14.48(3)  |  18.70     |  27.43(13)
+  WAT       |   6.94(22) |   8.93     |  15.73(34) |  30.25(6)
+  MSC       |   5.99(82) |   9.40(4)  |  13.59(9)  |  20.77(4)
+ ===============================================================
+
+ The "EMX win95" line was created for comparison, to check the performance
+ of emx 0.9 with the RSX extender in a DPMI environment. (This line was
+ produced by applying the "stubbed" EMX executable in a full screen DOS box.)
+
+
+B) Tests of UnZip
+  Commands :  <system>\unzip.exe -qt tes.zip         (testing performance)
+              <system>\unzip.exe -qo tes.zip -dtm    (extracting performance)
+
+  The tes.zip archive created by maximum compression with the Zip test
+  was used as example archive. Contents (archive size was 347783 bytes):
+   1028492 bytes uncompressed, 337235 bytes compressed, 67%, 85 files
+
+  The extraction directory tm was not deleted between the individual runs,
+  thus this measurement checks the "overwrite all" time.
+
+           |     testing               |          extracting
+  ===================================================================
+  EMX      |       1.98                |         6.43(8)
+  DJ2      |       2.09                |        11.85(39)
+  DJ1      |       2.09                |         7.46(9)
+  WAT      |       2.42                |         7.10(27)
+  MSC      |       4.94                |         9.57(31)
+
+Remarks:
+
+The executables compiled by me were generated with all "performance"
+options enabled (ASM_CRC, and ASMV for Zip), and with full crypt support.
+For DJ1 and DJ2, the GCC options were "-O2 -m486", for EMX "-O -m486".
+
+The Watcom UnZip was compiled with ASM_CRC code enabled as well,
+but the Watcom Zip example was made without any optional assembler code!
+
+
+
+Discussion of the results:
+
+In overall performance, the EMX executables clearly win.
+For UnZip, emx is by far the fastest program, and the Zip performance is
+comparable to the 16-bit "reference".
+
+Whenever "real" work including I/O is requested, the DJGPP versions
+lose badly because of poor I/O performance, this is the case especially
+for the "newer" DJGPP v2 !!!
+(I tried to tweak with the transfer buffer size, but without any success.)
+An interesting result is that DJ v1 UnZip works remarkably better than
+DJ v2 (in contrast to Zip, where both executables' performance is
+approximately equal).
+
+The Watcom C programs show a clear performance deficit in the "computational
+part" (Watcom C compiler produces code that is far from optimal), but
+the extender (which is mostly responsible for the I/O throughput) seems
+to be quite fast.
+
+The "natural" performance deficit of the 16-bit MSC code, which can be
+clearly seen in the "testing task" comparison for UnZip, is (mostly,
+for Zip more than) compensated by the better I/O throughput (due to the
+"direct interface" between "C RTL" and "DOS services", without any mode
+switching).
+
+But performance is only one aspect when choosing which compiler should
+be used for official distribution:
+
+Sizes of the executables:
+    |             Zip                ||           UnZip
+    | standalone           stub      || standalone    |     stub
+======================================================================
+EMX | 143,364  (1) |    94,212       ||  159,748  (1) |   110,596
+DJ2 | 118,272  (2) |       --        ||  124,928  (2) |      --
+DJ1 | 159,744      |    88,064       ||  177,152      |   105,472
+WAT | 140,073      |       --        ||  116,231      |      --
+MSC |  49,212  (3) |       --        ||   45,510  (3) |      --
+
+(1) does not run in "DPMI only" environment (Windows DOS box)
+(2) requires externally supplied DPMI server
+(3) compressed with LZexe 0.91
+
+Caveats/Bugs/Problems of the different extenders:
+
+EMX:
+- requires two different extenders to run in all DOS-compatible environments,
+  EMX for "raw/himem/vcpi" and RSX for "dpmi" (Windows).
+- does not properly support time zones (no daylight savings time)
+
+DJv2:
+- requires an external (freely available) DPMI extender when run on plain
+  DOS; this extender cannot (currently ??) be bound into the executable.
+
+DJv1:
+- uses up large amount of "low" dos memory (below 1M) when spawning
+  another program, each instance of a DJv1 program requires its private
+  GO32 extender copy in low dos memory (may be problem for the zip
+  "-T" feature)
+
+Watcom/PMODE:
+- extended memory is allocated statically (default: ALL available memory)
+  This means that a spawned program does not get any extended memory.
+  You can work around this problem by setting a hard limit on the amount
+  of extended memory available to the PMODE program, but this limit is
+  "hard" and restricts the allocatable memory for the program itself.
+  In detail:
+  The Watcom zip.exe as distributed did not allow the "zip -T" feature;
+  there was no extended memory left to spawn unzip.
+  I could work around this  problem by applying PMSETUP to change the
+  amount of allocated extended memory to 2.0 MByte (I had 4MB free extended
+  memory on my test system). But, this limit cannot be enlarged at
+  runtime, when zip needs more memory to store "header info" while
+  zipping up a huge drive, and on a system with less free memory, this
+  method is not applicable, either.
+
+Summary:
+
+For Zip:
+Use the 16-bit executable whenever possible (unless you need the
+larger memory capabilities when zipping up a huge amount of files)
+
+As 32-bit executable, we may distribute Watcom C (after we have confirmed
+that enabling ASMV and ASM_CRC give us some better computational
+performance.)
+The alternative for 32-bit remains DJGPP v1, which shows the least problems
+(to my knowledge); v2 and EMX cannot be used because of their lack of
+"universality".
+
+For UnZip:
+Here, the Watcom C 32-bit executable is probably the best compromise,
+but DJ v1 could be used as well.
+And, after all, the 16-bit version does not lose badly when doing
+"real" extraction! For the SFX stub, the 16-bit version remains first
+choice because of its much smaller size!
+
+Best regards
+
+Christian Spieler
diff --git a/proginfo/timezone.txt b/proginfo/timezone.txt
new file mode 100644 (file)
index 0000000..7868093
--- /dev/null
@@ -0,0 +1,85 @@
+Timezone strings:
+-----------------
+This is a description of valid timezone strings for ENV[ARC]:TZ:
+"XPG3TZ - time zone information"
+The form of the time zone information is based on the XPG3 specification of
+the TZ environment variable.  Spaces are allowed only in timezone
+designations, where they are significant.  The following description
+closely follows the XPG3 specification, except for the paragraphs starting
+**CLARIFICATION**.
+
+<std><offset>[<dst>[<offset>],<start>[/<time>],<end>[/<time>]]
+
+Where:
+<std> and <dst>
+      Are each three or more bytes that are the designation for the
+      standard (<std>) and daylight savings time (<dst>) timezones.
+      Only <std> is required - if <dst> is missing, then daylight
+      savings time does not apply in this locale.  Upper- and
+      lower-case letters are allowed.  Any characters except a
+      leading colon (:), digits, a comma (,), a minus (-) or a plus
+      (+) are allowed.
+      **CLARIFICATION**  The two-byte designation `UT' is permitted.
+<offset>
+      Indicates the value one must add to the local time to arrive
+      at Coordinated Universal Time.  The offset has the form:
+      <hh>[:<mm>[:<ss>]]
+      The minutes <mm> and seconds <ss> are optional.  The hour <hh>
+      is required and may be a single digit.  The offset following
+      <std> is required.  If no offset follows <dst>, daylight savings
+      time is assumed to be one hour ahead of standard time.  One or
+      more digits may be used; the value is always interpreted as a
+      decimal number.  The hour must be between 0 and 24, and the
+      minutes (and seconds) if present between 0 and 59.  Out of
+      range values may cause unpredictable behavior.  If preceded by
+      a `-', the timezone is east of the Prime Meridian; otherwise
+      it is west (which may be indicated by an optional preceding
+      `+' sign).
+      **CLARIFICATION**  No more than two digits are allowed in any
+      of <hh>, <mm> or <ss>.  Leading zeros are permitted.
+<start>/<time> and <end>/<time>
+      Indicates when to change to and back from daylight savings
+      time, where <start>/<time> describes when the change from
+      standard time to daylight savings time occurs, and
+      <end>/<time> describes when the change back happens.  Each
+      <time> field describes when, in current local time, the change
+      is made.
+      **CLARIFICATION**  It is recognized that in the Southern
+      hemisphere <start> will specify a date later than <end>.
+      The formats of <start> and <end> are one of the following:
+      J<n>    The Julian day <n> (1 <= <n> <= 365).  Leap days are not
+              counted.  That is, in all years, February 28 is day 59
+              and March 1 is day 60.  It is impossible to refer to
+              the occasional February 29.
+      <n>     The zero-based Julian day (0 <= <n> <= 365).  Leap days
+              are counted, and it is possible to refer to February
+              29.
+      M<m>.<n>.<d>
+              The <d>th day, (0 <= <d> <= 6) of week <n> of month <m>
+              of the year (1 <= <n> <= 5, 1 <= <m> <= 12), where week
+              5 means `the last <d>-day in month <m>' (which may
+              occur in either the fourth or the fifth week).  Week 1
+              is the first week in which the <d>th day occurs.  Day
+              zero is Sunday.
+              **CLARIFICATION**  Neither <n> nor <m> may have a
+              leading zero.  <d> must be a single digit.
+              **CLARIFICATION**  The default <start> and <end> values
+              are from the first Sunday in April until the last Sunday
+              in October.  This allows United States users to leave out
+              the <start> and <end> parts, as most are accustomed to
+              doing.
+      <time> has the same format as <offset> except that no leading
+      sign (`-' or `+') is allowed.  The default, if <time> is not
+      given is 02:00:00.
+      **CLARIFICATION**  The number of hours in <time> may be up
+      to 167, to allow encoding of rules such as `00:00hrs on the
+      Sunday after the second Friday in September'
+
+Example (for Central Europe):
+-----------------------------
+MET-1MEST,M3.5.0,M10.5.0/03
+
+Another example, for the US East Coast:
+---------------------------------------
+EST5EDT4,M4.1.0/02,M10.5.0/02
+This string describes the default values when no time zone is set.
diff --git a/proginfo/txtvsbin.txt b/proginfo/txtvsbin.txt
new file mode 100644 (file)
index 0000000..6ba2805
--- /dev/null
@@ -0,0 +1,112 @@
+A Fast Method of Identifying Plain Text Files
+=============================================
+
+
+Introduction
+------------
+
+Given a file coming from an unknown source, it is generally impossible
+to conclude automatically, and with 100% accuracy, whether that file is
+a plain text file, without performing a heavy-duty semantic analysis on
+the file contents.  It is, however, possible to obtain a fairly high
+degree of accuracy, by employing various simple heuristics.
+
+Previous versions of the zip tools were using a crude detection scheme,
+originally used by PKWare in its PKZip programs: if more than 80% (4/5)
+of the bytes are within the range [7..127], the file is labeled as plain
+text, otherwise it is labeled as binary.  A prominent limitation of this
+scheme is the restriction to Latin-based alphabets.  Other alphabets,
+like Greek, Cyrillic or Asian, make extensive use of the bytes within
+the range [128..255], and texts using these alphabets are most often
+mis-identified by this scheme; in other words, the rate of false
+negatives is sometimes too high, which means that the recall is low.
+Another weakness of this scheme is a reduced precision, due to the false
+positives that may occur when binary files containing a large amount of
+textual characters are mis-identified as plain text.
+
+In this article we propose a new detection scheme, with a much increased
+accuracy and precision, and a near-100% recall.  This scheme is designed
+to work on ASCII and ASCII-derived alphabets, and it handles single-byte
+alphabets (ISO-8859, OEM, KOI-8, etc.), and variable-sized alphabets
+(DBCS, UTF-8, etc.).  However, it cannot handle fixed-sized, multi-byte
+alphabets (UCS-2, UCS-4), nor UTF-16.  The principle used by this scheme
+can easily be adapted to non-ASCII alphabets like EBCDIC.
+
+
+The Algorithm
+-------------
+
+The algorithm works by dividing the set of bytes [0..255] into three
+categories:
+- The white list of textual bytecodes:
+  9 (TAB), 10 (LF), 13 (CR), 20 (SPACE) to 255
+- The gray list of tolerated bytecodes:
+  7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB), 27 (ESC)
+- The black list of undesired, non-textual bytecodes:
+  0 (NUL) to 6, 14 to 31.
+
+If a file contains at least one byte that belongs to the white list, and
+no byte that belongs to the black list, then the file is categorized as
+plain text.  Otherwise, it is categorized as binary.
+
+
+Rationale
+---------
+
+The idea behind this algorithm relies on two observations.
+
+The first observation is that, although the full range of 7-bit codes
+(0..127) is properly specified by the ASCII standard, most control
+characters in the range 0..31 are not used in practice.  The only
+widely-used, almost universally-portable control codes are 9 (TAB),
+10 (LF), and 13 (CR).  There are a few more control codes that are
+recognized on a reduced range of platforms and text viewers/editors:
+7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB), and 27 (ESC); but these
+codes are rarely (if ever) used alone, without being accompanied by
+some printable text.  Even the newer, portable text formats, such as
+XML, avoid using control characters outside the list mentioned here.
+
+The second observation is that most of the binary files tend to contain
+control characters, especially 0 (NUL); even though the older text
+detection schemes observe the presence of non-ASCII codes from the range
+[128..255], the precision rarely has to suffer if this upper range is
+labeled as textual, because the files that are genuinely binary tend to
+contain both control characters, and codes from the upper range.  On the
+other hand, the upper range needs to be labeled as textual,  because it
+is being used by virtually all ASCII extensions.  In particular, this
+range is being heavily used to encode non-Latin scripts.
+
+Given the two observations, the plain text detection algorithm becomes
+straightforward.  There must be at least some printable material, or
+some portable whitespace such as TAB, CR or LF, otherwise the file is
+not labeled as plain text.  (The boundary case, when the file is empty,
+automatically falls into this category.)  However, there must be no
+non-portable control characters, otherwise it's very likely that the
+intended reader of that file is a machine, rather than a human.
+
+Since there is no counting involved, other than simply observing the
+presence or the absence of some byte values, the algorithm produces
+uniform results on any particular text file, no matter what alphabet
+encoding is being used for that text.  (In contrast, if counting were
+involved, it could be possible to obtain different results on a text
+encoded, say, using ISO-8859-2 versus UTF-8.)  There is the category
+of plain text files that are "polluted" with one or a few black-listed
+codes, either by mistake, or by peculiar design considerations.  In such
+cases, a scheme that tolerates a small percentage of black-listed codes
+would provide an increased recall (i.e. more true positives).  This,
+however, incurs a reduced precision, since false positives are also more
+likely to appear in binary files that contain large chunks of textual
+data.  "Polluted" plain text may, in fact, be regarded as binary, on
+which text conversions should not be performed.  Under this premise, it
+is safe to say that the detection method provides a near-100% recall.
+
+Experiments have been run on a large set of files of various categories,
+including plain old texts, system logs, source code, formatted office
+documents, compiled object code, etcetera.  The results confirm the
+optimistic assumptions about the high accuracy, precision and recall
+offered by this algorithm.
+
+
+--
+Cosmin Truta
+Last updated: 2005-Feb-27
diff --git a/proginfo/ziplimit.txt b/proginfo/ziplimit.txt
new file mode 100644 (file)
index 0000000..feacabb
--- /dev/null
@@ -0,0 +1,243 @@
+ziplimit.txt
+
+Zip 3 and UnZip 6 now support many of the extended limits of Zip64.
+
+A) Hard limits of the Zip archive format:
+
+   Number of entries in Zip archive:            64 k (2^16 - 1 entries)
+   Compressed size of archive entry:            4 GByte (2^32 - 1 Bytes)
+   Uncompressed size of entry:                  4 GByte (2^32 - 1 Bytes)
+   Size of single-volume Zip archive:           4 GByte (2^32 - 1 Bytes)
+   Per-volume size of multi-volume archives:    4 GByte (2^32 - 1 Bytes)
+   Number of parts for multi-volume archives:   64 k (1^16 - 1 parts)
+   Total size of multi-volume archive:          256 TByte (4G * 64k)
+
+   The number of archive entries and of multivolume parts are limited by
+   the structure of the "end-of-central-directory" record, where the these
+   numbers are stored in 2-Byte fields.
+   Some Zip and/or UnZip implementations (for example Info-ZIP's) allow
+   handling of archives with more than 64k entries.  (The information
+   from "number of entries" field in the "end-of-central-directory" record
+   is not really neccessary to retrieve the contents of a Zip archive;
+   it should rather be used for consistency checks.)
+
+   Length of an archive entry name:             64 kByte (2^16 - 1)
+   Length of archive member comment:            64 kByte (2^16 - 1)
+   Total length of "extra field":               64 kByte (2^16 - 1)
+   Length of a single e.f. block:               64 kByte (2^16 - 1)
+   Length of archive comment:                   64 KByte (2^16 - 1)
+
+   Additional limitation claimed by PKWARE:
+     Size of local-header structure (fixed fields of 30 Bytes + filename
+      local extra field):                     < 64 kByte
+     Size of central-directory structure (46 Bytes + filename +
+      central extra field + member comment):  < 64 kByte
+
+   Note:
+   In 2001, PKWARE has published version 4.5 of the Zip format specification
+   (together with the release of PKZIP for Windows 4.5).  This specification
+   defines new extra field blocks that allow to break the size limits of the
+   standard zipfile structures.  In this extended Zip format, the size limits
+   of zip entries (and the complete zip archive) have been extended to
+   (2^64 - 1) Bytes and the maximum number of archive entries to (2^32-1).
+   Zip 3.0 supports these Zip64 extensions and should be released shortly.
+   UnZip 6.0 should support these standards.
+
+B) Implementation limits of UnZip:
+
+   Note:
+   This section should be updated when UnZip 6.0 is near release.
+
+ 1. Size limits caused by file I/O and decompression handling:
+   Size of Zip archive:                 2 GByte (2^31 - 1 Bytes)
+   Compressed size of archive entry:    2 GByte (2^31 - 1 Bytes)
+
+   Note: On some systems, UnZip may support archive sizes up to 4 GByte.
+         To get this support, the target environment has to meet the following
+         requirements:
+         a) The compiler's intrinsic "long" data types must be able to hold
+            integer numbers of 2^32. In other words - the standard intrinsic
+            integer types "long" and "unsigned long" have to be wider than
+            32 bit.
+         b) The system has to supply a C runtime library that is compatible
+            with the more-than-32-bit-wide "long int" type of condition a)
+         c) The standard file positioning functions fseek(), ftell() (and/or
+            the Unix style lseek() and tell() functions) have to be capable
+            to move to absolute file offsets of up to 4 GByte from the file
+            start.
+         On 32-bit CPU hardware, you generally cannot expect that a C compiler
+         provides a "long int" type that is wider than 32-bit. So, many of the
+         most popular systems (i386, PowerPC, 680x0, et. al) are out of luck.
+         You may find environment that provide all requirements on systems
+         with 64-bit CPU hardware. Examples might be Cray number crunchers
+         or Compaq (former DEC) Alpha AXP machines.
+
+   The number of Zip archive entries is unlimited. The "number-of-entries"
+   field of the "end-of-central-dir" record is checked against the "number
+   of entries found in the central directory" modulus 64k (2^16).
+
+   Multi-volume archive extraction is not supported.
+
+   Memory requirements are mostly independent of the archive size
+   and archive contents.
+   In general, UnZip needs a fixed amount of internal buffer space
+   plus the size to hold the complete information of the currently
+   processed entry's local header. Here, a large extra field
+   (could be up to 64 kByte) may exceed the available memory
+   for MSDOS 16-bit executables (when they were compiled in small
+   or medium memory model, with a fixed 64kByte limit on data space).
+
+   The other exception where memory requirements scale with "larger"
+   archives is the "restore directory attributes" feature. Here, the
+   directory attributes info for each restored directory has to be held
+   in memory until the whole archive has been processed. So, the amount
+   of memory needed to keep this info scales with the number of restored
+   directories and may cause memory problems when a lot of directories
+   are restored in a single run.
+
+C) Implementation limits of the Zip executables:
+
+   Note:
+   This section has been updated to reflect Zip 3.0.
+
+ 1. Size limits caused by file I/O and compression handling:
+   Without Zip64 extensions:
+    Size of Zip archive:                 2 GByte (2^31 - 1 Bytes)
+    Compressed size of archive entry:    2 GByte (2^31 - 1 Bytes)
+    Uncompressed size of entry:          2 GByte (2^31 - 1 Bytes),
+                                         (could/should be 4 GBytes...)
+   Using Zip64 extensions:
+    Size of Zip archive:                 2^63 - 1 Bytes
+    Compressed size of archive entry:    2^63 - 1 Bytes
+    Uncompressed size of entry:          2^63 - 1 Bytes
+   
+   Multi-volume archive creation now supported in the form of split
+   archvies.  Currently up to 99,999 splits are supported.
+
+ 2. Limits caused by handling of archive contents lists
+
+ 2.1. Number of archive entries (freshen, update, delete)
+     a) 16-bit executable:              64k (2^16 -1) or 32k (2^15 - 1),
+                                        (unsigned vs. signed type of size_t)
+     a1) 16-bit executable:             <16k ((2^16)/4)
+         (The smaller limit a1) results from the array size limit of
+         the "qsort()" function.)
+
+         32-bit executables:            <1G ((2^32)/4)
+         (usual system limit of the "qsort()" function on 32-bit systems)
+
+     b) stack space needed by qsort to sort list of archive entries
+
+     NOTE: In the current executables, overflows of limits a) and b) are NOT
+           checked!
+
+     c) amount of free memory to hold "central directory information" of
+        all archive entries; one entry needs:
+        96 bytes (32-bit) resp. 80 bytes (16-bit)
+        + 3 * length of entry name
+        + length of zip entry comment (when present)
+        + length of extra field(s) (when present, e.g.: UT needs 9 bytes)
+        + some bytes for book-keeping of memory allocation
+
+   Conclusion:
+     For systems with limited memory space (MSDOS, small AMIGAs, other
+     environments without virtual memory), the number of archive entries
+     is most often limited by condition c).
+     For example, with approx. 100 kBytes of free memory after loading and
+     initializing the program, a 16-bit DOS Zip cannot process more than 600
+     to 1000 (+) archive entries.  (For the 16-bit Windows DLL or the 16-bit
+     OS/2 port, limit c) is less important because Windows or OS/2 executables
+     are not restricted to the 1024k area of real mode memory.  These 16-bit
+     ports are limited by conditions a1) and b), say: at maximum approx.
+     16000 entries!)
+
+
+ 2.2. Number of "new" entries (add operation)
+     In addition to the restrictions above (2.1.), the following limits
+     caused by the handling of the "new files" list apply:
+
+     a) 16-bit executable:              <16k ((2^64)/4)
+
+     b) stack size required for "qsort" operation on "new entries" list.
+
+     NOTE: In the current executables, the overflow checks for these limits
+           are missing!
+
+     c) amount of free memory to hold the directory info list for new entries;
+        one entry needs:
+        24 bytes (32-bit) resp. 22 bytes (16-bit)
+        + 3 * length of filename
+
+     NOTE: For larger systems, the actual limits may be more performance
+     issues (how long you want to wait) rather than available memory and other
+     resources.
+
+D) Some technical remarks:
+
+ 1. For executables compiled without LARGE_FILE_SUPPORT and ZIP64_SUPPORT
+    enabled, the 2GByte size limit on archive files is a consequence of
+    the portable C implementation of the Info-ZIP programs.  Zip archive
+    processing requires random access to the archive file for jumping
+    between different parts of the archive's structure.  In standard C,
+    this is done via stdio functions fseek()/ftell() resp. unix-io functions
+    lseek()/tell().  In many (most?) C implementations, these functions use
+    "signed long" variables to hold offset pointers into sequential files.
+    In most cases, this is a signed 32-bit number, which is limited to
+    ca. 2E+09.  There may be specific C runtime library implementations
+    that interpret the offset numbers as unsigned, but for us, this is not
+    reliable in the context of portable programming.
+
+    If LARGE_FILE_SUPPORT and ZIP64_SUPPORT are defined and supported by
+    the system, 64-bit off_t file offsets are supported and the above
+    larger limits are supported.  As off_t is signed, the maximum offset
+    is usually limited to 2^63 - 1.
+
+ 2. The 2GByte limit on the size of a single compressed archive member
+    is again a consequence of the implementation in C.
+    The variables used internally to count the size of the compressed
+    data stream are of type "long", which is guaranted to be at least
+    32-bit wide on all supported environments.
+
+    But, why do we use "signed" long and not "unsigned long"?
+
+    Throughout the I/O handling of the compressed data stream, the
+    sign bit of the "long" numbers is (mis-)used as a kind of overflow
+    detection. In the end, this is caused by the fact that standard C
+    lacks any overflow checking on integer arithmetics and does not
+    support access to the underlying hardware's overflow detection
+    (the status bits, especially "carry" and "overflow" of the CPU's
+    flags-register) in a system-independent manner.
+
+    So, we "misuse" the most-significant bit of the compressed data
+    size counters as carry bit for efficient overflow/underflow detection.
+    We could change the code to a different method of overflow detection,
+    by using a bunch of "sanity" comparisons (kind of "is the calculated
+    result plausible when compared with the operands"). But, this would
+    "blow up" the code of the "inner loop", with remarkable loss of
+    processing speed. Or, we could reduce the amount of consistency checks
+    of the compressed data (e.g. detection of premature end of stream) to
+    an absolute minimum, at the cost of the programs' stability when
+    processing corrupted data.
+
+    Summary: Changing the compression/decompression core routines to
+    be "unsigned safe" would require excessive recoding, with little
+    gain on maximum processable uncompressed size (a gain can only be
+    expected for hardly compressable data), but at severe costs on
+    performance, stability and maintainability.  Therefore, it is
+    quite unlikely that this will ever happen for Zip/UnZip.
+
+    With LARGE_FILE_SUPPORT and ZIP64_SUPPORT enabled and supported,
+    the above arguments still apply, but the limits are based on 64 bits
+    instead of 32 and should allow most large files and archives to be
+    processed.
+
+    Anyway, the Zip archive format is more and more showing its age...
+    The effort to lift the 2GByte limits should be better invested in
+    creating a successor for the Zip archive format and tools.  But given
+    the latest improvements to the format and the wide acceptance of zip
+    files, the format will probably be around for awhile more.
+
+Please report any problems using the web contact form at:  www.Info-ZIP.org
+
+Last updated:  26 January 2002, Christian Spieler
+               25 May 2008, Ed Gordon
diff --git a/qdos/IZREADME.SMS b/qdos/IZREADME.SMS
new file mode 100644 (file)
index 0000000..9ad1503
--- /dev/null
@@ -0,0 +1,600 @@
+IZREADME_SMS (IZREADME.SMS): Info-ZIP for SMS/QDOS,   last revised: 15-Jun-1998
+===============================================================================
+[was "InfoZIP_SMSQDOS_ReadMe" in J. Hudson's original ports, ca. 08/1995]
+
+Info-ZIP Programs
+=================
+
+Zip
+UnZip
+UnZipSFX
+fUnZip
+
+Introduction
+------------
+
+This archive is a result of frustrations with contemporary (August 95)
+versions of Zip and UnZip. While they use the same compression
+algorithms as the Info-ZIP programs, there the compatibility ends. If
+you just use Zip/UnZip only on SMS/QDOS, then perhaps this is not a
+problem (but I know for some users it still is); if you use Zip/UnZip
+to transport source code and data between diverse systems, then the
+disregard for Info-ZIP standards is inconvenient, particularly the
+fact that directories are not supported and files are always stored
+underscored.
+
+This release of Zip/UnZip offers:
+
+    o   zipfile/directory compatibility with all other supported
+        platforms
+
+    o   SMS/QDOS compatibility and back-compatible with earlier
+        versions.
+
+    o   Improved performance (Zip is typically 50% faster)
+
+    o   Command-line compatibility with Info-ZIP
+
+    o   Self-extracting archives (but not very elegantly)
+
+    o   Archives are marked as 'created by SMS/QDOS'.
+
+    o   Optional recursion into directories
+
+    o   Directory structure restored on unzip of Info-ZIP/PKZIP-
+        compatible archives.
+
+    o   Config'urable for listing and unpack formats (Info-ZIP (.) or
+        SMS/QDOS (_) and 'Press any key' timeouts. Override options
+        from command line.
+
+Info-ZIP Standards
+------------------
+
+This (rather long-winded and waffling) section discusses the
+conventions and standards used by Info-ZIP-compatible archivers and how
+"Info-ZIP for SMS/QDOS" achieves compatibility.
+
+Info-ZIP Zip/UnZip on all supported platforms (Unix, DOS, OS/2, NT,
+VAX/VMS, Amiga etc etc), works in a specific way. (Until now SMS/QDOS
+was neither 'supported' nor Info-ZIP-compliant.)
+
+    a. The zipfile directory is in (/.) (Unix) format.
+
+    b. When zips are listed, it is in 'zipfile' (Unix) format.
+
+    c. When files are added, they are defined in native format.
+
+    d. When files are added, this is shown in 'zipfile' format.
+
+    e. When files are unpacked, this is done to native format, but
+       selection is done in 'zipfile' format.
+
+Basically, the listing and stored format of a file is that of the
+destination.
+
+So, given a file structure at some arbitrary 'root' level.
+
+    Makefile
+    src (Dir)
+        afile.c
+        bfile.c
+        docs (Dir)
+             prog.txt
+    hdr (Dir)
+        cfile.h
+        dfile.h
+
+Then these would be in Unix (and Amiga) as
+
+     Makefile
+     src/afile.c
+     src/bfile.c
+     src/docs/prog.txt
+     hdr/cfile.h
+     hdr/dfile.h
+
+This is also how the zipfile directory appears.
+
+And in DOS/OS2/NT
+
+    Makefile
+    src\afile.c
+    src\docs\prog.txt
+    hdr\cfile.h         .. etc
+
+And in VMS      (we SHOUT in VMS and have a silly file system)
+
+    MAKEFILE
+    [SRC]AFILE.C
+    [SRC.DOC]PROG.TXT
+    [HDR]CFILE.H        .. etc
+                        (OK VMS purist, [.SRC] etc. Only an example)
+
+And in SMS/QDOS (quiet again, but slightly ludicrous !)
+
+    Makefile
+    src_afile_c
+    src_doc_prog_txt
+    hdr_cfile_h         .. etc
+
+The main problem regarding SMS/QDOS is not that of extensions - (after
+all, only VMS and DOS _really_ have extensions; Unix, AmigaDOS, NT and
+OS/2 (and Win95) allow multiple '.' in.long.file.names.
+
+The SMS/QDOS problem is that '_' is both a legal file name character
+and a directory separator. This creates the difficulties, as
+directories and files are somewhat different objects.
+
+It is the intention that these versions of SMS/QDOS Zip/UnZip will
+follow the Info-ZIP rules, thus providing compatibility with the other
+platforms. It is possible to zip the file structure described above on
+SMS/QDOS and unpack it on VMS and get the VMS structure as shown in the
+example (and vice-versa). [We only choose the most obtuse file
+systems for the examples].
+
+In order to achieve this, SMS/QDOS names are mapped into Unix-style
+ones when the zipfile is created and un-mapped when it is unpacked.
+There is an option to unpack in 'zipfile' format (i.e. with '.' rather
+than '_'), but there will be no option to pack to all '_'. That would
+contravene the standard.  However, a file
+
+        src_split_name_c        (which is src->split_name_c !)
+                                          src/split_name.c)
+
+where src is a hard directory, would be stored in the zip directory as
+
+      src/split_name.c
+
+It does handle '_' with a little intelligence.
+
+The default UnZip option will be to translate '.' to '_'; this is
+because there are still many QDOS/Minerva users that cannot handle '.'
+without quotes, which is immensely inconvenient. For many SMS users
+'_' is also the most natural and convenient option. It also means that
+SMS/QDOS <-> SMS/QDOS Zip - UnZip sequences are transparent.
+
+There will, however, be two ways around this in UnZip.
+
+      1. It is possible to Config the UnZip default to be '.'
+         translations (or not).
+
+      2.  The UnZip -Q1 option will toggle the default (Config'ed)
+          state.
+
+Examples:
+
+Given that we want/have
+
+     Makefile                   (Makefile)
+     src/afile.c                (src_afile_c)
+     src/bfile.c                (src_bfile_c)
+     src/docs/prog.txt          (src_docs_prog_txt)
+     hdr/cfile.h                (hdr_cfile_h)
+     hdr/dfile.h                (hdr_dfile_h)
+
+Then on SMS/QDOS we might have added the *.c files as
+
+     ex zip;'-r test *_c'
+
+(or VMS, just to do something different)
+
+    zip -r test [.src]*.c
+
+In both cases the file lists as above (left).
+
+To unpack on SMS/QDOS (just the _c/.c files)
+
+   ex unzip;'test src/*.c'
+
+   (and VMS, unzip test src/*.c)
+
+i.e. in both cases using the 'zipfile' format. As a concession to
+SMS/QDOS, you could also have:
+
+   ex unzip;'test src_*_c'
+
+        but not unzip test [.src]*.c on VMS !!!!! Sorry, dinosaurs.
+
+Both SMS/QDOS commands unpack to
+
+     src_afile_c etc, where src_ is a hard sub-directory.
+
+(and the VMS example would unpack to [.src]afile.c, (or to src\afile.c on
+DOS/NT/OS2 etc).
+
+Options & SMS/QDOS Features
+---------------------------
+
+The options supported by Zip/UnZip are basically those documented in
+the Info-ZIP documents and shown in on-line 'usage'. In particular, -r
+and -j work as intended.
+
+PLEASE NOTE: Previous SMS/QDOS zip/unzips have NOT followed these
+conventions, for example -r was not implemented and -j was reversed.
+
+A number of -Q (SMS/QDOS-specific) options (not yet in the current
+documents or usage screens) are implemented.
+
+The Zip 2.0.1 (and later) default is to add SMS/QDOS headers where
+file type = 1 (exe) or 2 (rel) or (type > 0 && != 255 and (filesize %
+64) != 0). Directories are included anyway, unless you zip -D.
+
+Where a header is added for an 'exe' file a '*' is displayed after the
+name in the zip display  (and '#' for 'rel' files).
+
+The -Q options for Zip are:
+
+    -Q1  Don't add headers for ANY files
+    -Q2  Add headers for all files
+    -Q4  Don't wait for interactive key press
+
+    (additive, so -Q5 => no headers, no wait, -Q6 all headers,
+     no wait etc)
+
+    (the default is exec/rel headers, 5 sec wait)
+
+Zip has rationalised the file header storage in zipfiles. The
+previous Zip used to store a QDOS header for each file. This was very
+wasteful, for example compressing a SMS/QDOS release of PGP in this
+way came to 730Kb, too large for a DD disk. Changing the Zip program
+just to add a header record for the single PGP exe and the zipfile
+size went down to around 690Kb.
+
+And for UnZip
+
+    -Q1 Toggle unpack format status ('.' <-> '_')
+    -Q2 Toggle listing format
+    -Q4 Don't wait for key press
+
+Files Types
+-----------
+
+The history of QDOS suffers from incompatible feature
+implementations. For example, Thor directories have file type 3, CST
+have type 4 and Level 2 have type 255. Some software writers (both
+amateur and otherwise) have used type 3 or 4 for other purposes
+(backward compatibility ?? who cares ??).
+
+In order to bypass problems cause by incompatible (inconsiderate ?)
+usage of file types, the file type denoting a directory is a
+Config'urable item. The default is set to -1 (65535 in Config terms),
+which means "determine directory type from the file header of the root
+directory". If this is appears unsuccessful on your system, the value
+can be Config'ed in the range 3-255.
+
+Zip assumes a file is a directory if:
+
+        ((type == CONFIGed_type) && (file_size % 64) == 0)
+
+If you are unfortunate enough have files of that pass this test but
+are not directories, then Zip will loop endless, as SMS/QDOS opens the
+root directory again !!! (recursion: see recursion etc).
+
+I suggest you refrain from zipping such files and contact the software
+supplier and point out the error of their ways.
+
+File Naming Issues
+------------------
+
+Zip will append a '_zip' suffix to the archive filename when the
+supplied name (i.e. excluding device/directory parts) does not
+contain a '_' or a '.'. This is broadly compatible with Info-ZIP,
+taking into account the '_' aberation.
+
+So
+        ex zip;'ram2_test ...'          >> ram2_test_zip
+
+        ex zip;'ram2_test.zip ...'      >> ram2_test.zip
+
+        ex zip;'ram2_test_rep ... '     >> ram2_test_rep
+
+        ex zip;'ram2_fdbbs.rep ... '    >> ram2_fdbbs.rep
+
+        ex zip;'ram2_test_rep.zip ...'  >> ram2_test_rep.zip
+
+This implies that if a file ram2_test.zip exists, and you do:
+
+        ex zip;'ram2_test ...'
+
+Then a new file (test_zip) is created, rather than 'test.zip' being
+updated.
+
+Zip supports extensive recursive wild-carding, again the fact that '_'
+can be a directory separator as well as part of a file name makes this
+a bit tricky, but given the example:
+
+     test1_bas
+     test2_bas
+     dir1->demo1_bas            where -> indicates a sub dir
+     dir2->demo2_bas
+
+     ex zip;'ram2_test *_bas'
+     just finds test1_bas, test2_bas
+
+     ex zip;'-r ram2_test *_bas'
+     recurses and finds all the files
+
+You might think that
+
+    ex zip;'-r ram2_test *_*_bas'
+
+would just find the files in the subdirectories--well yes, but it will
+also find very other sub-dir'ed _bas file on the disk too. This is
+a feature.
+
+The pattern matching supports Unix-style 'regex' so you could:
+
+        ex zip;'ram2_test dir?_*_bas'
+        or
+        ex zip;'ram2_test dir[12]_*_bas
+
+
+UnZip has now got a fixed -d option. This is used to specify the
+directory to unpack the zipfile into, it must follow immediately
+after the zip name.
+
+        ex unzip;'ram2_test_zip -d ram3_ *_txt'
+
+would unpack all *_txt files to ram3_ .
+
+It is not necessary to set the default directory to pack files, Zip
+will remove any device names (and store any hard directory names,
+unless you zip -j).
+
+        ex zip;'ram1_test flp1_*'
+
+                ----->
+                        adding: file.dat (deflated 50%)
+                        adding: menu.rext # (deflated xx%)
+                        adding: zip * (deflated yy%)
+                        adding: hard_one (stored 0%)
+                        adding: hard_one/stuff.bas (deflated ...)
+
+Due to the way the file-mapping is implemented, it is not supported
+over the nX_ type network device.
+
+Config Options
+--------------
+
+A limited number of SMS/QDOS specific functions can be set using the
+QJump Config program.
+
+      For Zip:
+
+      Timeout for interactive 'Press any key' prompt
+
+       65535                  Wait forever      (aka -1)
+       0                      No wait
+       n (1-32767)            Wait for 'n' clocks (1/50 sec)
+
+       Other values are unsupported. Note Config works on 'unsigned'
+       integer values (at least according to my manual).
+
+       Directory file type key.
+
+       Config will accept any value in the range 3-255, known useful
+       values are 3 (Thor), 4 (CST) and 255 (Level 2 devices). A value
+       of 65535 (aka -1) means "determine from device info".
+
+       For UnZip:
+
+       Timeout as above
+
+       Unpack mode (SMS/QOS ('_') or Info-ZIP ('.')
+
+       List format (Info-ZIP ('.') or SMS/QDOS ('_')
+
+
+When the 'Press a key' text is displayed, if you press ESC, then it
+waits until you press any other key, infinite timeout. This may be
+useful if you want (much) more time to study a listing etc.
+
+Defaults for timeout and directory type are 250 and -1 respectively.
+
+More Goodies
+------------
+
+Part of the Zip compression code is now in assembler; it runs
+noticably faster than the previous version. Compressing some arbitrary
+files with the previous Zip it took 251 seconds, with Zip 2.0.1 it
+took (a mere) 170 seconds (68008 QL).
+
+More good news is that SMS/QDOS is just another system option on top
+of standard Info-ZIP, unlike the previous ports that were much more
+SMS/QDOS specific. For example, compiling the standard source with c68
+(i.e. #define QDOS), then you get an SMS/QDOS version.
+
+Compile with Linux/gcc and get the standard Linux version. Now, here's
+the cool bit; compile with Linux/gcc and "-DQLZIP", and get a standard
+Linux Zip/UnZip with SMS/QDOS (header) extensions.
+
+so, on Linux:
+
+            zip -Q stuff.zip qtpi zip unzip
+
+the -Q tells Zip to look for XTc68/Lux68 cross-compiler data size
+blocks and produce a zipfile with SMS/QDOS headers in it (for exec
+type programs). This works for exec files produced by the XTc68/Lux68
+cross compilers and ANY SMS/QDOS files copied to a Unix or MS-DOS disk
+from an SMS/QDOS floppy using 'qltools v2.2' (or later).
+
+Self Extracting Archives
+------------------------
+
+Info-ZIP self-extracting archives (_sfx) are created in a rather
+'brute-force' way. The UnZipSFX program is prepended to a zipfile.
+
+i.e.          file_sfx = unzipsfx + file_zip
+              ex file_sfx
+
+Although the UnZipSFX program is a cut-down UnZip, it is still around
+30Kb - 50Kb, depending on platform.
+
+The success of this approach depends on how the operating system
+loader loads executable files. On most systems where the loader only
+loads the actual program part (Unix, VMS, DOS et al), the this is
+quite efficient; if you make, say, a 4Mb zipfile and prepend a 30Kb
+UnZipSFX image, then the system only loads the 30Kb program and the
+process is efficient as the zipped data part is still unpacked from
+disk. These systems also supply the running UnZipSFX program stub with
+the path name of the file it was loaded from, so the program knows
+what it has to unpack (so on Linux, for example):
+
+     cat /usr/bin/unzipsfx test.zip > test.sfx  # concatenate the files
+     chmod 755 test.sfx                         # make executable
+     test.sfx                                   # to extract, it
+                                                # 'knows' it is "test.sfx"
+
+Unfortunately, the more simplistic nature of SMS/QDOS makes this much
+more difficult and rather less efficient as: (see note 1)
+
+     a. The SMS/QDOS 'loader' loads the whole file into memory.
+
+     b. The SMS/DOS 'loader'/c68 run-time system does not return the
+        name of the file from which it was loaded.
+
+     c. You cannot so easily create a image file by concatenating two
+        files, it is also necessary to ensure the executable file
+        header is set correctly.
+
+     d. The show stopper. The data space required for the
+        self-extracting archive is required, as not easily maintained
+        during electronic transfer.
+
+
+If anyone is still interested, then the following support for UnZipSFX
+is provided.
+
+ o A program 'makesfx' will combine a stub (callstub), UnZipSFX image
+   and a zipfile to produce a sfx (self-extracting zip) file.
+
+ o A callable interface is supplied. The user calls the SFX file,
+   which creates the files necessary to do the extraction.
+
+The makesfx program concatenates the supplied files to standard
+output.
+
+So, to create a sfx of all the _c files in the default directory.
+
+ # 1st create a zipfile of the required files
+
+ ex zip;'ram1_test_zip *_c'
+
+ # Now create the sfx file (ram2_test_sfx)
+ # our UnZipSFX image is in 'win1_bin'
+ # as is the call stub.
+
+ex makesfx;'-o test_sfx -x win1_bin_unzipsfx -s win1_bin_callstub -z ram1_test_zip'
+
+The arguments to makesfx are:
+
+    -s stubfile
+    -x UnZipSFX_program
+    -z Zip_file
+    -o Output_file
+
+You can now unpack the _sfx file on any SMS/QDOS-compatible
+system.
+
+        f$ = "win2_tmp_test_sfx"
+        a = alchp(flen(\f$))
+        lbytes f$,a
+        call a
+        rechp(a)
+
+ZipInfo
+-------
+
+Given the above note concerning SMS/QDOS programs not knowing the name
+by which the program was invoked, then the usual symbolic-link-of-unzip-
+to-zipinfo trick is unavailable (presupposing there is some some SMS/QDOS
+trick to emulate symbolic links).
+
+ZipInfo functionality is only available via 'unzip -Z'. There is no
+separate ZipInfo program.
+
+Caveat ATP Users
+----------------
+
+ATP for SMS/QDOS users should pay particular attention to the
+Zip/UnZip options in their atprc and compare with Info-ZIP Zip/UnZip
+usage. Older versions of Zip/UnZip screwed up -j.
+
+
+        zip -jk
+        unzip -jo
+
+Distribution & Copyright
+------------------------
+
+This software is written by and largely copyrighted by the 'Info-ZIP'
+group whose members are noted in the accompanying documentation. This
+particular SMS/QDOS port plus 'makesfx' was written by, but is not
+copyrighted by, Jonathan R Hudson. The SMS/QDOS code in this release
+is written from scratch and is not dependent on previous SMS/QDOS
+releases, but is (largely) compatible.
+
+As a courtesy to the authors of this package, please ensure that the
+documentation is supplied when it is re-distributed.
+
+In particular, if this archive is split into Zip and UnZip components,
+ensure that this document ("IZREADME_SMS") is supplied in
+each component.
+
+SMS/QDOS version by:
+Jonathan R Hudson (jrhudson@bigfoot.com)
+
+I am grateful to Graham Goodwin for finding some most imaginative
+means of breaking the beta code.
+
+I'd also like to thank Thierry Godefroy for providing the 2.1/5.2
+source code and making the initial contact with the Info-ZIP group.
+
+And of course, many, many thanks to the Info-ZIP workers for making
+this code freely available.
+
+Note 1
+------
+
+The 'C' language FAQ ('frequently asked questions' [comp.lang.c])
+notes on the matter of obtaining the load file name of a 'C' program:
+
+16.5:   How can my program discover the complete pathname to the
+        executable file from which it was invoked?
+
+A:      argv[0] may contain all or part of the pathname, or it may
+        contain nothing.  You may be able to duplicate the command
+        language interpreter's search path logic to locate the
+        executable if the name in argv[0] is present but incomplete.
+        However, there is no guaranteed or portable solution.
+                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Note 2
+------
+
+NUL files for SMS2. There appears to be a conflict between SMS2/LBASIC
+compiled programs and c68 programs using nul as stdin.
+
+        EW zip,nul;'ram1_test *_bas'    # will not work
+
+                                        # This does work !
+        EW zip,#FOP_IN('nul');'ram2_test *_bas' : CLOSE
+
+Note 3
+------
+
+version number incremented to 2.0.1a and 5.12a to accomodate Erling
+Jacobsen's exit message requirements
+
+version number incremented to Zip 2.0.1b to fix bug on zipping files
+starting with leading underscore.
+
+version number incremented to UnZip 5.12b to fix UnZip problem on
+files zipped with leading './', and linked with revised (fixed) c68
+'utime' function (could corrupt level 1 files). (source code _only_ as
+IZQ004.zip).
+
+Ported Zip 2.1 and UnZip 5.2 (July 1996). Released as INZIP005.zip
+
+All later versions --- see Info-ZIP release notes and documentation.
diff --git a/qdos/Makefile.qdos b/qdos/Makefile.qdos
new file mode 100644 (file)
index 0000000..df68aad
--- /dev/null
@@ -0,0 +1,145 @@
+include /etc/ql.mak
+
+# Makefile for Zip, ZipNote, ZipCloak and ZipSplit
+
+MAKE = make
+SHELL = /bin/sh
+
+#
+BIND = $(CC)
+
+# probably can change this to 'install' if you have it
+INSTALL = cp
+
+# target directories - where to install executables and man pages to
+BINDIR =
+manext=1
+MANDIR =
+ZIPMANUAL = MANUAL
+
+# flags
+#   CFLAGS    flags for C compile
+#   LFLAGS1   flags after output file spec, before obj file list
+#   LFLAGS2   flags after obj file list (libraries, etc)
+CFLAGS = -O -DASMV -DASM_CRC
+LFLAGS1 = -v
+#LFLAGS2 = -lutime
+
+all: zip
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crypt.o qdos.o ttyio.o
+OBJI = deflate.o trees.o qfileio.o crc32.o
+OBJA = config.o crc68.o match.o
+#  crc32.o
+OBJQ = qdos_.o config.o qfileio_.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o $(OBJQ)
+OBJN = zipnote.o  $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o
+OBJS = zipsplit.o $(OBJU)
+
+
+# suffix rules
+.SUFFIXES:
+.SUFFIXES: _.o .o .c .doc .1
+.c_.o:
+       rm -f $*_.c; ln $< $*_.c
+       $(CC) $(CFLAGS) -DUTIL -c $*_.c
+       rm -f $*_.c
+.c.o:
+       $(CC) $(CFLAGS) -c $<
+
+.1.doc:
+       nroff -man $< | col -b | uniq > $@
+
+# rules for zip, zipnote, zipcloak, zipsplit, and zip.doc.
+$(OBJZ): zip.h ziperr.h tailor.h
+$(OBJI): zip.h ziperr.h tailor.h
+$(OBJN): zip.h ziperr.h tailor.h
+$(OBJS): zip.h ziperr.h tailor.h
+$(OBJC): zip.h ziperr.h tailor.h
+zip.o zipup.o crc32.o crypt.o fileio.o zipfile.o:  crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o:  crc32.h
+zip.o zipup.o crypt.o zipup_.o zipcloak.o crypt_.o:  crypt.h
+
+qfileio.o: qdos/qfileio.c
+       cp qdos/qfileio.c qfileio.c
+       $(CC) $(CFLAGS) -c qfileio.c
+       rm -f qfileio.c
+
+qfileio_.o: qdos/qfileio.c
+       cp qdos/qfileio.c qfileio_.c
+       $(CC) $(CFLAGS) -DUTIL -c qfileio_.c
+       rm -f qfileio_.c
+
+match.o: qdos/match.s
+       cp qdos/match.s ./_match.s
+       $(AS) _match.s -o match.o
+       rm -f _match.s
+
+crc68.o: qdos/crc68.s
+       cp qdos/crc68.s ./crc68.s
+       $(AS) crc68.s -o crc68.o
+       rm -f crc68.s
+
+config.o: qdos/config.s
+       cp qdos/config.s ./config.x
+       $(CC) -c -DZIP config.x -o config.o
+       rm -f config.x
+
+ZIPS = zip$E zipnote$E zipsplit$E zipcloak$E
+
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zips: $(ZIPS)
+zipsman: $(ZIPS) $(ZIPMANUAL)
+
+qdos.o:   qdos/qdos.c
+       cp qdos/qdos.c .
+       $(CC) -c -oqdos.o qdos.c
+       rm -f qdos.c
+
+qdos_.o:  qdos/qdos.c
+       cp qdos/qdos.c ./qdos_.c
+       $(CC) -DUTIL -c -oqdos_.o qdos_.c
+       rm -f qdos_.c
+
+zip$E: $(OBJZ) $(OBJI) $(OBJA)
+       $(BIND) -o zip$E $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote$E: $(OBJN)
+       $(BIND) -o zipnote$E $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak$E: $(OBJC)
+       $(BIND) -o zipcloak$E $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit$E: $(OBJS)
+       $(BIND) -o zipsplit$E $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+$(ZIPMANUAL): man/zip.1
+       nroff -man man/zip.1 | col -b | uniq > $(ZIPMANUAL)
+
+# install
+install:        $(ZIPS)
+       $(INSTALL) $(ZIPS) $(BINDIR)
+       $(INSTALL) man/zip.1 $(MANDIR)/zip.$(manext)
+
+uninstall:
+       -cd $(BINDIR); rm -f $(ZIPS)
+       -cd $(MANDIR); rm -f zip.$(manext)
+
+flags:  configure
+       sh configure flags
+
+# These symbols, when #defined using -D have these effects on compilation:
+# ZMEM          - includes C language versions of memset(), memcpy(), and
+#                 memcmp() (util.c).
+# SYSV          - use <sys/dirent.h> and the library opendir()
+# DIRENT        - use <sys/dirent.h> and getdents() instead of <sys/dir.h>
+#                 and opendir(), etc. (fileio.c).
+# NODIR         - used for 3B1, which has neither getdents() nor opendir().
+# NDIR          - use "ndir.h" instead of <sys/dir.h> (fileio.c).
+# UTIL          - select routines for utilities (note, cloak, and split).
+# PROTO         - enable function prototypes.
+# RMDIR         - remove directories using a system("rmdir ...") call.
+# CONVEX        - for Convex make target.
+# AIX           - for AIX make target.
+# LINUX         - for linux make target.
+
+# end of Makefile
diff --git a/qdos/Makefile.qlzip b/qdos/Makefile.qlzip
new file mode 100644 (file)
index 0000000..d69009a
--- /dev/null
@@ -0,0 +1,141 @@
+# Makefile for Zip, ZipNote, ZipCloak and ZipSplit
+
+# what you can make ...
+all: zip
+
+#MAKE = make -f unix/Makefile
+SHELL = /bin/sh
+
+# (to use the Gnu compiler, change cc to gcc in CC and BIND)
+CC = cc
+BIND = $(CC)
+AS = $(CC) -c
+E =
+CPP = /lib/cpp
+
+# probably can change this to 'install' if you have it
+INSTALL = cp
+
+# target directories - where to install executables and man pages to
+prefix = /usr/local
+BINDIR = $(prefix)/bin
+manext=1
+MANDIR = $(prefix)/man/man$(manext)
+ZIPMANUAL = MANUAL
+
+# flags
+#   CFLAGS    flags for C compile
+#   LFLAGS1   flags after output file spec, before obj file list
+#   LFLAGS2   flags after obj file list (libraries, etc)
+CFLAGS = -O2 -fno-strength-reduce -I. -DUNIX -DQLZIP -DASM_CRC
+LFLAGS1 =
+LFLAGS2 = -s
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crypt.o ttyio.o \
+       unix.o crc_gcc.o crc32.o qdos.o
+OBJI = deflate.o trees.o
+OBJA =
+OBJU = zipfile_.o fileio_.o util_.o globals.o unix_.o
+OBJN = zipnote.o  $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h unix/osdep.h
+
+# suffix rules
+.SUFFIXES:
+.SUFFIXES: _.o .o .c .doc .1
+.c_.o:
+       rm -f $*_.c; ln $< $*_.c
+       $(CC) -c $(CFLAGS) -DUTIL $*_.c
+       rm -f $*_.c
+.c.o:
+       $(CC) -c $(CFLAGS) $<
+
+.1.doc:
+       nroff -man $< | col -b | uniq > $@
+
+# rules for zip, zipnote, zipcloak, zipsplit, and the Zip MANUAL.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o zipup.o crypt.o fileio.o zipfile.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: unix/zipup.h
+
+match.o: match.S
+       $(CPP) match.S > _match.s
+       $(AS) _match.s
+       mv _match.o match.o
+       rm -f _match.s
+
+unix.o: unix/unix.c
+       $(CC) -c $(CFLAGS) unix/unix.c
+
+unix_.o: unix/unix.c
+       rm -f $*_.c; ln unix/unix.c $*_.c
+       $(CC) -c $(CFLAGS) -DUTIL $*_.c
+       rm -f $*_.c
+
+qdos.o: qdos/qdos.c
+       $(CC) -c $(CFLAGS) qdos/qdos.c
+
+crc_gcc.o: crc_i386.S                  # 32bit, GNU AS
+       gcc -O3 -I. -DASM_CRC -Di386 -x assembler-with-cpp -c -o $@ crc_i386.S
+
+ZIPS = zip$E zipnote$E zipsplit$E zipcloak$E
+
+zips: $(ZIPS)
+zipsman: $(ZIPS) $(ZIPMANUAL)
+
+zip$E: $(OBJZ) $(OBJI) $(OBJA)
+       $(BIND) -o qlzip$E $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote$E: $(OBJN)
+       $(BIND) -o zipnote$E $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak$E: $(OBJC)
+       $(BIND) -o zipcloak$E $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit$E: $(OBJS)
+       $(BIND) -o zipsplit$E $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+$(ZIPMANUAL): man/zip.1
+       nroff -man man/zip.1 | col -b | uniq > $(ZIPMANUAL)
+
+# install
+install:        $(ZIPS)
+       $(INSTALL) $(ZIPS) $(BINDIR)
+       $(INSTALL) man/zip.1 $(MANDIR)/zip.$(manext)
+
+uninstall:
+       -cd $(BINDIR); rm -f $(ZIPS)
+       -cd $(MANDIR); rm -f zip.$(manext)
+
+dist:
+       zip -u9T zip`sed -e '/VERSION/!d' -e 's/.*"\(.*\)".*/\1/' \
+                         -e s/[.]//g -e q revision.h` \
+         `awk '/^Makefile/,/vms_zip.rnh/ {print $$1}' < contents`
+
+flags:  unix/configure
+       sh unix/configure "${CC}" "${CFLAGS}"
+
+# These symbols, when #defined using -D have these effects on compilation:
+# ZMEM                  - includes C language versions of memset(), memcpy(),
+#                         and memcmp() (util.c).
+# HAVE_DIRENT_H         - use <dirent.h> instead of <sys/dir.h>
+# NODIR                 - for 3B1, which has neither getdents() nor opendir().
+# HAVE_NDIR_H           - use <ndir.h> (unix/unix.c).
+# HAVE_SYS_DIR_H        - use <sys/dir.h>
+# HAVE_SYS_NDIR_H       - use <sys/ndir.h>
+# UTIL                  - select routines for utilities (note, cloak, split)
+# NO_RMDIR              - remove directories using a system("rmdir ...") call.
+# NO_PROTO              - cannot handle ANSI prototypes
+# NO_CONST              - cannot handle ANSI const
+
+#               Generic targets:
+
+# end of Makefile
diff --git a/qdos/config.s b/qdos/config.s
new file mode 100644 (file)
index 0000000..56a2a85
--- /dev/null
@@ -0,0 +1,153 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+#
+.globl _qlflag
+.globl _qlwait
+#ifdef ZIP
+.globl _dtype
+#endif
+
+.data
+        ds.w    0
+        dc.b    '<<QCFX>>01'
+#ifdef ZIP
+        dc.w    8
+        dc.b    'Info-ZIP'
+*                12345678901234567890
+        ds.w    0
+        dc.w    4
+        dc.b    'qdos'
+        ds.w    0
+#else
+        dc.w    10
+        dc.b    'Info-UNZIP'
+*                12345678901234567890
+        ds.w    0
+        dc.w    4
+        dc.b    'qdos'
+        ds.w    0
+#endif
+        dc.b    10
+        dc.b    0
+l_4:    dc.w    _qlwait-l_4
+        dc.w    0
+        dc.w    0
+l_5:    dc.w    hpt-l_5
+l_6:    dc.w    hxx-l_6
+
+#ifdef ZIP
+        dc.b    10
+        dc.b    0
+d_4:    dc.w    _dtype-d_4
+        dc.w    0
+        dc.w    0
+d_5:    dc.w    dpt-d_5
+d_6:    dc.w    dxx-d_6
+
+#else
+        dc.b    4
+        dc.b    0
+l5:
+        dc.w    list1-l5
+        dc.w    0
+l5a:
+        dc.w    Postit-l5a              ; post proc
+l6:
+        dc.w    apt-l6
+l7:
+        dc.w    axx-l7
+* -------------------------------------
+        dc.b    4
+        dc.b    0
+l8:
+        dc.w    list2-l8
+        dc.w    0
+l8a:
+        dc.w    Postit-l8a              ; post proc
+l9:
+        dc.w    bpt-l9
+la:
+        dc.w    bxx-la
+* -------------------------------------
+#endif
+        dc.w    -1                          ; end
+
+_qlflag:
+        dc.w    0
+_qlwait:
+        dc.w    250
+_dtype:
+        dc.w    255
+
+hpt:    dc.w    10
+        dc.b    'Exit Delay'
+*                12345678901234567890
+        ds.w    0
+hxx:    dc.w    0
+        dc.w    $ffff
+        dc.w    -1
+#ifdef  ZIP
+dpt:    dc.w    14
+        dc.b    'Directory Type'
+*                12345678901234567890
+        ds.w    0
+dxx:    dc.w    3
+        dc.w    $ff
+        dc.w    -1
+#else
+
+list1:
+        dc.b    0
+list2:
+        dc.b    0
+
+apt:
+        dc.w    11
+        dc.b    'Unpack Mode'
+*                12345678901234567890
+.even
+axx:    dc.b    0
+        dc.b    0
+        dc.w    8
+        dc.b    'SMS/QDOS'
+.even
+        dc.b    1
+        dc.b    0
+        dc.w    7
+        dc.b    'Default'
+.even
+        dc.w    -1
+.even
+bpt:
+        dc.w    12
+        dc.b    'Listing Mode'
+*                12345678901234567890
+.even
+bxx:
+        dc.w    0
+        dc.w    7
+        dc.b    'Default'
+.even
+        dc.b    2
+        dc.b    0
+        dc.w    8
+        dc.b    'SMS/QDOS'
+*                12345678901234567890
+.even
+         dc.w    -1
+Postit:
+        lea.l   _qlflag,a0
+        move.b  list1,d0
+        move.b  d0,(a0)
+        move.b  list2,d0
+        or.b    d0,(a0)
+        moveq   #0,d0
+        rts
+#endif
+        end
diff --git a/qdos/crc68.s b/qdos/crc68.s
new file mode 100644 (file)
index 0000000..9ee9df3
--- /dev/null
@@ -0,0 +1,99 @@
+;===========================================================================
+; Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 2000-Apr-09 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+.text
+
+.globl  _crc32          ; (ulg val, uch *buf, extent bufsize)
+.globl  _get_crc_table  ; ulg *get_crc_table(void)
+
+_crc32:
+        move.l  8(sp),d0
+        bne    valid
+        moveq  #0,d0
+        rts
+valid:  movem.l d2/d3,-(sp)
+        jsr     _get_crc_table
+        move.l  d0,a0
+        move.l  12(sp),d0
+        move.l  16(sp),a1
+        move.l  20(sp),d1
+        not.l   d0
+
+        move.l  d1,d2
+        lsr.l   #3,d1
+        bra     decr8
+loop8:  moveq  #0,d3
+        move.b (a1)+,d3
+        eor.b  d0,d3
+        lsl.w  #2,d3
+        move.l 0(a0,d3.w),d3
+        lsr.l  #8,d0
+        eor.l  d3,d0
+        moveq  #0,d3
+        move.b (a1)+,d3
+        eor.b  d0,d3
+        lsl.w  #2,d3
+        move.l 0(a0,d3.w),d3
+        lsr.l  #8,d0
+        eor.l  d3,d0
+        moveq  #0,d3
+        move.b (a1)+,d3
+        eor.b  d0,d3
+        lsl.w  #2,d3
+        move.l 0(a0,d3.w),d3
+        lsr.l  #8,d0
+        eor.l  d3,d0
+        moveq  #0,d3
+        move.b (a1)+,d3
+        eor.b  d0,d3
+        lsl.w  #2,d3
+        move.l 0(a0,d3.w),d3
+        lsr.l  #8,d0
+        eor.l  d3,d0
+        moveq  #0,d3
+        move.b (a1)+,d3
+        eor.b  d0,d3
+        lsl.w  #2,d3
+        move.l 0(a0,d3.w),d3
+        lsr.l  #8,d0
+        eor.l  d3,d0
+        moveq  #0,d3
+        move.b (a1)+,d3
+        eor.b  d0,d3
+        lsl.w  #2,d3
+        move.l 0(a0,d3.w),d3
+        lsr.l  #8,d0
+        eor.l  d3,d0
+        moveq  #0,d3
+        move.b (a1)+,d3
+        eor.b  d0,d3
+        lsl.w  #2,d3
+        move.l 0(a0,d3.w),d3
+        lsr.l  #8,d0
+        eor.l  d3,d0
+        moveq  #0,d3
+        move.b (a1)+,d3
+        eor.b  d0,d3
+        lsl.w  #2,d3
+        move.l 0(a0,d3.w),d3
+        lsr.l  #8,d0
+        eor.l  d3,d0
+decr8:  dbra   d1,loop8
+        and.w   #7,d2
+        bra     decr1
+loop1:  moveq  #0,d3
+        move.b (a1)+,d3
+        eor.b  d0,d3
+        lsl.w  #2,d3
+        move.l 0(a0,d3.w),d3
+        lsr.l  #8,d0
+        eor.l  d3,d0
+decr1:  dbra   d2,loop1
+done:   movem.l (sp)+,d2/d3
+        not.l   d0
+        rts
diff --git a/qdos/match.s b/qdos/match.s
new file mode 100644 (file)
index 0000000..53b3013
--- /dev/null
@@ -0,0 +1,138 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; match.a -- optional optimized asm version of longest match in deflate.c
+; Written by Jean-loup Gailly
+;
+; Adapted for the Amiga by Carsten Steger <stegerc@informatik.tu-muenchen.de>
+; using the code in match.S.
+; The major change in this code consists of removing all unaligned
+; word accesses, because they cause 68000-based Amigas to crash.
+; For maximum speed, UNALIGNED_OK can be defined in Makefile.sasc.
+; The program will then only run on 68020-based Amigas, though.
+;
+; This code will run with registerized parameters too, unless SAS
+; changes parameter passing conventions between new releases of SAS/C.
+
+
+;;Cur_Match      equr     d0      ; Must be in d0!
+;;Best_Len       equr     d1
+;;Loop_Counter   equr     d2
+;;Scan_Start     equr     d3
+;;Scan_End       equr     d4
+;;Limit          equr     d5
+;;Chain_Length   equr     d6
+;;Scan_Test      equr     d7
+;;Scan           equr     a0
+;;Match          equr     a1
+;;Prev_Address   equr     a2
+;;Scan_Ini       equr     a3
+;;Match_Ini      equr     a4
+
+MAX_MATCH       equ     258
+MIN_MATCH       equ     3
+WSIZE           equ     32768
+MAX_DIST        equ     WSIZE-MAX_MATCH-MIN_MATCH-1
+
+
+        .globl    _max_chain_length
+        .globl    _prev_length
+        .globl    _prev
+        .globl    _window
+        .globl    _strstart
+        .globl    _good_match
+        .globl    _match_start
+        .globl    _nice_match
+
+        .text
+        .globl   _match_init
+        .globl   _longest_match
+
+_match_init:
+        rts
+
+
+_longest_match:
+        move.l  4(sp),d0
+        movem.l d2-d7/a2-a4,-(sp)
+        move.l  _max_chain_length,d6
+        move.l  _prev_length,d1
+        lea     _prev,a2
+        lea     _window+MIN_MATCH,a4
+        move.l  _strstart,d5
+        move.l  a4,a3
+        add.l   d5,a3
+        subi.w  #MAX_DIST,d5
+        bhi     limit_ok
+        moveq   #0,d5
+limit_ok:
+        cmp.l   _good_match,d1
+        bcs     length_ok
+        lsr.l   #2,d6
+length_ok:
+        subq.l  #1,d6
+
+        move.b  -MIN_MATCH(a3),d3
+        lsl.w   #8,d3
+        move.b  -MIN_MATCH+1(a3),d3
+        move.b  -MIN_MATCH-1(a3,d1),d4
+        lsl.w   #8,d4
+        move.b  -MIN_MATCH(a3,d1),d4
+
+        bra     do_scan
+
+long_loop:
+
+        move.b  -MIN_MATCH-1(a3,d1),d4
+        lsl.w   #8,d4
+        move.b  -MIN_MATCH(a3,d1),d4
+
+short_loop:
+        lsl.w   #1,d0
+        move.w  0(a2,d0.l),d0
+        cmp.w   d5,d0
+        dbls    d6,do_scan
+        bra     return
+
+do_scan:
+        move.l  a4,a1
+        add.l   d0,a1
+
+        move.b  -MIN_MATCH-1(a1,d1),d7
+        lsl.w   #8,d7
+        move.b  -MIN_MATCH(a1,d1),d7
+        cmp.w   d7,d4
+        bne     short_loop
+        move.b  -MIN_MATCH(a1),d7
+        lsl.w   #8,d7
+        move.b  -MIN_MATCH+1(a1),d7
+        cmp.w   d7,d3
+        bne     short_loop
+
+        move.w  #(MAX_MATCH-MIN_MATCH),d2
+        move.l  a3,a0
+
+scan_loop:
+        cmpm.b  (a1)+,(a0)+
+        dbne    d2,scan_loop
+
+        sub.l   a3,a0
+        addq.l  #(MIN_MATCH-1),a0
+        cmp.l   d1,a0
+        bls     short_loop
+        move.l  a0,d1
+        move.l  d0,_match_start
+        cmp.l   _nice_match,d1
+        bcs     long_loop
+return:
+        move.l  d1,d0
+        movem.l (sp)+,d2-d7/a2-a4
+        rts
+        end
+
+
diff --git a/qdos/osdep.h b/qdos/osdep.h
new file mode 100644 (file)
index 0000000..72169c1
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef _QDOS_OPDEP
+#define _QDOS_OPDEP
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+char * ql2Unix(char *);
+char * Unix2ql(char *, char **);
+int wild (char *);
+char *LastDir(char *);
+void QDOSexit(void);
+short devlen(char *);
+
+/*
+ * XXX NO_RENAME instead of the following define ?
+ */
+#define link rename
+#define USE_CASE_MAP
+#define USE_EF_UT_TIME
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+                     procname(n, 1))
+#endif
diff --git a/qdos/qdos.c b/qdos/qdos.c
new file mode 100644 (file)
index 0000000..906519a
--- /dev/null
@@ -0,0 +1,879 @@
+/*
+  qdos/qdos.c
+
+  Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2005-Feb-10 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * Yes this  file is necessary; the QDOS file system is the most
+ * ludicrous known to man (even more so than VMS!).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include "zip.h"
+#include "crypt.h"
+#include "ttyio.h"
+
+#ifdef QDOS
+
+# include <qdos.h>
+
+#if CRYPT
+
+char *getp(m, p, n)
+    ZCONST char *m;              /* prompt for password */
+    char *p;                    /* return value: line input */
+    int n;                      /* bytes available in p[] */
+{
+    int c;                      /* one-byte buffer for read() to use */
+    int i;                      /* number of characters input */
+    char *w;                    /* warning on retry */
+
+    /* get password */
+    w = "";
+    sd_cure(getchid(0), -1);    /* enable cursor */
+    do {
+        fputs(w, stderr);       /* warning if back again */
+        fputs(m, stderr);       /* display prompt and flush */
+        fflush(stderr);
+        i = 0;
+        do {
+            c = getch();
+            if (c == 0xc2) {
+                if (i > 0) {
+                    i--; /* the `del' keys works */
+                    fputs("\b \b", stderr);
+                }
+            }
+            else if (i < n) {
+                p[i++] = c;     /* truncate past n */
+                if(c != '\n') putc('*', stderr);
+            }
+        } while (c != '\n');
+
+        putc('\n', stderr);  fflush(stderr);
+        w = "(line too long--try again)\n";
+    } while (p[i-1] != '\n');
+
+    p[i-1] = 0;                 /* terminate at newline */
+    sd_curs(getchid(0), -1);    /* suppress cursor */
+    return p;                   /* return pointer to password */
+
+} /* end function getp() */
+
+#endif /* CRYPT */
+
+
+#define __attribute__(p)
+
+int newname(char *, int, int);
+
+#else /* !QDOS */
+#define QDOS_FLMAX 36
+
+short qlflag = 0;
+
+struct qdirect  {
+    long            d_length __attribute__ ((packed));  /* file length */
+    unsigned char   d_access __attribute__ ((packed));  /* file access type */
+    unsigned char   d_type __attribute__ ((packed));    /* file type */
+    long            d_datalen __attribute__ ((packed)); /* data length */
+    long            d_reserved __attribute__ ((packed));/* Unused */
+    short           d_szname __attribute__ ((packed));  /* size of name */
+    char            d_name[QDOS_FLMAX] __attribute__ ((packed));/* name area */
+    long            d_update __attribute__ ((packed));  /* last update */
+    long            d_refdate __attribute__ ((packed));
+    long            d_backup __attribute__ ((packed));   /* EOD */
+    } ;
+#endif /* ?QDOS */
+
+#define SHORTID 0x4afb          /* in big-endian order !! */
+#define LONGID  "QDOS02"
+#define EXTRALEN (sizeof(struct qdirect) + 8)
+
+typedef struct
+{
+    unsigned short shortid __attribute__ ((packed));
+    struct
+    {
+        unsigned char lo __attribute__ ((packed));
+        unsigned char hi __attribute__ ((packed));
+    } len __attribute__ ((packed));
+    char        longid[8] __attribute__ ((packed));
+    struct      qdirect     header __attribute__ ((packed));
+} qdosextra;
+
+#ifdef USE_EF_UT_TIME
+local int GetExtraTime(struct zlist far *z, iztimes *z_utim, unsigned ut_flg);
+#endif
+
+#ifdef QDOS
+
+#define rev_short(x) (x)
+#define rev_long(x) (x)
+
+char _prog_name[] = "zip";
+char _copyright[] = "(c) Info-ZIP Group";
+long _stack = 16*1024;
+char *  _endmsg = NULL;
+
+extern void consetup_title(chanid_t,struct WINDOWDEF *);
+void (*_consetup)(chanid_t,struct WINDOWDEF *) = consetup_title;
+
+struct WINDOWDEF _condetails =
+{
+    2,
+    1,
+    0,
+    7,
+    500,
+    220,
+    2,
+    30
+};
+
+extern short qlwait;
+extern short dtype;
+
+#define CHECKDIR(p1) (((p1).d_type == dtype) && (((p1).d_length % 64) == 0))
+
+char * stpcpy (char *d, ZCONST char *s)
+{
+    while(*d++ = *s++)
+        ; /* Null loop */
+    return d-1;
+}
+
+static jobid_t chowner(chanid_t chan)
+{
+    extern char *_sys_var;
+    char *scht;
+    long *cdb;
+    long jid;
+
+    scht = *((char **)(_sys_var + 0x78));
+    cdb = *(long **)((long *)scht  + (chan & 0xffff));
+    jid = *(cdb + 2);
+    return jid;
+}
+
+void QDOSexit(void)
+{
+    jobid_t me,you;
+
+    me = getpid();
+    you = chowner(getchid(0));
+
+    if((me == you) && ((qlflag & 4) == 0))
+    {
+        if(isatty(0) && isatty(2) && qlwait)
+        {
+            char c = 0;
+            fputs("Press a key to exit", stderr);
+            if((io_fbyte(getchid(0), qlwait, &c) == 0) && c == 27)
+            {
+                io_fbyte(getchid(0), -1, &c);
+            }
+        }
+    }
+    exit(ZE_OK);
+}
+
+/* Access seems to be *always* broken in c68 */
+/* Not accurate, just works */
+
+int access (char *f, int mode)
+{
+    struct stat st;
+    int fd;
+
+    if((fd = stat(f, &st)) == 0)
+    {
+        switch(fd)
+        {
+        case F_OK:
+            break;
+        case R_OK:
+            fd = (st.st_mode & 0444) == 0;
+            break;
+        case W_OK:
+            fd = (st.st_mode & 0222) == 0;
+            break;
+        case X_OK:
+            fd = (st.st_mode & 0111) == 0;
+            break;
+        default:
+            fd = -1;
+            break;
+        }
+    }
+    return fd;
+}
+
+/* Fixup a Mickey Mouse file naming system */
+
+char * Unix2ql (char *qlname, char **dot)
+{
+    static char path[64];
+    char name[64];
+    char *q, *r, *s;
+
+    strcpy(name, qlname);
+    if(*name == '~')
+    {
+        r = name+1;
+        getcwd(path, sizeof(path));
+        q = path + strlen(path);
+        if(*(q-1) != '_')
+        {
+            *q++ = '_';
+        }
+    }
+    else
+    {
+        q = path;
+        r = name;
+    }
+
+    if(*r == '/')
+    {
+        r++;
+    }
+
+    strcpy(q, r);
+
+    while (*q)
+    {
+        if(*q == '/' || *q == '.')
+        {
+            if(*q == '.' && dot)
+            {
+                *dot = name + (q - path);
+            }
+            *q = '_';
+        }
+
+        q++;
+    }
+    return path;
+}
+
+#if 0                                 /* Not used in ZIP */
+
+GuessAltName(char *name, char *dot)
+{
+    if(dot)
+    {
+        *dot = '.';
+    }
+    else
+    {
+        if((dot = strrchr(name, '_')))
+        {
+            *dot = '.';
+        }
+    }
+}
+
+#endif /* 0 */
+
+short devlen(char *p)
+{
+    char defpath[40];
+    short deflen = 0, ok = 0;
+
+    getcwd(defpath, sizeof(defpath));
+    deflen = strlen(defpath);
+    if(deflen)
+    {
+        if(strnicmp(p, defpath, deflen) == 0)
+        {
+            ok = 1;
+        }
+    }
+
+    if(!ok)
+    {
+        if(isdirdev(p))
+        {
+            deflen = 5;
+        }
+        else
+        {
+            deflen = 0;
+        }
+    }
+    return deflen;
+}
+
+char * ql2Unix (char *qlname)
+{
+    struct stat st;
+    int sts;
+    char *p, *r, *s, *ldp;
+    char *pnam = NULL;
+    static char path[64];
+    short  deflen;
+    char name[64];
+
+    strcpy(name, qlname);
+    strcpy(path, name);
+
+    deflen = devlen(qlname);
+
+    p = name + deflen;
+    pnam = path + deflen;
+
+    if(s = strrchr(p, '_'))
+    {
+        *s = 0;
+        sts = stat(name, &st);
+        if(deflen && sts ==0 && (st.st_mode & S_IFDIR))
+        {
+            *(path+(s-name)) = '/';
+        }
+        else
+        {
+            *(path+(s-name)) = '.';
+        }
+    }
+
+    ldp = p;
+    for(r = p; *r; r++)
+    {
+        if(r != ldp && *r == '_')
+        {
+            *r = 0;
+            if(deflen)
+            {
+                sts = stat(name, &st);
+            }
+            else
+                sts = -1;
+
+            if(sts ==0 && (st.st_mode & S_IFDIR))
+            {
+                *(path+(r-name)) = '/';
+                ldp = r + 1;
+            }
+            else
+            {
+                *(path+(r-name)) = '_';
+            }
+            *r = '_';
+        }
+    }
+    return pnam;
+}
+
+char *LastDir(char *ws)
+{
+    char *p;
+    char *q = ws;
+    struct stat s;
+
+    for(p = ws; *p; p++)
+    {
+        if(p != ws && *p == '_')
+        {
+            char c;
+
+            p++;
+            c = *p;
+            *p = 0;
+            if(stat(ws, &s) == 0 && S_ISDIR(s.st_mode))
+            {
+                q = p;
+            }
+            *p = c;
+        }
+    }
+    return q;
+}
+
+# ifndef UTIL
+
+static int add_dir(char * dnam)
+{
+    int e = ZE_OK;
+    char *p;
+    short nlen;
+
+    nlen = strlen(dnam);
+    if(p = malloc(nlen + 2))
+    {
+        strncpy (p, dnam, nlen);
+        if(*(p+nlen) != '_')
+        {
+            *(p+nlen) = '_';
+            *(p+nlen+1) = '\0';
+        }
+        if ((e = newname(p, 1, 0)) != ZE_OK)
+        {
+                free(p);
+        }
+    }
+    else
+    {
+        e = ZE_MEM;
+    }
+    return e;
+}
+
+int qlwild (char *dnam, short dorecurse, short l)
+{
+    static char match[40] = {0};
+    static char ddev[8] =  {0};
+    static short nc;
+    static short llen;
+    static char base[40];
+
+    int chid;
+    struct qdirect qd;
+    char *dp;
+    int e = ZE_MISS;
+
+    if (l == 0)
+    {
+        nc = 0;
+        *base = '\0';
+        if (isdirdev (dnam))
+        {
+            dp = dnam;
+            strncpy (ddev, dnam, 5);
+        }
+        else
+        {
+
+            char *p;
+            char temp[40];
+
+            getcwd (temp, 40);
+
+            llen = strlen(temp);
+            p = (temp + llen - 1);
+            if (*p != '_')
+            {
+                *p++ = '_';
+                *p = 0;
+            }
+
+            strncpy (ddev, temp, 5);
+            dp = base;
+            p = stpcpy (dp, temp);
+            strcpy (p, dnam);
+        }
+
+        {
+            char *q = isshexp (dp);
+            if(q)
+            {
+                strcpy (match, dp + 5);
+                if (q)
+                {
+                    while (q != dp && *q != '_')
+                    {
+                        q--;
+                    }
+                    *(++q) = '\0';
+                }
+            }
+            else
+            {
+                struct stat s;
+                if (stat(dp, &s) == 0)
+                {
+                    if (!(s.st_mode & S_IFDIR))
+                    {
+                        return procname(dp, 0);
+                    }
+                }
+                else
+                {
+                    return ZE_MISS;  /* woops, no wildcards! */
+                }
+            }
+
+        }
+    }
+    else
+    {
+        dp = dnam;
+    }
+
+    if ((chid = io_open (dp, 4L)) > 0)
+    {
+        int id = 0;
+        while (io_fstrg (chid, -1, &qd, 64) > 0)
+        {
+            short j;
+
+            if (qd.d_szname)
+            {
+                if (CHECKDIR(qd))
+                {
+                    if(dorecurse)
+                    {
+                        char fnam[256], *p;
+
+                        p = stpcpy (fnam, ddev);
+                        strncpy (p, qd.d_name, qd.d_szname);
+                        *(p + qd.d_szname) = 0;
+                        e = qlwild (fnam, dorecurse, l+1);
+                    }
+                    else
+                    {
+                        continue;
+                    }
+                }
+                else
+                {
+                    char nam[48];
+                    strcpy(nam, ddev);
+
+                    strncpy (nam + 5, qd.d_name, qd.d_szname);
+                    *(nam + 5 + qd.d_szname) = 0;
+
+                    if (MATCH (match, nam + 5, 0) == 1)
+                    {
+                        if(dirnames && l && id == 0)
+                        {
+                            id = 1;
+                            if((e = add_dir(dp)) != ZE_OK)
+                            {
+                                return e;
+                            }
+                        }
+
+                        if((e = procname(nam, 0)) == ZE_OK)
+                        {
+                            nc++;
+                        }
+                    }
+                }
+            }
+        }
+        io_close (chid);
+    }
+
+    if (l == 0)
+    {
+        *ddev = 0;
+        *match = 0;
+        e = (nc) ? ZE_OK : ZE_MISS;
+    }
+    return e;
+
+}
+
+int wild(char *p)
+{
+    return qlwild(p, recurse, 0);
+}
+# endif /* !UTIL */
+
+/*
+ * Return QDOS error, 0 if exec 1 if found but not exe or rel
+ */
+int qlstat(char *name, struct qdirect *qs, char *flag)
+{
+    int r;
+    r = qstat(name, qs);
+    if(r == 0)
+    {
+        if(qs->d_type == 0)
+        {
+            r = 1;
+        }
+        else if(CHECKDIR(*qs))
+        {
+            r = 255;
+        }
+    }
+    return r;
+}
+
+#else /* !QDOS */
+
+long rev_long (ulg l)
+{
+    uch cc[4];
+    cc[0] = (uch)(l >> 24);
+    cc[1] = (uch)((l >> 16) & 0xff);
+    cc[2] = (uch)((l >> 8) & 0xff);
+    cc[3] = (uch)(l & 0xff);
+    return *(ulg *)cc;
+}
+
+short rev_short (ush s)
+{
+    uch cc[2];
+    cc[0] = (uch)((s >> 8) & 0xff);
+    cc[1] = (uch)(s & 0xff);
+    return *(ush *)cc;
+}
+
+#define O_BINARY 0
+
+int qlstat(char *name, struct qdirect *qs, char *flag)
+{
+    int r = -1;
+    int n, fd;
+    struct stat s;
+    struct _ntc_
+    {
+        long id;
+        long dlen;
+    } ntc;
+
+    *flag = 0;
+    if((fd = open(name, O_RDONLY | O_BINARY)) > 0)
+    {
+        short nl;
+
+        fstat(fd, &s);
+        lseek(fd, -8, SEEK_END);
+        read(fd, &ntc, 8);
+        qs->d_length = rev_long(s.st_size);
+        qs->d_update = rev_long(s.st_ctime + 283996800);
+
+        nl = strlen(name);
+        if(nl > QDOS_FLMAX)
+        {
+            nl = QDOS_FLMAX;
+            *flag = 1;
+        }
+        qs->d_szname = rev_short(nl);
+        memcpy(qs->d_name, name, nl);
+
+        if(ntc.id == *(long *)"XTcc")
+        {
+            qs->d_datalen = ntc.dlen;    /* This is big endian */
+            qs->d_type = 1;
+            r = 0;
+        }
+        else
+        {
+            qs->d_type = 0;
+            qs->d_datalen = 0;
+            r = 1;
+        }
+        close(fd);
+        return r;
+    }
+    else
+    {
+        fprintf(stderr, "Fails %d\n", fd);
+        return r;
+    }
+}
+
+#endif /* ?QDOS */
+
+#ifdef USE_EF_UT_TIME
+
+#define EB_L_UT_SIZE    (EB_HEADSIZE + eb_l_ut_len)
+#define EB_C_UT_SIZE    (EB_HEADSIZE + eb_c_ut_len)
+
+#ifdef UNIX
+#define EB_L_UX2_SIZE     (EB_HEADSIZE + EB_UX2_MINLEN)
+#define EB_C_UX2_SIZE     EB_HEADSIZE
+#define EF_L_UT_UX2_SIZE  (EB_L_UT_SIZE + EB_L_UX2_SIZE)
+#define EF_C_UT_UX2_SIZE  (EB_C_UT_SIZE + EB_C_UX2_SIZE)
+#else
+#define EF_L_UT_UX2_SIZE  EB_L_UT_SIZE
+#define EF_C_UT_UX2_SIZE  EB_C_UT_SIZE
+#endif
+
+local int GetExtraTime(struct zlist far *z, iztimes *z_utim, unsigned ut_flg)
+{
+  char *eb_l_ptr;
+  char *eb_c_ptr;
+  char *eb_pt;
+  extent eb_l_ut_len = 0;
+  extent eb_c_ut_len = 0;
+
+#ifdef UNIX
+  struct stat s;
+
+  /* For the full sized UT local field including the UID/GID fields, we
+   * have to stat the file, again.  */
+  if (stat(z->name, &s))
+    return ZE_OPEN;
+  /* update times in z_utim, stat() call might have changed atime... */
+  z_utim->mtime = s.st_mtime;
+  z_utim->atime = s.st_atime;
+  z_utim->ctime = s.st_mtime;   /* best guess (st_ctime != creation time) */
+#endif /* UNIX */
+
+#ifdef IZ_CHECK_TZ
+  if (!zp_tz_is_valid)
+    ut_flg = 0;          /* disable UT e.f creation if no valid TZ info */
+#endif
+  if (ut_flg != 0) {
+    if (ut_flg & EB_UT_FL_MTIME)
+      eb_l_ut_len = eb_c_ut_len = 1;
+    if (ut_flg & EB_UT_FL_ATIME)
+      eb_l_ut_len++;
+    if (ut_flg & EB_UT_FL_CTIME)
+      eb_l_ut_len++;
+
+    eb_l_ut_len = EB_UT_LEN(eb_l_ut_len);
+    eb_c_ut_len = EB_UT_LEN(eb_c_ut_len);
+  }
+
+  if (EF_L_UT_UX2_SIZE > EB_HEADSIZE) {
+    if(z->ext)
+      eb_l_ptr = realloc(z->extra, (z->ext + EF_L_UT_UX2_SIZE));
+    else
+      eb_l_ptr = malloc(EF_L_UT_UX2_SIZE);
+
+    if (eb_l_ptr == NULL)
+      return ZE_MEM;
+
+    if(z->cext)
+      eb_c_ptr = realloc(z->cextra, (z->cext + EF_C_UT_UX2_SIZE));
+    else
+      eb_c_ptr = malloc(EF_C_UT_UX2_SIZE);
+
+    if (eb_c_ptr == NULL)
+      return ZE_MEM;
+
+    z->extra = eb_l_ptr;
+    eb_l_ptr += z->ext;
+    z->ext += EF_L_UT_UX2_SIZE;
+
+    if (ut_flg != 0) {
+      eb_l_ptr[0]  = 'U';
+      eb_l_ptr[1]  = 'T';
+      eb_l_ptr[2]  = eb_l_ut_len;       /* length of data part of e.f. */
+      eb_l_ptr[3]  = 0;
+      eb_l_ptr[4]  = ut_flg;
+      eb_pt = eb_l_ptr + 5;
+      if (ut_flg & EB_UT_FL_MTIME) {
+        *eb_pt++ = (char)(z_utim->mtime);
+        *eb_pt++ = (char)(z_utim->mtime >> 8);
+        *eb_pt++ = (char)(z_utim->mtime >> 16);
+        *eb_pt++ = (char)(z_utim->mtime >> 24);
+      }
+      if (ut_flg & EB_UT_FL_ATIME) {
+        *eb_pt++ = (char)(z_utim->atime);
+        *eb_pt++ = (char)(z_utim->atime >> 8);
+        *eb_pt++ = (char)(z_utim->atime >> 16);
+        *eb_pt++ = (char)(z_utim->atime >> 24);
+      }
+      if (ut_flg & EB_UT_FL_CTIME) {
+        *eb_pt++ = (char)(z_utim->ctime);
+        *eb_pt++ = (char)(z_utim->ctime >> 8);
+        *eb_pt++ = (char)(z_utim->ctime >> 16);
+        *eb_pt++ = (char)(z_utim->ctime >> 24);
+      }
+    }
+#ifdef UNIX
+    else {
+      eb_pt = eb_l_ptr;
+    }
+    *eb_pt++ = 'U';
+    *eb_pt++ = 'x';
+    *eb_pt++ = EB_UX2_MINLEN;            /* length of data part of local e.f. */
+    *eb_pt++  = 0;
+    *eb_pt++ = (char)(s.st_uid);
+    *eb_pt++ = (char)(s.st_uid >> 8);
+    *eb_pt++ = (char)(s.st_gid);
+    *eb_pt++ = (char)(s.st_gid >> 8);
+#endif /* UNIX */
+
+    z->cextra = eb_c_ptr;
+    eb_c_ptr += z->cext;
+    z->cext += EF_C_UT_UX2_SIZE;
+
+    if (ut_flg != 0) {
+      memcpy(eb_c_ptr, eb_l_ptr, EB_C_UT_SIZE);
+      eb_c_ptr[EB_LEN] = eb_c_ut_len;
+    }
+#ifdef UNIX
+    memcpy(eb_c_ptr+EB_C_UT_SIZE, eb_l_ptr+EB_L_UT_SIZE, EB_C_UX2_SIZE);
+    eb_c_ptr[EB_LEN+EB_C_UT_SIZE] = 0;
+#endif /* UNIX */
+  }
+
+  return ZE_OK;
+}
+
+#endif /* USE_EF_UT_TIME */
+
+
+int set_extra_field (struct zlist *z, iztimes *z_utim )
+{
+    int rv = 0;
+    int last_rv = 0;
+    char flag = 0;
+
+    if ((qlflag & 3) != 1)
+    {
+        qdosextra       *lq, *cq;
+        if ((lq = (qdosextra *) calloc(sizeof(qdosextra), 1)) == NULL)
+            return ZE_MEM;
+        if ((cq = (qdosextra *) calloc(sizeof(qdosextra), 1)) == NULL)
+            return ZE_MEM;
+
+        rv = qlstat(z->name, &(lq->header), &flag);
+
+        if (rv == 0 || (rv == 1 && (qlflag & 2)))
+        {
+            lq->shortid = rev_short((short) SHORTID);
+            lq->len.lo  = (unsigned char)(EXTRALEN & 0xff);
+            lq->len.hi  = (unsigned char)(EXTRALEN >> 8);
+            strcpy(lq->longid, LONGID);
+
+            memcpy(cq, lq, sizeof(qdosextra));
+
+            z->ext      =   sizeof(qdosextra);
+            z->cext     =   sizeof(qdosextra);
+            z->extra    =   (void *) lq;
+            z->cextra   =   (void *) cq;
+            fprintf (stderr, " %c",
+                     lq->header.d_datalen ? '*' : '#');
+        }
+        else if (rv == -1)
+        {
+            fprintf(stderr,
+                    "%s: warning: cannot stat %s, no file header added\n",
+                    "zip", z->name);
+        }
+        if(flag)
+        {
+            fputs (" !", stderr);
+        }
+     }
+    last_rv = (rv == -1 ? ZE_OPEN : ZE_OK);
+
+#ifdef USE_EF_UT_TIME
+# ifdef QDOS
+#   define IZ_UT_FLAGS EB_UT_FL_MTIME
+# endif
+# ifdef UNIX
+#   define IZ_UT_FLAGS (EB_UT_FL_MTIME | EB_UT_FL_ATIME)
+# endif
+# ifndef IZ_UT_FLAGS
+#   define IZ_UT_FLAGS EB_UT_FL_MTIME
+# endif
+
+    rv = GetExtraTime(z, z_utim, IZ_UT_FLAGS);
+    if (rv != ZE_OK)
+        last_rv = rv;
+#endif /* USE_EF_UT_TIME */
+
+    return last_rv;
+}
diff --git a/qdos/qfileio.c b/qdos/qfileio.c
new file mode 100644 (file)
index 0000000..0029b8f
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#ifndef UTIL    /* the companion #endif is a bit of ways down ... */
+
+#include <time.h>
+#include <utime.h>
+
+#include <errno.h>
+
+#ifdef S_IWRITE
+# undef S_IWRITE
+#endif /* S_IWRITE */
+#define S_IWRITE S_IWUSR
+
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+
+typedef time_t statime;
+#define PAD 0
+#define PATH_END '/'
+
+/* Local functions */
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (SSTAT(n, &s) )
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free(p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+
+  if ((s.st_mode & S_IFDIR) == 0)
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0, caseflag)) != ZE_OK)
+      return m;
+  }
+  return ZE_OK;
+}
+
+
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t;              /* shortened name */
+  int dosflag;
+
+  t = ql2Unix(x);
+
+  dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+
+  if (!pathput)
+    t = last(t, PATH_END);
+
+  /* Discard directory names with zip -rj */
+  if (*t == '\0')
+    return t;
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL)
+    return NULL;
+  strcpy(n, t);
+
+  if (dosify)
+    msname(n);
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+  return n;
+}
+
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+       return NULL;
+  strcpy(x, Unix2ql(n, NULL));
+  return x;
+}
+
+
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+  struct utimbuf u;     /* argument for utime()  const ?? */
+
+  /* Convert DOS time to time_t format in u */
+  u.actime = u.modtime = dos2unixtime(d);
+  utime(f, &u);
+}
+
+ulg filetime(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  /* from FNMAX to malloc - 11/8/04 EG */
+  char *name;
+  int len = strlen(f);
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+  if (strcmp(f, "-") == 0) {
+    if (fstat(fileno(stdin), &s) != 0) {
+      free(name);
+      error("fstat(stdin)");
+    }
+  } else if (LSSTAT(name, &s) != 0) {
+             /* Accept about any file kind including directories
+              * (stored with trailing / with -r option)
+              */
+    free(name);
+    return 0;
+  }
+  free(name);
+
+  if (a != NULL) {
+    *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+    if ((s.st_mode & S_IFMT) == S_IFDIR) {
+      *a |= MSDOS_DIR_ATTR;
+    }
+  }
+  if (n != NULL)
+    *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = s.st_ctime;
+  }
+
+  return unix2dostime(&s.st_mtime);
+}
+
+
+int deletedir(d)
+char *d;                /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+   Return the result of rmdir(), delete(), or system().
+   For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
+ */
+{
+    return rmdir(d);
+}
+
+#endif /* !UTIL */
+
+
+void version_local()
+{
+    puts ("Compiled with c68 v4.2x on " __DATE__);
+}
diff --git a/qdos/zipup.h b/qdos/zipup.h
new file mode 100644 (file)
index 0000000..1de3f61
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+#  define O_RDONLY 0
+#endif
+#define fhow O_RDONLY
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/revision.h b/revision.h
new file mode 100644 (file)
index 0000000..7348cb7
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+  revision.h - Zip 3
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  revision.h by Mark Adler.
+ */
+
+#ifndef __revision_h
+#define __revision_h 1
+
+/* For api version checking */
+#define Z_MAJORVER   3
+#define Z_MINORVER   0
+#define Z_PATCHLEVEL 0
+#define Z_BETALEVEL "i BETA"
+
+#define VERSION "3.0"
+#define REVDATE "July 5th 2008"
+
+#define DW_MAJORVER    Z_MAJORVER
+#define DW_MINORVER    Z_MINORVER
+#define DW_PATCHLEVEL  Z_PATCHLEVEL
+
+#ifndef IZ_COMPANY_NAME               /* might be already defined... */
+#  define IZ_COMPANY_NAME "Info-ZIP"
+#endif
+
+#if !defined(WINDLL) && !defined(IZ_VERSION_SYMBOLS_ONLY)
+/* Copyright notice for binary executables--this notice only applies to
+ * those (zip, zipcloak, zipsplit, and zipnote), not to this file
+ * (revision.h).
+ */
+
+#ifndef DEFCPYRT
+/* copyright[] et.al. get defined only once ! */
+/* keep array sizes in sync with number of text */
+/* lines in the array definitions below !!      */
+extern ZCONST char *copyright[1];
+extern ZCONST char * far swlicense[50];
+extern ZCONST char * far versinfolines[7];
+extern ZCONST char * far cryptnote[7];
+
+#else /* DEFCPYRT */
+
+ZCONST char *copyright[] = {
+"Copyright (c) 1990-2008 Info-ZIP - Type '%s \"-L\"' for software license."
+/* XXX still necessary ???? */
+#ifdef AZTEC_C
+,        /* extremely lame compiler bug workaround */
+#endif
+};
+
+ZCONST char * far versinfolines[] = {
+"This is %s %s (%s), by Info-ZIP.",
+"Currently maintained by E. Gordon.  Please send bug reports to",
+"the authors using the web page at www.info-zip.org; see README for details.",
+"",
+"Latest sources and executables are at ftp://ftp.info-zip.org/pub/infozip,",
+"as of above date; see http://www.info-zip.org/ for other sites.",
+""
+};
+
+/* new notice - 4 March 2007 */
+ZCONST char * far cryptnote[] = {
+"Encryption notice:",
+"\tThe encryption code of this program is not copyrighted and is",
+"\tput in the public domain.  It was originally written in Europe",
+"\tand, to the best of our knowledge, can be freely distributed",
+"\tin both source and object forms from any country, including",
+"\tthe USA under License Exception TSU of the U.S. Export",
+"\tAdministration Regulations (section 740.13(e)) of 6 June 2002."
+};
+
+ZCONST char * far swlicense[] = {
+"Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.",
+"",
+"For the purposes of this copyright and license, \"Info-ZIP\" is defined as",
+"the following set of individuals:",
+"",
+"   Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,",
+"   Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth,",
+"   Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,",
+"   David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,",
+"   Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,",
+"   Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda,",
+"   Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren,",
+"   Rich Wales, Mike White",
+"",
+"This software is provided \"as is,\" without warranty of any kind, express",
+"or implied.  In no event shall Info-ZIP or its contributors be held liable",
+"for any direct, indirect, incidental, special or consequential damages",
+"arising out of the use of or inability to use this software.",
+"",
+"Permission is granted to anyone to use this software for any purpose,",
+"including commercial applications, and to alter it and redistribute it",
+"freely, subject to the above disclaimer and the following restrictions:",
+"",
+"    1. Redistributions of source code (in whole or in part) must retain",
+"       the above copyright notice, definition, disclaimer, and this list",
+"       of conditions.",
+"",
+"    2. Redistributions in binary form (compiled executables and libraries)",
+"       must reproduce the above copyright notice, definition, disclaimer,",
+"       and this list of conditions in documentation and/or other materials",
+"       provided with the distribution.  The sole exception to this condition",
+"       is redistribution of a standard UnZipSFX binary (including SFXWiz) as",
+"       part of a self-extracting archive; that is permitted without inclusion",
+"       of this license, as long as the normal SFX banner has not been removed",
+"       from the binary or disabled.",
+"",
+"    3. Altered versions--including, but not limited to, ports to new operating",
+"       systems, existing ports with new graphical interfaces, versions with",
+"       modified or added functionality, and dynamic, shared, or static library",
+"       versions not from Info-ZIP--must be plainly marked as such and must not",
+"       be misrepresented as being the original source or, if binaries,",
+"       compiled from the original source.  Such altered versions also must not",
+"       be misrepresented as being Info-ZIP releases--including, but not",
+"       limited to, labeling of the altered versions with the names \"Info-ZIP\"",
+"       (or any variation thereof, including, but not limited to, different",
+"       capitalizations), \"Pocket UnZip,\" \"WiZ\" or \"MacZip\" without the",
+"       explicit permission of Info-ZIP.  Such altered versions are further",
+"       prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP",
+"       e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP",
+"       will provide support for the altered versions.",
+"",
+"    4. Info-ZIP retains the right to use the names \"Info-ZIP,\" \"Zip,\" \"UnZip,\"",
+"       \"UnZipSFX,\" \"WiZ,\" \"Pocket UnZip,\" \"Pocket Zip,\" and \"MacZip\" for its",
+"       own source and binary releases."
+};
+#endif /* DEFCPYRT */
+#endif /* !WINDLL && !IZ_VERSION_SYMBOLS_ONLY */
+#endif /* !__revision_h */
diff --git a/tailor.h b/tailor.h
new file mode 100644 (file)
index 0000000..272f979
--- /dev/null
+++ b/tailor.h
@@ -0,0 +1,887 @@
+/*
+  tailor.h - Zip 3
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/* Some compiler distributions for Win32/i386 systems try to emulate
+ * a Unix (POSIX-compatible) environment.
+ */
+#if (defined(WIN32) && defined(UNIX))
+   /* Zip does not support merging both ports in a single executable. */
+#  if (defined(FORCE_WIN32_OVER_UNIX) && defined(FORCE_UNIX_OVER_WIN32))
+     /* conflicting choice requests -> we prefer the Win32 environment */
+#    undef FORCE_UNIX_OVER_WIN32
+#  endif
+#  ifdef FORCE_WIN32_OVER_UNIX
+     /* native Win32 support was explicitely requested... */
+#    undef UNIX
+#  else
+     /* use the POSIX (Unix) emulation features by default... */
+#    undef WIN32
+#  endif
+#endif
+
+
+/* UNICODE */
+#ifdef NO_UNICODE_SUPPORT
+# ifdef UNICODE_SUPPORT
+#   undef UNICODE_SUPPORT
+# endif
+#endif
+
+
+#ifdef AMIGA
+#include "amiga/osdep.h"
+#endif
+
+#ifdef AOSVS
+#include "aosvs/osdep.h"
+#endif
+
+#ifdef ATARI
+#include "atari/osdep.h"
+#endif
+
+#ifdef __ATHEOS__
+#include "atheos/osdep.h"
+#endif
+
+#ifdef __BEOS__
+#include "beos/osdep.h"
+#endif
+
+#ifdef DOS
+#include "msdos/osdep.h"
+#endif
+
+#ifdef __human68k__
+#include "human68k/osdep.h"
+#endif
+
+#if ((defined(__MWERKS__) && defined(macintosh)) || defined(MACOS))
+#include "macos/osdep.h"
+#endif
+
+#ifdef NLM
+#include "novell/osdep.h"
+#endif
+
+#ifdef OS2
+#include "os2/osdep.h"
+#endif
+
+#ifdef __riscos
+#include "acorn/osdep.h"
+#endif
+
+#ifdef QDOS
+#include "qdos/osdep.h"
+#endif
+
+#ifdef __TANDEM
+#include "tandem.h"
+#include "tanzip.h"
+#endif
+
+#ifdef UNIX
+#include "unix/osdep.h"
+#endif
+
+#if defined(__COMPILER_KCC__) || defined(TOPS20)
+#include "tops20/osdep.h"
+#endif
+
+#if defined(VMS) || defined(__VMS)
+#include "vms/osdep.h"
+#endif
+
+#if defined(__VM__) || defined(VM_CMS) || defined(MVS)
+#include "cmsmvs.h"
+#endif
+
+#ifdef WIN32
+#include "win32/osdep.h"
+#endif
+
+#ifdef THEOS
+#include "theos/osdep.h"
+#endif
+
+
+/* generic LARGE_FILE_SUPPORT defines
+   These get used if not defined above.
+   7/21/2004 EG
+*/
+/* If a port hasn't defined ZOFF_T_FORMAT_SIZE_PREFIX
+   then probably need to define all of these. */
+#ifndef ZOFF_T_FORMAT_SIZE_PREFIX
+
+# ifdef LARGE_FILE_SUPPORT
+    /* Probably passed in from command line instead of in above
+       includes if get here.  Assume large file support and hope. 8/14/04 EG */
+
+    /* Set the Large File Summit (LFS) defines to turn on large file support
+       in case it helps. */
+
+#   define _LARGEFILE_SOURCE    /* some OSes need this for fseeko */
+#   define _LARGEFILE64_SOURCE
+#   define _FILE_OFFSET_BITS 64 /* select default interface as 64 bit */
+#   define _LARGE_FILES         /* some OSes need this for 64-bit off_t */
+
+    typedef off_t zoff_t;
+    typedef unsigned long long uzoff_t;  /* unsigned zoff_t (12/29/04 EG) */
+
+    /* go with common prefix */
+#   define ZOFF_T_FORMAT_SIZE_PREFIX "ll"
+
+# else
+    /* Default type for offsets and file sizes was ulg but reports
+       of using ulg to create files from 2 GB to 4 GB suggest
+       it doesn't work well.  Now just switch to Zip64 or not
+       support over 2 GB.  7/24/04 EG */
+    /* Now use uzoff_t for unsigned things.  12/29/04 EG */
+    typedef long zoff_t;
+    typedef unsigned long uzoff_t;
+
+#   define ZOFF_T_FORMAT_SIZE_PREFIX "l"
+
+# endif
+
+  typedef struct stat z_stat;
+
+  /* flag that we are defaulting */
+# define USING_DEFAULT_LARGE_FILE_SUPPORT
+#endif
+
+
+#if (defined(USE_ZLIB) && defined(ASM_CRC))
+#  undef ASM_CRC
+#endif
+
+#if (defined(USE_ZLIB) && defined(ASMV))
+#  undef ASMV
+#endif
+
+/* When "void" is an alias for "int", prototypes cannot be used. */
+#if (defined(NO_VOID) && !defined(NO_PROTO))
+#  define NO_PROTO
+#endif
+
+/* Used to remove arguments in function prototypes for non-ANSI C */
+#ifndef NO_PROTO
+#  define OF(a) a
+#  define OFT(a) a
+#else /* NO_PROTO */
+#  define OF(a) ()
+#  define OFT(a)
+#endif /* ?NO_PROTO */
+
+/* If the compiler can't handle const define ZCONST in osdep.h */
+/* Define const itself in case the system include files are bonkers */
+#ifndef ZCONST
+#  ifdef NO_CONST
+#    define ZCONST
+#    define const
+#  else
+#    define ZCONST const
+#  endif
+#endif
+
+/*
+ * Some compiler environments may require additional attributes attached
+ * to declarations of runtime libary functions (e.g. to prepare for
+ * linking against a "shared dll" version of the RTL).  Here, we provide
+ * the "empty" default for these attributes.
+ */
+#ifndef IZ_IMP
+#  define IZ_IMP
+#endif
+
+/*
+ * case mapping functions. case_map is used to ignore case in comparisons,
+ * to_up is used to force upper case even on Unix (for dosify option).
+ */
+#ifdef USE_CASE_MAP
+#  define case_map(c) upper[(c) & 0xff]
+#  define to_up(c)    upper[(c) & 0xff]
+#else
+#  define case_map(c) (c)
+#  define to_up(c)    ((c) >= 'a' && (c) <= 'z' ? (c)-'a'+'A' : (c))
+#endif /* USE_CASE_MAP */
+
+/* Define void, zvoid, and extent (size_t) */
+#include <stdio.h>
+
+#ifndef NO_STDDEF_H
+#  include <stddef.h>
+#endif /* !NO_STDDEF_H */
+
+#ifndef NO_STDLIB_H
+#  include <stdlib.h>
+#endif /* !NO_STDLIB_H */
+
+#ifndef NO_UNISTD_H
+#  include <unistd.h> /* usually defines _POSIX_VERSION */
+#endif /* !NO_UNISTD_H */
+
+#ifndef NO_FCNTL_H
+#  include <fcntl.h>
+#endif /* !NO_FNCTL_H */
+
+#ifndef NO_STRING_H
+#  include <string.h>
+#else
+#  include <strings.h>
+#endif /* NO_STRING_H */
+
+#ifdef NO_VOID
+#  define void int
+   typedef char zvoid;
+#else /* !NO_VOID */
+# ifdef NO_TYPEDEF_VOID
+#  define zvoid void
+# else
+   typedef void zvoid;
+# endif
+#endif /* ?NO_VOID */
+
+#ifdef NO_STRRCHR
+#  define strrchr rindex
+#endif
+
+#ifdef NO_STRCHR
+#  define strchr index
+#endif
+
+/*
+ * A couple of forward declarations that are needed on systems that do
+ * not supply C runtime library prototypes.
+ */
+#ifdef NO_PROTO
+IZ_IMP char *strcpy();
+IZ_IMP char *strcat();
+IZ_IMP char *strrchr();
+/* XXX use !defined(ZMEM) && !defined(__hpux__) ? */
+#if !defined(ZMEM) && defined(NO_STRING_H)
+IZ_IMP char *memset();
+IZ_IMP char *memcpy();
+#endif /* !ZMEM && NO_STRING_H */
+
+/* XXX use !defined(__hpux__) ? */
+#ifdef NO_STDLIB_H
+IZ_IMP char *calloc();
+IZ_IMP char *malloc();
+IZ_IMP char *getenv();
+IZ_IMP long atol();
+#endif /* NO_STDLIB_H */
+
+#ifndef NO_MKTEMP
+IZ_IMP char *mktemp();
+#endif /* !NO_MKTEMP */
+
+#endif /* NO_PROTO */
+
+/*
+ * SEEK_* macros, should be defined in stdio.h
+ */
+/* Define fseek() commands */
+#ifndef SEEK_SET
+#  define SEEK_SET 0
+#endif /* !SEEK_SET */
+
+#ifndef SEEK_CUR
+#  define SEEK_CUR 1
+#endif /* !SEEK_CUR */
+
+#ifndef FALSE
+#  define FALSE 0
+#endif
+
+#ifndef TRUE
+#  define TRUE 1
+#endif
+
+#ifdef NO_SIZE_T
+   typedef unsigned int extent;
+   /* define size_t 3/17/05 EG */
+   typedef unsigned int size_t;
+#else
+   typedef size_t extent;
+#endif
+
+#ifdef NO_TIME_T
+   typedef long time_t;
+#endif
+
+/* DBCS support for Info-ZIP's zip  (mainly for japanese (-: )
+ * by Yoshioka Tsuneo (QWF00133@nifty.ne.jp,tsuneo-y@is.aist-nara.ac.jp)
+ * This code is public domain!   Date: 1998/12/20
+ */
+
+/* 2007-07-29 SMS.
+ * Include <locale.h> here if it will be needed later for Unicode.
+ * Otherwise, SETLOCALE may be defined here, and then defined again
+ * (differently) when <locale.h> is read later.
+ */
+#ifdef UNICODE_SUPPORT
+# if defined( UNIX) || defined( VMS)
+#   include <locale.h>
+# endif /* defined( UNIX) || defined( VMS) */
+# include <wchar.h>
+# include <wctype.h>
+#endif /* def UNICODE_SUPPORT */
+
+#ifdef _MBCS
+#   include <locale.h>
+
+    /* Multi Byte Character Set */
+    extern char *___tmp_ptr;
+    unsigned char *zmbschr OF((ZCONST unsigned char *, unsigned int));
+    unsigned char *zmbsrchr OF((ZCONST unsigned char *, unsigned int));
+#   define CLEN(ptr) mblen((ZCONST char *)ptr, MB_CUR_MAX)
+#   define PREINCSTR(ptr) (ptr += CLEN(ptr))
+#   define POSTINCSTR(ptr) (___tmp_ptr=(char *)ptr,ptr += CLEN(ptr),___tmp_ptr)
+    int lastchar OF((ZCONST char *ptr));
+#   define MBSCHR(str,c) (char *)zmbschr((ZCONST unsigned char *)(str), c)
+#   define MBSRCHR(str,c) (char *)zmbsrchr((ZCONST unsigned char *)(str), (c))
+#   ifndef SETLOCALE
+#      define SETLOCALE(category, locale) setlocale(category, locale)
+#   endif /* ndef SETLOCALE */
+#else /* !_MBCS */
+#   define CLEN(ptr) 1
+#   define PREINCSTR(ptr) (++(ptr))
+#   define POSTINCSTR(ptr) ((ptr)++)
+#   define lastchar(ptr) ((*(ptr)=='\0') ? '\0' : ptr[strlen(ptr)-1])
+#   define MBSCHR(str, c) strchr(str, c)
+#   define MBSRCHR(str, c) strrchr(str, c)
+#   ifndef SETLOCALE
+#      define SETLOCALE(category, locale)
+#   endif /* ndef SETLOCALE */
+#endif /* ?_MBCS */
+#define INCSTR(ptr) PREINCSTR(ptr)
+
+
+/* System independent replacement for "struct utimbuf", which is missing
+ * in many older OS environments.
+ */
+typedef struct ztimbuf {
+    time_t actime;              /* new access time */
+    time_t modtime;             /* new modification time */
+} ztimbuf;
+
+/* This macro round a time_t value to the OS specific resolution */
+#ifndef ROUNDED_TIME
+#  define ROUNDED_TIME(time)   (time)
+#endif
+
+/* Some systems define S_IFLNK but do not support symbolic links */
+#if defined (S_IFLNK) && defined(NO_SYMLINKS)
+#  undef S_IFLNK
+#endif
+
+#ifndef Z_UINT4_DEFINED
+#  if !defined(NO_LIMITS_H)
+#    if (defined(UINT_MAX) && (UINT_MAX == 0xffffffffUL))
+       typedef unsigned int     z_uint4;
+#      define Z_UINT4_DEFINED
+#    else
+#      if (defined(ULONG_MAX) && (ULONG_MAX == 0xffffffffUL))
+         typedef unsigned long    z_uint4;
+#        define Z_UINT4_DEFINED
+#      else
+#        if (defined(USHRT_MAX) && (USHRT_MAX == 0xffffffffUL))
+           typedef unsigned short   z_uint4;
+#          define Z_UINT4_DEFINED
+#        endif
+#      endif
+#    endif
+#  endif /* !defined(NO_LIMITS_H) */
+#endif /* ndef Z_UINT4_DEFINED */
+#ifndef Z_UINT4_DEFINED
+  typedef ulg                z_uint4;
+# define Z_UINT4_DEFINED
+#endif
+
+#ifndef FOPR    /* fallback default definitions for FOPR, FOPM, FOPW: */
+#  define FOPR "r"
+#  define FOPM "r+"
+#  define FOPW "w"
+#endif /* fallback definition */
+
+#ifndef FOPW_TMP    /* fallback default for opening writable temp files */
+#  define FOPW_TMP FOPW
+#endif
+
+/* Open the old zip file in exclusive mode if possible (to avoid adding
+ * zip file to itself).
+ */
+#ifdef OS2
+#  define FOPR_EX FOPM
+#else
+#  define FOPR_EX FOPR
+#endif
+
+
+/* MSDOS file or directory attributes */
+#define MSDOS_HIDDEN_ATTR 0x02
+#define MSDOS_DIR_ATTR 0x10
+
+
+/* Define this symbol if your target allows access to unaligned data.
+ * This is not mandatory, just a speed optimization. The compressed
+ * output is strictly identical.
+ */
+#if (defined(MSDOS) && !defined(WIN32)) || defined(i386)
+#    define UNALIGNED_OK
+#endif
+#if defined(mc68020) || defined(vax)
+#    define UNALIGNED_OK
+#endif
+
+#if (defined(SMALL_MEM) && !defined(CBSZ))
+#   define CBSZ 2048 /* buffer size for copying files */
+#   define ZBSZ 2048 /* buffer size for temporary zip file */
+#endif
+
+#if (defined(MEDIUM_MEM) && !defined(CBSZ))
+#  define CBSZ 8192
+#  define ZBSZ 8192
+#endif
+
+#ifndef CBSZ
+#  define CBSZ 16384
+#  define ZBSZ 16384
+#endif
+
+#ifndef SBSZ
+#  define SBSZ CBSZ     /* copy buf size for STORED entries, see zipup() */
+#endif
+
+#ifndef MEMORY16
+#  ifdef __WATCOMC__
+#    undef huge
+#    undef far
+#    undef near
+#  endif
+#  ifdef THEOS
+#    undef far
+#    undef near
+#  endif
+#  if (!defined(__IBMC__) || !defined(OS2))
+#    ifndef huge
+#      define huge
+#    endif
+#    ifndef far
+#      define far
+#    endif
+#    ifndef near
+#      define near
+#    endif
+#  endif
+#  define nearmalloc malloc
+#  define nearfree free
+#  define farmalloc malloc
+#  define farfree free
+#endif /* !MEMORY16 */
+
+#ifndef Far
+#  define Far far
+#endif
+
+/* MMAP and BIG_MEM cannot be used together -> let MMAP take precedence */
+#if (defined(MMAP) && defined(BIG_MEM))
+#  undef BIG_MEM
+#endif
+
+#if (defined(BIG_MEM) || defined(MMAP)) && !defined(DYN_ALLOC)
+#   define DYN_ALLOC
+#endif
+
+
+/* LARGE_FILE_SUPPORT
+ *
+ * Types are in osdep.h for each port
+ *
+ * LARGE_FILE_SUPPORT and ZIP64_SUPPORT are automatically
+ * set in osdep.h (for some ports) based on the port and compiler.
+ *
+ * Function prototypes are below as OF is defined earlier in this file
+ * but after osdep.h is included.  In the future ANSI prototype
+ * support may be required and the OF define may then go away allowing
+ * the function defines to be in the port osdep.h.
+ *
+ * E. Gordon 9/21/2003
+ * Updated 7/24/04 EG
+ */
+#ifdef LARGE_FILE_SUPPORT
+  /* 64-bit Large File Support */
+
+  /* Arguments for all functions are assumed to match the actual
+     arguments of the various port calls.  As such only the
+     function names are mapped below. */
+
+/* ---------------------------- */
+# ifdef UNIX
+
+  /* Assume 64-bit file environment is defined.  The below should all
+     be set to their 64-bit versions automatically.  Neat.  7/20/2004 EG */
+
+    /* 64-bit stat functions */
+#   define zstat stat
+#   define zfstat fstat
+#   define zlstat lstat
+
+# if defined(__alpha) && defined(__osf__)  /* support for osf4.0f */
+    /* 64-bit fseek */
+#   define zfseeko fseek
+
+    /* 64-bit ftell */
+#   define zftello ftell
+
+# else
+     /* 64-bit fseeko */
+#   define zfseeko fseeko
+
+     /* 64-bit ftello */
+#   define zftello ftello
+# endif                                    /* __alpha && __osf__ */
+
+    /* 64-bit fopen */
+#   define zfopen fopen
+#   define zfdopen fdopen
+
+# endif /* UNIX */
+
+/* ---------------------------- */
+# ifdef VMS
+
+    /* 64-bit stat functions */
+#   define zstat stat
+#   define zfstat fstat
+#   define zlstat lstat
+
+    /* 64-bit fseeko */
+#   define zfseeko fseeko
+
+    /* 64-bit ftello */
+#   define zftello ftello
+
+    /* 64-bit fopen */
+#   define zfopen fopen
+#   define zfdopen fdopen
+
+# endif /* def VMS */
+
+/* ---------------------------- */
+# ifdef WIN32
+
+#   if defined(__MINGW32__)
+    /* GNU C, linked against "msvcrt.dll" */
+
+      /* 64-bit stat functions */
+#     define zstat _stati64
+# ifdef UNICODE_SUPPORT
+#     define zwfstat _fstati64
+#     define zwstat _wstati64
+#     define zw_stat struct _stati64
+# endif
+#     define zfstat _fstati64
+#     define zlstat lstat
+
+      /* 64-bit fseeko */
+      /* function in win32.c */
+      int zfseeko OF((FILE *, zoff_t, int));
+
+      /* 64-bit ftello */
+      /* function in win32.c */
+      zoff_t zftello OF((FILE *));
+
+      /* 64-bit fopen */
+#     define zfopen fopen
+#     define zfdopen fdopen
+
+#   endif
+
+#   if defined(__CYGWIN__)
+    /* GNU C, CygWin with its own POSIX compatible runtime library */
+
+      /* 64-bit stat functions */
+#     define zstat stat
+#     define zfstat fstat
+#     define zlstat lstat
+
+      /* 64-bit fseeko */
+#     define zfseeko fseeko
+
+      /* 64-bit ftello */
+#     define zftello ftello
+
+      /* 64-bit fopen */
+#     define zfopen fopen
+#     define zfdopen fdopen
+
+#   endif
+
+#   ifdef __WATCOMC__
+    /* WATCOM C */
+
+      /* 64-bit stat functions */
+#     define zstat _stati64
+# ifdef UNICODE_SUPPORT
+#     define zwfstat _fstati64
+#     define zwstat _wstati64
+#     define zw_stat struct _stati64
+# endif
+#     define zfstat _fstati64
+#     define zlstat lstat
+
+      /* 64-bit fseeko */
+      /* function in win32.c */
+      int zfseeko OF((FILE *, zoff_t, int));
+
+      /* 64-bit ftello */
+      /* function in win32.c */
+      zoff_t zftello OF((FILE *));
+
+      /* 64-bit fopen */
+#     define zfopen fopen
+#     define zfdopen fdopen
+
+#   endif
+
+#   ifdef _MSC_VER
+    /* MS C and VC */
+
+      /* 64-bit stat functions */
+#     define zstat _stati64
+# ifdef UNICODE_SUPPORT
+#     define zwfstat _fstati64
+#     define zwstat _wstati64
+#     define zw_stat struct _stati64
+# endif
+#     define zfstat _fstati64
+#     define zlstat lstat
+
+      /* 64-bit fseeko */
+      /* function in win32.c */
+      int zfseeko OF((FILE *, zoff_t, int));
+
+      /* 64-bit ftello */
+      /* function in win32.c */
+      zoff_t zftello OF((FILE *));
+
+      /* 64-bit fopen */
+#     define zfopen fopen
+#     define zfdopen fdopen
+
+#   endif
+
+#   ifdef __IBMC__
+      /* IBM C */
+
+      /* 64-bit stat functions */
+
+      /* 64-bit fseeko */
+      /* function in win32.c */
+      int zfseeko OF((FILE *, zoff_t, int));
+
+      /* 64-bit ftello */
+      /* function in win32.c */
+      zoff_t zftello OF((FILE *));
+
+      /* 64-bit fopen */
+
+#   endif
+
+# endif /* WIN32 */
+
+#else
+  /* No Large File Support or default for 64-bit environment */
+
+# define zstat stat
+# define zfstat fstat
+# define zlstat lstat
+# define zfseeko fseek
+# define zftello ftell
+# define zfopen fopen
+# define zfdopen fdopen
+# ifdef UNICODE_SUPPORT
+#   define zwfstat _fstat
+#   define zwstat _wstat
+#   define zw_stat struct _stat
+# endif
+
+#endif
+
+#ifdef LARGE_FILE_SUPPORT         /* E. Gordon 9/12/2003 */
+
+# ifndef SSTAT
+#  define SSTAT      zstat
+#  ifdef UNICODE_SUPPORT
+#    define SSTATW   zwstat
+#  endif
+# endif
+# ifdef S_IFLNK
+#  define LSTAT      zlstat
+#  define LSSTAT(n, s)  (linkput ? zlstat((n), (s)) : SSTAT((n), (s)))
+# else
+#  define LSTAT      SSTAT
+#  define LSSTAT     SSTAT
+#  ifdef UNICODE_SUPPORT
+#    define LSSTATW  SSTATW
+#  endif
+# endif
+
+#else /* no LARGE_FILE_SUPPORT */
+
+# ifndef SSTAT
+#  define SSTAT      stat
+# endif
+# ifdef S_IFLNK
+#  define LSTAT      lstat
+#  define LSSTAT(n, s)  (linkput ? lstat((n), (s)) : SSTAT((n), (s)))
+# else
+#  define LSTAT      SSTAT
+#  define LSSTAT     SSTAT
+#  ifdef UNICODE_SUPPORT
+#    define LSSTATW  SSTATW
+#  endif
+# endif
+
+#endif
+
+
+/*---------------------------------------------------------------------*/
+
+
+/* 2004-12-01 SMS.
+ * Added fancy zofft() macros, et c.
+ */
+
+/* Default fzofft() format selection.
+ * Modified 2004-12-27 EG
+ */
+
+#ifndef FZOFFT_FMT
+# define FZOFFT_FMT      ZOFF_T_FORMAT_SIZE_PREFIX /* printf for zoff_t values */
+
+# ifdef LARGE_FILE_SUPPORT
+#   define FZOFFT_HEX_WID_VALUE     "16"  /* width of 64-bit hex values */
+# else
+#   define FZOFFT_HEX_WID_VALUE     "8"   /* digits in 32-bit hex values */
+# endif
+
+#endif /* ndef FZOFFT_FMT */
+
+#define FZOFFT_HEX_WID ((char *) -1)
+#define FZOFFT_HEX_DOT_WID ((char *) -2)
+
+
+
+
+/* The following default definition of the second input for the crypthead()
+ * random seed computation can be used on most systems (all those that
+ * supply a UNIX compatible getpid() function).
+ */
+#ifdef ZCRYPT_INTERNAL
+#  ifndef ZCR_SEED2
+#    define ZCR_SEED2     (unsigned) getpid()   /* use PID as seed pattern */
+#  endif
+#endif /* ZCRYPT_INTERNAL */
+
+/* The following OS codes are defined in pkzip appnote.txt */
+#ifdef AMIGA
+#  define OS_CODE  0x100
+#endif
+#ifdef VMS
+#  define OS_CODE  0x200
+#endif
+/* unix    3 */
+#ifdef VM_CMS
+#  define OS_CODE  0x400
+#endif
+#ifdef ATARI
+#  define OS_CODE  0x500
+#endif
+#ifdef OS2
+#  define OS_CODE  0x600
+#endif
+#ifdef MACOS
+#  define OS_CODE  0x700
+#endif
+/* z system 8 */
+/* cp/m     9 */
+#ifdef TOPS20
+#  define OS_CODE  0xa00
+#endif
+#ifdef WIN32
+#  define OS_CODE  0xb00
+#endif
+#ifdef QDOS
+#  define OS_CODE  0xc00
+#endif
+#ifdef RISCOS
+#  define OS_CODE  0xd00
+#endif
+#ifdef VFAT
+#  define OS_CODE  0xe00
+#endif
+#ifdef MVS
+#  define OS_CODE  0xf00
+#endif
+#ifdef __BEOS__
+#  define OS_CODE  0x1000
+#endif
+#ifdef TANDEM
+#  define OS_CODE  0x1100
+#endif
+#ifdef THEOS
+#  define OS_CODE  0x1200
+#endif
+/* Yes, there is a gap here. */
+#ifdef __ATHEOS__
+#  define OS_CODE  0x1E00
+#endif
+
+#define NUM_HOSTS 31
+/* Number of operating systems. Should be updated when new ports are made */
+
+#if defined(DOS) && !defined(OS_CODE)
+#  define OS_CODE  0x000
+#endif
+
+#ifndef OS_CODE
+#  define OS_CODE  0x300  /* assume Unix */
+#endif
+
+/* can't use "return 0" from main() on VMS */
+#ifndef EXIT
+#  define EXIT  exit
+#endif
+#ifndef RETURN
+#  define RETURN return
+#endif
+
+#ifndef ZIPERR
+#  define ZIPERR ziperr
+#endif
+
+#if (defined(USE_ZLIB) && defined(MY_ZCALLOC))
+   /* special zcalloc function is not needed when linked against zlib */
+#  undef MY_ZCALLOC
+#endif
+
+#if (!defined(USE_ZLIB) && !defined(MY_ZCALLOC))
+   /* Any system without a special calloc function */
+#  define zcalloc(items,size) \
+          (zvoid far *)calloc((unsigned)(items), (unsigned)(size))
+#  define zcfree    free
+#endif /* !USE_ZLIB && !MY_ZCALLOC */
+
+/* end of tailor.h */
diff --git a/tandem/HISTORY b/tandem/HISTORY
new file mode 100644 (file)
index 0000000..59d3429
--- /dev/null
@@ -0,0 +1,97 @@
+Tandem Port History
+===================
+
+Hi, I'm Dave Smith and I work at BP Oil UK, looking after their European card
+processing system since 1992.  We need to send lots of files via FTP to other
+BP machines (Novell, NT, Sun...). Sending large files was frowned upon, so the
+search for a zip product was on.
+
+We tried the GZIP product from Twinsoft Netherlands but it was complicated to
+use and it was not widely known by other arts of BP.
+
+What we really wanted was a PKZIP compatible product, as this is a widely known
+product.  By chance when surfing the web I discovered the Info-ZIP web site.
+This claimed PKZIP 2.04g compatibility and had a number of ports, was free, and
+even had source code, but unfortunately no Tandem version :-(
+
+Thus in the autumn 1996 I bit the bullet and took on the job of porting the
+code to Tandem NSK (Guardian).  This meant dusting off my circa 1985 'C'
+programming skills and firing up the Tandem 'C' compiler - not known for its
+ease of use, especially debugging 8-;  This was all on D30 by the way.
+
+To start this off I had to choose an existing port to base te Tandem one on.
+Nearest (?) was the VM-CMS/MVS port by George Petrov.  The main similarity
+being that these machines are record based, and have a similarish filing system
+to Guardian.
+
+First to be tackled was ZIP.  By the end of 1996 I had a version which compiled
+and ran (giving the program banner) - which seemed like a major acheivement at
+the time.
+
+In December 1996 I forwarded a version of ZIP to Info-ZIP which wor
+ked only on Edit files, and had no concept of directories.  Became ZIP 2.1
+
+By March 1997 I had improved ZIP so that it could cope with Unstructured files
+as well (Became ZIP 2.2).  I also had ported a version of UNZIP which could
+create Unstructured files (not Edit) - UNZIP 5.20
+
+At the start of September 1997 I sent UNZIP with Edit file support to Info-ZIP
+(incorporated into 5.32)
+
+In March 1998 I submitted file I/O improvements (SBB) for ZIP (2.3a)
+
+In August 1998 I added Tandem DEFINE processing for ZIP (2.3e).  This was a
+feature required by BP to allow them to store files with a different internal
+name than the physical file being zipped (without renaming it).
+Also added storing of proper UTC timestamps which allow for DST & timezone.
+
+Also in August I added the same file I/O improvements for UNZIP (5.33f)
+
+I then added the ability to update the unzipped files last modified and last
+open timestamps - this required help from TNSC to allow me access to the
+priviliged procedure call.  Also can give the files back to the original user
+by use of the '-X' flag.
+
+At the end of 1998 I was given the go ahead to add the zipping of Enscribe
+files.  This first version stores all Enscribe file attributes EXCEPT SQL, alt
+key and partition information.
+
+ZIP now uses its own Guardian I/O (rather than the 'C'library) for the reading
+of files to be zipped.
+
+Unstructured files use Large Transfer mode and READ (56K or 30K reads)
+Edit files use IOEdit routines
+Enscribe files use READ and SBB and add LF to the end of each record.
+
+UNZIP has the ability to update the filecode of files restored to ther original
+value (Unstructured only)
+
+
+To Do ZIP
+===========
+1. Change I/O to use NSK/Large Transfer mode in fwrite of ZIP file itself- this
+   will dramaticaly speed up updating an existing zipfile. When updating an
+   existing zipfile it copies it to a temporary file currently using only SBB.
+2. Add raw binary mode to allow storing of raw data in zip file - e.g. only to
+   be unzipped on Tandem !  This is simplest/fastest way to provide full
+   Enscribe support for Tandem platform - with no cross-platform support.
+3. Add SQL support !!
+
+To Do UNZIP
+===========
+1. Re-write the I/O routines to use NSK to recreate the original Enscribe file
+   structure.
+2. Use NSK Large Transfer mode I/O for reading/writing of ZIP file
+3. Add raw binary mode to allow restoration of Tandem file from previous raw
+   data ZIP (see above)
+4. Add SQL support !!
+
+
+
+Current Versions on Website
+===========================
+
+ZIP 2.3
+UNZIP 5.5
+
+As of February 17th 2002
diff --git a/tandem/README b/tandem/README
new file mode 100644 (file)
index 0000000..f877aeb
--- /dev/null
@@ -0,0 +1,95 @@
+Tandem Port of Info ZIP (zip)
+=======================
+
+History:
+1. Tidy up COMMACS/MACROS/MAKE
+2. Changes for version 5.32d affected files:
+- TANDEMC     (changes to stat() for UNZIP)
+- ZIPUPC      (changes to use REVISIOH rather than REVISEH)
+- ZIPFILEC    (don't add ".zip" to ZIP name)
+- FILEIOC     (cosmetic missing "*/")
+3. Fix to allow zipping of files called ZIP (e.g. DAVES.ZIP)
+03/08/98  2.3e   Process Tandem DEFINE names - use define name as internal name
+                 Remove BITSO from build of ZIPLIB
+                 New DOIT macro for extracting files from archive
+17/08/98  2.3e   Set USE_EF_UT_TIME to allow for timezone changes
+18/08/98  2.3e   Use define LICENSED to build object able to update timestamps
+30/11/98  2.3h   Updated mapname/chmod/in2ex, include licensing in MAKE
+21/12/98  2.3i   Add simple Enscribe file handling, consisting of:
+                 - storing Enscribe files as LF delimited text files
+                 - adding Tandem Extra Field, holding Enscribe file attributes
+                 Create ZIP file with Tandem File Code 1001
+                 Rationalised TANDEMH and TANDEMC wth UNZIP 5.40d
+12/01/99  2.3i   Correct bug stopping setting of last open timestamp
+25/01/99  2.3k   Add '-B' flag to zip Enscribe files with no record delimiters
+26/01/99  2.3k   Make CRLF the default delimiter for Structured and Text files
+01/02/99  2.3k   Use maximum size large transfer read (57344) as default, allow
+                 smaller value as option
+01/02/99  2.3k   Redefine -B flag for Edit/Enscribe files as in table below.
+                 Default (-B or -B0 or no flag) is add CR/LF
+
+                 -B<number> options at present are:
+                 Bit 0 -  Don't add delimiter (Edit/Enscribe)
+                 Bit 1 -  Use LF rather than CR/LF as delimiter (Edit/Enscribe)
+                 Bit 2 -  Space fill record to max record length (Enscribe)
+                 Bit 3 -  Trim trailing space (Edit/Enscribe)
+
+                 Bit 8 -  Force 30K (Expand) large read for Unstructured files
+
+06/02/99  2.3k   Attempt to catch Large Transfer mode failure (err 21) when
+                 attempting 56K reads, add substitute 30K reads (Expand files)
+24/03/99  2.3m   Split TANDEMC into TANDEMC/TANZIPC/TANUNZC
+24/03/99  2.3m   Added TANNSKH to allow for declarations which require
+                 structures defined in ZIPH after call to TANDEMH
+11/05/99  2.3m   Change zopen in TANZIPC to allow opening of files with
+                 missing alt keys (err 4)
+                 Assume not DST if can't resolve time (no DST table available)
+27/09/99  2.3o   Fixed bug in -B0 option causing files to be stored rather than
+                 deflated. Created TANZIPH
+29/04/02  2.4g   Fixed contention on temporary file when multiple ZIPs run
+
+A few notes about the files on this subvol
+
+COMMACS   -  used by MAKE (compiler)
+DOIT      -  macro to extract required Tandem files from archive and rename
+MACROS    -  used by MAKE (bind)
+MAKE      -  recompile ZIP code, attempts to only recompile changed code
+README    -  this file
+ZIPLIB    -  library of ZIP compiled routines, used by ZIP/ZIPNOTE etc
+ZIPL      -  ZIP object (bound using LARGE memory model)
+ZIPNOTE   -  ZIPNOTE object (bound using LARGE memory model)
+
+*C        -  Source file
+*H        -  Header files
+*O        -  Individual object files (when compiled by MAKE)
+
+Install Notes:
+==============
+Stage 1 - get ZIP object onto Tandem
+- download Tandem Zip executables archive from Web
+- using PC unzip program (e.g. pkunzip/WinZip) extract ZIP
+- copy ZIP from PC to Tandem in Binary mode s(FTP/IXF)
+- alter file code to 100
+- optionally place in $SYSTEM.SYSTEM to allow easy access from command line
+
+Stage 2 - (optional) compile source code (requires UNZIP on Tandem)
+- download ZIP source archive fwom web - contains all supported platforms
+- copy archive onto Tandem as Binary
+- extract Tandem DOIT macro ( UNZIP -j <archive> tandem/DOIT )
+- update DOIT macro to point at archive file
+- restore relevant files by running DOIT
+- NOTE that revision.h must be restored as REVISIOH
+- replace references to $T with a collector on your system
+- replace references to SUPER.DAVES with whatever user id you use
+- to compile run MAKE (compiles, accelerates, licences)
+- NOTE:  Always run the accelerated object on TNS/R systems, otherwise
+         it runs extremely slow.
+
+
+Additional Notes - LICENSE the object:
+======================================
+If you wish to be able to update the last modified time of the zip file
+(-o option) you need to add the line "#define LICENSED" to the TANDEMH file.
+If you set this option then you MUST FUP LICENSE the file as SUPER.SUPER.
+This is a Tandem restriction since we have to call a PRIV procedure to update
+the file label.  For ZIP the define is setup (default) in tandem.h
diff --git a/tandem/commacs b/tandem/commacs
new file mode 100644 (file)
index 0000000..31e91a1
--- /dev/null
@@ -0,0 +1,94 @@
+?section CC ROUTINE
+#FRAME
+[#PUSH file stem src obj htime file prev time stime otime
+       comp out options sup buf col locn group
+]
+
+[#IF [#ARGUMENT /VALUE file/ WORD /SPACE/ END]]
+[#IF [#EMPTYV file] |THEN|
+  #OUTPUT Syntax: CC <file> <collector> <comp-options>
+  #RESET FRAMES
+  #RETURN
+]
+
+[#IF NOT [#FILEINFO /EXISTENCE/ [file]]
+|THEN|
+  #OUTPUT [file] does not exist !
+  #RESET FRAMES
+  #RETURN
+]
+
+#PUSH #DEFAULTS vol subvol
+#SETMANY vol subvol src, [#FILEINFO /VOLUME, SUBVOL, FILE/ [file]]
+VOLUME [vol].[subvol]
+
+#SETV stem file
+#CHARDEL stem [#CHARCOUNT stem]
+#SET obj [stem]O
+#SETV stem src
+#CHARDEL stem [#CHARCOUNT stem]
+
+[#IF [#ARGUMENT /VALUE out/ DEVICE END]]
+[#IF [#EMPTYV out] |THEN| #SET out $T.#C]
+
+#SETMANY col group, [#FILEINFO /VOLUME, SUBVOL/ [out]]
+#SET locn [group].[stem]
+#SET sup [#LOOKUPPROCESS /ANCESTOR/ [col]]
+
+#SET options [#REST]
+
+== Find newest Header file
+#SET htime 0
+#SET file [#FILENAMES /MAXIMUM 1/ *H]
+[#LOOP |WHILE| NOT [#EMPTYV file]
+|DO|
+  #SET time [#FILEINFO /MODIFICATION/ [file]]
+  [#IF time > htime |THEN| #SETV htime time]
+
+  #SETV prev file
+  #SET file [#FILENAMES /MAXIMUM 1, PREVIOUS [prev]/ *H]
+]
+
+#SET stime [#FILEINFO /MODIFICATION/ [src]]
+#SET otime [#FILEINFO /MODIFICATION/ [obj]]
+
+#SET comp 0
+
+[#IF otime < htime
+|THEN|
+  #OUTPUT Header file(s) changed since object [obj] compiled
+  #SET comp -1
+]
+
+[#IF otime < stime
+|THEN|
+  #OUTPUT Source file [src] changed since object [obj] compiled
+  #SET comp -1
+]
+
+[#IF comp
+|THEN|
+  SPOOLCOM /OUTV buf/ OPEN [sup];JOB (OWNER, LOC [locn]),STATUS,DELETE !
+  #SET buf
+  #OUTPUT Compiling [src]... [options]
+  C /IN [src], OUT [out].[stem]/[obj];SYMBOLS,HIGHPIN [options]
+  [#CASE [tacl^completioncode]
+  | 0 |
+    #OUTPUT Compiled OK: [src]
+    SPOOLCOM /OUTV buf/ OPEN [sup];JOB (OWNER, LOC [locn]),STATUS,DELETE !
+    #SET _completion:completioncode 0
+  | 1 |
+    #OUTPUT [src]: Compile Warnings
+    SPOOLCOM /OUTV buf/ OPEN [sup];JOB (OWNER, LOC [locn]),STATUS
+    #OUTPUTV buf
+  |OTHERWISE|
+    #OUTPUT [src]: Compile FAILED !
+    SPOOLCOM /OUTV buf/ OPEN [sup];JOB (OWNER, LOC [locn]),STATUS
+    #OUTPUTV buf
+  ]
+|ELSE|
+  #OUTPUT Object file [obj] is up to date
+  #SET _completion:completioncode 0
+]
+
+#UNFRAME
diff --git a/tandem/doit b/tandem/doit
new file mode 100644 (file)
index 0000000..1388730
--- /dev/null
@@ -0,0 +1,21 @@
+?tacl macro
+#frame
+#push zipfile
+#SET zipfile [#FILEINFO /SUBVOL/ A]
+
+unzip -a [zipfile] *.c  -x */*
+== Following not required
+RENAME apic     apicz
+RENAME timezonc timezonz
+
+unzip -a [zipfile] *.h -x */*
+== Following not required
+RENAME apih    apizh
+
+unzip -aj [zipfile] tandem/*.h
+
+unzip -aj [zipfile] tandem/*.c
+
+unzip -aj [zipfile] tandem/* -x tandem/*.*
+
+#unframe
diff --git a/tandem/macros b/tandem/macros
new file mode 100644 (file)
index 0000000..ab1505b
--- /dev/null
@@ -0,0 +1,571 @@
+?section ADD^LIST routine
+[#IF [#ARGUMENT /VALUE item/ WORD/SPACE/]]
+#APPEND bin ADD * FROM [item]
+#SET itime [#FILEINFO /MODIFICATION/ [item]]
+[#IF itime > ntime |THEN| #SETV ntime itime]
+
+?section BBZIPLIB MACRO
+#FRAME
+#push bin item ntime itime libtime
+#SET ntime 0
+
+#OUTPUT Building [lib]
+#APPEND bin CLEAR
+add^list CRC32O
+add^list CRYPTO
+add^list DEFLATEO
+add^list FILEIOO
+add^list GLOBALSO
+add^list TANDEMO
+add^list TANZIPO
+add^list TREESO
+add^list TTYIOO
+add^list UTILO
+add^list ZIPFILEO
+add^list ZIPUPO
+#APPEND bin INFO UNRESOLVED *
+#APPEND bin BUILD [lib] ! , LIST * OFF
+
+#SET libtime [#FILEINFO /MODIFICATION/ [lib]]
+[#IF libtime < ntime
+|THEN|
+  #OUTPUT [lib] needs re-building
+  BIND /NAME,INV BIN/
+  [#CASE [tacl^completioncode]
+  | 0         | #OUTPUT Bound [lib] OK
+  | 1         | #OUTPUT [lib]: BIND Failed with Warnings
+  | OTHERWISE | #OUTPUT [lib]: BIND Failed with ERRORS !
+  ]
+|ELSE|
+  #OUTPUT [lib] is up to date
+]
+
+#UNFRAME
+
+?section BBZIP MACRO
+#FRAME
+#push bin ziptime build
+#SET build 0
+#OUTPUT Building %1% with %2% memory model
+#APPEND bin CLEAR
+#APPEND bin ADD * FROM ZIPO
+#APPEND bin select search ($system.system.c%2%, [lib])
+#APPEND bin select runnable object on
+#APPEND bin select list * off
+#APPEND bin set heap 20 pages
+#APPEND bin set symbols on
+#APPEND bin set saveabend on
+#APPEND bin set inspect on
+#APPEND bin info unresolved *
+#APPEND bin BUILD %1%   !
+
+#SET ziptime [#FILEINFO /MODIFICATION/ %1%]
+[#IF ziptime < [#FILEINFO /MODIFICATION/ ZIPO] |THEN|
+  #OUTPUT %1% is older than ZIPO
+  #SET build -1
+]
+[#IF ziptime < [#FILEINFO /MODIFICATION/ [lib]] |THEN|
+  #OUTPUT %1% is older than [lib]
+  #SET build -1
+]
+[#IF build
+|THEN|
+  #OUTPUT %1% is out of date, re-building
+  BIND /NAME,INV BIN/
+  [#CASE [tacl^completioncode]
+  | 0         | #OUTPUT Bound %1% OK
+  | 1         | #OUTPUT %1%: BIND Failed with Warnings
+  | OTHERWISE | #OUTPUT %1%: BIND Failed with ERRORS !
+  ]
+|ELSE|
+  #OUTPUT %1% is up to date, no re-build required
+]
+
+#UNFRAME
+
+?section BBANY MACRO
+#FRAME
+#push bin memory anytime build
+#SET build 0
+#SETMANY memory, %2% LARGE
+#OUTPUT Building %1% with [memory] memory model
+#APPEND bin CLEAR
+#APPEND bin ADD * FROM %1%O
+#APPEND bin select search ($system.system.c[memory],[lib])
+#APPEND bin select runnable object on
+#APPEND bin select list * off
+#APPEND bin set heap 20 pages
+#APPEND bin set symbols on
+#APPEND bin set saveabend on
+#APPEND bin set inspect on
+#APPEND bin info unresolved *
+#APPEND bin BUILD %1%   !
+
+#SET anytime [#FILEINFO /MODIFICATION/ %1%]
+[#IF anytime < [#FILEINFO /MODIFICATION/ %1%O] |THEN|
+  #OUTPUT %1% is older than %1%O
+  #SET build -1
+]
+[#IF anytime < [#FILEINFO /MODIFICATION/ [lib]] |THEN|
+  #OUTPUT %1% is older than [lib]
+  #SET build -1
+]
+[#IF build
+|THEN|
+  #OUTPUT %1% is out of date, re-building
+  BIND /NAME,INV BIN/
+  [#CASE [tacl^completioncode]
+  | 0         | #OUTPUT Bound %1% OK
+  | 1         | #OUTPUT %1%: BIND Failed with Warnings
+  | OTHERWISE | #OUTPUT %1%: BIND Failed with ERRORS !
+  ]
+|ELSE|
+  #OUTPUT %1% is up to date, no re-build required
+]
+
+#UNFRAME
+
+
+?section BBUNZIPLIB MACRO
+#FRAME
+#push bin item ntime itime libtime
+#SET ntime 0
+
+#OUTPUT Building [lib]
+#APPEND bin CLEAR
+add^list CRC32O
+add^list CRYPTO
+add^list ENVARGSO
+add^list EXPLODEO
+add^list EXTRACTO
+add^list FILEIOO
+add^list GLOBALSO
+add^list INFLATEO
+add^list LISTO
+add^list MATCHO
+add^list PROCESSO
+add^list TANDEMO
+add^list TANUNZO
+add^list TTYIOO
+add^list UNSHRINO
+add^list ZIPINFOO
+#APPEND bin INFO UNRESOLVED *
+#APPEND bin BUILD [lib] ! , LIST * OFF
+
+#SET libtime [#FILEINFO /MODIFICATION/ [lib]]
+[#IF libtime < ntime
+|THEN|
+  #OUTPUT [lib] needs re-building
+  BIND /NAME,INV BIN/
+  [#CASE [tacl^completioncode]
+  | 0         | #OUTPUT Bound [lib] OK
+  | 1         | #OUTPUT [lib]: BIND Failed with Warnings
+  | OTHERWISE | #OUTPUT [lib]: BIND Failed with ERRORS !
+  ]
+|ELSE|
+  #OUTPUT [lib] is up to date
+]
+
+#UNFRAME
+
+?section BBUNZIP MACRO
+#FRAME
+#push bin ziptime build
+#SET build 0
+#OUTPUT Building %1% with %2% memory model
+#APPEND bin CLEAR
+#APPEND bin ADD * FROM UNZIPO
+#APPEND bin select search ($system.system.c%2%,[lib])
+#APPEND bin select runnable object on
+#APPEND bin select list * off
+#APPEND bin set heap 20 pages
+#APPEND bin set symbols on
+#APPEND bin set saveabend on
+#APPEND bin set inspect on
+#APPEND bin info unresolved *
+#APPEND bin BUILD %1%   !
+
+#SET ziptime [#FILEINFO /MODIFICATION/ %1%]
+[#IF ziptime < [#FILEINFO /MODIFICATION/ UNZIPO] |THEN|
+  #OUTPUT %1% is older than UNZIPO
+  #SET build -1
+]
+[#IF ziptime < [#FILEINFO /MODIFICATION/ [lib]] |THEN|
+  #OUTPUT %1% is older than [lib]
+  #SET build -1
+]
+[#IF build
+|THEN|
+  #OUTPUT %1% is out of date, re-building
+  BIND /NAME,INV BIN/
+  [#CASE [tacl^completioncode]
+  | 0         | #OUTPUT Bound %1% OK
+  | 1         | #OUTPUT %1%: BIND Failed with Warnings
+  | OTHERWISE | #OUTPUT %1%: BIND Failed with ERRORS !
+  ]
+|ELSE|
+  #OUTPUT %1% is up to date, no re-build required
+]
+
+#UNFRAME
+
+?section BBSFXLIB MACRO
+#FRAME
+#push bin item ntime itime libtime
+#SET ntime 0
+
+#OUTPUT Building [lib]
+#APPEND bin CLEAR
+add^list CRC32O
+add^list EXTRACTX
+add^list FILEIOX
+add^list GLOBALSX
+add^list INFLATEX
+add^list MATCHX
+add^list PROCESSX
+add^list TANDEMX
+add^list TANUNZX
+add^list TTYIOX
+#APPEND bin INFO UNRESOLVED *
+#APPEND bin BUILD [lib] ! , LIST * OFF
+
+#SET libtime [#FILEINFO /MODIFICATION/ [lib]]
+[#IF libtime < ntime
+|THEN|
+  #OUTPUT [lib] needs re-building
+  BIND /NAME,INV BIN/
+  [#CASE [tacl^completioncode]
+  | 0         | #OUTPUT Bound [lib] OK
+  | 1         | #OUTPUT [lib]: BIND Failed with Warnings
+  | OTHERWISE | #OUTPUT [lib]: BIND Failed with ERRORS !
+  ]
+|ELSE|
+  #OUTPUT [lib] is up to date
+]
+
+#UNFRAME
+
+?section BBSFX MACRO
+#FRAME
+#push bin ziptime build
+#SET build 0
+#OUTPUT Building %1% with %2% memory model
+#APPEND bin CLEAR
+#APPEND bin ADD * FROM UNZIPX
+#APPEND bin select search ($system.system.c%2%,[lib])
+#APPEND bin select runnable object on
+#APPEND bin select list * off
+#APPEND bin set heap 20 pages
+#APPEND bin set symbols on
+#APPEND bin set saveabend on
+#APPEND bin set inspect on
+#APPEND bin info unresolved *
+#APPEND bin BUILD %1%   !
+
+#SET ziptime [#FILEINFO /MODIFICATION/ %1%]
+[#IF ziptime < [#FILEINFO /MODIFICATION/ UNZIPX] |THEN|
+  #OUTPUT %1% is older than UNZIPX
+  #SET build -1
+]
+[#IF ziptime < [#FILEINFO /MODIFICATION/ [lib]] |THEN|
+  #OUTPUT %1% is older than [lib]
+  #SET build -1
+]
+[#IF build
+|THEN|
+  #OUTPUT %1% is out of date, re-building
+  BIND /NAME,INV BIN/
+  [#CASE [tacl^completioncode]
+  | 0         | #OUTPUT Bound %1% OK
+  | 1         | #OUTPUT %1%: BIND Failed with Warnings
+  | OTHERWISE | #OUTPUT %1%: BIND Failed with ERRORS !
+  ]
+|ELSE|
+  #OUTPUT %1% is up to date, no re-build required
+]
+
+#UNFRAME
+
+?section accel^file MACRO
+#FRAME
+#PUSH buf
+[#IF [#FILEINFO /MODIFICATION/ %1%]
+   > [#FILEINFO /MODIFICATION/ %2%]
+|THEN|
+  #OUTPUT %2% is older than %1%
+  #OUTPUT Accelerating %1% to %2%
+  AXCEL /OUTV buf/ %1%,%2%
+  #OUTPUTV buf
+  [#CASE [tacl^completioncode]
+  | 0         | #OUTPUT Accelerated %2% OK
+  | 1         | #OUTPUT %2%: AXCEL Failed with Warnings
+  | OTHERWISE | #OUTPUT %2%: AXCEL Failed with ERRORS !
+  ]
+|ELSE|
+  #OUTPUT %2% is up to date
+]
+
+#UNFRAME
+
+?section fup^license ROUTINE
+#FRAME
+#PUSH #DEFAULTS filename old^user current^user
+
+[#IF [#ARGUMENT /VALUE filename/ FILENAME]]
+
+#SET old^user [#USERNAME [#PROCESSINFO /PAID/]]
+#SETV current^user old^user
+[#LOOP |WHILE| current^user '<>' "SUPER.SUPER"
+               AND NOT [#INPUTEOF]
+|DO|
+  #OUTPUT Please log on as SUPER.SUPER (CTRL-Y aborts)
+  logon SUPER.SUPER
+  #SET current^user [#USERNAME [#PROCESSINFO /PAID/]]
+  #OUTPUT
+]
+
+[#IF current^user '=' "SUPER.SUPER" |THEN|
+  #OUTPUT Licensing [filename]
+  $SYSTEM.SYSTEM.FUP LICENSE [filename]
+]
+
+[#LOOP |WHILE| current^user '<>' old^user
+               AND NOT [#INPUTEOF]
+|DO|
+  #OUTPUT Please log on as [old^user] (CTRL-Y aborts)
+  logon [old^user]
+  #SET current^user [#USERNAME [#PROCESSINFO /PAID/]]
+  #OUTPUT
+]
+
+#UNFRAME
+
+
+?section CODE routine
+#FRAME
+#PUSH delta arg
+
+#SET /TYPE delta/ DELTA
+
+[#LOOP |WHILE| [#COMPUTE [#ARGUMENT /VALUE arg/ NUMBER END] = 1 ]
+|DO|
+  #APPEND DELTA [arg]I
+]
+
+#RESULT [#DELTA /COMMANDS DELTA/]
+
+#UNFRAME
+
+
+?section TACL^COMPLETIONCODE routine
+#RESULT [_completion:completioncode]
+
+?SECTION INCREMENT routine
+#FRAME
+#PUSH increment_variable increment_value
+
+[#IF [#ARGUMENT /VALUE increment_variable/ VARIABLE]]
+[#IF [#EMPTYV [increment_variable]]|THEN|#SET [increment_variable] 0]
+[#IF [#MORE]
+  |THEN|
+    [#IF [#ARGUMENT /VALUE increment_value/ NUMBER]]
+  |ELSE|
+    #SET increment_value 1
+]
+[#IF [#ARGUMENT END]]
+
+#SET [increment_variable] [#COMPUTE [increment_variable] + [increment_value]]
+
+#UNFRAME
+
+?section ERROR^IN^FUP^OUTPUT routine
+#FRAME
+#PUSH err output last line type
+
+#SETMANY err output, 0 0
+
+[#LOOP |WHILE| NOT [#EMPTYV fup^out]
+|DO|
+   #EXTRACTV fup^out line
+   [#SETMANY type, [#CHARGET line 1 TO 7] .]
+   [#CASE [type]
+     | ERROR     | #SETMANY output err, -1 -1
+     | WARNING   | #SET output -1
+     | OTHERWISE |
+   ]
+   [#IF output |THEN|
+     #OUTPUTV last
+     #OUTPUTV line
+     #SET output 0
+     #EXTRACTV fup^out line
+   ]
+   #SETV last line
+]
+
+#RESULT [err]
+
+#UNFRAME
+
+?section SECURE^FILE routine
+#FRAME
+
+[#DEF fup^out TEXT |BODY|]
+[#DEF fup^buf TEXT |BODY|]
+
+[#DEF fup^cmd MACRO |BODY|
+  FUP /OUTV fup^out/ %*%
+  #SETV fup^buf fup^out
+  [#IF [error^in^fup^output]
+  |THEN|
+    #OUTPUT Error detected in FUP output, ABORTING !!
+    #OUTPUT ..............................................................
+    #OUTPUTV fup^buf
+    #OUTPUT ..............................................................
+    #RAISE _BREAK
+  ]
+]
+
+[#DEF display^action MACRO |BODY|
+  [#IF NOT action |THEN|
+    #OUTPUT /HOLD/ Updating [file] ...
+    #SET action -1
+    #SET count 0
+  ]
+  #OUTPUT /COLUMN 3/ ... %*%
+]
+
+[#DEF display^noaction MACRO |BODY|
+  [#IF count
+  |THEN|
+    increment count
+  |ELSE|
+    #OUTPUT
+    #SET count 1
+  ]
+  [#IF count |THEN|
+    #OUTPUT /COLUMN [count]/ [code 27]A.
+    [#IF count > 75
+    |THEN|
+      #SET count 0
+    ]
+  ]
+]
+
+[#DEF process^file TEXT |BODY|
+  #SET action 0
+  #SETMANY cur^owner cur^security cur^license cur^progid, &
+    [#FILEINFO /OWNER, SECURITY, LICENSED, PROGID/ [file]]
+
+  #SET cur^owner [#USERNAME [cur^owner]]
+
+  [#IF NOT [#EMPTYV owner]
+  |THEN|
+    [#IF owner '<>' cur^owner
+    |THEN|
+      display^action giving to [owner]  (was [cur^owner])
+      fup^cmd GIVE [file], [owner]
+      [#IF cur^progid
+      |THEN|
+        #OUTPUT /COLUMN 3/... WARNING!  Loss of PROGID flag
+        #SET cur^progid 0
+      ]
+    ]
+  ]
+  [#IF NOT [#EMPTYV security]
+  |THEN|
+    [#IF security '<>' cur^security
+    |THEN|
+      display^action securing to [security] (was [cur^security])
+      fup^cmd SECURE [file], [security]
+    ]
+  ]
+  [#IF license |THEN|
+    [#IF NOT cur^license
+    |THEN|
+      display^action licensed
+      fup^cmd LICENSE [file]
+    ]
+  ]
+  [#IF progid |THEN|
+    [#IF NOT cur^progid
+    |THEN|
+      display^action PROGID flag set
+      fup^cmd SECURE [file],, PROGID
+    ]
+  ]
+  [#IF action
+  |THEN|
+    fup^cmd INFO [file]
+  |ELSE|
+    [#IF tflag
+    |THEN|
+      display^noaction
+    |ELSE|
+      #OUTPUT  /HOLD/ Unchanged : [file]
+      [#IF cur^progid  |THEN| #OUTPUT /COLUMN 39,HOLD/ P]
+      [#IF cur^license |THEN| #OUTPUT /COLUMN 40,HOLD/ L]
+      #OUTPUTV /COLUMN 43,HOLD/ cur^security
+      #OUTPUTV /COLUMN 50,HOLD/ cur^owner
+      #OUTPUT
+    ]
+ ]
+]
+
+#PUSH arg template file security owner progid license prev action count tflag
+#PUSH cur^security cur^owner cur^license cur^progid
+
+#SETMANY license progid, 0 0
+#SET count 0
+#SET tflag 0
+
+[#LOOP |WHILE| [#MORE]
+|DO|
+  [#CASE [#ARGUMENT /VALUE arg/ FILENAME
+                                USER /USERNAME/
+                                USER
+                                SECURITY
+                                KEYWORD /WORDLIST LICENSE/
+                                KEYWORD /WORDLIST PROGID/
+                                TEMPLATE
+         ]
+  | 1 | #SETV file     arg
+  | 2 | #SETV owner    arg
+  | 3 | #SET  owner [#USERNAME [arg]]
+  | 4 | #SETV security arg
+  | 5 | #SET  license  -1
+  | 6 | #SET  progid   -1
+  | 7 | #SETV template arg
+  ]
+]
+[#IF [#ARGUMENT END]]
+
+
+[#IF [#EMPTYV template]
+|THEN|
+  #SETV template file
+|ELSE|
+  #SET tflag -1
+  #OUTPUT /HOLD/ Template : [template]
+  [#IF progid  |THEN| #OUTPUT /COLUMN 39,HOLD/ P]
+  [#IF license |THEN| #OUTPUT /COLUMN 40,HOLD/ L]
+  [#IF NOT [#EMPTYV security] |THEN| #OUTPUTV /HOLD/ "  "[security]""]
+  [#IF NOT [#EMPTYV owner]    |THEN| #OUTPUTV /HOLD/ "  [owner]"]
+  #OUTPUT
+]
+
+[#IF [#EMPTYV template]
+|THEN|
+  #OUTPUT ERROR!  No filename specified
+  #RESET FRAMES
+  #RETURN
+|ELSE|
+  #SET file [#FILENAMES /MAXIMUM 1/ [template]]
+  [#LOOP |WHILE| NOT [#EMPTYV file]
+  |DO|
+    process^file
+    #SETV prev file
+    #SET file [#FILENAMES /MAXIMUM 1, PREVIOUS [prev]/ [template]]
+  ]
+]
+
+#UNFRAME
diff --git a/tandem/make b/tandem/make
new file mode 100644 (file)
index 0000000..84efb4d
--- /dev/null
@@ -0,0 +1,130 @@
+?tacl routine
+#FRAME
+SINK [#LOAD /keep 1/ commacs]
+SINK [#LOAD /keep 1/ macros]
+
+[#PUSH file prev memory clib OK model zip lib accel unlicensed licensed
+       options fileset nocrypt crypt
+]
+#PUSH #DEFAULTS
+
+#SET OK -1
+
+[#IF [#ARGUMENT /VALUE memory/ KEYWORD /WORDLIST LARGE SMALL/ OTHERWISE ]]
+[#IF [#ARGUMENT /VALUE model/ KEYWORD /WORDLIST NOWIDE WIDE/ OTHERWISE ]]
+[#IF [#ARGUMENT /VALUE unlicensed/ KEYWORD /WORDLIST UNLICENSED/ OTHERWISE ]]
+[#IF [#ARGUMENT /VALUE nocrypt/ KEYWORD /WORDLIST NOCRYPT/ OTHERWISE ]]
+[#IF [#ARGUMENT /VALUE fileset/ TEMPLATE FILENAME OTHERWISE ]]
+
+[#IF [#EMPTYV memory] |THEN| #SET memory LARGE]
+[#IF [#EMPTYV model] |THEN| #SET model NOWIDE]
+
+[#IF model '=' "WIDE"
+  |THEN| #SETV clib model
+  |ELSE| #SETV clib memory
+]
+
+[#IF model '=' "WIDE"
+|THEN|
+  #SET zip ZIPW
+|ELSE|
+  #SET zip ZIPL
+]
+#SET lib [zip]B
+#SET accel ZIP
+#SET options [options], [model]
+
+[#IF unlicensed '=' "UNLICENSED"
+|THEN|
+  #SET zip [zip]U
+  #SET accel [accel]U
+  #SET lib   [lib]U
+|ELSE|
+  #SET licensed LICENSED
+  #SET options [options], define [licensed]
+]
+
+[#IF nocrypt '=' "NOCRYPT"
+|THEN|
+|ELSE|
+  #SET crypt USE_CRYPT
+  #SET options [options], define [crypt]
+]
+
+[#IF [#EMPTYV fileset] |THEN| #SET fileset *C]
+
+#OUTPUT Files to compile: [fileset]
+#OUTPUT Pointer Model   : [model]
+#OUTPUT Memory Model    : [memory]
+#OUTPUT C Library       : [clib]
+#OUTPUT Axcel Object    : [accel]
+#OUTPUT Run Object      : [zip]
+#OUTPUT Library Object  : [lib]
+#OUTPUT Compile Options : [options]
+#OUTPUT
+
+#SET file [#FILENAMES /MAXIMUM 1/ [fileset]]
+[#loop |while| NOT [#EMPTYV file]
+|do|
+  #SETV prev file
+  CC [file] $T.#ZIP [options]
+  [#IF [tacl^completioncode] > 1 |THEN| #set OK 0 ]
+  #SET file [#FILENAMES /MAXIMUM 1, PREVIOUS [prev]/ [fileset]]
+]
+
+[#IF OK |THEN|
+  BBZIPLIB
+  [#IF [tacl^completioncode] > 0 |THEN| #SET OK 0]
+]
+
+#PUSH #PROCESSFILESECURITY
+VOLUME ,"NUNU"
+
+[#IF OK |THEN|
+  BBZIP [zip] [clib]
+  [#IF [tacl^completioncode] > 0 |THEN| #SET OK 0]
+]
+
+[#IF OK |THEN|
+  secure^file [accel] "UUUU" SUPER.DAVES
+  accel^file [zip] [accel]
+  [#IF [tacl^completioncode] > 0 |THEN| #SET OK 0]
+]
+
+[#IF OK
+  |THEN| #OUTPUT Successfully produced Accelerated Object [accel]
+         secure^file [accel] "UUUU" SUPER.DAVES
+         [#IF [#INTERACTIVE] |THEN|
+           [#IF licensed '=' "LICENSED" |THEN|
+             #OUTPUT [accel] will not run without being LICENSED
+             [#IF [#FILEINFO /LICENSED/ [accel]]
+             |THEN|
+               #OUTPUT [accel] already LICENSED
+             |ELSE|
+               [#IF [#MATCH Y* [#INPUT [accel] License [accel] ?]] |THEN|
+                 fup^license [accel]
+               ]
+             ]
+           ]
+         ]
+  |ELSE| #OUTPUT Failed to produce Accelerated Object [accel]
+]
+
+#OUTPUT Finished
+
+#OUTPUT Setting up additonal utilities
+== ZIPNOTE
+CC ZIPNOTEC $T.#ZIP [options]
+#SET zip ZIPNOTE
+#SET accel ZIPNOTE
+[#IF OK |THEN|
+  BBANY [zip] [clib]
+  [#IF [tacl^completioncode] > 0 |THEN| #SET OK 0]
+]
+[#IF OK |THEN|
+  secure^file [accel] "UUUU" SUPER.DAVES
+  accel^file [zip] [accel]
+  [#IF [tacl^completioncode] > 0 |THEN| #SET OK 0]
+]
+
+#UNFRAME
diff --git a/tandem/tandem.c b/tandem/tandem.c
new file mode 100644 (file)
index 0000000..0aa1e06
--- /dev/null
@@ -0,0 +1,889 @@
+/*
+  Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * routines common to TANDEM (ZIP and UNZIP)
+ */
+
+#include "zip.h"   /* This sets up ZIP / UNZIP define */
+
+#include <tal.h>
+#include "$system.zsysdefs.zsysc" nolist
+#include <cextdecs> nolist
+#include "tannsk.h"
+
+static time_t gmt_to_time_t (long long *);
+
+int isatty (fnum)
+int fnum;
+{
+  return 1;
+}
+
+/********************/
+/* Function in2ex() */
+/********************/
+
+#ifdef UNZIP
+char *in2ex(__G__ n)
+  __GDEF
+#else
+char *in2ex(n)
+#endif
+  char *n;              /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name buffer */
+  char *y;              /* pointer to external buffer */
+  char *max;            /* pointer to max end of next file part */
+  char *t;              /* pointer to internal - start of substring */
+  char *p;              /* pointer to internal - TANDEM delimiter */
+  char *e;              /* pointer to internal - DOS extension delimiter */
+  char *z;              /* pointer to internal - end of substring */
+  int len;              /* length of substring to copy to external name */
+  int allow_dollar;     /* $ symbol allowed as next character */
+
+  if ((x = malloc(strlen(n) + 4)) == NULL)  /* + 4 for safety */
+    return NULL;
+
+  *x = '\0';
+
+  /* Junk pathname as requested */
+#ifdef UNZIP
+  if (uO.jflag && (t = strrchr(n, INTERNAL_DELIMITER)) != NULL)
+    ++t;
+  else
+    t = n;
+#endif /* UNZIP */
+#ifdef ZIP
+  if (!pathput)
+    t = last(n, INTERNAL_DELIMITER);
+  else
+    t = n;
+#endif /* ZIP */
+
+  allow_dollar = TRUE;
+
+  while (*t != '\0') {  /* File part could be sys, vol, subvol or file */
+    if (*t == INTERNAL_DELIMITER) {    /* System, Volume or Subvol Name */
+      t++;
+      if (*t == INTERNAL_DELIMITER) {  /* System */
+        strcat(x, TANDEM_NODE_STR);
+        t++;
+      }
+      else {
+        strcat(x, TANDEM_DELIMITER_STR);
+        allow_dollar = FALSE;
+      }
+    }
+    /* Work out where end of current external string is */
+    y = x + strlen(x);
+
+    /* Work out substring to copy and externalise */
+    p = strchr(t, INTERNAL_DELIMITER);
+    e = strchr(t, DOS_EXTENSION);
+    if (p != NULL) {
+      if (e > p)
+        e = NULL;
+    }
+
+    z = e;
+    if (z == NULL)
+      z = p;
+    if (z == NULL)
+      z = t + strlen(t);
+
+    /* can't have Tandem name longer than 8 characters */
+    max = y + MAXFILEPARTLEN;
+
+    /* Allow $ symbol as first character in some cases */
+    if (*t == '$') {
+      if (allow_dollar)
+        *y++ = *t++;
+      else;
+        *t++;
+    }
+
+    /* Make sure first real character is alpha */
+    if (! isalpha(*t) )
+      *y++ = 'A';
+
+    /* Characters left to process */
+    len = z - t;
+
+    while ( len > 0 ) {
+      if ( isalnum(*t) ) {
+        *y++ = toupper(*t++);
+        if (y >= max)
+          break;
+      }
+      else
+        t++;
+      len--;
+    }
+    *y = '\0';
+    t = p;
+
+    if (p == NULL) {
+      /* Last part of filename, store pseudo extension if available */
+      if (e != NULL) {
+        strcat(x, TANDEM_EXTENSION_STR);
+        y = x + strlen(x);
+
+        /* no restriction on extension length as its virtual */
+        z = e + 1;
+        while ( *z != '\0' ) {
+          *y++ = toupper(*z++);
+        }
+        *y = '\0';
+      }
+      break;
+    }
+  }
+
+  return x;
+}
+
+void zexit(status)
+  int status;
+{
+  /* Exit(>0) creates saveabend files */
+  terminate_program (0,0,(short)status,,,);
+}
+
+/************************/
+/*  Function zputc()    */
+/************************/
+
+#ifdef putc
+#  undef putc
+#endif
+
+int zputc(ch, fptr)
+  int ch;
+  FILE *fptr;
+{
+  int err;
+  err = putc(ch,fptr);
+  fflush(fptr);
+  return err;
+}
+#define putc zputc
+
+#ifdef LICENSED
+_tal _priv short FILE_CHANGELABEL_ (
+ short,          /* IN */
+ short,          /* IN */
+ const short _far *    /* IN */
+ );
+
+_c _callable int changelabel OF((short, const short *, const short *));
+
+_c _callable int changelabel(fnum, modtime, actime)
+  short fnum;
+  const short *modtime;
+  const short *actime;
+{
+  int err;
+
+  err = FILE_CHANGELABEL_(fnum, 16, modtime);
+  if (!err)
+    err = FILE_CHANGELABEL_(fnum, 17, actime);
+  return err;
+}
+
+int islicensed(void)
+{
+  #define plist_items 1
+  #define plist_size 10
+
+  short myphandle[ZSYS_VAL_PHANDLE_WLEN];
+  short licensetag[plist_items] = {37};
+  short licensed[plist_size];
+  short maxlen = plist_size;
+  short items = plist_items;
+  short resultlen[1], err;
+
+  err = PROCESSHANDLE_NULLIT_(myphandle);
+
+  if (!err)
+    err = PROCESS_GETINFO_(myphandle);
+
+  if (!err)
+    err = PROCESS_GETINFOLIST_(/*cpu*/,
+                               /*pin*/,
+                               /*nodename*/,
+                               /*nodenamelen*/,
+                               myphandle,
+                               licensetag,
+                               items,
+                               licensed,
+                               maxlen,
+                               resultlen
+                              );
+
+  if (err != 0)
+    return 0;
+  else
+    return licensed[0];
+}
+#endif /* LICENSED */
+
+int utime(file, time)
+  const char *file;
+  const ztimbuf *time;
+{
+#ifdef LICENSED
+  int result, err;
+  union timestamp_ov {
+    long long fulltime;
+    short wordtime[4];
+  };
+  union timestamp_ov lasttime, opentime;
+  struct tm *modt, *opent;
+  short datetime[8], errormask[1];
+  short len, fnum, access, exclus, options;
+  char fname[FILENAME_MAX + 1];
+  short extension;
+  char ext[EXTENSION_MAX + 1];
+
+  if (islicensed() ) {
+    /* Attempt to update file label */
+    modt = gmtime( &time->modtime );
+
+    datetime[0] = modt->tm_year + 1900;
+    datetime[1] = modt->tm_mon + 1;
+    datetime[2] = modt->tm_mday;
+    datetime[3] = modt->tm_hour;
+    datetime[4] = modt->tm_min;
+    datetime[5] = modt->tm_sec;
+    datetime[6] = datetime[7] = 0;
+    errormask[0] = 0;
+    lasttime.fulltime = COMPUTETIMESTAMP (datetime, errormask);
+
+    opent = gmtime( &time->actime );
+
+    datetime[0] = opent->tm_year + 1900;
+    datetime[1] = opent->tm_mon + 1;
+    datetime[2] = opent->tm_mday;
+    datetime[3] = opent->tm_hour;
+    datetime[4] = opent->tm_min;
+    datetime[5] = opent->tm_sec;
+    datetime[6] = datetime[7] = 0;
+    errormask[0] = 0;
+    opentime.fulltime = COMPUTETIMESTAMP (datetime, errormask);
+
+    /* Remove any (pseudo) file extension */
+    extension = parsename (file,fname,ext);
+    len = strlen(fname);
+
+    access = NSK_WRONLY;
+    exclus = NSK_SHARED;
+    options = NSK_NOUPDATEOPENTIME;
+
+    extension = parsename (file,fname,ext);
+    len = strlen(fname);
+
+    err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,,,options,,,);
+    result = changelabel(fnum,lasttime.wordtime,opentime.wordtime);
+    err = FILE_CLOSE_(fnum);
+    return result;
+  }
+  return -1;
+#else  /* !LICENSED */
+  return 0;             /* "no error", to suppress annoying failure messages */
+#endif  /* ?LICENSED */
+}
+
+/* TANDEM version of chmod() function */
+
+int chmod(file, unix_sec)
+  const char *file;
+  mode_t unix_sec;
+{
+  FILE *stream;
+  struct nsk_sec_type {
+    unsigned progid : 1;
+    unsigned clear  : 1;
+    unsigned null   : 2;
+    unsigned read   : 3;
+    unsigned write  : 3;
+    unsigned execute: 3;
+    unsigned purge  : 3;
+  };
+  union nsk_sec_ov {
+    struct nsk_sec_type bit_ov;
+    short int_ov;
+  };
+  union nsk_sec_ov nsk_sec;
+  short fnum, err, nsk_sec_int;
+  short len, access, exclus, extension, options;
+  char fname[FILENAME_MAX + 1];
+  char ext[EXTENSION_MAX + 1];
+
+  nsk_sec.bit_ov.progid = 0;
+  nsk_sec.bit_ov.clear  = 0;
+  nsk_sec.bit_ov.null   = 0;
+
+  /*  4="N", 5="C", 6="U", 7="-"   */
+
+  if (unix_sec & S_IROTH) nsk_sec.bit_ov.read = 4;
+  else if (unix_sec & S_IRGRP) nsk_sec.bit_ov.read = 5;
+  else if (unix_sec & S_IRUSR) nsk_sec.bit_ov.read = 6;
+  else nsk_sec.bit_ov.read = 7;
+
+  if (unix_sec & S_IWOTH) nsk_sec.bit_ov.write = 4;
+  else if (unix_sec & S_IWGRP) nsk_sec.bit_ov.write = 5;
+  else if (unix_sec & S_IWUSR) nsk_sec.bit_ov.write = 6;
+  else nsk_sec.bit_ov.write = 7;
+
+  if (unix_sec & S_IXOTH) nsk_sec.bit_ov.execute = 4;
+  else if (unix_sec & S_IXGRP) nsk_sec.bit_ov.execute = 5;
+  else if (unix_sec & S_IXUSR) nsk_sec.bit_ov.execute = 6;
+  else nsk_sec.bit_ov.execute = 7;
+
+  nsk_sec.bit_ov.purge = nsk_sec.bit_ov.write;
+
+  nsk_sec_int = nsk_sec.int_ov;
+
+  access = NSK_RDONLY;
+  exclus = NSK_SHARED;
+  options = NSK_NOUPDATEOPENTIME;
+
+  extension = parsename (file,fname,ext);
+  len = strlen(fname);
+
+  err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,,,options,,,);
+  err = (SETMODE(fnum, SET_FILE_SECURITY, nsk_sec_int) != CCE);
+  err = FILE_CLOSE_(fnum);
+
+  return (err != 0 ? -1 : 0);
+}
+
+/* TANDEM version of chown() function */
+
+int chown(file, uid, gid)
+  const char *file;
+  uid_t uid;
+  gid_t gid;
+{
+  FILE *stream;
+  struct nsk_own_type {
+    unsigned group  : 8;
+    unsigned user   : 8;
+  };
+  union nsk_own_ov {
+    struct nsk_own_type bit_ov;
+    short int_ov;
+  };
+  union nsk_own_ov nsk_own;
+  short fnum, err, nsk_own_int;
+  short len, access, exclus, extension, options;
+  char fname[FILENAME_MAX + 1];
+  char ext[EXTENSION_MAX + 1];
+
+  nsk_own.bit_ov.group = gid;
+  nsk_own.bit_ov.user  = uid;
+
+  nsk_own_int = nsk_own.int_ov;
+
+  access = NSK_RDONLY;
+  exclus = NSK_SHARED;
+  options = NSK_NOUPDATEOPENTIME;
+
+  extension = parsename (file,fname,ext);
+  len = strlen(fname);
+
+  err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,,,options,,,);
+  err = (SETMODE(fnum, SET_FILE_OWNER, nsk_own_int) != CCE);
+  err = FILE_CLOSE_(fnum);
+  return (err != 0 ? -1 : 0);
+}
+
+/* TANDEM version of getch() - non-echo character reading */
+int zgetch(void)
+{
+  char ch;
+  short f, err, count, fnum, rlen;
+
+  rlen = 1;
+  f = (short)fileno(stdin);
+  fnum = fdtogfn (f);
+  #define ECHO_MODE 20
+  err = (SETMODE(fnum, ECHO_MODE, 0) != CCE);
+  err = (READX(fnum, &ch, rlen, (short *) &count) != CCE);
+  err = (SETMODE(fnum, ECHO_MODE, 1) != CCE);
+
+  if (err)
+    if (err != 1)
+      return EOF;
+    else
+      ch = 'q';
+  else
+    if (count == 0)
+      ch = '\r';
+
+  return (int)ch;
+}
+
+short parsename(srce, fname, ext)
+  const char *srce;
+  char *fname;
+  char *ext;
+{
+  /* As a way of supporting DOS extensions from Tandem we look for a space
+     separated extension string after the Guardian filename
+     e.g. ZIP ZIPFILE "$DATA4.TESTING.INVOICE TXT"
+  */
+
+  char *fstart;
+  char *fptr;
+  short extension = 0;
+
+  *fname = *ext = '\0';  /* set to null string */
+
+  fstart = (char *) srce;
+
+  if ((fptr = strrchr(fstart, TANDEM_EXTENSION)) != NULL) {
+    extension = 1;
+
+    fptr++;
+    strncat(ext, fptr, _min(EXTENSION_MAX, strlen(fptr)));
+
+    fptr = strchr(fstart, TANDEM_EXTENSION);  /* End of filename */
+    strncat(fname, fstart, _min(FILENAME_MAX, (fptr - fstart)));
+  }
+  else {
+    /* just copy string */
+    strncat(fname, srce, _min(FILENAME_MAX, strlen(srce)));
+  }
+
+  return extension;
+}
+
+static time_t gmt_to_time_t (gmt)
+  long long *gmt;
+{
+  #define GMT_TO_LCT 0
+  #define GMT_TO_LST 1
+
+  struct tm temp_tm;
+  short  date_time[8];
+  long   julian_dayno;
+  long long lct, lst, itime;
+  short  err[1], type;
+
+  type = GMT_TO_LCT;
+  lct = CONVERTTIMESTAMP(*gmt, type,, err);
+
+  if (!err[0]) {
+    type = GMT_TO_LST;
+    lst = CONVERTTIMESTAMP(*gmt, type,, err);
+  }
+
+  itime = (err[0] ? *gmt : lct);
+  /* If we have no DST in force then make sure we give it a value,
+     else mktime screws up if we set the isdst flag to -1 */
+  temp_tm.tm_isdst = (err[0] ? 0 : ((lct == lst) ? 0 : 1));
+
+  julian_dayno = INTERPRETTIMESTAMP(itime, date_time);
+
+  temp_tm.tm_sec   = date_time[5];
+  temp_tm.tm_min   = date_time[4];
+  temp_tm.tm_hour  = date_time[3];
+  temp_tm.tm_mday  = date_time[2];
+  temp_tm.tm_mon   = date_time[1] - 1;     /* C's so sad */
+  temp_tm.tm_year  = date_time[0] - 1900;  /* it's almost funny */
+
+  return (mktime(&temp_tm));
+}
+
+/* TANDEM version of stat() function */
+int stat(n, s)
+  const char *n;
+  struct stat *s;
+{
+  #define ilist_items 26
+  #define klist_items 4
+  #define slist_items 3
+  #define ulist_items 1
+  #define flist_size 100
+
+  short err, i, extension;
+  char fname[FILENAME_MAX + 1];
+  short fnamelen;
+  char ext[EXTENSION_MAX + 1];
+
+                         /* #0  #1  #2  #3  #4  #5  #6  #7  #8  #9 */
+  short ilist[ilist_items]={56,144, 54,142, 58, 62, 60, 41, 42, 44,
+                            50, 51, 52, 61, 63, 66, 67, 70, 72, 73,
+                            74, 75, 76, 77, 78, 79                 };
+  short ilen[ilist_items] ={ 4,  4,  4,  2,  1,  2,  1,  1,  1,  1,
+                             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+                             1,  1,  1,  1,  1,  1                 };
+  short ioff[ilist_items];
+
+                         /* #0  #1  #2  #3  #4  #5  #6  #7  #8  #9 */
+  short klist[klist_items]={45, 46, 68, 69                         };
+  short klen[klist_items] ={ 1,  1,  1,  1                         };
+  short koff[klist_items];
+
+                         /* #0  #1  #2  #3  #4  #5  #6  #7  #8  #9 */
+  short slist[slist_items]={43, 80, 90                             };
+  short slen[slist_items] ={ 1,  1,  1                             };
+  short soff[slist_items];
+
+                         /* #0  #1  #2  #3  #4  #5  #6  #7  #8  #9 */
+  short ulist[ulist_items]={65                                     };
+  short ulen[ulist_items] ={ 1                                     };
+  short uoff[ulist_items];
+
+  short flist[flist_size];
+  short extra[2];
+  short *rlen=&extra[0];
+  short *err_item=&extra[1];
+  unsigned short *fowner;
+  unsigned short *fprogid;
+  char *fsec;
+
+  nsk_stat_ov *nsk_ov;
+  nsk_file_attrs *nsk_attr;
+
+  short end, count, kind, level, options, searchid;
+  short info[5];
+
+  /* Initialise stat structure */
+  s->st_dev = _S_GUARDIANOBJECT;
+  s->st_ino = 0;
+  s->st_nlink = 0;
+  s->st_rdev = 0;
+  s->st_uid = s->st_gid = 0;
+  s->st_size = 0;
+  s->st_atime = s->st_ctime = s->st_mtime = 0;
+  s->st_reserved[0] = 0;
+  s->st_reserved[1] = 0;
+  s->st_reserved[2] = 0;
+  nsk_ov = (nsk_stat_ov *)&s->st_reserved[0];
+  nsk_attr = (nsk_file_attrs *)&nsk_ov->ov.nsk_ef_region;
+
+  /* Check to see if name contains a (pseudo) file extension */
+  extension = parsename (n,fname,ext);
+
+  fnamelen = strlen(fname);
+
+  options = 3; /* Allow Subvols and Templates */
+  err = FILENAME_SCAN_( fname,
+                        fnamelen,
+                        &count,
+                        &kind,
+                        &level,
+                        options
+                      );
+
+  /* allow kind == 2 (DEFINE names) */
+  if (err != 0) return -1;
+
+  if (kind == 1 || (kind == 0 && level < 2)) {
+    /* Pattern, Subvol Name or One part Filename - lets see if it exists */
+    err = FILENAME_FINDSTART_ ( &searchid,
+                                fname,
+                                fnamelen,
+                                ,
+                                DISK_DEVICE
+                              );
+
+    if (err != 0) {
+      end = FILENAME_FINDFINISH_ ( searchid );
+      return -1;
+    }
+
+    err = FILENAME_FINDNEXT_ ( searchid,
+                               fname,
+                               FILENAME_MAX,
+                               &fnamelen,
+                               info
+                              );
+    end = FILENAME_FINDFINISH_ ( searchid );
+
+    if (err != 0)
+      return -1;  /* Non existing template, subvol or file */
+
+    if (kind == 1 || info[2] == -1) {
+      s->st_mode = S_IFDIR;    /* Its an existing template or directory */
+      return 0;
+    }
+
+    /* Must be a real file so drop to code below to get info on it */
+  }
+
+  err = FILE_GETINFOLISTBYNAME_( fname,
+                                 fnamelen,
+                                 ilist,
+                                 ilist_items,
+                                 flist,
+                                 flist_size,
+                                 rlen,
+                                 err_item
+                               );
+  if (err != 0) return -1;
+
+  ioff[0] = 0;
+
+  /*  Build up table of offets into result list */
+  for (i=1; i < ilist_items; i++)
+    ioff[i] = ioff[i-1] + ilen[i-1];
+
+  /* Set up main stat fields */
+
+  /* Setup timestamps */
+  s->st_atime = gmt_to_time_t ((long long *)&flist[ioff[0]]);
+  s->st_mtime = s->st_ctime = gmt_to_time_t ((long long *)&flist[ioff[1]]);
+  nsk_ov->ov.creation_time = gmt_to_time_t ((long long *)&flist[ioff[2]]);
+
+  s->st_size = *(off_t *)&flist[ioff[3]];
+
+  fowner = (unsigned short *)&flist[ioff[4]];
+  s->st_uid = *fowner & 0x00ff;
+  s->st_gid = *fowner >> 8;
+
+  /* Note that Purge security (fsec[3]) in NSK has no relevance to stat() */
+  fsec = (char *)&flist[ioff[5]];
+  fprogid = (unsigned short *)&flist[ioff[6]];
+
+  s->st_mode = S_IFREG |  /* Regular File */
+  /*  Parse Read Flag */
+               ((fsec[0] & 0x03) == 0x00 ? S_IROTH : 0) |
+               ((fsec[0] & 0x02) == 0x00 ? S_IRGRP : 0) |
+               ((fsec[0] & 0x03) != 0x03 ? S_IRUSR : 0) |
+  /*  Parse Write Flag */
+               ((fsec[1] & 0x03) == 0x00 ? S_IWOTH : 0) |
+               ((fsec[1] & 0x02) == 0x00 ? S_IWGRP : 0) |
+               ((fsec[1] & 0x03) != 0x03 ? S_IWUSR : 0) |
+  /*  Parse Execute Flag */
+               ((fsec[2] & 0x03) == 0x00 ? S_IXOTH : 0) |
+               ((fsec[2] & 0x02) == 0x00 ? S_IXGRP : 0) |
+               ((fsec[2] & 0x03) != 0x03 ? S_IXUSR : 0) |
+  /*  Parse Progid */
+               (*fprogid == 1 ? (S_ISUID | S_ISGID) : 0) ;
+
+  /* Set up NSK additional stat fields */
+  nsk_attr->progid   = (unsigned) flist[ioff[6]];
+  nsk_attr->filetype = (unsigned) flist[ioff[7]];
+  nsk_attr->filecode = (unsigned) flist[ioff[8]];
+  nsk_attr->block    = (unsigned short) flist[ioff[9]];
+  nsk_attr->priext   = (unsigned short) flist[ioff[10]];
+  nsk_attr->secext   = (unsigned short) flist[ioff[11]];
+  nsk_attr->maxext   = (unsigned short) flist[ioff[12]];
+  nsk_attr->flags.clearonpurge = (unsigned) flist[ioff[13]];
+  nsk_attr->licensed     = (unsigned) flist[ioff[14]];
+  nsk_attr->flags.audited      = (unsigned) flist[ioff[15]];
+  nsk_attr->flags.acompress    = (unsigned) flist[ioff[16]];
+  nsk_attr->flags.refresheof   = (unsigned) flist[ioff[17]];
+  nsk_attr->flags.buffered     = (unsigned) (flist[ioff[18]] == 0 ? 1 : 0);
+  nsk_attr->flags.verified     = (unsigned) flist[ioff[19]];
+  nsk_attr->flags.serial       = (unsigned) flist[ioff[20]];
+  nsk_attr->flags.crashopen    = (unsigned) flist[ioff[22]];
+  nsk_attr->flags.rollforward  = (unsigned) flist[ioff[23]];
+  nsk_attr->flags.broken       = (unsigned) flist[ioff[24]];
+  nsk_attr->flags.corrupt      = (unsigned) flist[ioff[25]];
+  nsk_attr->fileopen     = (unsigned) flist[ioff[21]];
+
+
+  if (nsk_attr->filetype == NSK_UNSTRUCTURED) {
+    /* extra info for Unstructured files */
+    err = FILE_GETINFOLISTBYNAME_( fname,
+                                   fnamelen,
+                                   ulist,
+                                   ulist_items,
+                                   flist,
+                                   flist_size,
+                                   rlen,
+                                   err_item
+                                 );
+    if (err != 0) return -1;
+
+    uoff[0] = 0;
+
+    /*  Build up table of offets into result list */
+    for (i=1; i < ulist_items; i++)
+      uoff[i] = uoff[i-1] + ulen[i-1];
+  }
+  else {
+    /* extra info for Structured files */
+    err = FILE_GETINFOLISTBYNAME_( fname,
+                                   fnamelen,
+                                   slist,
+                                   slist_items,
+                                   flist,
+                                   flist_size,
+                                   rlen,
+                                   err_item
+                                 );
+    if (err != 0) return -1;
+
+    soff[0] = 0;
+
+    /*  Build up table of offets into result list */
+    for (i=1; i < slist_items; i++)
+      soff[i] = soff[i-1] + slen[i-1];
+
+    nsk_attr->reclen   = (unsigned) flist[soff[0]];
+    nsk_attr->flags.secpart   = (unsigned) flist[soff[1]];
+    nsk_attr->flags.primpart  = (unsigned)
+     ( (flist[soff[2]] > 0 && nsk_attr->flags.secpart == 0) ? 1 : 0 );
+
+    if (nsk_attr->filetype == NSK_KEYSEQUENCED) {
+      /* extra info for Key Sequenced files */
+      err = FILE_GETINFOLISTBYNAME_( fname,
+                                     fnamelen,
+                                     klist,
+                                     klist_items,
+                                     flist,
+                                     flist_size,
+                                     rlen,
+                                     err_item
+                                   );
+      if (err != 0) return -1;
+
+      koff[0] = 0;
+
+      /*  Build up table of offets into result list */
+      for (i=1; i < klist_items; i++)
+        koff[i] = koff[i-1] + klen[i-1];
+
+      nsk_attr->keyoff   = (unsigned) flist[koff[0]];
+      nsk_attr->keylen   = (unsigned) flist[koff[1]];
+      nsk_attr->flags.dcompress = (unsigned) flist[koff[2]];
+      nsk_attr->flags.icompress = (unsigned) flist[koff[3]];
+    }
+  }
+
+  return 0;
+}
+
+#ifndef SFX
+/* TANDEM Directory processing */
+
+DIR *opendir(const char *dirname)
+{
+   short i, resolve;
+   char sname[FILENAME_MAX + 1];
+   short snamelen;
+   char fname[FILENAME_MAX + 1];
+   short fnamelen;
+   char *p;
+   short searchid, err, end;
+   struct dirent *entry;
+   DIR *dirp;
+   char ext[EXTENSION_MAX + 1];
+   short extension;
+
+   extension = parsename(dirname, sname, ext);
+   snamelen = strlen(sname);
+
+   /*  First we work out how detailed the template is...
+    *  e.g. If the template is DAVES*.* we want the search result
+    *       in the same format
+    */
+
+   p = sname;
+   i = 0;
+   while ((p = strchr(p, TANDEM_DELIMITER)) != NULL){
+     i++;
+     p++;
+   };
+   resolve = 2 - i;
+
+   /*  Attempt to start a filename template */
+   err = FILENAME_FINDSTART_ ( &searchid,
+                               sname,
+                               snamelen,
+                               resolve,
+                               DISK_DEVICE
+                             );
+   if (err != 0) {
+     end = FILENAME_FINDFINISH_(searchid);
+     return NULL;
+   }
+
+   /* Create DIR structure */
+   if ((dirp = malloc(sizeof(DIR))) == NULL ) {
+     end = FILENAME_FINDFINISH_(searchid);
+     return NULL;
+   }
+   dirp->D_list = dirp->D_curpos = NULL;
+   strcpy(dirp->D_path, dirname);
+
+   while ((err = FILENAME_FINDNEXT_(searchid,
+                                    fname,
+                                    FILENAME_MAX,
+                                    &fnamelen
+                                   )
+           ) == 0 ){
+     /*  Create space for entry */
+     if ((entry = malloc (sizeof(struct dirent))) == NULL) {
+       end = FILENAME_FINDFINISH_(searchid);
+       return NULL;
+     }
+
+     /*  Link to last entry */
+     if (dirp->D_curpos == NULL)
+       dirp->D_list = dirp->D_curpos = entry;  /* First name */
+     else {
+       dirp->D_curpos->d_next = entry;         /* Link */
+       dirp->D_curpos = entry;
+     };
+     /* Add directory entry */
+     *dirp->D_curpos->d_name = '\0';
+     strncat(dirp->D_curpos->d_name,fname,fnamelen);
+     if (extension) {
+       strcat(dirp->D_curpos->d_name,TANDEM_EXTENSION_STR);
+       strcat(dirp->D_curpos->d_name,ext);
+     };
+     dirp->D_curpos->d_next = NULL;
+   };
+
+   end = FILENAME_FINDFINISH_(searchid);
+
+   if (err == 1) {  /*  Should return EOF at end of search */
+     dirp->D_curpos = dirp->D_list;        /* Set current pos to start */
+     return dirp;
+   }
+   else
+     return NULL;
+}
+
+struct dirent *readdir(DIR *dirp)
+{
+   struct dirent *cur;
+
+   cur = dirp->D_curpos;
+   dirp->D_curpos = dirp->D_curpos->d_next;
+   return cur;
+}
+
+void rewinddir(DIR *dirp)
+{
+   dirp->D_curpos = dirp->D_list;
+}
+
+int closedir(DIR *dirp)
+{
+   struct dirent *node;
+
+   while (dirp->D_list != NULL) {
+      node = dirp->D_list;
+      dirp->D_list = dirp->D_list->d_next;
+      free( node );
+   }
+   free( dirp );
+   return 0;
+}
+
+#endif /* !SFX */
diff --git a/tandem/tandem.h b/tandem/tandem.h
new file mode 100644 (file)
index 0000000..7296d26
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+  Copyright (c) 1990-2006 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __tandem_h   /* prevent multiple inclusions */
+#define __tandem_h
+
+#ifndef TANDEM
+#  define TANDEM     /* better than __TANDEM */
+#endif
+
+/* LICENSED define now supplied by compile time option (MAKE) */
+
+#define NO_UNISTD_H
+#define NO_RMDIR
+#define NO_MKTEMP
+
+/* TANDEM supplies proper UTC vs. local time conversion, so enable Info-ZIP's
+   UT e.f. support unless explicitly suppressed by a compilation option. */
+#if (!defined(USE_EF_UT_TIME) && !defined(NO_EF_UT_TIME))
+#  define USE_EF_UT_TIME
+#endif
+#if (defined(NO_EF_UT_TIME) && defined(USE_EF_UT_TIME))
+#  undef USE_EF_UT_TIME
+#endif
+
+/* Include file for TANDEM */
+
+#ifndef NULL
+#  define NULL 0
+#endif
+
+#include <time.h>               /* the usual non-BSD time functions */
+#include <stdio.h>
+#include <sysstat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+
+#define PASSWD_FROM_STDIN
+                  /* Kludge until we know how to open a non-echo tty channel */
+
+#define NSK_UNSTRUCTURED   0
+#define NSK_RELATIVE       1
+#define NSK_ENTRYSEQUENCED 2
+#define NSK_KEYSEQUENCED   3
+#define NSK_OBJECTFILECODE 100
+#define NSK_EDITFILECODE   101
+#define NSK_ZIPFILECODE    1001
+#define TANDEM_BLOCKSIZE   4096
+#define MAX_NORMAL_READ    4096
+#define MAX_EDIT_READ      255
+#define MAX_LARGE_READ        57344
+#define MAX_LARGE_READ_EXPAND 30720
+
+#define MAXFILEPARTLEN     8
+#define MAXPATHLEN         128
+#define EXTENSION_MAX      3
+/* FILENAME_MAX is defined in stdio.h */
+
+#define EXIT zexit      /*  To stop creation of Abend files */
+#define RETURN zexit    /*  To stop creation of Abend files */
+#define putc zputc      /*  To allow us to auto flush  */
+
+
+#define FOPR "rb"
+#define FOPM "r+"
+#define FOPW "wb"
+#define FOPWT "w"
+
+#define NAMELEN FILENAME_MAX+1+EXTENSION_MAX   /* allow for space extension */
+
+struct dirent {
+   struct dirent *d_next;
+   char   d_name[NAMELEN+1];
+};
+
+typedef struct _DIR {
+   struct  dirent *D_list;
+   struct  dirent *D_curpos;
+   char            D_path[NAMELEN+1];
+} DIR;
+
+DIR *          opendir(const char *dirname);
+struct dirent *readdir(DIR *dirp);
+void           rewinddir(DIR *dirp);
+int            closedir(DIR *dirp);
+char *         readd(DIR *dirp);
+
+#define DISK_DEVICE         3
+
+/* SETMODE Literals */
+#define SET_FILE_SECURITY   1
+#define SET_FILE_OWNER      2
+#define SET_FILE_BUFFERED   90
+#define SET_FILE_MAXEXTENTS 92
+#define SET_FILE_BUFFERSIZE 93
+#define SET_LARGE_TRANSFERS 141
+
+/* FILE_OPEN_ Literals */
+#define NSK_RDWR             0
+#define NSK_RDONLY           1
+#define NSK_WRONLY           2
+#define NSK_APPEND           3
+#define NSK_SHARED           0
+#define NSK_EXCLUSIVE        1
+#define NSK_PROCESSEXCLUSIVE 2
+#define NSK_PROTECTED        3
+#define NSK_UNSTRUCTUREDACCESS 0x8000
+#define NSK_NOUPDATEOPENTIME   0x2000
+
+#define NSK_NO_DELIMITER        0x0001
+#define NSK_USE_FF_DELIMITER    0x0002
+#define NSK_SPACE_FILL          0x0004
+#define NSK_TRIM_TRAILING_SPACE 0x0008
+#define NSK_LARGE_READ_EXPAND   0x0100     /* use smaller value for Expand */
+
+#define DOS_EXTENSION      '.'
+#define TANDEM_EXTENSION   ' '
+#define TANDEM_DELIMITER   '.'
+#define TANDEM_NODE        '\\'
+#define INTERNAL_DELIMITER '/'
+#define INTERNAL_NODE      '//'
+#define TANDEM_WILD_1      '*'
+#define TANDEM_WILD_2      '?'
+
+#define DOS_EXTENSION_STR      "."
+#define TANDEM_EXTENSION_STR   " "
+#define TANDEM_DELIMITER_STR   "."
+#define TANDEM_NODE_STR        "\\"
+#define INTERNAL_DELIMITER_STR "/"
+#define INTERNAL_NODE_STR      "//"
+
+/* Use 'spare' area at end of stat structure to hold additional Tandem/NSK
+   file details. Initially used to hold Creation time, now also holds most
+   Enscribe details */
+
+struct nsk_stat_reserved
+{
+  int64_t spare[3];
+};
+
+#pragma FIELDALIGN SHARED8 nsk_owner
+struct nsk_owner
+{
+  unsigned group   : 8;
+  unsigned user    : 8;
+};
+
+#pragma FIELDALIGN SHARED8 nsk_file_flags
+struct nsk_file_flags
+{
+  unsigned buffered    : 1;
+  unsigned audited     : 1;
+  unsigned acompress   : 1;
+  unsigned icompress   : 1;
+  unsigned dcompress   : 1;
+  unsigned oddunstr    : 1;
+  unsigned verified    : 1;
+  unsigned serial      : 1;
+  unsigned refresheof  : 1;
+  unsigned broken      : 1;
+  unsigned corrupt     : 1;
+  unsigned primpart    : 1;
+  unsigned secpart     : 1;
+  unsigned crashopen   : 1;
+  unsigned rollforward : 1;
+  unsigned clearonpurge: 1;
+};
+
+#pragma FIELDALIGN SHARED8 nsk_file_attrs_def
+struct nsk_file_attrs_def
+{
+  unsigned short filecode;  /* 16 */
+  unsigned short block;     /* 16 */  /* Allow of block > 4096 one day ! */
+  struct nsk_file_flags flags;     /* 16 */
+  struct nsk_owner owner;   /* 16 */
+  unsigned short priext;    /* 16 */
+  unsigned short secext;    /* 16 */
+  unsigned maxext    : 10;
+  unsigned read      : 3;
+  unsigned write     : 3;
+  unsigned execute   : 3;
+  unsigned delete    : 3;
+  unsigned licensed  : 1;
+  unsigned progid    : 1;
+  unsigned keylen    : 8;
+  unsigned           : 5;
+  unsigned keyoff    : 11;
+  unsigned           : 1;
+  unsigned filetype  : 2;
+  unsigned fileopen  : 1;
+  unsigned reclen    : 12;
+};
+typedef struct nsk_file_attrs_def nsk_file_attrs;
+
+#pragma FIELDALIGN SHARED8 nsk_stat_overlay
+struct nsk_stat_overlay
+{
+  time_t creation_time;       /* 32 bits */
+  nsk_file_attrs nsk_ef_region;
+ /*  char   nsk_ef_region[20]; *//* EF region */
+};
+
+typedef union
+{
+  struct nsk_stat_reserved reserved;
+  struct nsk_stat_overlay  ov;
+} nsk_stat_ov;
+
+/* Prototype function declarations */
+
+void zexit (int);
+
+int zputc(
+  int,
+  FILE *
+);
+
+int zgetch (void);
+
+short parsename(
+  const char *,
+  char *,
+  char *
+);
+
+int islicensed (void);
+
+/* End of prototype function declarations */
+
+#endif /* !__tandem_h */
diff --git a/tandem/tannsk.h b/tandem/tannsk.h
new file mode 100644 (file)
index 0000000..34ad49c
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+  Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  Header declaration(s) which are forced to go after earlier includes
+ */
+
+#ifndef __tannsk_h   /* prevent multiple inclusions */
+#define __tannsk_h
+
+/* ztimbuf is declared in zip\tailor.h after include of tandem.h */
+int utime (const char *, const ztimbuf *);
+
+#endif /* !__tannsk_h */
diff --git a/tandem/tanzip.c b/tandem/tanzip.c
new file mode 100644 (file)
index 0000000..5985b33
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+  Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * routines only used by TANDEM ZIP
+ */
+
+#include "zip.h"
+#include "crypt.h"
+#include <tal.h>
+#include "$system.zsysdefs.zsysc" nolist
+#include <cextdecs> nolist
+#include "tannsk.h"
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+void version_local()
+{
+    static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+#if 0
+    char buf[40];
+#endif
+
+    printf(CompiledWith,
+
+#ifdef __GNUC__
+      "gcc ", __VERSION__,
+#else
+     "C ", "T9255D44 - (16OCT98)",
+#endif
+
+     "NonStop ", "(Tandem/NSK)",
+
+#ifdef __DATE__
+      " on ", __DATE__
+#else
+      "", ""
+#endif
+      );
+
+} /* end function version_local() */
+
+
+/************************/
+/*  Function nskopen()  */
+/************************/
+
+#ifdef fopen
+#  undef fopen
+#endif
+
+FILE *nskopen(fname, opt)
+const char *fname;
+const char *opt;
+{
+  int fdesc;
+  short fnum, err, len;
+  int priext, secext;
+  short maxext, filecode, blocksize;
+
+  #define alist_items 1
+  #define vlist_bytes 2
+  short alist[alist_items]={42};
+  unsigned short vlist[alist_items];
+  short extra, *err_item=&extra;
+
+  char nsk_work[FILENAME_MAX + 1], *nsk_fname=&nsk_work[0];
+
+  /* See if we want to create a new file */
+  if ((strcmp(opt,FOPW) == 0) || (strcmp(opt,FOPWT) == 0)) {
+    blocksize = TANDEM_BLOCKSIZE;
+    priext = 100;
+    secext = 500;
+    maxext = 978;
+    filecode = NSK_ZIPFILECODE;
+
+    if ((fdesc = creat(fname,,priext,secext)) != -1){
+      fnum = fdtogfn ((short)fdesc);
+      err = (SETMODE (fnum, SET_FILE_BUFFERSIZE, blocksize) != CCE);
+      err = (SETMODE (fnum, SET_FILE_BUFFERED, 0, 0) != CCE);
+      err = (SETMODE (fnum, SET_FILE_BUFFERED, 0, 1) != CCE);
+      err = (SETMODE (fnum, SET_FILE_MAXEXTENTS, maxext) != CCE);
+      err = close(fdesc);
+
+      vlist[0] = filecode;
+
+      /* Note that FILE_ALTERLIST_ expects uppercase names */
+      /* Need to call strlen and upshift                   */
+      len = strlen(fname);
+      err = STRING_UPSHIFT_((char *)fname,
+                            len,
+                            nsk_fname,
+                            len);
+
+      err = FILE_ALTERLIST_(nsk_fname,
+                            len,
+                            alist,
+                            alist_items,
+                            vlist,
+                            vlist_bytes,
+                            ,
+                            err_item);
+    };
+  };
+
+  return fopen(fname,opt);
+}
+#define fopen nskopen
+
+
+  int Bflag = 0;            /* Special formatting options for Tandem        */
+                            /* Bit 0 = Add delimiter (0 = Yes, 1 = No)      */
+                            /* Bit 1 = Delimiter Type (0 = CR/LF, 1 = LF)   */
+                            /* Bit 2 = Space Fill records (0 = No, 1 = Yes) */
+                            /* Bit 3 = Trim trailing space(0 = No, 1 = Yes) */
+                            /* Thus, default is to add CR/LF, no padding    */
+                            /* Bit 8 = Use 'safe' large read size (Expand)  */
+  char nsk_delim[2] = {'\r', '\n'}; /* CR/LF */
+  int nsk_delim_len = 2;
+  int nsk_space_fill = 0;   /* 0 = No, 1 = Yes          */
+  int nsk_trim_space = 0;   /* 0 = No, 1 = Yes          */
+  unsigned short nsk_large_read = MAX_LARGE_READ;
+
+  /* Following holds details of file currently used by zopen & zread */
+  struct stat znsk_stat;
+  nsk_stat_ov *znsk_ov = (nsk_stat_ov *)&znsk_stat.st_reserved[0];
+  nsk_file_attrs *znsk_attr = (nsk_file_attrs *)
+    ( (char *)(&znsk_stat.st_reserved[0]) +
+      offsetof (struct nsk_stat_overlay, nsk_ef_region) );
+
+  /* Following items used by zread to avoid overwriting window */
+  char zreadbuf[MAX_LARGE_READ];       /* Buffer as large as biggest read */
+  char *zreadptr = (char *) zreadbuf;  /* pointer to start of buffer      */
+  char *zread_ovptr = NULL;            /* pointer to left overs           */
+  long zread_ovlen = 0;                /* size of remaining left overs    */
+
+  int zopen (filename, opt)
+    const char *filename;
+    int opt;
+  {
+    /* Currently ignore opt.  Choose method of I/O based on NSK file type */
+    short err, len, fnum, access, exclus, bufferlen, options;
+    long recnum;
+    char fname[FILENAME_MAX + 1];
+    short extension;
+    char ext[EXTENSION_MAX + 1];
+
+    /* Remove any (pseudo) file extension */
+    extension = parsename (filename,fname,ext);
+    len = strlen(fname);
+
+    fnum = 0;
+    access = NSK_RDONLY;
+    exclus = NSK_SHARED;
+
+    err = stat(fname, &znsk_stat); /* Setup global struct, used by zread */
+
+    if (znsk_attr->filetype == NSK_UNSTRUCTURED)
+      if (znsk_attr->filecode == NSK_EDITFILECODE) {
+        /* Edit File */
+        fnum = -1; /* Ask OPENEDIT_ to open the file for us */
+        err = OPENEDIT_ ((char *)fname, len, &fnum, access, exclus);
+        if (!err) {
+          recnum = -1; /* Position to first line */
+          err = POSITIONEDIT (fnum, recnum);
+        }
+      }
+      else {
+        /* Unstructured File */
+        options = NSK_UNSTRUCTUREDACCESS;
+        err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,
+                         ,,options,,,);
+        if (!err)
+          /* Ask for large transfer mode */
+          err = (SETMODE (fnum, SET_LARGE_TRANSFERS, 1) != CCE);
+      }
+    else {
+      /* Structured File */
+      bufferlen = 4096;  /* request SBB */
+      err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,
+                       ,,,, bufferlen ,);
+      if (err == 4)
+        err = 0;  /* Allow saving of files that have missing altkeys */
+    }
+
+    return (err == 0 ? (int)fnum : -1);
+  }
+
+  unsigned zread (fnum, buf, len)
+    int fnum;
+    char *buf;
+    unsigned len;
+  {
+    short err, trail;
+    long total, movelen;
+    unsigned short countread;
+    unsigned readlen;  /* typed to match incoming arg */
+    char *bufptr, *readptr;
+
+    total = err = 0;
+    bufptr = buf;
+
+    /* We use a separate buffer to read in data as it can be larger than
+       WSIZE, and hence would overwrite memory */
+
+    /* We always attempt to give the user the exact requested size
+       Hence we make use of an overfow buffer for previously truncated data */
+
+    /* see if we have some left over characters from last time */
+    if (zread_ovlen) {
+       movelen = _min(len,zread_ovlen);
+       memcpy(bufptr, zread_ovptr, movelen);
+       bufptr += movelen;
+       total += movelen;
+       zread_ovptr += movelen;
+       zread_ovlen -= movelen;
+    }
+
+    while (!err && (total < len)) {
+      readptr = zreadptr;
+
+      if (znsk_attr->filetype == NSK_UNSTRUCTURED)
+        if (znsk_attr->filecode == NSK_EDITFILECODE){
+          /* Edit File */
+          trail = 1;
+          readlen = MAX_EDIT_READ; /* guarantee it fits in buffer */
+
+          /* get line and preserve any trailing space characters */
+          err = READEDIT (fnum,, zreadptr, (short) readlen,
+                            (short *) &countread,,, trail);
+          /* if countread is ever negative then we will skip a line */
+
+          if (!err) {
+            readptr = zreadptr + countread;
+            /* Note it is possible for Edit files to hold trailing space */
+            if (nsk_trim_space)
+              while (*(readptr-1) == ' ') {
+                readptr--;
+                countread--;
+              }
+
+            if (nsk_delim_len) {
+              memcpy(readptr, nsk_delim, nsk_delim_len);
+              readptr += nsk_delim_len;
+              countread += nsk_delim_len;
+            }
+          }
+        }
+        else {
+          /* Unstructured File */
+
+          /* Using large transfer mode so we have to use 2K multiples
+             Use largest size possible and put remains in overflow    */
+
+          readlen = nsk_large_read; /* use largest read, overflow into buffer*/
+
+          err = (READX(fnum, zreadptr, readlen, (short *)&countread) != CCE);
+          if (err && (errno == EINVAL)) {
+            /* Read too big so scale back to smaller value */
+            readlen = nsk_large_read = MAX_LARGE_READ_EXPAND;
+            err = (READX(fnum, zreadptr, readlen, (short *)&countread) != CCE);
+          }
+          if (!err)
+            readptr = zreadptr + countread;
+        }
+      else {
+        /* Structured File */
+        readlen = znsk_attr->reclen;
+
+        err = (READX(fnum, zreadptr, readlen, (short *)&countread)!= CCE);
+
+        if (!err) {
+          readptr = zreadptr + countread;
+          if (nsk_space_fill)
+            while (countread < readlen) {
+              *readptr++ = ' ';
+              countread++;
+            }
+          else
+            if (nsk_trim_space)
+              while (*(readptr-1) == ' ') {
+                readptr--;
+                countread--;
+              }
+
+          if (nsk_delim_len) {
+            memcpy(readptr, nsk_delim, nsk_delim_len);
+            readptr += nsk_delim_len;
+            countread += nsk_delim_len;
+          }
+        }
+      }
+      if (!err) {
+         movelen = _min((len-total), countread);
+         memcpy(bufptr, zreadptr, movelen);
+         bufptr += movelen;
+         total += movelen;
+         if (movelen < countread) { /* still stuff in Read buffer */
+           zread_ovptr = zreadptr + movelen;   /* pointer to whats left */
+           zread_ovlen = countread - movelen;  /* how much is left      */
+         }
+      }
+    }
+
+    return ((unsigned)total);
+  }
+
+  int zclose (fnum)
+    int fnum;
+  {
+    short err;
+
+    if ((znsk_attr->filetype == NSK_UNSTRUCTURED)
+      && (znsk_attr->filecode == NSK_EDITFILECODE))
+      err = CLOSEEDIT_(fnum);
+    else
+      err = FILE_CLOSE_(fnum);
+
+    return (err != 0);
+  }
+
+/* modified to work with get_option which returns
+   a string with the number value without leading option */
+void nskformatopt(p)
+char *p;
+{
+  /* set up formatting options for ZIP */
+
+  Bflag = 0; /* default option */
+
+  Bflag = strtoul(p, NULL, 10);
+
+  if (Bflag & NSK_SPACE_FILL)
+    nsk_space_fill = 1;
+  else
+    nsk_space_fill = 0;
+
+  if (Bflag & NSK_TRIM_TRAILING_SPACE)
+    nsk_trim_space = 1;
+  else
+    nsk_trim_space = 0;
+
+  if (Bflag & NSK_NO_DELIMITER)
+    nsk_delim_len = 0;
+  else {
+    if (Bflag & NSK_USE_FF_DELIMITER) {
+      nsk_delim[0] = '\n';
+      nsk_delim_len = 1;
+    }
+    else {   /* CR/LF */
+      nsk_delim[0] = '\r';
+      nsk_delim[1] = '\n';
+      nsk_delim_len = 2;
+    }
+  }
+
+  if (Bflag & NSK_LARGE_READ_EXPAND)
+    nsk_large_read = MAX_LARGE_READ_EXPAND;
+  else
+    nsk_large_read = MAX_LARGE_READ;
+
+}
+
+
+  int deletedir(d)
+    char *d;                /* directory to delete */
+  /* Delete the directory *d if it is empty, do nothing otherwise.
+     Return the result of rmdir(), delete(), or system().
+     For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
+   */
+  {
+      return rmdir(d);
+  }
+
+  local char *readd(d)
+    DIR *d;                 /* directory stream to read from */
+  /* Return a pointer to the next name in the directory stream d, or NULL if
+     no more entries or an error occurs. */
+  {
+    struct dirent *e;
+
+    e = readdir(d);
+    return e == NULL ? (char *) NULL : e->d_name;
+  }
+
+  int procname(n, caseflag)
+    char *n;                /* name to process */
+    int caseflag;           /* true to force case-sensitive match */
+  /* Process a name or sh expression to operate on (or exclude).  Return
+     an error code in the ZE_ class. */
+  {
+    char *a;              /* path and name for recursion */
+    DIR *d;               /* directory stream from opendir() */
+    char *e;              /* pointer to name from readd() */
+    int m;                /* matched flag */
+    char *p;              /* path for recursion */
+    struct stat s;        /* result of stat() */
+    struct zlist far *z;  /* steps through zfiles list */
+
+    if (strcmp(n, "-") == 0)   /* if compressing stdin */
+      return newname(n, 0, caseflag);
+    else if (stat(n, &s))
+    {
+      /* Not a file or directory--search for shell expression in zip file */
+      p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+      m = 1;
+      for (z = zfiles; z != NULL; z = z->nxt) {
+        if (MATCH(p, z->zname, caseflag))
+        {
+          z->mark = pcount ? filter(z->zname, caseflag) : 1;
+          if (verbose)
+              fprintf(mesg, "zip diagnostic: %scluding %s\n",
+                 z->mark ? "in" : "ex", z->name);
+          m = 0;
+        }
+      }
+      free((zvoid *)p);
+      return m ? ZE_MISS : ZE_OK;
+    }
+
+    /* Live name--use if file, recurse if directory */
+    if ((s.st_mode & S_IFDIR) == 0)
+    {
+      /* add or remove name of file */
+      if ((m = newname(n, 0, caseflag)) != ZE_OK)
+        return m;
+    } else {
+      if ((p = malloc(strlen(n)+4)) == NULL)
+        return ZE_MEM;
+
+      strcpy(p, n);
+
+      /* No concept of directories on Tandem - so do not store them ...*/
+      /* code removed from which attempted to save dir name if dirnames set */
+
+      /*  Test for recurse being set removed, since Tandem has no dir concept*/
+      /*  recurse into template */
+      if ((d = opendir(n)) != NULL)
+      {
+        while ((e = readd(d)) != NULL) {
+          if ((m = procname(e, caseflag)) != ZE_OK)   /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", e);
+            else
+              ziperr(m, e);
+          }
+        }
+        closedir(d);
+      }
+      free((zvoid *)p);
+    } /* (s.st_mode & S_IFDIR) == 0) */
+    return ZE_OK;
+  }
+
+  char *ex2in(x, isdir, pdosflag)
+    char *x;                /* external file name */
+    int isdir;              /* input: x is a directory */
+    int *pdosflag;          /* output: force MSDOS file attributes? */
+  /* Convert the external file name to a zip file name, returning the malloc'ed
+     string or NULL if not enough memory. */
+  {
+    char *n;              /* internal file name (malloc'ed) */
+    char *t;              /* shortened name */
+    int dosflag;
+    char *p;               /* pointer to temp area */
+    char fname[FILENAME_MAX + 1]= ""; /* file name */
+    char ext[EXTENSION_MAX + 1] = ""; /* extension name */
+    short extension;    /* does the filename contain an extension */
+
+    dosflag = dosify;  /* default for non-DOS non-OS/2 */
+
+    /* Find starting point in name before doing malloc */
+    if (*x == '=')
+      t = x + 1;   /* store DEFINE names without the '=' */
+    else
+      t = x;
+
+    /* Make changes, if any, to the copied name (leave original intact) */
+
+    if (!pathput)
+      t = last(t, TANDEM_DELIMITER);
+
+    /* Malloc space for internal name and copy it */
+    if ((n = malloc(strlen(t) + 4)) == NULL) /* + 4 for safety */
+      return NULL;
+
+    extension = parsename(t,fname,ext);
+    t = fname;
+
+    *n= '\0';
+
+    while (*t != '\0') {  /* File part could be sys,vol,subvol or file */
+      if (*t == TANDEM_NODE) {    /* System Name */
+        strcat(n, INTERNAL_NODE_STR);
+        t++;
+      }
+      else if (*t == TANDEM_DELIMITER) {  /* Volume or Subvol */
+             strcat(n, INTERNAL_DELIMITER_STR);
+             t++;
+           };
+      p = strchr(t,TANDEM_DELIMITER);
+      if (p == NULL) break;
+      strncat(n,t,(p - t));
+      t = p;
+    }
+
+    strcat(n,t);  /* mop up any left over characters */
+
+    if (extension) {
+      strcat(n,DOS_EXTENSION_STR);
+      strcat(n,ext);
+    };
+
+    if (isdir == 42) return n;      /* avoid warning on unused variable */
+
+    if (dosify)
+      msname(n);
+
+    /* Returned malloc'ed name */
+    if (pdosflag)
+      *pdosflag = dosflag;
+
+    return n;
+  }
+
+  void stamp(f, d)
+    char *f;                /* name of file to change */
+    ulg d;                  /* dos-style time to change it to */
+  /* Set last updated and accessed time of file f to the DOS time d. */
+  {
+    ztimbuf u;            /* argument for utime() */
+
+    /* Convert DOS time to time_t format in u.actime and u.modtime */
+    u.actime = u.modtime = dos2unixtime(d);
+
+    utime(f, &u);
+  }
+
+  ulg filetime(f, a, n, t)
+    char *f;                /* name of file to get info on */
+    ulg *a;                 /* return value: file attributes */
+    long *n;                /* return value: file size */
+    iztimes *t;             /* return value: access and modification time */
+  {
+    struct stat s;
+    nsk_stat_ov *nsk_ov;
+
+    if (strcmp(f, "-") == 0) {    /* if compressing stdin */
+      if (n != NULL) {
+        *n = -1L;
+      }
+    }
+
+    if (stat(f, &s) != 0) return 0;
+
+    if (a!= NULL) {
+      *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWUSR);
+      if ((s.st_mode & S_IFMT) == S_IFDIR) {
+        *a |= MSDOS_DIR_ATTR;
+      }
+    }
+
+    if (n!= NULL)
+      *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+
+    if (t != NULL) {
+      t->atime = s.st_atime;
+      t->mtime = s.st_mtime;
+      nsk_ov = (nsk_stat_ov *)&s.st_reserved[0];
+      t->ctime = nsk_ov->ov.creation_time;
+    }
+
+    return unix2dostime(&s.st_mtime);
+  }
+
+  int set_extra_field(z, z_utim)
+    struct zlist far *z;
+    iztimes *z_utim;
+    /* create extra field and change z->att if desired */
+    /* store full data in local header but just modification time stamp info
+       in central header */
+  {
+    struct stat s;
+    nsk_stat_ov *nsk_ov = (nsk_stat_ov *)&s.st_reserved[0];
+    nsk_file_attrs *nsk_attr = (nsk_file_attrs *)&nsk_ov->ov.nsk_ef_region;
+    char *ext, *cext;
+    int lsize, csize;
+#ifdef USE_EF_UT_TIME
+    char *UTptr, *Uxptr;
+#endif /* USE_EF_UT_TIME */
+
+    /* For the Tandem and UT local field including the UID/GID fields, we
+       have to stat the file again. */
+    if (LSSTAT(z->name, &s))
+      return ZE_OPEN;
+
+    z->ext = z->cext = 0;
+
+  #define EB_TANDEM_SIZE 20
+  #define EF_TANDEM_SIZE (EB_HEADSIZE + EB_TANDEM_SIZE)
+
+    /* allocate size of buffers to allow Tandem field */
+    lsize = EF_TANDEM_SIZE;
+    csize = EF_TANDEM_SIZE;
+
+#ifdef USE_EF_UT_TIME
+
+  #define EB_L_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(3))
+  #define EB_C_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(1))
+  #define EB_L_UX2_SIZE   (EB_HEADSIZE + EB_UX2_MINLEN)
+  #define EB_C_UX2_SIZE   EB_HEADSIZE
+  #define EF_L_UNIX_SIZE  (EB_L_UT_SIZE + EB_L_UX2_SIZE)
+  #define EF_C_UNIX_SIZE  (EB_C_UT_SIZE + EB_C_UX2_SIZE)
+
+    /* resize to allow for UT fields */
+    lsize += EF_L_UNIX_SIZE;
+    csize += EF_C_UNIX_SIZE;
+
+#endif /* USE_EF_UT_TIME */
+
+    if ((z->extra = (char *)malloc(lsize)) == NULL)
+      return ZE_MEM;
+    ext = z->extra;
+
+    if ((z->cextra = (char *)malloc(csize)) == NULL)
+      return ZE_MEM;
+    cext = z->cextra;
+
+    /* Place Tandem field first so its on an even boundary */
+    *ext++ = *cext++ = 'T';
+    *ext++ = *cext++ = 'A';
+    *ext++ = *cext++ = (char)EB_TANDEM_SIZE;  /*length of data part of e.f.*/
+    *ext++ = *cext++  = 0;
+
+    /* Copy Tandem specific file information */
+    memcpy(ext, (char *)nsk_attr, EB_TANDEM_SIZE);
+    ext += EB_TANDEM_SIZE;
+    z->ext += EF_TANDEM_SIZE;
+
+    /* Copy same data to central field */
+    memcpy(cext, (char *)nsk_attr, EB_TANDEM_SIZE);
+    cext += EB_TANDEM_SIZE;
+    z->cext += EF_TANDEM_SIZE;
+
+#ifdef USE_EF_UT_TIME
+    UTptr = ext;
+    *ext++  = 'U';
+    *ext++  = 'T';
+    *ext++  = (char)EB_UT_LEN(3);    /* length of data part of local e.f. */
+    *ext++  = 0;
+    *ext++  = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME;
+    *ext++  = (char)(s.st_mtime);
+    *ext++  = (char)(s.st_mtime >> 8);
+    *ext++  = (char)(s.st_mtime >> 16);
+    *ext++  = (char)(s.st_mtime >> 24);
+    *ext++  = (char)(s.st_atime);
+    *ext++ = (char)(s.st_atime >> 8);
+    *ext++ = (char)(s.st_atime >> 16);
+    *ext++ = (char)(s.st_atime >> 24);
+
+    *ext++ = (char)(nsk_ov->ov.creation_time);
+    *ext++ = (char)(nsk_ov->ov.creation_time >> 8);
+    *ext++ = (char)(nsk_ov->ov.creation_time >> 16);
+    *ext++ = (char)(nsk_ov->ov.creation_time >> 24);
+
+    Uxptr = ext;
+    *ext++ = 'U';
+    *ext++ = 'x';
+    *ext++ = (char)EB_UX2_MINLEN;   /* length of data part of local e.f. */
+    *ext++ = 0;
+    *ext++ = (char)(s.st_uid);
+    *ext++ = (char)(s.st_uid >> 8);
+    *ext++ = (char)(s.st_gid);
+    *ext++ = (char)(s.st_gid >> 8);
+
+    z->ext += EF_L_UNIX_SIZE;
+
+    memcpy(cext, UTptr, EB_C_UT_SIZE);
+    cext[EB_LEN] = (char)EB_UT_LEN(1);
+    memcpy(cext+EB_C_UT_SIZE, Uxptr, EB_C_UX2_SIZE);
+    cext[EB_LEN+EB_C_UT_SIZE] = 0;
+
+    z->cext += EF_C_UNIX_SIZE;
+    cext += EF_C_UNIX_SIZE;
+
+#endif /* USE_EF_UT_TIME */
+
+    return ZE_OK;
+  }
+
+#if CRYPT
+  /* getpid() only available on OSS so make up dummy version using NSK PID */
+  unsigned zgetpid (void)
+  {
+    short myphandle[ZSYS_VAL_PHANDLE_WLEN];
+    short err;
+    unsigned retval;
+
+    err = PROCESSHANDLE_NULLIT_(myphandle);
+
+    if (!err)
+      err = PROCESS_GETINFO_(myphandle);
+
+    if (!err)
+      retval = (unsigned) myphandle[ZSYS_VAL_PHANDLE_WLEN - 3];
+    else
+#ifndef __INT32
+      retval = (unsigned) 31415;
+#else
+      retval = (unsigned) 3141592654L;
+#endif /* __INT32 */
+
+    return retval;
+  }
+#endif  /* CRYPT */
diff --git a/tandem/tanzip.h b/tandem/tanzip.h
new file mode 100644 (file)
index 0000000..528337d
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __tanzip_h   /* prevent multiple inclusions */
+#define __tanzip_h
+
+# define fopen nskopen  /*  To allow us to set extent sizes */
+
+#  define USE_CASE_MAP
+
+  FILE     *nskopen(const char *, const char *);
+  int       zopen  (const char *, int);
+  int       zclose (int);
+  unsigned  zread (int, char *, unsigned);
+  void      nskformatopt(char *);
+
+  #define   getpid  zgetpid
+  unsigned  zgetpid (void);
+
+#define CBSZ 0x10000  /* Was used for both fcopy and file_read.        */
+                      /* Created separate define (SBSZ) for file_read  */
+                      /* fcopy param is type size_t (unsigned long)    */
+                      /* For Guardian we choose a multiple of 4K       */
+
+#define ZBSZ 0x10000  /* This is used in call to setvbuf, 64K seems to work  */
+                      /* in all memory models. Again it is an unsigned long  */
+                      /* For Guardian we choose a multiple of 4K             */
+
+#ifndef __INT32
+#define SBSZ 0x0e000  /* Maximum of size unsigned (int). Only used in STORE  */
+                      /* method.  We can use up to 56K bytes thanks to large */
+                      /* transfer mode.  Note WSIZE is limited to 32K, which */
+                      /* limits the DEFLATE read size to same value.         */
+#else
+#define SBSZ 0x10000  /* WIDE model so we can use 64K                        */
+#endif /* __INT32 */
+
+#endif /* !__tanzip_h */
diff --git a/tandem/zipup.h b/tandem/zipup.h
new file mode 100644 (file)
index 0000000..19d92ad
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+  Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+#  define O_RDONLY 0
+#endif
+#define fhow O_RDONLY
+#define fbad (-1)
+typedef int ftype;
+
+/* Now we create Guardian versions of zopen, zread, zclose instead
+   moved prototypes to tanzip.h as they are now coded in tanzip.c
+   #define zopen(n,p) open(n,p)
+   #define zread(f,b,n) read(f,b,n)
+   #define zclose(f) close(f)
+*/
+
+
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
+
diff --git a/theos/Makefile b/theos/Makefile
new file mode 100644 (file)
index 0000000..acdbb12
--- /dev/null
@@ -0,0 +1,138 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# THEOS ANSI C
+# To use, do "make -f theos/makefile"
+# This make file uses cl, a C compiler and linker driver written by
+# Jean-Michel Dubois. Send a mail to jmdubois@ibcfrance.fr to get it for free.
+# MAINWA_BUG    Workaround argument expansion failure
+# LOCATE_BUG    Workaround stat, fopen and open failure on relative paths to
+#               root dir.
+
+CC=cl
+CFLAGS=-Zi -W3 -DDYN_ALLOC -DCRYPT -DMAINWA_BUG -DLOCATE_BUG
+LD=cl -o
+LDFLAGS=-m -Zi
+AS=cc
+ASFLAGS=
+
+UTILFLAGS=-DUTIL $(CFLAGS) -Fo
+
+# variables
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crypt.o ttyio.o \
+       theos.o crc32.o _fprintf.o _stat.o _chmod.o _isatty.o \
+       _setargv.o _rename.o
+OBJI = deflate.o trees.o
+OBJA =
+OBJU = zipfile_.o fileio_.o util_.o globals.o theos_.o _rename.o _stat.o \
+       _chmod.o _fprintf.o
+OBJN = zipnote.o  $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+OSDEP_H = theos/osdep.h
+ZIP_H = zip.h ziperr.h tailor.h $(OSDEP_H)
+
+ZIPS = zip.command zipnote.command zipsplit.command zipcloak.command
+
+zips:  $(ZIPS)
+
+zip.o: zip.c $(ZIP_H) crc32.h crypt.h ttyio.h revision.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipfile.o:     zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipup.o:       zipup.c $(ZIP_H) revision.h crc32.h crypt.h
+       $(CC) -c $(CFLAGS) $*.c
+
+fileio.o:      fileio.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+util.o:        util.c $(ZIP_H) theos/charconv.h
+       $(CC) -c $(CFLAGS) $*.c
+
+globals.o:     globals.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+crc32.o:       crc32.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+deflate.o:     deflate.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+trees.o:       trees.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+crypt.o:       crypt.c $(ZIP_H) crc32.h crypt.h
+       $(CC) -c $(CFLAGS) $*.c
+
+theos.o:       theos/theos.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) -Fo$@ theos/theos.c
+
+_fprintf.o:    theos/_fprintf.c
+       $(CC) -c $(CFLAGS) -Fo$@ theos/_fprintf.c
+
+_stat.o:       theos/_stat.c
+       $(CC) -c $(CFLAGS) -Fo$@ theos/_stat.c
+
+_chmod.o:      theos/_chmod.c
+       $(CC) -c $(CFLAGS) -Fo$@ theos/_chmod.c
+
+_isatty.o:     theos/_isatty.c
+       $(CC) -c $(CFLAGS) -Fo$@ theos/_isatty.c
+
+_rename.o:     theos/_rename.c
+       $(CC) -c $(CFLAGS) -Fo$@ theos/_rename.c
+
+_setargv.o:    theos/_setargv.c
+       $(CC) -c $(CFLAGS) -Fo$@ theos/_setargv.c
+
+ttyio.o:       $(ZIP_H) ttyio.h ttyio.c
+       $(CC) -c $(CFLAGS) $*.c
+
+zipcloak.o:    zipcloak.c $(ZIP_H) crc32.h crypt.h ttyio.h revision.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipnote.o:     zipnote.c $(ZIP_H) revision.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipsplit.o:    $(ZIP_H) revision.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipfile_.o:    zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS)$@ zipfile.c
+
+fileio_.o:     fileio.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS)$@ fileio.c
+
+theos_.o:      theos/theos.c $(ZIP_H)
+       $(CC) -c $(UTILFLAGS)$@ theos/theos.c
+
+util_.o:       util.c $(ZIP_H)
+       $(CC) -c $(UTILFLAGS)$@ util.c
+
+crc32_.o:      crc32.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS)$@ $*.c
+
+crypt_.o:      crypt.c $(ZIP_H) crc32.h crypt.h
+       $(CC) -c $(UTILFLAGS)$@ crypt.c
+
+zip.command: $(OBJZ) $(OBJI)
+       $(LD) $@ $(OBJZ) $(OBJI) $(LDFLAGS)
+
+zipcloak.command: $(OBJC)
+       $(LD) $@ $(OBJC) $(LDFLAGS)
+
+zipnote.command: $(OBJN)
+       $(LD) $@ $(OBJN) $(LDFLAGS)
+
+zipsplit.command: $(OBJS)
+       $(LD) $@ $(OBJS) $(LDFLAGS)
+
+install:       $(ZIPS)
+       copy *.command /system.cmd32.=(rep noq not
+
+clean:
+       erase *.o(noq not
+       erase *.command(noq not
diff --git a/theos/README b/theos/README
new file mode 100644 (file)
index 0000000..1ec99d3
--- /dev/null
@@ -0,0 +1,34 @@
+This Theos port supports all the unusual features of Theos filesystem.
+
+Under Theos filesystem files are typed. Types include :
+- stream
+- relative
+- keyed
+- indexed (ISAM)
+- program (86 real mode, 16 bits protected mode, 32 bits protected mode)
+- directory
+- library (contains files of any other types librry and directory excepted).
+
+Most of the information on the type and on the structure of a file are not
+contained in the file itself but its in directory entry. For all types of
+files, directory and stream files excepted, this information is vital. If it
+is lost, the file can no longer be usable.
+
+In zip files the information is stored in an extra block with type "Th".
+
+A few years ago I ported ZIP for internal use and spreaded it a little around
+me. It was using a non portable extra block structure. Its type was "TH".
+For backward compatibility it is supported by UNZIP 5.4.0 port to Theos.
+ZIP archives created with ZIP 2.3 port MUST be unzipped with 5.4.0 or a later
+version.
+
+Also disk search sequence is supported. The disk name is not stored into
+the zip archive.
+
+Thanks to Bob Baker from Stockboy Services who spent his time to check this
+port under other conditions than mines.
+
+Jean-Michel Dubois
+IBC France / THEOS France
+jmdubois@ibcfrance.fr
+jean-michel-dubois@wanadoo.fr
diff --git a/theos/_chmod.c b/theos/_chmod.c
new file mode 100644 (file)
index 0000000..0937b45
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/* Change UNIX modes */
+
+#pragma library
+
+#include <sc.h>
+
+int _chmod(const char *fname, short mask)
+{
+    extern char _um2tm_(short);
+
+    return _filechange(fname,'p',(size_t) _um2tm_(mask)|0x80);
+}
+
diff --git a/theos/_fprintf.c b/theos/_fprintf.c
new file mode 100644 (file)
index 0000000..36a21a6
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#include <stdio.h>
+#include <stdarg.h>
+
+/* for Info and similar macroes. fprintf is already a macro and fprintf x
+ * fools the preprocessor
+ */
+
+int _fprintf(FILE* fp, const char* fmt, ...)
+{
+    va_list ap;
+    long n;
+
+    va_start(ap, fmt);
+    n = vfprintf(fp, fmt, (long*) ap);
+    va_end(ap);
+    return n;
+}
+
diff --git a/theos/_isatty.c b/theos/_isatty.c
new file mode 100644 (file)
index 0000000..3283e90
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* replace standard library function who needs a FILE* */
+
+#pragma library
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sc.h>
+#include <lub.h>
+
+short _isatty(int fd)
+{
+    register short lub;
+
+    lub = (int) _fcntl(&stdin[fd], 5, (size_t) 0);
+    return (lub >= CONIN && lub <= CONOUT)
+        || (lub >= COM1 && lub <= COM4)
+        || (lub >= COM5 && lub <= COM16);
+}
diff --git a/theos/_rename.c b/theos/_rename.c
new file mode 100644 (file)
index 0000000..04eb204
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define EXDEV 590
+
+#define _sys_rename()   _sc_140()
+extern unsigned short   _sys_rename(const char _far *oldfn, char *newfn);
+
+/* rename a file. Report an error on cross disk renames */
+
+static void _n_(const char* fn, char* bfn)
+{
+    if (*fn != '.' && *fn != '/')
+        strcpy(bfn, "./");
+    else
+        *bfn = '\0';
+    strcat(bfn, fn);
+}
+
+int _rename(const char* old, const char* new)
+{
+    char* p;
+    char* q;
+    char* r;
+    char olddrv, newdrv;
+    char dir[FILENAME_MAX];
+    short status;
+    char bold[FILENAME_MAX], bnew[FILENAME_MAX];
+
+    p = strrchr(old, ':');
+    q = strrchr(new, ':');
+
+    /* if at least one path includes a disk name, check for equality */
+    if (p != NULL || q != NULL) {
+        /* getcwd return a NULL pointer for /:S */
+        getcwd(dir, FILENAME_MAX);
+        r = strrchr(dir, ':');
+
+        if (p == NULL)
+            p = r;
+        olddrv = p ? p[1] : 'S';
+
+        if (q == NULL)
+            q = r;
+        newdrv = q ? q[1] : 'S';
+
+        /* return an error if uppercased disk names are not the same */
+        if ((old & ~0x20) != (new & ~0x20)) {
+            _errarg = NULL;
+            return errno = _errnum = EXDEV;
+        }
+    }
+    /* prepend ./ if there is no path to force rename to work on files
+     * in the current directory instead of default library
+     */
+    _n_(old, bold);
+    _n_(new, bnew);
+
+    status = _sys_rename(bold, bnew);
+    /* can be :
+     *  0 no error
+     * 19 "old" file not found
+     * 44 "new" file already exist
+     * 45 "new" filename missing
+     * 46 "old" file name missing
+     */
+    if (status) {
+        errno = _errnum = status;
+        _errarg = (status == 44 || status == 45) ? new : old;
+    }
+
+    return status;
+}
diff --git a/theos/_setargv.c b/theos/_setargv.c
new file mode 100644 (file)
index 0000000..d76f955
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ * __setargv.c - command argument expander
+ *
+ * Author  : Jean-Michel Dubois
+ * Date    : 09/26/92
+ *
+ * Function: Expands the command line arguments by replacing any filename
+ *           including wilcards by the sorted list of matching files name.
+ *           Strings beginning by a dash are considered as options and left
+ *           unchanged.
+ *
+ * Syntax  : void _setargv(int *argc, char ***argv);
+ *
+ * Returns : new argc. Caller's argc and argv are updated.
+ *           If a insufficient memory condition occurs, return 0 and errno
+ *           is set to ENOMEM.
+ *
+ * Example :
+ *              main(int argc, char **argv)
+ *              {
+ *                      if (_setargv(&argc, &argv)) {
+ *                              ...
+ */
+#pragma library
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <scr.h>
+#include <peek.h>
+
+/* Allocate argv array in 16 entries chunks */
+
+static int allocarg(int n, int l, char ***nargv, char *s)
+{
+    if ((n+1) > l) {    /* If array full */
+        l += 16;        /* increase size and reallocate */
+        if (!(*nargv = (char **) realloc(*nargv,l * sizeof (void *)))) {
+            errno = _errnum = ENOMEM;    /* Not enough memory */
+            return 0;
+        }
+    }
+    (*nargv)[n] = strdup(s);    /* Save argument */
+    return l;            /* Return new maxsize */
+}
+
+/* Comparison function for qsort */
+
+static int sortcmp(char **p, char **q)
+{
+    return stricmp(*p,*q);
+}
+
+/* Main body of the function */
+
+int _setargv(int *argc, char ***argv)
+{
+    register int nargc;     /* New arguments counter */
+    char **nargv;           /* New arguments pointers */
+    register int i, l, base;
+    char *p, *q, *r;
+    char path[FILENAME_MAX];
+
+    _errnum = 0;
+    nargc = 0;          /* Initialise counter, size counter */
+    l = *argc;          /* and new argument vector to the */
+                        /* current argv array size */
+
+    if ((nargv = (char **) calloc((size_t) *argc, sizeof (void *))) != NULL) {
+        /* For each initial argument */
+        for (i = 0; i < *argc; i++) {
+            q = (*argv)[i];
+            if (q[0] == '-' || ! testwild(q)) {
+                /* if it begins with a dash or doesnt include
+                 * wildcard simply add it to the new array
+                 */
+                if (! (l = allocarg(nargc, l, &nargv, q)))
+                    return 0;    /* Not enough memory */
+                nargc++;
+            } else {
+                /* else keep current counter for qsort */
+                base = nargc;
+                /* open directory with argument */
+                diropen(q);
+                while ((r = dirread()) != NULL) {
+                    /* reduce path to given one */
+                    if ((p = strrchr(q, '/')) != NULL) {
+                        strncpy(path, q, p-q+1);
+                        path[p-q+1] = '\0';
+                    } else
+                        path[0] = '\0';
+
+                    if ((p = strrchr(r, '/')) != NULL)
+                        strcat(path, p+1);
+                    else
+                        strcat(path, r);
+
+                    if (peekscr(&SCR->searchseq[1]) == 255
+                     && strchr(q, ':') == NULL) {
+                        *strchr(path, ':') = '\0';
+                    }
+                    /* and add each matching filename. */
+                    if (! (l = allocarg(nargc,l,&nargv,path)))
+                        return 0;/* Not enough memory */
+                    nargc++;
+                }
+                if (nargc == base) {
+                    /* if no match found include wild card name */
+                    if (! (l = allocarg(nargc, l, &nargv, q)))
+                        return 0;    /* Not enough memory */
+                    nargc++;
+                } else if ((nargc - base) > 1)
+                    /* If more than one file name matchs */
+                    /* sort arguments. */
+                    qsort(&(nargv[base]),(size_t)nargc-base,
+                        sizeof(void *),sortcmp);
+                dirclose();
+            }
+        }
+        /* Update caller's parameters */
+        *argc = nargc;
+        *argv = nargv;
+        /* and sign on success */
+        return nargc;
+    }
+
+    /* If it is not possible to allocate initial array, sign on error */
+    _errnum = ENOMEM;
+    return 0;
+}
diff --git a/theos/_stat.c b/theos/_stat.c
new file mode 100644 (file)
index 0000000..6855d28
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#pragma library
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sc.h>
+#include <peek.h>
+#include <lub.h>
+#include <fdb.h>
+#include <fsa.h>
+#include "theos/stat.h"
+
+/* replacement for standard library functions stat and fstat */
+
+int _stat_(struct stat* st, struct fdb* fdb);
+int _dstat_(struct stat* st);
+
+#define peekucb() peeknuc()
+
+/* map THEOS protection code to Unix modes */
+
+unsigned short _tm2um_(char protect)
+{
+    unsigned short umask = 0;
+
+    if (!(protect & _FDB_READ_PROTECT))
+        umask = S_IRUSR|S_IRGRP;
+
+    if (!(protect & _FDB_WRITE_PROTECT))
+        umask |= S_IWUSR|S_IWGRP;
+
+    if (!(protect & _FDB_EXECUTE_PROTECT))
+        umask |= S_IXUSR|S_IXGRP;
+
+    if (!(protect & _FDB_ERASE_PROTECT))
+        umask |= S_IEUSR|S_IEGRP;
+
+    if (!(protect & _FDB_SHARED_READ_PROTECT)) {
+        if (_osmajor > 3)
+            umask |= S_IROTH|S_IXOTH;
+        else
+            umask |= S_IROTH;
+    }
+
+    if (!(protect & _FDB_SHARED_WRITE_PROTECT))
+        umask |= S_IWOTH;
+
+    if (!(protect & _FDB_MODIFIED)) {
+        if (_osmajor > 3)
+            umask |= S_IMODF;
+        else
+            umask |= S_IXOTH;
+    }
+
+    if (protect & _FDB_NOT_HIDDEN)
+        umask |= S_INHID;
+
+    return umask;
+}
+
+/* map Unix modes to THEOS protections */
+
+char _um2tm_(unsigned short mask)
+{
+    char protect = 0;
+
+    if (!(mask & (S_IRUSR|S_IRGRP)))
+        protect |= _FDB_READ_PROTECT;
+
+    if (!(mask & (S_IWUSR|S_IWGRP)))
+        protect |= _FDB_WRITE_PROTECT;
+
+    if (!(mask & (S_IXUSR|S_IXGRP)))
+        protect |= _FDB_EXECUTE_PROTECT;
+
+    if (!(mask & (S_IEUSR|S_IEGRP)))
+        protect |= _FDB_ERASE_PROTECT;
+
+    if (_osmajor < 4) {
+        if (!(mask & S_IROTH))
+            protect |= _FDB_SHARED_READ_PROTECT;
+    } else {
+        if (!(mask & (S_IROTH|S_IXOTH)))
+            protect |= _FDB_SHARED_READ_PROTECT;
+    }
+
+    if (!(mask & S_IWOTH))
+        protect |= _FDB_SHARED_WRITE_PROTECT;
+
+    if (mask & S_IMODF && _osmajor > 3)
+        protect |= _FDB_MODIFIED;
+
+    if (mask & S_INHID && _osmajor > 3)
+        protect |= _FDB_NOT_HIDDEN;
+
+    return protect;
+}
+
+/* root directory stat */
+
+static int rdirstat(const char* fn, struct stat *st)
+{
+    register char* p = strchr(fn, ':');
+    char drive;
+
+    drive = p ? p[1] : 'S';
+
+    if (drive >= 'a' && drive <= 'Z')
+        drive -= 0x40;
+
+    memset(st, 0, sizeof(struct stat));
+
+    if (getlub(drive - 'A') != 255) {
+        st->st_org = _FDB_STAT_DIRECTORY;
+        st->st_mode = S_IFDIR|S_IRUSR|S_IWUSR|S_IROTH|S_IWOTH;
+        st->st_nlink = 1;
+        st->st_dev = st->st_rdev = drive - 'A';
+        st->st_uid = st->st_gid = getuid();
+        st->st_protect = _FDB_ERASE_PROTECT;
+        return 0;
+    }
+    errno = _errnum = ENOENT;
+    _errarg = fn;
+    return -1;
+}
+
+#ifdef LOCATE_BUG
+
+/* locate fails when stating a file in root dir from a directory with a
+ * relative path. Workaround by setting directory to root dir
+ * getting the file directory block, then restoring the current directory.
+ */
+
+struct fdb* __locate(const char* fn, char* buf, short* drv)
+{
+    struct fdb* fdb;
+    char buf2[FILENAME_MAX];
+    char cwd[FILENAME_MAX];
+    char drive[3];
+    char* p;
+    char* q;
+
+    /* return if file found */
+    if (fdb = _locate(fn, buf, drv))
+        return fdb;
+
+    /* if file name does not contain a path delimiter it really does not exist.
+     */
+    strcpy(buf2, fn);
+
+    if ((p = strrchr(buf2, '/')) == NULL)
+        return NULL;
+
+    /* get drive name from file path */
+    q = strrchr(buf2, ':');
+
+    /* cat drive name if any to directory path */
+    if (q) {
+        strncpy(drive, q, 2);
+        drive[2] = '\0';
+        strcpy(p, q);
+    } else
+        *p = '\0';
+    /* save current directory */
+    getcwd(cwd, FILENAME_MAX);
+    /* chdir to directory path */
+    chdir(buf2);
+    /* get File Directory Block */
+    p = strrchr(fn, '/');
+    fdb = _locate(p + 1, buf, drv);
+    /* restore current directory */
+    chdir(cwd);
+    return fdb;
+}
+
+#undef _locate
+#define _locate() __locate()
+
+/* same cause, same consequence for fopen and open.
+*/
+
+FILE* _fopen(const char* fn, const char* mode)
+{
+    FILE* fp;
+    char buf[FILENAME_MAX];
+    short drv;
+
+    /* prepend a path to current dir to avoid use of default library */
+    if (*fn != '.' && *fn != '/') {
+        strcpy(buf, "./");
+        strcat(buf, fn);
+        return fopen(buf, mode);
+    }
+
+    if (fp = fopen(fn, mode))
+        return fp;
+
+    /* see comment for _locate */
+    if (_locate(fn, buf, &drv)) {
+        fn = strrchr(fn, '/');
+        return fopen(fn, mode);
+    }
+    return NULL;
+}
+
+#undef open
+int open(const char*, int, ...);
+
+int __open(const char* fn, int mode)
+{
+    int fd;
+    char buf[FILENAME_MAX];
+    short drv;
+
+    /* prepend a path to current dir to avoid use of default library */
+    if (*fn != '.' && *fn != '/') {
+        strcpy(buf, "./");
+        strcat(buf, fn);
+        return open(buf, mode);
+    }
+
+    if ((fd = open(fn, mode)) != EOF)
+        return fd;
+
+    /* see comment for _locate */
+    if (_locate(fn, buf, &drv)) {
+        fn = strrchr(fn, '/');
+        if (fn)
+            return open(fn, mode);
+    }
+    return EOF;
+}
+#endif
+
+/* replacement for standard file stat */
+
+int _stat(const char *_fn, struct stat *st)
+{
+    char buf[FILENAME_MAX], buf2[FILENAME_MAX], buf3[FILENAME_MAX];
+    register struct fdb* fdb;
+    register char* p;
+    register char* fn;
+
+    fn = strcpy(buf3, _fn);
+
+    if (p = strrchr(fn, ':'))
+        *p = 0;
+
+    /* on current drive ./:d and .:m point to current dir
+     * on another drive to root directory, workaround to avoid it */
+
+    if (! strcmp(fn, "/") || ! strcmp(fn, ".") || ! strcmp(fn, "./")) {
+        if (p == NULL) {
+            /* current dir on current drive */
+            fn = getcwd(buf2, FILENAME_MAX);
+            /* getcwd returns NULL on root dir on drive S */
+            if (fn == NULL)
+                fn = strcpy(buf2, "/:S");
+            /* getcwd returns /:d on root dir on any other drive */
+            if (fn[1] == ':')
+                return rdirstat(fn, st);
+        } else {
+            *p = ':';
+            return rdirstat(fn, st);
+        }
+        if (p)
+            *p = ':';
+    } else {
+        if (p)
+            *p = ':';
+        if (*fn != '.' && *fn != '/') {
+            strcpy(buf2, "./");
+            fn = strcat(buf2, fn);
+        }
+    }
+
+    if (buf2 != fn)
+        strcpy(buf2, fn);
+    /* remove trailing slash before optional disk name */
+    if (p = strrchr(buf2, '/')) {
+        if (p[1] == ':') {
+            *p = p[1];
+            p[1] = p[2];
+            p[2] = p[3];
+        } else if (p[1] == '\0')
+            *p = '\0';
+    }
+    /* if fn is a file get file directory block structure and device */
+    if (fdb = _locate(buf2, buf, &st->st_dev)) {
+        /* is it a file from another user... */
+        if (strchr(buf2, '\\')
+        /* a public system file... */
+         || fdb->fileowner == 0
+        /* or a file from the current user account ? */
+         || fdb->fileowner == getuid())
+        /* yes, return stat */
+            return _stat_(st, fdb);
+        else {
+            /* no, say file doesn't exist */
+            errno = _errnum = ENOENT;
+            _errarg = fn;
+            return -1;
+        }
+    }
+    /* else should be a device, get device number from device name */
+    st->st_rdev = st->st_dev = _lub_name(*fn == ':' ? fn+1 : fn);
+    /* if it is really a device return device status */
+    if (st->st_dev != -1 && getlub(st->st_dev) != 255)
+        return _dstat_(st);
+    /* neither an existing file or a device name, return EOF */
+    st->st_rdev = st->st_dev = 0;
+    errno = _errnum = ENOENT;
+    _errarg = fn;
+    return -1;
+}
+
+/* replacement for fstat */
+
+int _fstat(int fd, struct stat *st)
+{
+    unsigned short fsanum;
+    struct fsa fsa;
+    register FILE *fp;
+    int status;
+    register int i;
+    register char *p;
+
+    if (fd < FOPEN_MAX) {
+        fp = &stdin[fd];
+        /* get File Save Area number */
+        if (_fcntl(fp,1,0) & 0x80) {
+            fsanum = (unsigned short) _fcntl(fp,83,0);
+            st->st_dev = (unsigned short) _fcntl(fp,5,0);
+
+            if (st->st_dev >= A_DISK && st->st_dev <= Z_DISK) {
+                /* if opened file is a disk file */
+                /* copy far fsa in protected segment to local fsa */
+                for (i = 0, fsanum *= sizeof(fsa), p = (char *) &fsa;
+                     i < (sizeof(fsa));
+                     i++, fsanum++, p++)
+                    *p = _peekfsa((char *) fsanum);
+                /* build stat structure from fsa */
+                status = _stat_(st, (struct fdb*) &fsa);
+                /* get blocksize */
+                if ((st->st_blksize = _fcntl(fp,817,0)) == 0)
+                    st->st_blksize = BUFSIZ;
+                return status;
+            }
+            /* return device status */
+            return _dstat_(st);
+        }
+    }
+    errno = _errnum = EBADF;
+    return -1;
+}
+
+static int _isprt(int dev)
+{
+    return IS_PRT_LUB(dev);
+}
+
+/* device stat */
+
+int _dstat_(st)
+register struct stat* st;
+{
+    register struct ucb* ucb;
+
+    ucb = getucb(st->st_dev);
+    st->st_ino = 0;
+    if (st->st_dev <= Z_DISK
+     || (st->st_dev >= TAPE1 && st->st_dev <= TAPE4)) {
+        st->st_mode = S_IFBLK | S_IWUSR | S_IRUSR;
+        if (peekucb(&ucb->devowner) == 255)
+            st->st_mode |= S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH;
+    } else {
+        st->st_mode = S_IFCHR | S_IWUSR;
+        if (_isprt(st->st_dev))
+            st->st_mode |= S_IRUSR;
+        if (peekucb(&ucb->devowner) == 255) {
+            st->st_mode |= S_IWGRP | S_IWOTH;
+            if (_isprt(st->st_dev))
+                st->st_mode |= S_IRGRP | S_IROTH;
+        }
+    }
+    st->st_nlink = 1;
+    st->st_uid = st->st_gid = getuid();
+    st->st_size = 0;
+    st->st_atime = st->st_mtime = st->st_ctime = 0;
+    st->st_rlen = 0;
+    st->st_klen = 0;
+    st->st_grow = 0;
+    st->st_blksize = 0;
+    return 0;
+}
+
+/* regular file stat */
+
+int _stat_(st, fdb)
+register struct stat* st;
+register struct fdb* fdb;
+{
+    st->st_rdev = st->st_dev;
+    st->st_ino = 0;
+    st->st_org = fdb->filestat;
+
+    /* map fdb file status to stat mode */
+    switch (fdb->filestat) {
+    case _FDB_STAT_LIBRARY:         st->st_mode = S_IFLIB;    break;
+    case _FDB_STAT_DIRECTORY:       st->st_mode = S_IFDIR;    break;
+    case _FDB_STAT_STREAM:          st->st_mode = S_IFREG;    break;
+    case _FDB_STAT_RELATIVE:        st->st_mode = S_IFREL;    break;
+    case _FDB_STAT_KEYED:           st->st_mode = S_IFKEY;    break;
+    case _FDB_STAT_INDEXED:         st->st_mode = S_IFIND;    break;
+    case _FDB_STAT_RANDOM:          st->st_mode = S_IFRND;    break;
+    case _FDB_STAT_PROGRAM:         st->st_mode = S_IFR16;    break;
+    case _FDB_STAT_16_BIT_PROGRAM:  st->st_mode = S_IFP16;    break;
+    case _FDB_STAT_32_BIT_PROGRAM:  st->st_mode = S_IFP32;    break;
+    }
+
+    /* map theos file protection codes to stat mode */
+    st->st_mode |= _tm2um_(st->st_protect = fdb->protect);
+    st->st_nlink = 1;
+    st->st_uid = st->st_gid = fdb->fileowner;
+    st->st_size = fdb->filesize;
+    st->st_atime = st->st_mtime = st->st_ctime = getfiledate(fdb);
+    st->st_blksize = 0;
+    /* specific theos information */
+    st->st_rlen = fdb->reclen;
+    st->st_klen = fdb->keylen;
+    st->st_grow = fdb->filegrow;
+    return 0;
+}
+
+#include <direct.h>
+
+/* standard diropen fails on path endung with a '/', workaround */
+
+struct dirent* _opendir(const char* dirpath)
+{
+    int l;
+    char dirp[FILENAME_MAX];
+    struct dirent* dir;
+
+    if (dirpath && (l = strlen(dirpath))) {
+        if (dirpath[l - 1] == '/') {
+            strcpy(dirp, dirpath);
+            dirp[l - 1] = '\0';
+            return opendir(dirp);
+        }
+    }
+    return opendir(dirpath);
+}
diff --git a/theos/charconv.h b/theos/charconv.h
new file mode 100644 (file)
index 0000000..3189170
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+#ifdef IZ_THS2ISO_ARRAY
+ZCONST uch Far ths2iso[] = {
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,  /* 80 - 87 */
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,  /* 88 - 8F */
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,  /* 90 - 97 */
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,  /* 98 - 9F */
+    0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B,  /* A0 - A7 */
+    0x2B, 0x2D, 0x7C, 0x2B, 0x2B, 0x2B, 0x2B, 0x23,  /* A8 - AF */
+    0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,  /* B0 - B7 */
+    0x3D, 0x23, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,  /* B8 - BF */
+    0xC4, 0xE4, 0xE2, 0xE0, 0xE1, 0xC9, 0xEB, 0xEA,  /* C0 - C7 */
+    0xE8, 0xE9, 0xEF, 0xEE, 0xEC, 0xED, 0xD6, 0xF6,  /* C8 - CF */
+    0xF4, 0xF2, 0xF3, 0xDC, 0xFC, 0xFB, 0xF9, 0xFA,  /* D0 - D7 */
+    0xC7, 0xE7, 0xD1, 0xF1, 0xC6, 0xE6, 0xC5, 0xE5,  /* D8 - DF */
+    0xDF, 0xBF, 0xA1, 0xA2, 0xA3, 0xA5, 0xB5, 0xA4,  /* E0 - E7 */
+    0xBC, 0xBD, 0xFF, 0xA7, 0xB0, 0xB2, 0x20, 0x20,  /* E8 - EF */
+    0x20, 0xB1, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,  /* F0 - F7 */
+    0x20, 0x20, 0xB7, 0x20, 0x20, 0x20, 0x20, 0x20   /* F8 - FF */
+};
+#endif /* IZ_THS2ISO_ARRAY */
+
+#ifdef IZ_THS2OEM_ARRAY
+ZCONST uch Far ths2oem[] = {
+    254,254,254,254, 254,254,134,135,   /* 80 - 87 */
+    136,137,138,139, 140,141,142,143,   /* 88 - 8F */
+    144,145,146,147, 148,149,150,151,   /* 90 - 97 */
+    152,153,154,155, 156,157,158,159,   /* 98 - 9F */
+    218,191,217,192, 197,195,180,194,   /* A0 - A7 */
+    193,196,179,218, 191,217,192,201,   /* A8 - AF */
+    183,188,200,206, 199,182,203,202,   /* B0 - B7 */
+    205,186,186,187, 188,189,190,191,   /* B8 - BF */
+    142,132,131,133, 160,144,137,136,   /* C0 - C7 */
+    138,130,139,140, 141,161,153,148,   /* C8 - CF */
+    147,149,162,154, 129,150,151,163,   /* D0 - D7 */
+    128,135,165,164, 146,145,143,134,   /* D8 - DF */
+    225,168,173,155, 156,157,158, 31,   /* E0 - E7 */
+    172,171,152, 21, 248,253,238,239,   /* E8 - EF */
+    240,241,242,243, 244,245,246,247,   /* F0 - F7 */
+    248,249,250,251, 252,253,254,255    /* F8 - FF */
+};
+#endif /* IZ_THS2OEM_ARRAY */
+
+#ifdef IZ_ISO2THS_ARRAY
+ZCONST uch Far iso2ths[] = {
+    0x3F, 0x3F, 0x27, 0x3F, 0x22, 0x2E, 0xA4, 0xB3,  /* 80 - 87 */
+    0x5E, 0x25, 0x53, 0x3C, 0x4F, 0x3F, 0x3F, 0x3F,  /* 88 - 8F */
+    0x3F, 0x27, 0x27, 0x22, 0x22, 0x07, 0x2D, 0x2D,  /* 90 - 97 */
+    0x7E, 0x54, 0x73, 0x3E, 0x6F, 0x3F, 0x3F, 0x59,  /* 98 - 9F */
+    0x20, 0xE2, 0xE3, 0xE4, 0xE7, 0xE5, 0x7C, 0xEB,  /* A0 - A7 */
+    0x20, 0x20, 0x20, 0x22, 0x20, 0x2D, 0x20, 0x2D,  /* A8 - AF */
+    0xEC, 0xF1, 0xED, 0x20, 0x20, 0xE6, 0x20, 0xFA,  /* B0 - B7 */
+    0x20, 0x20, 0x20, 0x22, 0xE8, 0xE9, 0x20, 0xE1,  /* B8 - BF */
+    0xC3, 0xC4, 0xC2, 0x41, 0xC0, 0xDE, 0xDC, 0xD8,  /* C0 - C7 */
+    0xC8, 0xC5, 0xC7, 0xC6, 0xCC, 0xCD, 0xCB, 0xCA,  /* C8 - CF */
+    0x44, 0xDA, 0xD1, 0xD2, 0xD0, 0x4F, 0xCE, 0x78,  /* D0 - D7 */
+    0x4F, 0xD6, 0xD7, 0xD5, 0xD3, 0x59, 0x20, 0xE0,  /* D8 - DF */
+    0xC3, 0xC4, 0xC2, 0x61, 0xC1, 0xDF, 0xDD, 0xD9,  /* E0 - E7 */
+    0xC8, 0xC9, 0xC7, 0xC6, 0xCC, 0xCD, 0xCB, 0xCA,  /* E8 - EF */
+    0x64, 0xDB, 0xD1, 0xD2, 0xD0, 0x4F, 0xCF, 0xF1,  /* F0 - F7 */
+    0x6F, 0xD6, 0xD7, 0xD5, 0xD4, 0x79, 0x20, 0xEA   /* F8 - FF */
+};
+#endif /* IZ_ISO2THS_ARRAY */
+
+#ifdef IZ_OEM2THS_ARRAY
+ZCONST uch Far oem2ths[] = {
+    216,212,201,194, 193,195,223,217,   /* 80 - 87 */
+    199,198,200,202, 203,204,192,222,   /* 88 - 8F */
+    197,221,220,208, 207,209,213,214,   /* 90 - 97 */
+    234,206,211,227, 228,229,230,159,   /* 98 - 9F */
+    196,205,210,215, 219,218,254,254,   /* A0 - A7 */
+    225,254,254,233, 232,226, 34, 34,   /* A8 - AF */
+    254,254,254,170, 166,166,181,176,   /* B0 - B7 */
+    161,181,185,176, 177,177,162,161,   /* B8 - BF */
+    163,168,167,165, 169,164,165,180,   /* C0 - C7 */
+    178,175,183,182, 180,184,179,168,   /* C8 - CF */
+    183,167,182,178, 163,160,175,179,   /* D0 - D7 */
+    164,162,160,254, 254,254,254,254,   /* D8 - DF */
+    254,224,254,254, 254,254,254, 31,   /* E0 - E7 */
+    254,254,254, 21, 254,254,238,239,   /* E8 - EF */
+    240,241,242,243, 244,245,246,247,   /* F0 - F7 */
+    236,249,250,251, 252,237,254,255    /* F8 - FF */
+};
+#endif /* IZ_OEM2THS_ARRAY */
+
diff --git a/theos/osdep.h b/theos/osdep.h
new file mode 100644 (file)
index 0000000..4f4857e
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ * XXX this should somehow depend on the stuff in revision.h
+ */
+#pragma prog 2.3,0,0,0
+
+/* use argument expansion */
+#if !defined(UTIL) && !defined(MAINWA_BUG)
+#  pragma wild argv
+#endif
+
+#include <stdio.h>
+#include <malloc.h>
+#include <handle.h>
+#include <conio.h>>
+#include <locale.h>
+#include <sys/types.h>
+#include "theos/stat.h" /* use JMD's extended stat function */
+
+#define isatty() _isatty() /* THEOS isatty uses a FILE* instead of a fd */
+int _isatty(int fd);
+
+#define deletedir(d) rmdir(d)
+
+/* will come later */
+#if 0
+#define USE_EF_UT_TIME          /* Enable use of "UT" extra field time info */
+#endif
+
+#if DEBUG
+int _fprintf(FILE* fp, const char* fmt, ...);
+#endif
+
+/* for rename() replacement. Standard function is bugged */
+
+int _rename(const char* old, const char* new);
+#define rename(a,b) _rename(a,b)
+
+#ifdef LOCATE_BUG
+/* for fopen replacement. Standard function fails on relative path pointing
+ * to root directory.
+ */
+#undef _fopen
+#undef open
+#define fopen() _fopen()
+FILE* _fopen(const char*, const char*);
+#define open() __open()
+FILE* __open(const char*, int);
+#endif
+
+#define EXDEV   10000
diff --git a/theos/stat.h b/theos/stat.h
new file mode 100644 (file)
index 0000000..ffcec0f
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef __theos_stat_h
+#define __theos_stat_h
+/*
+  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/* extended stat structure for stat, fstat, chmod */
+/* Written by Jean-Michel Dubois */
+
+#pragma field word
+struct stat {
+    unsigned short  st_mode;        /* file attributes */
+        #define S_IFMT      0xf000      /* file type mask */
+        #define S_IFIFO     0x1000      /* pipe */
+        #define S_IFCHR     0x2000      /* char device */
+        #define S_IFSOCK    0x3000      /* socket */
+        #define S_IFDIR     0x4000      /* directory */
+        #define S_IFLIB     0x5000      /* library */
+        #define S_IFBLK     0x6000      /* block device */
+        #define S_IFREG     0x8000      /* regular file */
+        #define S_IFREL     0x9000      /* relative (direct) */
+        #define S_IFKEY     0xA000      /* keyed */
+        #define S_IFIND     0xB000      /* indexed */
+        #define S_IFRND     0xC000      /* ???? */
+        #define S_IFR16     0xD000      /* 16 bit real mode program */
+        #define S_IFP16     0xE000      /* 16 bit protected mode prog */
+        #define S_IFP32     0xF000      /* 32 bit protected mode prog */
+
+        #define S_ISUID     0x0800      /* meaningless */
+        #define S_ISGID     0x0400      /* meaningless */
+        #define S_ISVTX     0x0200      /* meaningless */
+
+        #define S_IMODF     0x0800      /* modified */
+        #define S_INHID     0x0400      /* not hidden */
+
+        #define S_IRWXU     0x03c0      /* read,write,execute: owner */
+        #define S_IEUSR     0x0200      /* erase permission: owner */
+        #define S_IRUSR     0x0100      /* read permission: owner */
+        #define S_IWUSR     0x0080      /* write permission: owner */
+        #define S_IXUSR     0x0040      /* execute permission: owner */
+    /* group permissions */
+        #define S_IRWXG     0x0238
+        #define S_IEGRP     0x0200
+        #define S_IRGRP     0x0020
+        #define S_IWGRP     0x0010
+        #define S_IXGRP     0x0008
+    /* other never has erase permission */
+        #define S_IRWXO     0x0207      /* read,write,execute: other */
+        #define S_IROTH     0x0004      /* read permission: other */
+        #define S_IWOTH     0x0002      /* write permission: other */
+        #define S_IXOTH     0x0001      /* execute permission: other */
+
+        #define S_IREAD     0x0100      /* read permission, owner */
+        #define S_IEXEC     0x0040      /* execute permission, owner */
+        #define S_IWRITE    0x0080      /* write permission, owner */
+    short           st_ino;         /* not used */
+    short           st_dev;         /* not used */
+    short           st_rdev;        /* not used */
+    short           st_nlink;       /* not used */
+    short           st_uid;         /* owner id */
+    short           st_gid;         /* not used */
+    unsigned long   st_size;        /* size of file */
+    unsigned long   st_atime;       /* not used */
+    unsigned long   st_mtime;       /* date & time last modified */
+    unsigned long   st_ctime;       /* not used */
+    unsigned long   st_blksize;     /* buffer size */
+    unsigned short  st_org;         /* organization */
+    unsigned short  st_rlen;        /* record size */
+    unsigned short  st_klen;        /* key size */
+    char            st_grow;        /* growing factor */
+    char            st_protect;     /* native protections */
+};
+#pragma field
+
+#define S_ISREG(m)      (((m) & S_IFMT) >= S_IFREG)
+#define S_ISLIB(m)      (((m) & S_IFMT) == S_IFLIB)
+#define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
+#define S_ISCHR(m)      (((m) & S_IFMT) == S_IFCHR)
+#define S_ISBLK(m)      (((m) & S_IFMT) == S_IFBLK)
+
+#define S_ISSEQ(m)      (((m) & S_IFMT) == S_IFREG)
+#define S_ISREL(m)      (((m) & S_IFMT) == S_IFREL)
+#define S_ISKEY(m)      (((m) & S_IFMT) == S_IFKEY)
+#define S_ISIND(m)      (((m) & S_IFMT) == S_IFIND)
+#define S_ISPRG(m)      (((m) & S_IFMT) >= S_IFP16)
+#define S_ISLNK(m)      0
+
+/* avoid conflict with original THEOS functions */
+
+#define stat(a,b)       _stat(a,b)
+#define fstat(a,b)      _fstat(a,b)
+#define chmod(a,b)      _chmod(a,b)
+
+extern int _stat(const char *file, struct stat *statptr);
+extern int _fstat(int fd, struct stat *statptr);
+extern int _chmod(const char *file, short mask);
+
+#define _chstat(a,b)    ((int) _sc_168(a,'p',(size_t)(b)))
+extern unsigned short   _sc_168(const char _far *fn, int cmd, size_t value);
+
+#endif /* !__theos_stat_h */
diff --git a/theos/theos.c b/theos/theos.c
new file mode 100644 (file)
index 0000000..5da3f8b
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+  theos.c (zip)
+
+  Contribution by Jean-Michel Dubois. 20-Jun-1995, 20-Dec-98
+
+  THEOS specific extra informations
+
+  ---------------------------------------------------------------------------*/
+
+
+#include <stdio.h>
+
+#ifndef UTIL
+
+#include "zip.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+#include <sc.h>
+#include <direct.h>
+#include <sys/utime.h>
+
+#define opendir(a) _opendir(a)
+extern struct dirent* _opendir(char* fname);
+
+#define PAD 0
+
+#define RET_ERROR 1
+#define RET_SUCCESS 0
+#define RET_EOF 0
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* match from Phase One Systems */
+
+int match(char *s, char *p)    /*S Returns non-zero if string matches
+                                   the literal mask */
+{
+  int matched, k;
+
+  if (!(*p))
+    return 1;
+  for(;;) {
+    if ( (!(*s)) && (!(*p)) )
+      return(1);
+    else if ( !(*p) )
+      return(0);
+    else if (*p == '*') {
+      if (!*(p+1))
+        return(1);
+      k=0;
+      do {
+        matched = match(s+k,p+1);
+        k++;
+      } while ( (!matched) && *(s+k));
+      return(matched);
+    } else if (*p == '@') {
+      if (!((*s >= 'a' && *s <= 'z')
+          ||(*s >= 'A' && *s <= 'Z')))
+        return(0);
+    } else if (*p == '#') {
+      if (*s < '0' || *s > '9')
+        return(0);
+    } else if (*p != '?') {
+      if (tolower(*s) != tolower(*p))
+        return(0);
+    }
+    s++; p++;
+  }
+}
+
+local char *readd(d)
+DIR *d; /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+   no more entries or an error occurs. */
+{
+  struct dirent *e;
+
+  e = readdir(d);
+  return e == NULL ? (char *) NULL : e->d_name;
+}
+
+/* check if file is a member of a library */
+
+int ismember(char* path)
+{
+    char* p;
+
+    if ((p = strrchr(path, '/')) == NULL)
+        p = path;
+    return ((p = strchr(p, '.')) && (p = strchr(p + 1, '.')));
+}
+
+/* extract library name from a file name */
+
+char* libname(char* path)
+{
+    char* p;
+    static char lib[FILENAME_MAX];
+    char drive[3];
+
+    strcpy(lib, path);
+    if (p = strrchr(lib, ':')) {
+        strncpy(drive, p, 2);
+        drive[2] = '\0';
+        *p = '\0' ;
+    } else
+        drive[0] = '\0';
+
+    if ((p = strrchr(lib, '/')) == NULL)
+        p = lib;
+
+    p = strchr(p, '.');
+    p = strchr(p + 1, '.');
+    *p = 0;
+    strcat(lib, drive);
+    return lib;
+}
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  DIR *d;               /* directory stream from opendir() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist *z;      /* steps through zfiles list */
+  struct flist *f;      /* steps through files list */
+  char* path;           /* full name */
+  char drive[3];        /* drive name */
+  int recursion;        /* save recurse flag */
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (LSSTAT(n, &s)) {
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (match(z->iname, p))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory or library */
+  if (S_ISREG(s.st_mode)) {
+    if ((path = malloc(strlen(n) + 2)) == NULL)
+      return ZE_MEM;
+
+    strcpy(path, n);
+
+    /* if member name, include library name before any member name */
+    if (ismember(path)) {
+      strcpy(path, libname(path));
+      /* mask recursion flag to avoid endless loop recursion
+       * if -r is used with member names
+       */
+      recursion = recurse;
+      recurse = FALSE;
+      if ((m = procname(path, caseflag)) != ZE_OK)   /* recurse on name */
+      {
+        if (m == ZE_MISS)
+          zipwarn("name not matched: ", path);
+        else
+          ziperr(m, a);
+      }
+      /* restore recursion flag */
+      recurse = recursion;
+    }
+
+    strcpy(path, n);
+
+    if ((p = strchr(path, ':')) != NULL) {
+      p[2] = '\0';
+      strcpy(drive, p);
+    } else
+      drive[0] = '\0';
+
+    /* remove trailing dot in flat file name */
+    p = strend(path) - 1;
+    if (*p == '.')
+      *p = '\0';
+
+    strcat(path, drive);
+    /* add or remove name of file */
+    if ((m = newname(path, 0, caseflag)) != ZE_OK) {
+      free(path);
+      return m;
+    }
+    free(path);
+  } else if (S_ISLIB(s.st_mode)) {
+    if ((path = malloc(strlen(n) + 2)) == NULL)
+      return ZE_MEM;
+
+    strcpy(path, n);
+
+    if ((p = strchr(path, ':')) != NULL) {
+      p[2] = '\0';
+      strcpy(drive, p);
+    } else
+      drive[0] = '\0';
+
+    /* add a trailing dot in flat file name... */
+    p = strend(path) - 1;
+    if (*p != '/')
+      strcat(path, "/");
+    p = strend(path);
+    /* ... then add drive name */
+    strcpy(p, drive);
+
+    /* don't include the library name twice... or more */
+    for (f = found; f != NULL; f = f->nxt) {
+      if (! stricmp(path, f->name)) {
+        free(path);
+        return ZE_OK;
+      }
+    }
+    /* add or remove name of library */
+    if ((m = newname(path, 0, caseflag)) != ZE_OK) {
+      free(path);
+      return m;
+    }
+    /* recurse into library if required */
+    strcpy(p - 1, ".*");
+    strcat(p, drive);
+    if (recurse && diropen(path) == 0)
+    {
+      while ((e = dirread()) != NULL) {
+        if (strcmp(e, ".") && strcmp(e, ".."))
+        {
+          if (*drive == '\0')
+            *strchr(e, ':') = '\0';
+          if ((a = malloc(strlen(e) + 1)) == NULL)
+          {
+            dirclose();
+            free((zvoid *)p);
+            return ZE_MEM;
+          }
+          strcpy(a, e);
+          if ((m = procname(a, caseflag)) != ZE_OK)   /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", a);
+            else
+              ziperr(m, a);
+          }
+          free((zvoid *)a);
+        }
+      }
+      dirclose();
+    }
+    free(path);
+  } else {
+    /* Add trailing / to the directory name */
+    if ((p = malloc(strlen(n)+2)) == NULL)
+      return ZE_MEM;
+    if (strcmp(n, ".") == 0) {
+      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      strcpy(p, n);
+      a = p + strlen(p);
+      if (a[-1] != '/')
+        strcpy(a, "/");
+      if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+        free((zvoid *)p);
+        return m;
+      }
+    }
+    /* recurse into directory */
+    if (recurse && (d = opendir(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if (strcmp(e, ".") && strcmp(e, ".."))
+        {
+          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+          {
+            closedir(d);
+            free((zvoid *)p);
+            return ZE_MEM;
+          }
+          strcat(strcpy(a, p), e);
+          if ((m = procname(a, caseflag)) != ZE_OK)   /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", a);
+            else
+              ziperr(m, a);
+          }
+          free((zvoid *)a);
+        }
+      }
+      closedir(d);
+    }
+    free((zvoid *)p);
+  }
+  return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t;              /* shortened name */
+  char *p;
+  int dosflag;
+
+  dosflag = dosify;  /* default for non-DOS and non-OS/2 */
+
+  /* Find starting point in name before doing malloc */
+  for (t = x; *t == '/'; t++)
+    ;
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+  if (!pathput)
+    t = last(t, '/');
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL)
+    return NULL;
+
+  strcpy(n, t);
+  if (p = strchr(n, ':'))
+    *p = '\0';
+  for (p = n; *p = tolower(*p); p++);
+
+  if (isdir == 42) return n;      /* avoid warning on unused variable */
+
+  if (dosify)
+    msname(n);
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+  return n;
+}
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+    return NULL;
+  strcpy(x, n);
+  return x;
+}
+
+/*
+ * XXX use ztimbuf in both POSIX and non POSIX cases ?
+ */
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+  struct utimbuf u;     /* argument for utime()  const ?? */
+
+  /* Convert DOS time to time_t format in u */
+  u.actime = u.modtime = dos2unixtime(d);
+  utime(f, &u);
+}
+
+ulg filetime(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes. Bits 8 to 15 contains native THEOS protection
+   code. If n is not NULL, store the file size there.  If t is not NULL,
+   the file's access, modification and creation times are stored there as
+   UNIX time_t values. If f is "-", use standard input as the file. If f is
+   a device, return a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  /* from FNMAX to malloc - 11/8/04 EG */
+  char *name;
+  int len = strlen(f);
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+
+  if (name[len - 1] == '/' || name[len - 1] == '.')
+    name[len - 1] = '\0';
+
+  /* not all systems allow stat'ing a file with / appended */
+  if (strcmp(f, "-") == 0) {
+    if (fstat(fileno(stdin), &s) != 0) {
+      free(name);
+      error("fstat(stdin)");
+    }
+  } else if (LSSTAT(name, &s) != 0) {
+    /* Accept about any file kind including directories
+     * (stored with trailing / with -r option)
+     */
+    free(name);
+    return 0;
+  }
+  free(name);
+
+  if (a != NULL) {
+    *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+    if ((s.st_mode & S_IFMT) == S_IFDIR
+     || (s.st_mode & S_IFMT) == S_IFLIB) {
+      *a |= MSDOS_DIR_ATTR;
+    }
+    /* Map Theos' hidden attribute to DOS's hidden attribute */
+    if (!(st.st_protect & 0x80))
+      *a |= MSDOS_HIDDEN_ATTR;
+    *a |= ((ulg) s.st_protect) << 8;
+  }
+  if (n != NULL)
+    *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = t->mtime;   /* best guess, (s.st_ctime: last status change!!) */
+  }
+  return unix2dostime(&s.st_mtime);
+}
+/*
+ *      Get file THEOS attributes and store them into extent fields.
+ *      On error leave z intact.
+ */
+
+/*
+*   Extra record format
+*   ===================
+*   signature       (2 bytes)   = 'T','h'
+*   size            (2 bytes)
+*   flags           (1 byte)
+*   filesize        (4 bytes)
+*   keylen          (2 bytes)
+*   reclen          (2 bytes)
+*   filegrow        (1 byte)
+*   reserved        (4 bytes)
+*/
+
+#define EB_L_THSIZE     4
+#define EB_L_TH_SIZE    14
+
+int set_extra_field(z, z_utim)
+  struct zlist *z;
+  iztimes *z_utim;
+  /* store full data in local header but just modification time stamp info
+     in central header */
+{
+  char *extra = NULL;
+  char *p;
+  char c;
+  struct stat st;
+  int status;
+
+  if (status = stat(z->name, &st)) {
+    p = &z->name[strlen(z->name) - 1];
+    if (*p == '/' || *p == '.') {
+      c = *p;
+      *p = '\0';
+      status = stat(z->name, &st);
+      *p = c;
+    }
+#ifdef DEBUG
+    fprintf(stderr, "set_extra_field: stat for file %s:\n status = %d\n",
+        z->name, status);
+#endif
+    if (status)
+      return RET_ERROR;
+  }
+
+  if ((extra = malloc(EB_L_TH_SIZE)) == NULL ) {
+    fprintf(stderr, "set_extra_field: Insufficient memory.\n" );
+    return RET_ERROR;
+  }
+
+
+  extra[0] = 'T';
+  extra[1] = 'h';
+  extra[2] = EB_L_TH_SIZE;
+  extra[3] = EB_L_TH_SIZE >> 8;
+  extra[4] = 0;
+  extra[5] = st.st_size;
+  extra[6] = st.st_size >> 8;
+  extra[7] = st.st_size >> 16;
+  extra[8] = st.st_size >> 24;
+  extra[9] = st.st_org;
+  extra[10] = st.st_rlen;
+  extra[11] = st.st_rlen >> 8;
+  extra[12] = st.st_klen;
+  extra[13] = st.st_klen >> 8;
+  extra[14] = st.st_grow;
+  extra[15] = st.st_protect;
+  extra[16] = 0;
+  extra[17] = 0;
+  z->ext = z->cext = EB_L_TH_SIZE + EB_HEADSIZE;
+  z->extra = z->cextra = extra;
+  return RET_SUCCESS;
+}
+#endif
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+void version_local()
+{
+  printf("Compiled with THEOS C 5.28 for THEOS 4.x on %s %s.\n\n",
+    __DATE__, __TIME__);
+}
+
diff --git a/theos/zipup.h b/theos/zipup.h
new file mode 100644 (file)
index 0000000..1de3f61
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+#  define O_RDONLY 0
+#endif
+#define fhow O_RDONLY
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/timezone.c b/timezone.c
new file mode 100644 (file)
index 0000000..485ec02
--- /dev/null
@@ -0,0 +1,815 @@
+/*
+  timezone.c - Zip 3
+
+  Copyright (c) 1990-2004 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2003-May-08 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* Replacement time library functions, based on platform independent public
+ * domain timezone code from ftp://elsie.nci.nih.gov/pub, with mktime and
+ * mkgmtime from our own mktime.c in Zip.
+ *
+ * Contains:  tzset()
+ *            __tzset()
+ *            gmtime()
+ *            localtime()
+ *            mktime()
+ *            mkgmtime()
+ *            GetPlatformLocalTimezone()  [different versions]
+ */
+
+/* HISTORY/CHANGES
+ * 17 Jun 00, Paul Kienitz, added the PD-based tzset(), localtime(), and so on
+ *            to amiga/filedate.c, replacing GNU-based functions which had
+ *            replaced time_lib.c, both having been rejected for licensing
+ *            reasons.  Support for timezone files and leap seconds was removed.
+ *
+ * 23 Aug 00, Paul Kienitz, split into separate timezone.c file, made platform
+ *            independent, copied in mktime() and mkgmtime() from Zip, renamed
+ *            locale_TZ as GetPlatformLocalTimezone(), for use as a generic
+ *            hook by other platforms.
+ */
+
+#ifndef __timezone_c
+#define __timezone_c
+
+
+#include "zip.h"
+#include "timezone.h"
+#include <ctype.h>
+#include <errno.h>
+
+#ifdef IZTZ_DEFINESTDGLOBALS
+long timezone = 0;
+int daylight = 0;
+char *tzname[2];
+#endif
+
+#ifndef IZTZ_GETLOCALETZINFO
+#  define IZTZ_GETLOCALETZINFO(ptzstruct, pgenrulefunct) (FALSE)
+#endif
+
+int real_timezone_is_set = FALSE;       /* set by tzset() */
+
+
+#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
+#define TZDEFAULT       "EST5EDT"
+
+#define SECSPERMIN      60
+#define MINSPERHOUR     60
+#define HOURSPERDAY     24
+#define DAYSPERWEEK     7
+#define DAYSPERNYEAR    365
+#define DAYSPERLYEAR    366
+#define SECSPERHOUR     (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY      ((long) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR 12
+
+#define EPOCH_WDAY      4     /* Jan 1, 1970 was thursday */
+#define EPOCH_YEAR      1970
+#define TM_YEAR_BASE    1900
+#define FIRST_GOOD_YEAR ((time_t) -1 < (time_t) 1 ? EPOCH_YEAR-68 : EPOCH_YEAR)
+#define LAST_GOOD_YEAR  (EPOCH_YEAR + ((time_t) -1 < (time_t) 1 ? 67 : 135))
+
+#define YDAYS(month, year) yr_days[leap(year)][month]
+
+/* Nonzero if `y' is a leap year, else zero. */
+#define leap(y)  (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
+
+/* Number of leap years from EPOCH_YEAR  to `y' (not including `y' itself). */
+#define _P4      ((EPOCH_YEAR / 4) * 4 + 1)
+#define _P100    ((EPOCH_YEAR / 100) * 100 + 1)
+#define _P400    ((EPOCH_YEAR / 400) * 400 + 1)
+#define nleap(y) (((y) - _P4) / 4 - ((y) - _P100) / 100 + ((y) - _P400) / 400)
+
+/* Length of month `m' (0 .. 11) */
+#define monthlen(m, y) (yr_days[0][(m)+1] - yr_days[0][m] + \
+                        ((m) == 1 && leap(y)))
+
+/* internal module-level constants */
+#ifndef IZ_MKTIME_ONLY
+static ZCONST char  gmt[] = "GMT";
+static ZCONST int    mon_lengths[2][MONSPERYEAR] = {
+    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+#endif /* !IZ_MKTIME_ONLY */
+static ZCONST int    yr_days[2][MONSPERYEAR+1] = {
+    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+};
+#ifndef IZ_MKTIME_ONLY
+static ZCONST int   year_lengths[2] = {
+    DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+/* internal variables */
+static struct state statism;
+
+
+/* prototypes of static functions */
+static time_t transtime OF((ZCONST time_t janfirst, ZCONST int year,
+                            ZCONST struct rule * ZCONST rulep,
+                            ZCONST long offset));
+static void generate_transitions OF((register struct state * ZCONST sp,
+                                     ZCONST struct rule * ZCONST start,
+                                     ZCONST struct rule * ZCONST end));
+static ZCONST char *getzname OF((ZCONST char *strp));
+static ZCONST char *getnum OF((ZCONST char *strp, int * ZCONST nump,
+                               ZCONST int min, ZCONST int max));
+static ZCONST char *getsecs OF((ZCONST char *strp, long * ZCONST secsp));
+static ZCONST char *getoffset OF((ZCONST char *strp, long * ZCONST offsetp));
+static ZCONST char *getrule OF((ZCONST char *strp, struct rule * ZCONST rulep));
+static int Parse_TZ OF((ZCONST char *name, register struct state * ZCONST sp));
+
+
+static time_t transtime(janfirst, year, rulep, offset)
+     ZCONST time_t janfirst;
+     ZCONST int year;
+     ZCONST struct rule * ZCONST rulep;
+     ZCONST long offset;
+{
+    register int    leapyear;
+    register time_t value;
+    register int    i;
+    int             d, m1, yy0, yy1, yy2, dow;
+
+    value = 0;
+    leapyear = leap(year);
+    switch (rulep->r_type) {
+
+    case JULIAN_DAY:
+        /*
+        ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
+        ** years.
+        ** In non-leap years, or if the day number is 59 or less, just
+        ** add SECSPERDAY times the day number-1 to the time of
+        ** January 1, midnight, to get the day.
+        */
+        value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
+        if (leapyear && rulep->r_day >= 60)
+            value += SECSPERDAY;
+        break;
+
+    case DAY_OF_YEAR:
+        /*
+        ** n - day of year.
+        ** Just add SECSPERDAY times the day number to the time of
+        ** January 1, midnight, to get the day.
+        */
+        value = janfirst + rulep->r_day * SECSPERDAY;
+        break;
+
+    case MONTH_NTH_DAY_OF_WEEK:
+        /*
+        ** Mm.n.d - nth "dth day" of month m.
+        */
+        value = janfirst;
+/*
+        for (i = 0; i < rulep->r_mon - 1; ++i)
+            value += mon_lengths[leapyear][i] * SECSPERDAY;
+*/
+        value += yr_days[leapyear][rulep->r_mon - 1] * SECSPERDAY;
+
+        /*
+        ** Use Zeller's Congruence to get day-of-week of first day of
+        ** month.
+        */
+        m1 = (rulep->r_mon + 9) % 12 + 1;
+        yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
+        yy1 = yy0 / 100;
+        yy2 = yy0 % 100;
+        dow = ((26 * m1 - 2) / 10 +
+            1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
+        if (dow < 0)
+            dow += DAYSPERWEEK;
+
+        /*
+        ** "dow" is the day-of-week of the first day of the month.  Get
+        ** the day-of-month (zero-origin) of the first "dow" day of the
+        ** month.
+        */
+        d = rulep->r_day - dow;
+        if (d < 0)
+            d += DAYSPERWEEK;
+        for (i = 1; i < rulep->r_week; ++i) {
+            if (d + DAYSPERWEEK >= mon_lengths[leapyear][rulep->r_mon - 1])
+                break;
+            d += DAYSPERWEEK;
+        }
+
+        /*
+        ** "d" is the day-of-month (zero-origin) of the day we want.
+        */
+        value += d * SECSPERDAY;
+        break;
+    }
+
+    /*
+    ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
+    ** question.  To get the Epoch-relative time of the specified local
+    ** time on that day, add the transition time and the current offset
+    ** from UTC.
+    */
+    return value + rulep->r_time + offset;
+}
+
+static void generate_transitions(sp, start, end)
+     register struct state * ZCONST sp;
+     ZCONST struct rule * ZCONST start;
+     ZCONST struct rule * ZCONST end;
+{
+    register int             year;
+    register time_t          janfirst;
+    time_t                   starttime;
+    time_t                   endtime;
+    long                     stdoffset = -sp->ttis[0].tt_gmtoff;
+    long                     dstoffset = -sp->ttis[1].tt_gmtoff;
+    register time_t *        atp;
+    register unsigned char * typep;
+
+    /*
+    ** Two transitions per year, from EPOCH_YEAR to LAST_GOOD_YEAR.
+    */
+    sp->timecnt = 2 * (LAST_GOOD_YEAR - EPOCH_YEAR + 1);
+    atp = sp->ats;
+    typep = sp->types;
+    janfirst = 0;
+    for (year = EPOCH_YEAR; year <= LAST_GOOD_YEAR; ++year) {
+        starttime = transtime(janfirst, year, start, stdoffset);
+        endtime = transtime(janfirst, year, end, dstoffset);
+        if (starttime > endtime) {
+            *atp++ = endtime;
+            *typep++ = 0;   /* DST ends */
+            *atp++ = starttime;
+            *typep++ = 1;   /* DST begins */
+        } else {
+            *atp++ = starttime;
+            *typep++ = 1;   /* DST begins */
+            *atp++ = endtime;
+            *typep++ = 0;   /* DST ends */
+        }
+        janfirst += year_lengths[leap(year)] * SECSPERDAY;
+    }
+}
+
+static ZCONST char *getzname(strp)
+     ZCONST char *strp;
+{
+    register char   c;
+
+    while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
+        c != '+')
+            ++strp;
+    return strp;
+}
+
+static ZCONST char *getnum(strp, nump, min, max)
+     ZCONST char *strp;
+     int * ZCONST nump;
+     ZCONST int min;
+     ZCONST int max;
+{
+    register char   c;
+    register int    num;
+
+    if (strp == NULL || !isdigit(c = *strp))
+        return NULL;
+    num = 0;
+    do {
+        num = num * 10 + (c - '0');
+        if (num > max)
+            return NULL;    /* illegal value */
+        c = *++strp;
+    } while (isdigit(c));
+    if (num < min)
+        return NULL;        /* illegal value */
+    *nump = num;
+    return strp;
+}
+
+static ZCONST char *getsecs(strp, secsp)
+     ZCONST char *strp;
+     long * ZCONST secsp;
+{
+    int num;
+
+    /*
+    ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
+    ** "M10.4.6/26", which does not conform to Posix,
+    ** but which specifies the equivalent of
+    ** ``02:00 on the first Sunday on or after 23 Oct''.
+    */
+    strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
+    if (strp == NULL)
+        return NULL;
+    *secsp = num * (long) SECSPERHOUR;
+    if (*strp == ':') {
+        ++strp;
+        strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
+        if (strp == NULL)
+            return NULL;
+        *secsp += num * SECSPERMIN;
+        if (*strp == ':') {
+            ++strp;
+            /* `SECSPERMIN' allows for leap seconds.  */
+            strp = getnum(strp, &num, 0, SECSPERMIN);
+            if (strp == NULL)
+                return NULL;
+            *secsp += num;
+        }
+    }
+    return strp;
+}
+
+static ZCONST char *getoffset(strp, offsetp)
+     ZCONST char *strp;
+     long * ZCONST offsetp;
+{
+    register int    neg = 0;
+
+    if (*strp == '-') {
+        neg = 1;
+        ++strp;
+    } else if (*strp == '+')
+        ++strp;
+    strp = getsecs(strp, offsetp);
+    if (strp == NULL)
+        return NULL;        /* illegal time */
+    if (neg)
+        *offsetp = -*offsetp;
+    return strp;
+}
+
+static ZCONST char *getrule(strp, rulep)
+     ZCONST char *strp;
+     struct rule * ZCONST rulep;
+{
+    if (*strp == 'J') {
+        /*
+        ** Julian day.
+        */
+        rulep->r_type = JULIAN_DAY;
+        ++strp;
+        strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
+    } else if (*strp == 'M') {
+        /*
+        ** Month, week, day.
+        */
+        rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
+        ++strp;
+        strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
+        if (strp == NULL)
+            return NULL;
+        if (*strp++ != '.')
+            return NULL;
+        strp = getnum(strp, &rulep->r_week, 1, 5);
+        if (strp == NULL)
+            return NULL;
+        if (*strp++ != '.')
+            return NULL;
+        strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
+    } else if (isdigit(*strp)) {
+        /*
+        ** Day of year.
+        */
+        rulep->r_type = DAY_OF_YEAR;
+        strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
+    } else  return NULL;        /* invalid format */
+    if (strp == NULL)
+        return NULL;
+    if (*strp == '/') {
+        /*
+        ** Time specified.
+        */
+        ++strp;
+        strp = getsecs(strp, &rulep->r_time);
+    } else
+        rulep->r_time = 2 * SECSPERHOUR;    /* default = 2:00:00 */
+    return strp;
+}
+
+static int Parse_TZ(name, sp)
+     ZCONST char *name;
+     register struct state * ZCONST sp;
+{
+    ZCONST char *            stdname;
+    ZCONST char *            dstname;
+    size_t                   stdlen;
+    size_t                   dstlen;
+    long                     stdoffset;
+    long                     dstoffset;
+    register char *          cp;
+
+    dstname = NULL;
+    stdname = name;
+    name = getzname(name);
+    stdlen = name - stdname;
+    if (stdlen < 3)
+        return -1;
+    if (*name == '\0')
+        return -1;
+    name = getoffset(name, &stdoffset);
+    if (name == NULL)
+        return -1;
+    if (*name != '\0') {
+        dstname = name;
+        name = getzname(name);
+        dstlen = name - dstname;    /* length of DST zone name */
+        if (dstlen < 3)
+            return -1;
+        if (*name != '\0' && *name != ',' && *name != ';') {
+            name = getoffset(name, &dstoffset);
+            if (name == NULL)
+                return -1;
+        } else
+            dstoffset = stdoffset - SECSPERHOUR;
+        if (*name == '\0')
+            name = TZDEFRULESTRING;
+        if (*name == ',' || *name == ';') {
+            struct rule     start;
+            struct rule     end;
+
+            ++name;
+            if ((name = getrule(name, &start)) == NULL)
+                return -1;
+            if (*name++ != ',')
+                return -1;
+            if ((name = getrule(name, &end)) == NULL)
+                return -1;
+            if (*name != '\0')
+                return -1;
+            sp->typecnt = 2;    /* standard time and DST */
+            sp->ttis[0].tt_gmtoff = -stdoffset;
+            sp->ttis[0].tt_isdst = 0;
+            sp->ttis[0].tt_abbrind = 0;
+            sp->ttis[1].tt_gmtoff = -dstoffset;
+            sp->ttis[1].tt_isdst = 1;
+            sp->ttis[1].tt_abbrind = stdlen + 1;
+            generate_transitions(sp, &start, &end);
+        }
+    } else {
+        dstlen = 0;
+        sp->typecnt = 1;        /* only standard time */
+        sp->timecnt = 0;
+        sp->ttis[0].tt_gmtoff = -stdoffset;
+        sp->ttis[0].tt_isdst = 0;
+        sp->ttis[0].tt_abbrind = 0;
+    }
+    sp->charcnt = stdlen + 1;
+    if (dstlen != 0)
+        sp->charcnt += dstlen + 1;
+    if ((size_t) sp->charcnt > sizeof(sp->chars))
+        return -1;
+    cp = sp->chars;
+    (void) strncpy(cp, stdname, stdlen);
+    cp += stdlen;
+    *cp++ = '\0';
+    if (dstlen != 0) {
+        (void) strncpy(cp, dstname, dstlen);
+        *(cp + dstlen) = '\0';
+    }
+    return 0;
+}
+
+void tzset()
+{
+    char *TZstring;
+    int dstfirst;
+    static char *old_TZstring = NULL;
+
+    TZstring = getenv("TZ");    /* read TZ envvar */
+    if (old_TZstring && TZstring && !strcmp(old_TZstring, TZstring))
+        /* do not repeatedly parse an unchanged TZ specification */
+        return;
+    if ((TZstring && TZstring[0] && Parse_TZ(TZstring, &statism) == 0)
+                || IZTZ_GETLOCALETZINFO(&statism, generate_transitions)
+                || Parse_TZ(gmt, &statism) == 0) {
+        daylight  = statism.typecnt > 1;
+        dstfirst  = daylight && statism.ttis[0].tt_isdst && !statism.ttis[1].tt_isdst;
+        timezone  = -statism.ttis[dstfirst].tt_gmtoff;
+        tzname[0] = statism.chars + statism.ttis[dstfirst].tt_abbrind;
+        tzname[1] = statism.chars + statism.ttis[!dstfirst].tt_abbrind;
+        real_timezone_is_set = TRUE;
+        if (TZstring) {
+            if (old_TZstring)
+                old_TZstring = realloc(old_TZstring, strlen(TZstring) + 1);
+            else
+                old_TZstring = malloc(strlen(TZstring) + 1);
+            if (old_TZstring)
+                strcpy(old_TZstring, TZstring);
+        }
+    } else {
+        timezone = 0;   /* default is GMT0 which means no offsets */
+        daylight = 0;   /* from local system time                 */
+        real_timezone_is_set = FALSE;
+        if (old_TZstring) {
+            free(old_TZstring);
+            old_TZstring = NULL;
+        }
+    }
+#ifdef IZTZ_SETLOCALTZINFO
+    /* Some SAS/C library functions, e.g. stat(), call library       */
+    /* __tzset() themselves. So envvar TZ *must* exist in order to   */
+    /* to get the right offset from GMT.  XXX  TRY HARD to fix this! */
+    set_TZ(timezone, daylight);
+#endif /* IZTZ_SETLOCALTZINFO */
+}
+
+/* XXX  Does this also help SAS/C library work? */
+void __tzset()
+{
+    if (!real_timezone_is_set) tzset();
+}
+
+static struct tm _tmbuf;
+
+struct tm *gmtime(when)
+     ZCONST time_t *when;
+{
+    long days = *when / SECSPERDAY;
+    long secs = *when % SECSPERDAY;
+    int isleap;
+
+    memset(&_tmbuf, 0, sizeof(_tmbuf));   /* get any nonstandard fields */
+    _tmbuf.tm_wday = (days + EPOCH_WDAY) % 7;
+    _tmbuf.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
+    isleap = leap(_tmbuf.tm_year + TM_YEAR_BASE);
+    while (days >= year_lengths[isleap]) {
+        days -= year_lengths[isleap];
+        _tmbuf.tm_year++;
+        isleap = leap(_tmbuf.tm_year + TM_YEAR_BASE);
+    }
+    _tmbuf.tm_mon = 0;
+    _tmbuf.tm_yday = days;
+    while (days >= mon_lengths[isleap][_tmbuf.tm_mon])
+        days -= mon_lengths[isleap][_tmbuf.tm_mon++];
+    _tmbuf.tm_mday = days + 1;
+    _tmbuf.tm_isdst = 0;
+    _tmbuf.tm_sec = secs % SECSPERMIN;
+    _tmbuf.tm_min = (secs / SECSPERMIN) % SECSPERMIN;
+    _tmbuf.tm_hour = secs / SECSPERHOUR;
+    return &_tmbuf;
+}
+
+struct tm *localtime(when)
+     ZCONST time_t *when;
+{
+    time_t     localwhen = *when;
+    int        timetype;
+    struct tm *ret;
+
+    __tzset();
+    if (statism.timecnt == 0 || localwhen < statism.ats[0])
+        timetype = statism.ttis[0].tt_isdst && statism.typecnt > 1 &&
+                   !statism.ttis[1].tt_isdst;
+    else {
+        for (timetype = 1; timetype < statism.timecnt; ++timetype)
+            if (localwhen < statism.ats[timetype])
+                break;
+        timetype = statism.types[timetype - 1];
+    }
+    localwhen += statism.ttis[timetype].tt_gmtoff;
+    ret = gmtime(&localwhen);
+    ret->tm_isdst = statism.ttis[timetype].tt_isdst;
+    return ret;
+}
+
+#ifdef NEED__ISINDST
+int _isindst(tb)
+    struct tm *tb;
+{
+    time_t     localt;          /* time_t equivalent of given tm struct */
+    time_t     univt;           /* assumed UTC value of given time */
+    long       tzoffset_adj;    /* timezone-adjustment `remainder' */
+    int        bailout_cnt;     /* counter of tries for tz correction */
+    int        timetype;
+
+    __tzset();
+
+    /* when DST is unsupported in current timezone, DST is always off */
+    if (statism.typecnt <= 1) return FALSE;
+
+    localt = mkgmtime(tb);
+    if (localt == (time_t)-1)
+        /* specified time is out-of-range, default to FALSE */
+        return FALSE;
+
+    univt = localt - statism.ttis[0].tt_gmtoff;
+    bailout_cnt = 3;
+    do {
+        if (statism.timecnt == 0 || univt < statism.ats[0])
+            timetype = statism.ttis[0].tt_isdst && statism.typecnt > 1 &&
+                       !statism.ttis[1].tt_isdst;
+        else {
+            for (timetype = 1; timetype < statism.timecnt; ++timetype)
+                if (univt < statism.ats[timetype])
+                    break;
+            timetype = statism.types[timetype - 1];
+        }
+        if ((tzoffset_adj = localt - univt - statism.ttis[timetype].tt_gmtoff)
+            == 0L)
+            break;
+        univt += tzoffset_adj;
+    } while (--bailout_cnt > 0);
+
+    /* return TRUE when DST is active at given time */
+    return (statism.ttis[timetype].tt_isdst);
+}
+#endif /* NEED__ISINDST */
+#endif /* !IZ_MKTIME_ONLY */
+
+/* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
+   of the local time and date in the exploded time structure `tm',
+   adjust out of range fields in `tm' and set `tm->tm_yday', `tm->tm_wday'.
+   If `tm->tm_isdst < 0' was passed to mktime(), the correct setting of
+   tm_isdst is determined and returned. Otherwise, mktime() assumes this
+   field as valid; its information is used when converting local time
+   to UTC.
+   Return -1 if time in `tm' cannot be represented as time_t value. */
+
+time_t mktime(tm)
+     struct tm *tm;
+{
+  struct tm *ltm;               /* Local time. */
+  time_t loctime;               /* The time_t value of local time. */
+  time_t then;                  /* The time to return. */
+  long tzoffset_adj;            /* timezone-adjustment `remainder' */
+  int bailout_cnt;              /* counter of tries for tz correction */
+  int save_isdst;               /* Copy of the tm->isdst input value */
+
+  save_isdst = tm->tm_isdst;
+  loctime = mkgmtime(tm);
+  if (loctime == -1) {
+    tm->tm_isdst = save_isdst;
+    return (time_t)-1;
+  }
+
+  /* Correct for the timezone and any daylight savings time.
+     The correction is verified and repeated when not correct, to
+     take into account the rare case that a change to or from daylight
+     savings time occurs between when it is the time in `tm' locally
+     and when it is that time in Greenwich. After the second correction,
+     the "timezone & daylight" offset should be correct in all cases. To
+     be sure, we allow a third try, but then the loop is stopped. */
+  bailout_cnt = 3;
+  then = loctime;
+  do {
+    ltm = localtime(&then);
+    if (ltm == (struct tm *)NULL ||
+        (tzoffset_adj = loctime - mkgmtime(ltm)) == 0L)
+      break;
+    then += tzoffset_adj;
+  } while (--bailout_cnt > 0);
+
+  if (ltm == (struct tm *)NULL || tzoffset_adj != 0L) {
+    /* Signal failure if timezone adjustment did not converge. */
+    tm->tm_isdst = save_isdst;
+    return (time_t)-1;
+  }
+
+  if (save_isdst >= 0) {
+    if (ltm->tm_isdst  && !save_isdst)
+    {
+      if (then + 3600 < then)
+        then = (time_t)-1;
+      else
+        then += 3600;
+    }
+    else if (!ltm->tm_isdst && save_isdst)
+    {
+      if (then - 3600 > then)
+        then = (time_t)-1;
+      else
+        then -= 3600;
+    }
+    ltm->tm_isdst = save_isdst;
+  }
+
+  if (tm != ltm)  /* `tm' may already point to localtime's internal storage */
+    *tm = *ltm;
+
+  return then;
+}
+
+
+#ifndef NO_TIME_T_MAX
+   /* Provide default values for the upper limit of the time_t range.
+      These are the result of the decomposition into a `struct tm' for
+      the time value 0xFFFFFFFEL ( = (time_t)-2 ).
+      Note: `(time_t)-1' is reserved for "invalid time"!  */
+#  ifndef TM_YEAR_MAX
+#    define TM_YEAR_MAX         2106
+#  endif
+#  ifndef TM_MON_MAX
+#    define TM_MON_MAX          1       /* February */
+#  endif
+#  ifndef TM_MDAY_MAX
+#    define TM_MDAY_MAX         7
+#  endif
+#  ifndef TM_HOUR_MAX
+#    define TM_HOUR_MAX         6
+#  endif
+#  ifndef TM_MIN_MAX
+#    define TM_MIN_MAX          28
+#  endif
+#  ifndef TM_SEC_MAX
+#    define TM_SEC_MAX          14
+#  endif
+#endif /* NO_TIME_T_MAX */
+
+/* Adjusts out-of-range values for `tm' field `tm_member'. */
+#define ADJUST_TM(tm_member, tm_carry, modulus) \
+  if ((tm_member) < 0) { \
+    tm_carry -= (1 - ((tm_member)+1) / (modulus)); \
+    tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \
+  } else if ((tm_member) >= (modulus)) { \
+    tm_carry += (tm_member) / (modulus); \
+    tm_member = (tm_member) % (modulus); \
+  }
+
+/* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
+   of the Greenwich Mean time and date in the exploded time structure `tm'.
+   This function does always put back normalized values into the `tm' struct,
+   parameter, including the calculated numbers for `tm->tm_yday',
+   `tm->tm_wday', and `tm->tm_isdst'.
+   Returns -1 if the time in the `tm' parameter cannot be represented
+   as valid `time_t' number. */
+
+time_t mkgmtime(tm)
+     struct tm *tm;
+{
+  int years, months, days, hours, minutes, seconds;
+
+  years = tm->tm_year + TM_YEAR_BASE;   /* year - 1900 -> year */
+  months = tm->tm_mon;                  /* 0..11 */
+  days = tm->tm_mday - 1;               /* 1..31 -> 0..30 */
+  hours = tm->tm_hour;                  /* 0..23 */
+  minutes = tm->tm_min;                 /* 0..59 */
+  seconds = tm->tm_sec;                 /* 0..61 in ANSI C. */
+
+  ADJUST_TM(seconds, minutes, 60)
+  ADJUST_TM(minutes, hours, 60)
+  ADJUST_TM(hours, days, 24)
+  ADJUST_TM(months, years, 12)
+  if (days < 0)
+    do {
+      if (--months < 0) {
+        --years;
+        months = 11;
+      }
+      days += monthlen(months, years);
+    } while (days < 0);
+  else
+    while (days >= monthlen(months, years)) {
+      days -= monthlen(months, years);
+      if (++months >= 12) {
+        ++years;
+        months = 0;
+      }
+    }
+
+  /* Restore adjusted values in tm structure */
+  tm->tm_year = years - TM_YEAR_BASE;
+  tm->tm_mon = months;
+  tm->tm_mday = days + 1;
+  tm->tm_hour = hours;
+  tm->tm_min = minutes;
+  tm->tm_sec = seconds;
+
+  /* Set `days' to the number of days into the year. */
+  days += YDAYS(months, years);
+  tm->tm_yday = days;
+
+  /* Now calculate `days' to the number of days since Jan 1, 1970. */
+  days = (unsigned)days + 365 * (unsigned)(years - EPOCH_YEAR) +
+         (unsigned)(nleap (years));
+  tm->tm_wday = ((unsigned)days + EPOCH_WDAY) % 7;
+  tm->tm_isdst = 0;
+
+  if (years < EPOCH_YEAR)
+    return (time_t)-1;
+
+#if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX))
+#if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX))
+  if (years > TM_YEAR_MAX ||
+      (years == TM_YEAR_MAX &&
+       (tm->tm_yday > (YDAYS(TM_MON_MAX, TM_YEAR_MAX) + (TM_MDAY_MAX - 1)) ||
+        (tm->tm_yday == (YDAYS(TM_MON_MAX, TM_YEAR_MAX) + (TM_MDAY_MAX - 1)) &&
+         (hours > TM_HOUR_MAX ||
+          (hours == TM_HOUR_MAX &&
+           (minutes > TM_MIN_MAX ||
+            (minutes == TM_MIN_MAX && seconds > TM_SEC_MAX) )))))))
+    return (time_t)-1;
+#endif
+#endif
+
+  return (time_t)(SECSPERDAY * (unsigned long)(unsigned)days +
+                  SECSPERHOUR * (unsigned long)hours +
+                  (unsigned long)(SECSPERMIN * minutes + seconds));
+}
+
+#endif /* __timezone_c */
diff --git a/timezone.h b/timezone.h
new file mode 100644 (file)
index 0000000..f4f46f2
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+  timezone.h - Zip 3
+
+  Copyright (c) 1990-2004 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2003-May-08 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __timezone_h
+#define __timezone_h
+
+#ifndef IZ_MKTIME_ONLY
+
+/* limits for our timezone info data:
+ * we support only basic standard and daylight time, with max 2 transitions
+ * per year, but for the maximum range of years a 32-bit second counter
+ * can cover (these are 136 years plus a bit more than one month)
+ */
+#define TZ_MAX_TIMES    272 /* (=2*(LastGoodYr + 1 - FirstGoodYr) */
+#define TZ_MAX_TYPES    2   /* We only support basic standard and daylight */
+#ifdef WIN32    /* Win32 tzinfo supplies at max (2 * 32) chars of tz names */
+#define TZ_MAX_CHARS    64  /* Maximum number of abbreviation characters */
+#else
+#define TZ_MAX_CHARS    50  /* Maximum number of abbreviation characters */
+#endif
+
+/* supported types of transition rules */
+#define JULIAN_DAY              0   /* Jn - Julian day */
+#define DAY_OF_YEAR             1   /* n - day of year */
+#define MONTH_NTH_DAY_OF_WEEK   2   /* Mm.n.d - month, week, day of week */
+
+
+struct ttinfo {
+    long            tt_gmtoff;  /* UTC offset in seconds */
+    int             tt_isdst;   /* used to set tm_isdst */
+    int             tt_abbrind; /* abbreviation list index */
+};
+
+struct state {
+    int             timecnt;
+    int             typecnt;
+    int             charcnt;
+    time_t          ats[TZ_MAX_TIMES];
+    unsigned char   types[TZ_MAX_TIMES];
+    struct ttinfo   ttis[TZ_MAX_TYPES];
+    char            chars[TZ_MAX_CHARS];
+};
+
+struct rule {
+    int             r_type;     /* type of rule--JULIAN_DAY etc */
+    int             r_day;      /* day number of rule */
+    int             r_week;     /* week number of rule */
+    int             r_mon;      /* month number of rule */
+    long            r_time;     /* transition time of rule */
+};
+
+extern int real_timezone_is_set;        /* set by tzset() */
+
+
+/* prototypes of functions not in time.h */
+
+void __tzset OF((void));
+
+#ifdef NEED__ISINDST
+int _isindst OF((struct tm *tb));
+#endif
+
+/* callback function to be supplied by the program that uses this library */
+int GetPlatformLocalTimezone OF((register struct state * ZCONST sp,
+        void (*fill_tzstate_from_rules)(struct state * ZCONST sp_res,
+                                        ZCONST struct rule * ZCONST start,
+                                        ZCONST struct rule * ZCONST end)));
+#ifdef IZTZ_SETLOCALTZINFO
+void set_TZ OF((long time_zone, int day_light));
+#endif
+
+#endif /* !IZ_MKTIME_ONLY */
+
+time_t mkgmtime OF((struct tm *tm));
+
+#endif
diff --git a/tops20/make.mic b/tops20/make.mic
new file mode 100644 (file)
index 0000000..5930847
--- /dev/null
@@ -0,0 +1,35 @@
+@te no pau e
+@cc -c -q zip
+@cc -c -q zipfil
+@cc -c -q zipup
+@cc -c -q fileio
+@cc -c -q util
+@cc -c -q crc32
+@cc -c -q global
+@cc -c -q deflat
+@cc -c -q trees
+@cc -c -q crypt
+@cc -c -q ttyio
+@cc -c -q tops20
+@cc -i -o zip zip.rel zipfil.rel zipup.rel fileio.rel util.rel crc32.rel global.rel deflat.rel trees.rel crypt.rel ttyio.rel tops20.rel
+@cc -c -q zipnot
+@rename zipfil.c zipfix.c
+@rename fileio.c filiox.c
+@rename util.c utilx.c
+@rename tops20.c tops2x.c
+@cc -c -q -DUTIL zipfix
+@cc -c -q -DUTIL filiox
+@cc -c -q -DUTIL utilx
+@cc -c -q -DUTIL tops2x
+@rename zipfix.c zipfil.c
+@rename filiox.c fileio.c
+@rename utilx.c util.c
+@rename tops2x.c tops20.c
+@cc -i -o zipnot zipnot.rel zipfix.rel filiox.rel utilx.rel global.rel tops2x.rel
+@reset
+@rename zipnot.exe zipnote.exe
+@cc -c -q zipspl
+@cc -i -o zipspl zipspl.rel zipfix.rel filiox.rel utilx.rel global.rel tops2x.rel
+@reset
+@rename zipspl.exe zipsplit.exe
+@kmic
diff --git a/tops20/osdep.h b/tops20/osdep.h
new file mode 100644 (file)
index 0000000..c750c2d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef TOPS20
+#define TOPS20
+#endif
+
+#define NO_PROTO
+#define NO_SYMLINKS
+#define NO_TERMIO
+#define DIRENT
+#define BIG_MEM
+#define REALLY_SHORT_SYMS
+#define window_size winsiz
+
+extern int isatty();
+
+#define FOPR "rb"
+#define FOPM "r+b"
+#define FOPW "w8"
+
+#define CBSZ 524288
+#define ZBSZ 524288
+
+#include <sys/types.h>
+#include <sys/stat.h>
diff --git a/tops20/rename.mic b/tops20/rename.mic
new file mode 100644 (file)
index 0000000..6a45d26
--- /dev/null
@@ -0,0 +1,6 @@
+@rename zipfile.c zipfil.c
+@rename globals.c global.c
+@rename deflate.c deflat.c
+@rename zipnote.c zipnot.c
+@rename zipsplit.c zipspl.c
+@kmic
diff --git a/tops20/tops20.c b/tops20/tops20.c
new file mode 100644 (file)
index 0000000..a2b63e7
--- /dev/null
@@ -0,0 +1,574 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#ifndef UTIL    /* the companion #endif is a bit of ways down ... */
+
+#include <time.h>
+
+#define PATH_START '<'
+#define PATH_END   '>'
+
+/* Extra malloc() space in names for cutpath() */
+#define PAD 5         /* may have to change .FOO] to ]FOO.DIR;1 */
+
+
+#define TRUE 1
+#define FALSE 0
+#define O_RDONLY (0)
+#define O_T20_WILD (1<<18)
+#include <monsym.h>    /* Get amazing monsym() macro */
+extern int jsys(), fstat();
+extern char *getcwd();
+extern int _gtjfn(), _rljfn();
+#define JSYS_CLASS    0070000000000
+#define FLD(val,mask) (((unsigned)(val)*((mask)&(-(mask))))&(mask))
+#define _DEFJS(name,class) (FLD(class, JSYS_CLASS) | (monsym(name)&0777777))
+#define JFNS  _DEFJS("JFNS%", 1)
+#define GNJFN _DEFJS("GNJFN%", 0)
+static int wfopen(), wfnext(), strlower(), strupper();
+static char *wfname();
+typedef struct {
+   int  wfjfn;
+   int  more;
+} DIR;
+
+/* Library functions not in (most) header files */
+
+extern int stat(), chmod(), toupper(), tolower();
+
+int utime OF((char *, ztimbuf *));
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Local functions */
+local char *readd OF((DIR *));
+
+
+local DIR *opendir(n)
+char *n;                /* directory name to open */
+/* Open the directory *n, returning a pointer to an allocated DIR, or
+   NULL if error. */
+{
+    DIR *d;             /* pointer to malloc'ed directory stream */
+    char    *c;                         /* scans TOPS20 path */
+    int     m;                          /* length of name */
+    char    *p;                         /* temp string */
+
+    if (((d = (DIR *)malloc(sizeof(DIR))) == NULL) ||
+        ((p = (char *)malloc((m = strlen(n)) + 4)) == NULL)) {
+            return NULL;
+    }
+
+/* Directory may be in form "<DIR.SUB1.SUB2>" or "<DIR.SUB1>SUB2.DIRECTORY".
+** If latter, convert to former. */
+
+    if ((m > 0)  &&  (*(c = strcpy(p,n) + m-1) != '>')) {
+        c -= 10;
+        *c-- = '\0';        /* terminate at "DIRECTORY.1" */
+        *c = '>';           /* "." --> ">" */
+        while ((c > p)  &&  (*--c != '>'));
+        *c = '.';           /* ">" --> "." */
+    }
+    strcat(p, "*.*");
+    if ((d->wfjfn = wfopen(p)) == 0) {
+        free((zvoid *)d);
+        free((zvoid *)p);
+        return NULL;
+    }
+    free((zvoid *)p);
+    d->more = TRUE;
+    return (d);
+}
+
+local char *readd(d)
+DIR *d;                 /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+   no more entries or an error occurs. */
+{
+  char    *p;
+  if ((d->more == FALSE) || ((p = wfname(d->wfjfn)) == NULL)) {
+      return NULL;
+  }
+  if (wfnext(d->wfjfn) == 0) {
+      d->more = FALSE;
+  }
+  return p;
+}
+
+
+local void closedir(d)
+DIR *d;                 /* directory stream to close */
+/* Close the directory stream */
+{
+  free((zvoid *)d);
+}
+
+/* Wildcard filename routines */
+
+/* WFOPEN - open wild card filename
+**      Returns wild JFN for filespec, 0 if failure.
+*/
+static int
+wfopen(name)
+char *name;
+{
+    return (_gtjfn(name, (O_RDONLY | O_T20_WILD)));
+}
+
+/* WFNAME - Return filename for wild JFN
+**      Returns pointer to dynamically allocated filename string
+*/
+static char *
+wfname(jfn)
+int jfn;
+{
+    char *fp, fname[200];
+    int ablock[5];
+
+    ablock[1] = (int) (fname - 1);
+    ablock[2] = jfn & 0777777;  /* jfn, no flags */
+    ablock[3] = 0111110000001;  /* DEV+DIR+NAME+TYPE+GEN, punctuate */
+    if (!jsys(JFNS, ablock))
+        return NULL;            /* something bad happened */
+    if ((fp = (char *)malloc(strlen(fname) + 1)) == NULL) {
+        return NULL;
+    }
+    strcpy(fp, fname);          /* copy the file name here */
+    return fp;
+}
+
+/* WFNEXT - Make wild JFN point to next real file
+**      Returns success or failure (not JFN)
+*/
+static int
+wfnext(jfn)
+int jfn;
+{
+    int ablock[5];
+
+    ablock[1] = jfn;            /* save jfn and flags */
+    return jsys(GNJFN, ablock);
+}
+
+
+static int
+strupper(s)     /* Returns s in uppercase */
+char *s;        /* String to be uppercased */
+{
+    char    *p;
+
+    p = s;
+    for (; *p; p++)
+        *p = toupper (*p);
+}
+
+static int
+strlower(s)     /* Returns s in lowercase. */
+char *s;        /* String to be lowercased */
+{
+    char    *p;
+
+    p = s;
+    for (; *p; p++)
+        *p = tolower (*p);
+}
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  DIR *d;               /* directory stream from opendir() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (LSSTAT(n, &s))
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    if (caseflag) {
+      p = malloc(strlen(n) + 1);
+      if (p != NULL)
+        strcpy(p, n);
+    } else
+      p = ex2in(n, 0, (int *)NULL);     /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  if ((s.st_mode & S_IFDIR) == 0)
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0, caseflag)) != ZE_OK)
+      return m;
+  } else {
+    if (dirnames && (m = newname(n, 1, caseflag)) != ZE_OK) {
+      return m;
+    }
+    /* recurse into directory */
+    if (recurse && (d = opendir(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if ((m = procname(e, caseflag)) != ZE_OK)     /* recurse on name */
+        {
+          closedir(d);
+          return m;
+        }
+      }
+      closedir(d);
+    }
+  } /* (s.st_mode & S_IFDIR) == 0) */
+  return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t;              /* shortened name */
+  int dosflag;
+
+  int jfn;
+  char *fp, fname[200];
+  int ablock[5];
+
+  jfn = _gtjfn(x, (O_RDONLY));
+  ablock[1] = (int) (fname - 1);
+  ablock[2] = jfn & 0777777;    /* jfn, no flags */
+  ablock[3] = 0111100000001;    /* DEV+DIR+NAME+TYPE, punctuate */
+  if (!jsys(JFNS, ablock)) {
+      _rljfn(jfn);
+      return NULL;              /* something bad happened */
+  }
+  _rljfn(jfn);
+  if ((fp = (char *)malloc(strlen(fname) + 1)) == NULL) {
+      return NULL;
+  }
+  strcpy(fp, fname);            /* copy the file name here */
+  x = fp;
+
+  dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+  /* Find starting point in name before doing malloc */
+  t = x;
+  if ((n = strrchr(t, ':')) != NULL)
+    t = n + 1;
+  if (*t == PATH_START && (n = strrchr(t, PATH_END)) != NULL)
+    if (*(++t) == '.')
+      /* path is relative to current directory, skip leading '.' */
+      t++;
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+  if (!pathput)
+    t = last(t, PATH_END);
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL)
+    return NULL;
+  strcpy(n, t);
+
+  if ((t = strrchr(n, PATH_END)) != NULL)
+  {
+    *t = '/';
+    while (--t > n)
+      if (*t == '.')
+        *t = '/';
+  }
+
+  /* Fix from Greg Roelofs: */
+  /* Get current working directory and strip from n (t now = n) */
+  {
+    char cwd[256], *p, *q;
+    int c;
+
+    if (getcwd(cwd, 256) && ((p = strchr(cwd, PATH_START)) != NULL))
+    {
+      if (*(++p) == '.')
+        p++;
+      if ((q = strrchr(p, PATH_END)) != NULL)
+      {
+        *q = '/';
+        while (--q > p)
+          if (*q == '.')
+            *q = '/';
+
+        /* strip bogus path parts from n */
+        if (strncmp(n, p, (c=strlen(p))) == 0)
+        {
+          q = n + c;
+          while (*t++ = *q++)
+            ;
+        }
+      }
+    }
+  }
+  strlower(n);
+
+  if (isdir)
+  {
+    if (strcmp((t=n+strlen(n)-6), ".dir;1"))
+      error("directory not version 1");
+    else
+      strcpy(t, "/");
+  }
+
+  if ((t = strrchr(n, '.')) != NULL)
+  {
+    if ( t[1] == '\0')             /* "filename." -> "filename" */
+      *t = '\0';
+  }
+
+  if (dosify)
+    msname(n);
+
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+  return n;
+}
+
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+  char *t;              /* scans name */
+
+  if ((t = strrchr(n, '/')) == NULL)
+  {
+    if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+      return NULL;
+    strcpy(x, n);
+  }
+  else
+  {
+    if ((x = malloc(strlen(n) + 3 + PAD)) == NULL)
+      return NULL;
+    x[0] = PATH_START;
+    x[1] = '.';
+    strcpy(x + 2, n);
+    *(t = x + 2 + (t - n)) = PATH_END;
+    while (--t > x)
+      if (*t == '/')
+        *t = '.';
+  }
+  strupper(x);
+
+  return x;
+}
+
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+  ztimbuf u;            /* argument for utime() */
+
+  /* Convert DOS time to time_t format in u */
+  u.actime = u.modtime = dos2unixtime(d);
+
+  /* Set updated and accessed times of f */
+  utime(f, &u);
+}
+
+ulg filetime(f, a, n, t)
+char *f;                /* name of file to get info on */
+ulg *a;                 /* return value: file attributes */
+long *n;                /* return value: file size */
+iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  /* converted from FNAMX to malloc - 11/8/04 EG */
+  char *name;
+  int len = strlen(f);
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+
+  if (strcmp(f, "-") == 0) {
+    if (fstat(fileno(stdin), &s) != 0) {
+      free(name);
+      error("fstat(stdin)");
+    }
+  } else if (LSSTAT(name, &s) != 0) {
+             /* Accept about any file kind including directories
+              * (stored with trailing / with -r option)
+              */
+    free(name);
+    return 0;
+  }
+  free(name);
+
+  if (a != NULL) {
+    *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+    if ((s.st_mode & S_IFDIR) != 0) {
+      *a |= MSDOS_DIR_ATTR;
+    }
+  }
+  if (n != NULL)
+    *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = s.st_ctime;
+  }
+
+  return unix2dostime(&s.st_mtime);
+}
+
+#include <monsym.h>   /* Get amazing monsym() macro */
+#define       _FBBYV  monsym(".FBBYV")
+#define         FBBSZ_S       -24     /* Obsolete, replace by FLDGET! */
+#define         FBBSZ_M       077     /* ditto */
+
+extern int _gtjfn(), _rljfn(), _gtfdb(), stat();
+
+int set_extra_field(z, z_utim)
+  struct zlist far *z;
+  iztimes *z_utim;
+  /* create extra field and change z->att if desired */
+{
+  int jfn;
+
+  translate_eol = 0;
+  jfn = _gtjfn(z->name, O_RDONLY);
+  z->att = (((_gtfdb (jfn, _FBBYV) << FBBSZ_S) & FBBSZ_M) != 8) ?
+           ASCII :BINARY;
+  _rljfn(jfn);
+
+#ifdef USE_EF_UT_TIME
+  if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
+    return ZE_MEM;
+
+  z->extra[0]  = 'U';
+  z->extra[1]  = 'T';
+  z->extra[2]  = EB_UT_LEN(1);          /* length of data part of e.f. */
+  z->extra[3]  = 0;
+  z->extra[4]  = EB_UT_FL_MTIME;
+  z->extra[5]  = (char)(z_utim->mtime);
+  z->extra[6]  = (char)(z_utim->mtime >> 8);
+  z->extra[7]  = (char)(z_utim->mtime >> 16);
+  z->extra[8]  = (char)(z_utim->mtime >> 24);
+
+  z->cext = z->ext = (EB_HEADSIZE+EB_UT_LEN(1));
+  z->cextra = z->extra;
+#endif /* USE_EF_UT_TIME */
+
+  return ZE_OK;
+}
+
+int deletedir(d)
+char *d;                /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+   Return the result of rmdir(), delete(), or system().
+   For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
+ */
+{
+    zipwarn("deletedir not implemented yet", "");
+    return 127;
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+void version_local()
+{
+    static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+#if 0
+    char buf[40];
+#endif
+
+    printf(CompiledWith,
+
+#ifdef __GNUC__
+      "gcc ", __VERSION__,
+#else
+#  if 0
+      "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
+#  else
+#  ifdef __COMPILER_KCC__
+      "KCC", "",
+#  else
+      "unknown compiler", "",
+#  endif
+#  endif
+#endif
+
+      "TOPS-20",
+
+#if defined(foobar) || defined(FOOBAR)
+      " (Foo BAR)",   /* OS version or hardware */
+#else
+      "",
+#endif /* Foo BAR */
+
+#ifdef __DATE__
+      " on ", __DATE__
+#else
+      "", ""
+#endif
+      );
+
+} /* end function version_local() */
diff --git a/tops20/zipup.h b/tops20/zipup.h
new file mode 100644 (file)
index 0000000..47ec563
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define O_RDONLY (0)
+#define O_UNCONVERTED     (0400) /* Forced NO conversion requested */
+#define fhow (O_RDONLY | O_UNCONVERTED)
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/trees.c b/trees.c
new file mode 100644 (file)
index 0000000..aefe639
--- /dev/null
+++ b/trees.c
@@ -0,0 +1,1474 @@
+/*
+  trees.h - Zip 3
+
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2005-Feb-10 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  trees.c by Jean-loup Gailly
+ *
+ *  This is a new version of im_ctree.c originally written by Richard B. Wales
+ *  for the defunct implosion method.
+ *  The low level bit string handling routines from bits.c (originally
+ *  im_bits.c written by Richard B. Wales) have been merged into this version
+ *  of trees.c.
+ *
+ *  PURPOSE
+ *
+ *      Encode various sets of source values using variable-length
+ *      binary code trees.
+ *      Output the resulting variable-length bit strings.
+ *      Compression can be done to a file or to memory.
+ *
+ *  DISCUSSION
+ *
+ *      The PKZIP "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in the ZIP file in a compressed form
+ *      which is itself a Huffman encoding of the lengths of
+ *      all the code strings (in ascending order by source values).
+ *      The actual code strings are reconstructed from the lengths in
+ *      the UNZIP process, as described in the "application note"
+ *      (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
+ *
+ *      The PKZIP "deflate" file format interprets compressed file data
+ *      as a sequence of bits.  Multi-bit strings in the file may cross
+ *      byte boundaries without restriction.
+ *      The first bit of each byte is the low-order bit.
+ *
+ *      The routines in this file allow a variable-length bit value to
+ *      be output right-to-left (useful for literal values). For
+ *      left-to-right output (useful for code strings from the tree routines),
+ *      the bits must have been reversed first with bi_reverse().
+ *
+ *      For in-memory compression, the compressed bit stream goes directly
+ *      into the requested output buffer. The buffer is limited to 64K on
+ *      16 bit machines; flushing of the output buffer during compression
+ *      process is not supported.
+ *      The input data is read in blocks by the (*read_buf)() function.
+ *
+ *      For more details about input to and output from the deflation routines,
+ *      see the actual input functions for (*read_buf)(), flush_outbuf(), and
+ *      the filecompress() resp. memcompress() wrapper functions which handle
+ *      the I/O setup.
+ *
+ *  REFERENCES
+ *
+ *      Lynch, Thomas J.
+ *          Data Compression:  Techniques and Applications, pp. 53-55.
+ *          Lifetime Learning Publications, 1985.  ISBN 0-534-03418-7.
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ *
+ *  INTERFACE
+ *
+ *      void ct_init (ush *attr, int *method)
+ *          Allocate the match buffer, initialize the various tables and save
+ *          the location of the internal file attribute (ascii/binary) and
+ *          method (DEFLATE/STORE)
+ *
+ *      void ct_tally (int dist, int lc);
+ *          Save the match info and tally the frequency counts.
+ *
+ *      uzoff_t flush_block (char *buf, ulg stored_len, int eof)
+ *          Determine the best encoding for the current block: dynamic trees,
+ *          static trees or store, and output the encoded block to the zip
+ *          file. Returns the total compressed length for the file so far.
+ *
+ *      void bi_init (char *tgt_buf, unsigned tgt_size, int flsh_allowed)
+ *          Initialize the bit string routines.
+ *
+ *    Most of the bit string output functions are only used internally
+ *    in this source file, they are normally declared as "local" routines:
+ *
+ *      local void send_bits (int value, int length)
+ *          Write out a bit string, taking the source bits right to
+ *          left.
+ *
+ *      local unsigned bi_reverse (unsigned code, int len)
+ *          Reverse the bits of a bit string, taking the source bits left to
+ *          right and emitting them right to left.
+ *
+ *      local void bi_windup (void)
+ *          Write out any remaining bits in an incomplete byte.
+ *
+ *      local void copy_block(char *buf, unsigned len, int header)
+ *          Copy a stored block to the zip file, storing first the length and
+ *          its one's complement if requested.
+ *
+ *    All output that exceeds the bitstring output buffer size (as initialized
+ *    by bi_init() is fed through an externally provided transfer routine
+ *    which flushes the bitstring output buffer on request and resets the
+ *    buffer fill counter:
+ *
+ *      extern void flush_outbuf(char *o_buf, unsigned *o_idx);
+ *
+ */
+#define __TREES_C
+
+/* Put zip.h first as when using 64-bit file environment in unix ctype.h
+   defines off_t and then while other files are using an 8-byte off_t this
+   file gets a 4-byte off_t.  Once zip.h sets the large file defines can
+   then include ctype.h and get 8-byte off_t.  8/14/04 EG */
+#include "zip.h"
+#include <ctype.h>
+
+#ifndef USE_ZLIB
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+
+local int near extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local int near extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local int near extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#ifndef LIT_BUFSIZE
+#  ifdef SMALL_MEM
+#    define LIT_BUFSIZE  0x2000
+#  else
+#  ifdef MEDIUM_MEM
+#    define LIT_BUFSIZE  0x4000
+#  else
+#    define LIT_BUFSIZE  0x8000
+#  endif
+#  endif
+#endif
+#define DIST_BUFSIZE  LIT_BUFSIZE
+/* Sizes of match buffers for literals/lengths and distances.  There are
+ * 4 reasons for limiting LIT_BUFSIZE to 64K:
+ *   - frequencies can be kept in 16 bit counters
+ *   - if compression is not successful for the first block, all input data is
+ *     still in the window so we can still emit a stored block even when input
+ *     comes from standard input.  (This can also be done for all blocks if
+ *     LIT_BUFSIZE is not greater than 32K.)
+ *   - if compression is not successful for a file smaller than 64K, we can
+ *     even emit a stored file instead of a stored block (saving 5 bytes).
+ *   - creating new Huffman trees less frequently may not provide fast
+ *     adaptation to changes in the input data statistics. (Take for
+ *     example a binary file with poorly compressible code followed by
+ *     a highly compressible string table.) Smaller buffer sizes give
+ *     fast adaptation but have of course the overhead of transmitting trees
+ *     more frequently.
+ *   - I can't count above 4
+ * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
+ * memory at the expense of compression). Some optimizations would be possible
+ * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+/* ===========================================================================
+ * Local data
+ */
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+local ct_data near dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+local ct_data near dyn_dtree[2*D_CODES+1]; /* distance tree */
+
+local ct_data near static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see ct_init
+ * below).
+ */
+
+local ct_data near static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+local ct_data near bl_tree[2*BL_CODES+1];
+/* Huffman tree for the bit lengths */
+
+typedef struct tree_desc {
+    ct_data near *dyn_tree;      /* the dynamic tree */
+    ct_data near *static_tree;   /* corresponding static tree or NULL */
+    int     near *extra_bits;    /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+    int     max_code;            /* largest code with non zero frequency */
+} tree_desc;
+
+local tree_desc near l_desc =
+{dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0};
+
+local tree_desc near d_desc =
+{dyn_dtree, static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS, 0};
+
+local tree_desc near bl_desc =
+{bl_tree, NULL,       extra_blbits, 0,         BL_CODES, MAX_BL_BITS, 0};
+
+
+local ush near bl_count[MAX_BITS+1];
+/* number of codes at each bit length for an optimal tree */
+
+local uch near bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+local int near heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+local int heap_len;               /* number of elements in the heap */
+local int heap_max;               /* element of largest frequency */
+/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+local uch near depth[2*L_CODES+1];
+/* Depth of each subtree used as tie breaker for trees of equal frequency */
+
+local uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local uch dist_code[512];
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+local int near base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int near base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#ifndef DYN_ALLOC
+  local uch far l_buf[LIT_BUFSIZE];  /* buffer for literals/lengths */
+  local ush far d_buf[DIST_BUFSIZE]; /* buffer for distances */
+#else
+  local uch far *l_buf;
+  local ush far *d_buf;
+#endif
+
+local uch near flag_buf[(LIT_BUFSIZE/8)];
+/* flag_buf is a bit array distinguishing literals from lengths in
+ * l_buf, and thus indicating the presence or absence of a distance.
+ */
+
+local unsigned last_lit;    /* running index in l_buf */
+local unsigned last_dist;   /* running index in d_buf */
+local unsigned last_flags;  /* running index in flag_buf */
+local uch flags;            /* current flags not yet saved in flag_buf */
+local uch flag_bit;         /* current bit used in flags */
+/* bits are filled in flags starting at bit 0 (least significant).
+ * Note: these flags are overkill in the current code since we don't
+ * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+
+local ulg opt_len;        /* bit length of current block with optimal trees */
+local ulg static_len;     /* bit length of current block with static trees */
+
+/* zip64 support 08/29/2003 R.Nausedat */
+/* now all file sizes and offsets are zoff_t 7/24/04 EG */
+local uzoff_t cmpr_bytelen;     /* total byte length of compressed file */
+local ulg cmpr_len_bits;        /* number of bits past 'cmpr_bytelen' */
+
+#ifdef DEBUG
+local uzoff_t input_len;        /* total byte length of input file */
+/* input_len is for debugging only since we can get it by other means. */
+#endif
+
+local ush *file_type;       /* pointer to UNKNOWN, BINARY or ASCII */
+local int *file_method;     /* pointer to DEFLATE or STORE */
+
+/* ===========================================================================
+ * Local data used by the "bit string" routines.
+ */
+
+local int flush_flg;
+
+#if (!defined(ASMV) || !defined(RISCOS))
+local unsigned bi_buf;
+#else
+unsigned bi_buf;
+#endif
+/* Output buffer. bits are inserted starting at the bottom (least significant
+ * bits). The width of bi_buf must be at least 16 bits.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf may be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+#if (!defined(ASMV) || !defined(RISCOS))
+local int bi_valid;
+#else
+int bi_valid;
+#endif
+/* Number of valid bits in bi_buf.  All bits above the last valid bit
+ * are always zero.
+ */
+
+#if (!defined(ASMV) || !defined(RISCOS))
+local char *out_buf;
+#else
+char *out_buf;
+#endif
+/* Current output buffer. */
+
+#if (!defined(ASMV) || !defined(RISCOS))
+local unsigned out_offset;
+#else
+unsigned out_offset;
+#endif
+/* Current offset in output buffer.
+ * On 16 bit machines, the buffer is limited to 64K.
+ */
+
+#if !defined(ASMV) || !defined(RISCOS)
+local unsigned out_size;
+#else
+unsigned out_size;
+#endif
+/* Size of current output buffer */
+
+/* Output a 16 bit value to the bit stream, lower (oldest) byte first */
+#define PUTSHORT(w) \
+{ if (out_offset >= out_size-1) \
+    flush_outbuf(out_buf, &out_offset); \
+  out_buf[out_offset++] = (char) ((w) & 0xff); \
+  out_buf[out_offset++] = (char) ((ush)(w) >> 8); \
+}
+
+#define PUTBYTE(b) \
+{ if (out_offset >= out_size) \
+    flush_outbuf(out_buf, &out_offset); \
+  out_buf[out_offset++] = (char) (b); \
+}
+
+#ifdef DEBUG
+local uzoff_t bits_sent;   /* bit length of the compressed data */
+extern uzoff_t isize;      /* byte length of input file */
+#endif
+
+extern long block_start;       /* window offset of current block */
+extern unsigned near strstart; /* window offset of current string */
+
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void init_block     OF((void));
+local void pqdownheap     OF((ct_data near *tree, int k));
+local void gen_bitlen     OF((tree_desc near *desc));
+local void gen_codes      OF((ct_data near *tree, int max_code));
+local void build_tree     OF((tree_desc near *desc));
+local void scan_tree      OF((ct_data near *tree, int max_code));
+local void send_tree      OF((ct_data near *tree, int max_code));
+local int  build_bl_tree  OF((void));
+local void send_all_trees OF((int lcodes, int dcodes, int blcodes));
+local void compress_block OF((ct_data near *ltree, ct_data near *dtree));
+local void set_file_type  OF((void));
+#if (!defined(ASMV) || !defined(RISCOS))
+local void send_bits      OF((int value, int length));
+local unsigned bi_reverse OF((unsigned code, int len));
+#endif
+local void bi_windup      OF((void));
+local void copy_block     OF((char *buf, unsigned len, int header));
+
+
+#ifndef DEBUG
+#  define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+#  define send_code(c, tree) \
+     { if (verbose>1) fprintf(mesg,"\ncd %3d ",(c)); \
+       send_bits(tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+#define Max(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Allocate the match buffer, initialize the various tables and save the
+ * location of the internal file attribute (ascii/binary) and method
+ * (DEFLATE/STORE).
+ */
+void ct_init(attr, method)
+    ush  *attr;   /* pointer to internal file attribute */
+    int  *method; /* pointer to compression method */
+{
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+
+    file_type = attr;
+    file_method = method;
+    cmpr_len_bits = 0L;
+    cmpr_bytelen = (uzoff_t)0;
+#ifdef DEBUG
+    input_len = (uzoff_t)0;
+#endif
+
+    if (static_dtree[0].Len != 0) return; /* ct_init already called */
+
+#ifdef DYN_ALLOC
+    d_buf = (ush far *) zcalloc(DIST_BUFSIZE, sizeof(ush));
+    l_buf = (uch far *) zcalloc(LIT_BUFSIZE/2, 2);
+    /* Avoid using the value 64K on 16 bit machines */
+    if (l_buf == NULL || d_buf == NULL)
+        ziperr(ZE_MEM, "ct_init: out of memory");
+#endif
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            length_code[length++] = (uch)code;
+        }
+    }
+    Assert(length == 256, "ct_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert(dist == 256, "ct_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert(dist == 256, "ct_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data near *)static_ltree, L_CODES+1);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = (ush)bi_reverse(n, 5);
+    }
+
+    /* Initialize the first block of the first file: */
+    init_block();
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block()
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) bl_tree[n].Freq = 0;
+
+    dyn_ltree[END_BLOCK].Freq = 1;
+    opt_len = static_len = 0L;
+    last_lit = last_dist = last_flags = 0;
+    flags = 0; flag_bit = 1;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(tree, top) \
+{\
+    top = heap[SMALLEST]; \
+    heap[SMALLEST] = heap[heap_len--]; \
+    pqdownheap(tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(tree, k)
+    ct_data near *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = heap[k];
+    int j = k << 1;  /* left son of k */
+    int htemp;       /* required because of bug in SASC compiler */
+
+    while (j <= heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < heap_len && smaller(tree, heap[j+1], heap[j])) j++;
+
+        /* Exit if v is smaller than both sons */
+        htemp = heap[j];
+        if (smaller(tree, v, htemp)) break;
+
+        /* Exchange v with the smallest son */
+        heap[k] = htemp;
+        k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(desc)
+    tree_desc near *desc; /* the tree descriptor */
+{
+    ct_data near *tree  = desc->dyn_tree;
+    int near *extra     = desc->extra_bits;
+    int base            = desc->extra_base;
+    int max_code        = desc->max_code;
+    int max_length      = desc->max_length;
+    ct_data near *stree = desc->static_tree;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[heap[heap_max]].Len = 0; /* root of the heap */
+
+    for (h = heap_max+1; h < HEAP_SIZE; h++) {
+        n = heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        opt_len += (ulg)f * (bits + xbits);
+        if (stree) static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (bl_count[bits] == 0) bits--;
+        bl_count[bits]--;           /* move one leaf down the tree */
+        bl_count[bits+1] += (ush)2; /* move one overflow item as its brother */
+        bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = bl_count[bits];
+        while (n != 0) {
+            m = heap[--h];
+            if (m > max_code) continue;
+            if (tree[m].Len != (ush)bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                opt_len += ((long)bits-(long)tree[m].Len)*(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code)
+    ct_data near *tree;        /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (ush)((code + bl_count[bits-1]) << 1);
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert(code + bl_count[MAX_BITS]-1 == (1<< ((ush) MAX_BITS)) - 1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = (ush)bi_reverse(next_code[len]++, len);
+
+        Tracec(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(desc)
+    tree_desc near *desc; /* the tree descriptor */
+{
+    ct_data near *tree   = desc->dyn_tree;
+    ct_data near *stree  = desc->static_tree;
+    int elems            = desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node = elems;  /* next internal node of the tree */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    heap_len = 0, heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            heap[++heap_len] = max_code = n;
+            depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (heap_len < 2) {
+        int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0);
+        tree[new].Freq = 1;
+        depth[new] = 0;
+        opt_len--; if (stree) static_len -= stree[new].Len;
+        /* new is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = heap_len/2; n >= 1; n--) pqdownheap(tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    do {
+        pqremove(tree, n);   /* n = node of least frequency */
+        m = heap[SMALLEST];  /* m = node of next least frequency */
+
+        heap[--heap_max] = n; /* keep the nodes sorted by frequency */
+        heap[--heap_max] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = (ush)(tree[n].Freq + tree[m].Freq);
+        depth[node] = (uch) (Max(depth[n], depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == bl_tree) {
+            fprintf(mesg,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        heap[SMALLEST] = node++;
+        pqdownheap(tree, SMALLEST);
+
+    } while (heap_len >= 2);
+
+    heap[--heap_max] = heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen((tree_desc near *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data near *)tree, max_code);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree. Updates opt_len to take into account the repeat
+ * counts. (The contribution of the bit length codes will be added later
+ * during the construction of bl_tree.)
+ */
+local void scan_tree (tree, max_code)
+    ct_data near *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)-1; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            bl_tree[curlen].Freq += (ush)count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) bl_tree[curlen].Freq++;
+            bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            bl_tree[REPZ_3_10].Freq++;
+        } else {
+            bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (tree, max_code)
+    ct_data near *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(curlen, bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(curlen, bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(REP_3_6, bl_tree); send_bits(count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(REPZ_3_10, bl_tree); send_bits(count-3, 3);
+
+        } else {
+            send_code(REPZ_11_138, bl_tree); send_bits(count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree()
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree((ct_data near *)dyn_ltree, l_desc.max_code);
+    scan_tree((ct_data near *)dyn_dtree, d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree((tree_desc near *)(&bl_desc));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len, static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(lcodes, dcodes, blcodes)
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert(lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert(lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(lcodes-257, 5);
+    /* not +255 as stated in appnote.txt 1.93a or -256 in 2.04c */
+    send_bits(dcodes-1,   5);
+    send_bits(blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %s",
+     zip_fuzofft(bits_sent, NULL, NULL)));
+
+    send_tree((ct_data near *)dyn_ltree, lcodes-1); /* send the literal tree */
+    Tracev((stderr, "\nlit tree: sent %s",
+     zip_fuzofft(bits_sent, NULL, NULL)));
+
+    send_tree((ct_data near *)dyn_dtree, dcodes-1); /* send the distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld",
+     zip_fuzofft(bits_sent, NULL, NULL)));
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length (in bytes) for the file so far.
+ */
+/* zip64 support 08/29/2003 R.Nausedat */
+uzoff_t flush_block(buf, stored_len, eof)
+    char *buf;        /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    flag_buf[last_flags] = flags; /* Save the flags for the last 8 items */
+
+     /* Check if the file is ascii or binary */
+    if (*file_type == (ush)UNKNOWN) set_file_type();
+
+    /* Construct the literal and distance trees */
+    build_tree((tree_desc near *)(&l_desc));
+    Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len));
+
+    build_tree((tree_desc near *)(&d_desc));
+    Tracev((stderr, "\ndist data: dyn %ld, stat %ld", opt_len, static_len));
+    /* At this point, opt_len and static_len are the total bit lengths of
+     * the compressed block data, excluding the tree representations.
+     */
+
+    /* Build the bit length tree for the above two trees, and get the index
+     * in bl_order of the last bit length code to send.
+     */
+    max_blindex = build_bl_tree();
+
+    /* Determine the best encoding. Compute first the block length in bytes */
+    opt_lenb = (opt_len+3+7)>>3;
+    static_lenb = (static_len+3+7)>>3;
+#ifdef DEBUG
+    input_len += stored_len; /* for debugging only */
+#endif
+
+    Trace((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
+            opt_lenb, opt_len, static_lenb, static_len, stored_len,
+            last_lit, last_dist));
+
+    if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+#ifndef PGP /* PGP can't handle stored blocks */
+    /* If compression failed and this is the first and last block,
+     * the whole file is transformed into a stored file:
+     */
+#ifdef FORCE_METHOD
+    if (level == 1 && eof && file_method != NULL &&
+        cmpr_bytelen == (uzoff_t)0 && cmpr_len_bits == 0L
+       ) { /* force stored file */
+#else
+    if (stored_len <= opt_lenb && eof && file_method != NULL &&
+        cmpr_bytelen == (uzoff_t)0 && cmpr_len_bits == 0L &&
+        seekable() && !use_descriptors) {
+#endif
+        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+        if (buf == NULL) error ("block vanished");
+
+        copy_block(buf, (unsigned)stored_len, 0); /* without header */
+        cmpr_bytelen = stored_len;
+        *file_method = STORE;
+    } else
+#endif /* PGP */
+
+#ifdef FORCE_METHOD
+    if (level <= 2 && buf != (char*)NULL) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)NULL) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        send_bits((STORED_BLOCK<<1)+eof, 3);  /* send block type */
+        cmpr_bytelen += ((cmpr_len_bits + 3 + 7) >> 3) + stored_len + 4;
+        cmpr_len_bits = 0L;
+
+        copy_block(buf, (unsigned)stored_len, 1); /* with header */
+
+#ifdef FORCE_METHOD
+    } else if (level == 3) { /* force static trees */
+#else
+    } else if (static_lenb == opt_lenb) {
+#endif
+        send_bits((STATIC_TREES<<1)+eof, 3);
+        compress_block((ct_data near *)static_ltree, (ct_data near *)static_dtree);
+        cmpr_len_bits += 3 + static_len;
+        cmpr_bytelen += cmpr_len_bits >> 3;
+        cmpr_len_bits &= 7L;
+    } else {
+        send_bits((DYN_TREES<<1)+eof, 3);
+        send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1);
+        compress_block((ct_data near *)dyn_ltree, (ct_data near *)dyn_dtree);
+        cmpr_len_bits += 3 + opt_len;
+        cmpr_bytelen += cmpr_len_bits >> 3;
+        cmpr_len_bits &= 7L;
+    }
+    Assert(((cmpr_bytelen << 3) + cmpr_len_bits) == bits_sent,
+            "bad compressed size");
+    init_block();
+
+    if (eof) {
+#if defined(PGP) && !defined(MMAP)
+        /* Wipe out sensitive data for pgp */
+# ifdef DYN_ALLOC
+        extern uch *window;
+# else
+        extern uch window[];
+# endif
+        memset(window, 0, (unsigned)(2*WSIZE-1)); /* -1 needed if WSIZE=32K */
+#else /* !PGP */
+        Assert(input_len == isize, "bad input size");
+#endif
+        bi_windup();
+        cmpr_len_bits += 7;  /* align on byte boundary */
+    }
+    Tracev((stderr,"\ncomprlen %s(%s) ",
+     zip_fuzofft( cmpr_bytelen + (cmpr_len_bits>>3), NULL, NULL),
+     zip_fuzofft( (cmpr_bytelen << 3) + cmpr_len_bits - 7*eof, NULL, NULL)));
+    Trace((stderr, "\n"));
+
+    return cmpr_bytelen + (cmpr_len_bits >> 3);
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ct_tally (dist, lc)
+    int dist;  /* distance of matched string */
+    int lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    l_buf[last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        dyn_ltree[lc].Freq++;
+    } else {
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "ct_tally: bad match");
+
+        dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+        dyn_dtree[d_code(dist)].Freq++;
+
+        d_buf[last_dist++] = (ush)dist;
+        flags |= flag_bit;
+    }
+    flag_bit <<= 1;
+
+    /* Output the flags if they fill a byte: */
+    if ((last_lit & 7) == 0) {
+        flag_buf[last_flags++] = flags;
+        flags = 0, flag_bit = 1;
+    }
+    /* Try to guess if it is profitable to stop the current block here */
+    if (level > 2 && (last_lit & 0xfff) == 0) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)last_lit*8L;
+        ulg in_length = (ulg)strstart-block_start;
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)dyn_dtree[dcode].Freq*(5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Trace((stderr,"\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
+               last_lit, last_dist, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (last_dist < last_lit/2 && out_length < in_length/2) return 1;
+    }
+    return (last_lit == LIT_BUFSIZE-1 || last_dist == DIST_BUFSIZE);
+    /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(ltree, dtree)
+    ct_data near *ltree; /* literal tree */
+    ct_data near *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned dx = 0;    /* running index in d_buf */
+    unsigned fx = 0;    /* running index in flag_buf */
+    uch flag = 0;       /* current flags */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (last_lit != 0) do {
+        if ((lx & 7) == 0) flag = flag_buf[fx++];
+        lc = l_buf[lx++];
+        if ((flag & 1) == 0) {
+            send_code(lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = length_code[lc];
+            send_code(code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(lc, extra);        /* send the extra length bits */
+            }
+            dist = d_buf[dx++];
+            /* Here, dist is the match distance - 1 */
+            code = d_code(dist);
+            Assert(code < D_CODES, "bad d_code");
+
+            send_code(code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+        flag >>= 1;
+    } while (lx < last_lit);
+
+    send_code(END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Set the file type to TEXT (ASCII) or BINARY, using following algorithm:
+ * - TEXT, either ASCII or an ASCII-compatible extension such as ISO-8859,
+ *   UTF-8, etc., when the following two conditions are satisfied:
+ *    a) There are no non-portable control characters belonging to the
+ *       "black list" (0..6, 14..25, 28..31).
+ *    b) There is at least one printable character belonging to the
+ *       "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
+ * - BINARY otherwise.
+ *
+ * Note that the following partially-portable control characters form a
+ * "gray list" that is ignored in this detection algorithm:
+ * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
+ *
+ * Also note that, unlike in the previous 20% binary detection algorithm,
+ * any control characters in the black list will set the file type to
+ * BINARY.  If a text file contains a single accidental black character,
+ * the file will be flagged as BINARY in the archive.
+ *
+ * IN assertion: the fields freq of dyn_ltree are set.
+ */
+local void set_file_type()
+{
+    /* bit-mask of black-listed bytes
+     * bit is set if byte is black-listed
+     * set bits 0..6, 14..25, and 28..31
+     * 0xf3ffc07f = binary 11110011111111111100000001111111
+     */
+    unsigned long mask = 0xf3ffc07fL;
+    int n;
+
+    /* Check for non-textual ("black-listed") bytes. */
+    for (n = 0; n <= 31; n++, mask >>= 1)
+        if ((mask & 1) && (dyn_ltree[n].Freq != 0))
+        {
+            *file_type = BINARY;
+            return;
+        }
+
+    /* Check for textual ("white-listed") bytes. */
+    *file_type = ASCII;
+    if (dyn_ltree[9].Freq != 0 || dyn_ltree[10].Freq != 0
+            || dyn_ltree[13].Freq != 0)
+        return;
+    for (n = 32; n < LITERALS; n++)
+        if (dyn_ltree[n].Freq != 0)
+            return;
+
+    /* This deflate stream is either empty, or
+     * it has tolerated ("gray-listed") bytes only.
+     */
+    *file_type = BINARY;
+}
+
+
+/* ===========================================================================
+ * Initialize the bit string routines.
+ */
+void bi_init (tgt_buf, tgt_size, flsh_allowed)
+    char *tgt_buf;
+    unsigned tgt_size;
+    int flsh_allowed;
+{
+    out_buf = tgt_buf;
+    out_size = tgt_size;
+    out_offset = 0;
+    flush_flg = flsh_allowed;
+
+    bi_buf = 0;
+    bi_valid = 0;
+#ifdef DEBUG
+    bits_sent = (uzoff_t)0;
+#endif
+}
+
+#if (!defined(ASMV) || !defined(RISCOS))
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+local void send_bits(value, length)
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+#ifdef DEBUG
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    bits_sent += (uzoff_t)length;
+#endif
+    /* If not enough room in bi_buf, use (bi_valid) bits from bi_buf and
+     * (Buf_size - bi_valid) bits from value to flush the filled bi_buf,
+     * then fill in the rest of (value), leaving (length - (Buf_size-bi_valid))
+     * unused bits in bi_buf.
+     */
+    bi_buf |= (value << bi_valid);
+    bi_valid += length;
+    if (bi_valid > (int)Buf_size) {
+        PUTSHORT(bi_buf);
+        bi_valid -= Buf_size;
+        bi_buf = (unsigned)value >> (length - bi_valid);
+    }
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+    unsigned code; /* the value to invert */
+    int len;       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+#endif /* !ASMV || !RISCOS */
+
+/* ===========================================================================
+ * Write out any remaining bits in an incomplete byte.
+ */
+local void bi_windup()
+{
+    if (bi_valid > 8) {
+        PUTSHORT(bi_buf);
+    } else if (bi_valid > 0) {
+        PUTBYTE(bi_buf);
+    }
+    if (flush_flg) {
+        flush_outbuf(out_buf, &out_offset);
+    }
+    bi_buf = 0;
+    bi_valid = 0;
+#ifdef DEBUG
+    bits_sent = (bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block to the zip file, storing first the length and its
+ * one's complement if requested.
+ *
+ * Buffer Overwrite fix
+ *
+ * A buffer flush has been added to fix a bug when encrypting deflated files
+ * with embedded "copied blocks".  When encrypting, the flush_out() routine
+ * modifies its data buffer because encryption is done "in-place" in
+ * zfwrite(), whereas without encryption, the flush_out() data buffer is
+ * left unaltered.  This can be a problem as noted below by the submitter.
+ *
+ * "But an exception comes when a block of stored data (data that could not
+ * be compressed) is being encrypted. In this case, the data that is passed
+ * to zfwrite (and is therefore encrypted-in-place) is actually a block of
+ * data from within the sliding input window that is being managed by
+ * deflate.c.
+ *
+ * "Since part of the sliding input window has now been overwritten by
+ * encrypted (and essentially random) data, deflate.c's search for previous
+ * text that matches the current text will usually fail but on rare
+ * occasions will find a match with something in the encrypted data. This
+ * incorrect match then causes incorrect information to be placed in the
+ * ZIP file."
+ *
+ * The problem results in the zip file having bad data and so a bad CRC.
+ * This does not happen often and to recreate the problem a large file
+ * with non-compressable data is needed so that deflate chooses to store the
+ * data.  A test file of 400 MB seems large enough to recreate the problem
+ * using a command such as
+ *     zip -1 -e crcerror.zip testfile.dat
+ * maybe half the time.
+ *
+ * This problem has been fixed by copying the data into the deflate output
+ * buffer before calling flush_outbuf(), when encryption is enabled.
+ *
+ * Thanks to the nice people at WinZip for identifying the problem and
+ * passing it on.  Also see Changes.
+ *
+ * 2006-03-06 EG, CS
+ */
+local void copy_block(block, len, header)
+    char *block;  /* the input data */
+    unsigned len; /* its length */
+    int header;   /* true if block header must be written */
+{
+    bi_windup();              /* align on byte boundary */
+
+    if (header) {
+        PUTSHORT((ush)len);
+        PUTSHORT((ush)~len);
+#ifdef DEBUG
+        bits_sent += 2*16;
+#endif
+    }
+    if (flush_flg) {
+        flush_outbuf(out_buf, &out_offset);
+        if (key != (char *)NULL) {  /* key is the global password pointer */
+            /* Encryption modifies the data in the output buffer. But the
+             * copied input data must remain intact for further deflate
+             * string matching lookups.  Therefore, the input data is
+             * copied into the compression output buffer for flushing
+             * to the compressed/encrypted output stream.
+             */
+            while(len > 0) {
+                out_offset = (len < out_size ? len : out_size);
+                memcpy(out_buf, block, out_offset);
+                block += out_offset;
+                len -= out_offset;
+                flush_outbuf(out_buf, &out_offset);
+            }
+        } else {
+            /* Without encryption, the output routines do not touch the
+             * written data, so there is no need for an additional copy
+             * operation.
+             */
+            out_offset = len;
+            flush_outbuf(block, &out_offset);
+        }
+    } else if (out_offset + len > out_size) {
+        error("output buffer too small for in-memory compression");
+    } else {
+        memcpy(out_buf + out_offset, block, len);
+        out_offset += len;
+    }
+#ifdef DEBUG
+    bits_sent += (ulg)len<<3;
+#endif
+}
+
+#endif /* !USE_ZLIB */
diff --git a/ttyio.c b/ttyio.c
new file mode 100644 (file)
index 0000000..5899fdc
--- /dev/null
+++ b/ttyio.c
@@ -0,0 +1,702 @@
+/*
+  ttyio.c - Zip 3
+
+  Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2005-Feb-10 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+  ttyio.c
+
+  This file contains routines for doing console input/output, including code
+  for non-echoing input.  It is used by the encryption/decryption code but
+  does not contain any restricted code itself.  This file is shared between
+  Info-ZIP's Zip and UnZip.
+
+  Contains:  echo()         (VMS only)
+             Echon()        (Unix only)
+             Echoff()       (Unix only)
+             screensize()   (Unix only)
+             zgetch()       (Unix, VMS, and non-Unix/VMS versions)
+             getp()         ("PC," Unix/Atari/Be, VMS/VMCMS/MVS)
+
+  ---------------------------------------------------------------------------*/
+
+#define __TTYIO_C       /* identifies this source module */
+
+#include "zip.h"
+#include "crypt.h"
+
+#if (CRYPT || (defined(UNZIP) && !defined(FUNZIP)))
+/* Non-echo console/keyboard input is needed for (en/de)cryption's password
+ * entry, and for UnZip(SFX)'s MORE and Pause features.
+ * (The corresponding #endif is found at the end of this module.)
+ */
+
+#include "ttyio.h"
+
+#ifndef PUTC
+#  define PUTC putc
+#endif
+
+#ifdef ZIP
+#  ifdef GLOBAL          /* used in Amiga system headers, maybe others too */
+#    undef GLOBAL
+#  endif
+#  define GLOBAL(g) g
+#else
+#  define GLOBAL(g) G.g
+#endif
+
+#if (defined(__ATHEOS__) || defined(__BEOS__))  /* why yes, we do */
+#  define HAVE_TERMIOS_H
+#endif
+
+#ifdef _POSIX_VERSION
+#  ifndef USE_POSIX_TERMIOS
+#    define USE_POSIX_TERMIOS  /* use POSIX style termio (termios) */
+#  endif
+#  ifndef HAVE_TERMIOS_H
+#    define HAVE_TERMIOS_H     /* POSIX termios.h */
+#  endif
+#endif /* _POSIX_VERSION */
+
+#ifdef UNZIP            /* Zip handles this with the unix/configure script */
+#  ifndef _POSIX_VERSION
+#    if (defined(SYSV) || defined(CRAY)) &&  !defined(__MINT__)
+#      ifndef USE_SYSV_TERMIO
+#        define USE_SYSV_TERMIO
+#      endif
+#      ifdef COHERENT
+#        ifndef HAVE_TERMIO_H
+#          define HAVE_TERMIO_H
+#        endif
+#        ifdef HAVE_SYS_TERMIO_H
+#          undef HAVE_SYS_TERMIO_H
+#        endif
+#      else /* !COHERENT */
+#        ifdef HAVE_TERMIO_H
+#          undef HAVE_TERMIO_H
+#        endif
+#        ifndef HAVE_SYS_TERMIO_H
+#           define HAVE_SYS_TERMIO_H
+#        endif
+#      endif /* ?COHERENT */
+#    endif /* (SYSV || CRAY) && !__MINT__ */
+#  endif /* !_POSIX_VERSION */
+#  if !(defined(BSD4_4) || defined(SYSV) || defined(__convexc__))
+#    ifndef NO_FCNTL_H
+#      define NO_FCNTL_H
+#    endif
+#  endif /* !(BSD4_4 || SYSV || __convexc__) */
+#endif /* UNZIP */
+
+#ifdef HAVE_TERMIOS_H
+#  ifndef USE_POSIX_TERMIOS
+#    define USE_POSIX_TERMIOS
+#  endif
+#endif
+
+#if (defined(HAVE_TERMIO_H) || defined(HAVE_SYS_TERMIO_H))
+#  ifndef USE_SYSV_TERMIO
+#    define USE_SYSV_TERMIO
+#  endif
+#endif
+
+#if (defined(UNZIP) && !defined(FUNZIP) && defined(UNIX) && defined(MORE))
+#  include <sys/ioctl.h>
+#  define GOT_IOCTL_H
+   /* int ioctl OF((int, int, zvoid *));   GRR: may need for some systems */
+#endif
+
+#ifndef HAVE_WORKING_GETCH
+   /* include system support for switching of console echo */
+#  ifdef VMS
+#    include <descrip.h>
+#    include <iodef.h>
+#    include <ttdef.h>
+#    include <starlet.h>
+#    include <ssdef.h>
+#  else /* !VMS */
+#    ifdef HAVE_TERMIOS_H
+#      include <termios.h>
+#      define sgttyb termios
+#      define sg_flags c_lflag
+#      define GTTY(f, s) tcgetattr(f, (zvoid *) s)
+#      define STTY(f, s) tcsetattr(f, TCSAFLUSH, (zvoid *) s)
+#    else /* !HAVE_TERMIOS_H */
+#      ifdef USE_SYSV_TERMIO           /* Amdahl, Cray, all SysV? */
+#        ifdef HAVE_TERMIO_H
+#          include <termio.h>
+#        endif
+#        ifdef HAVE_SYS_TERMIO_H
+#          include <sys/termio.h>
+#        endif
+#        ifdef NEED_PTEM
+#          include <sys/stream.h>
+#          include <sys/ptem.h>
+#        endif
+#        define sgttyb termio
+#        define sg_flags c_lflag
+#        define GTTY(f,s) ioctl(f,TCGETA,(zvoid *)s)
+#        define STTY(f,s) ioctl(f,TCSETAW,(zvoid *)s)
+#      else /* !USE_SYSV_TERMIO */
+#        ifndef CMS_MVS
+#          if (!defined(MINIX) && !defined(GOT_IOCTL_H))
+#            include <sys/ioctl.h>
+#          endif
+#          include <sgtty.h>
+#          define GTTY gtty
+#          define STTY stty
+#          ifdef UNZIP
+             /*
+              * XXX : Are these declarations needed at all ????
+              */
+             /*
+              * GRR: let's find out...   Hmmm, appears not...
+             int gtty OF((int, struct sgttyb *));
+             int stty OF((int, struct sgttyb *));
+              */
+#          endif
+#        endif /* !CMS_MVS */
+#      endif /* ?USE_SYSV_TERMIO */
+#    endif /* ?HAVE_TERMIOS_H */
+#    ifndef NO_FCNTL_H
+#      ifndef UNZIP
+#        include <fcntl.h>
+#      endif
+#    else
+       char *ttyname OF((int));
+#    endif
+#  endif /* ?VMS */
+#endif /* !HAVE_WORKING_GETCH */
+
+
+
+#ifndef HAVE_WORKING_GETCH
+#ifdef VMS
+
+static struct dsc$descriptor_s DevDesc =
+        {11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND"};
+     /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */
+
+/*
+ * Turn keyboard echoing on or off (VMS).  Loosely based on VMSmunch.c
+ * and hence on Joe Meadows' file.c code.
+ */
+int echo(opt)
+    int opt;
+{
+    /*
+     * For VMS v5.x:
+     *   IO$_SENSEMODE/SETMODE info:  Programming, Vol. 7A, System Programming,
+     *     I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6
+     *   sys$assign(), sys$qio() info:  Programming, Vol. 4B, System Services,
+     *     System Services Reference Manual, pp. sys-23, sys-379
+     *   fixed-length descriptor info:  Programming, Vol. 3, System Services,
+     *     Intro to System Routines, sec. 2.9.2
+     * Greg Roelofs, 15 Aug 91
+     */
+
+    short           DevChan, iosb[4];
+    long            status;
+    unsigned long   ttmode[2];  /* space for 8 bytes */
+
+
+    /* assign a channel to standard input */
+    status = sys$assign(&DevDesc, &DevChan, 0, 0);
+    if (!(status & 1))
+        return status;
+
+    /* use sys$qio and the IO$_SENSEMODE function to determine the current
+     * tty status (for password reading, could use IO$_READVBLK function
+     * instead, but echo on/off will be more general)
+     */
+    status = sys$qiow(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0,
+                     ttmode, 8, 0, 0, 0, 0);
+    if (!(status & 1))
+        return status;
+    status = iosb[0];
+    if (!(status & 1))
+        return status;
+
+    /* modify mode buffer to be either NOECHO or ECHO
+     * (depending on function argument opt)
+     */
+    if (opt == 0)   /* off */
+        ttmode[1] |= TT$M_NOECHO;                       /* set NOECHO bit */
+    else
+        ttmode[1] &= ~((unsigned long) TT$M_NOECHO);    /* clear NOECHO bit */
+
+    /* use the IO$_SETMODE function to change the tty status */
+    status = sys$qiow(0, DevChan, IO$_SETMODE, &iosb, 0, 0,
+                     ttmode, 8, 0, 0, 0, 0);
+    if (!(status & 1))
+        return status;
+    status = iosb[0];
+    if (!(status & 1))
+        return status;
+
+    /* deassign the sys$input channel by way of clean-up */
+    status = sys$dassgn(DevChan);
+    if (!(status & 1))
+        return status;
+
+    return SS$_NORMAL;   /* we be happy */
+
+} /* end function echo() */
+
+
+/*
+ * Read a single character from keyboard in non-echoing mode (VMS).
+ * (returns EOF in case of errors)
+ */
+int tt_getch()
+{
+    short           DevChan, iosb[4];
+    long            status;
+    char            kbbuf[16];  /* input buffer with - some - excess length */
+
+    /* assign a channel to standard input */
+    status = sys$assign(&DevDesc, &DevChan, 0, 0);
+    if (!(status & 1))
+        return EOF;
+
+    /* read a single character from SYS$COMMAND (no-echo) and
+     * wait for completion
+     */
+    status = sys$qiow(0,DevChan,
+                      IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
+                      &iosb, 0, 0,
+                      &kbbuf, 1, 0, 0, 0, 0);
+    if ((status&1) == 1)
+        status = iosb[0];
+
+    /* deassign the sys$input channel by way of clean-up
+     * (for this step, we do not need to check the completion status)
+     */
+    sys$dassgn(DevChan);
+
+    /* return the first char read, or EOF in case the read request failed */
+    return (int)(((status&1) == 1) ? (uch)kbbuf[0] : EOF);
+
+} /* end function tt_getch() */
+
+
+#else /* !VMS:  basically Unix */
+
+
+/* For VM/CMS and MVS, non-echo terminal input is not (yet?) supported. */
+#ifndef CMS_MVS
+
+#ifdef ZIP                      /* moved to globals.h for UnZip */
+   static int echofd=(-1);      /* file descriptor whose echo is off */
+#endif
+
+/*
+ * Turn echo off for file descriptor f.  Assumes that f is a tty device.
+ */
+void Echoff(__G__ f)
+    __GDEF
+    int f;                    /* file descriptor for which to turn echo off */
+{
+    struct sgttyb sg;         /* tty device structure */
+
+    GLOBAL(echofd) = f;
+    GTTY(f, &sg);             /* get settings */
+    sg.sg_flags &= ~ECHO;     /* turn echo off */
+    STTY(f, &sg);
+}
+
+/*
+ * Turn echo back on for file descriptor echofd.
+ */
+void Echon(__G)
+    __GDEF
+{
+    struct sgttyb sg;         /* tty device structure */
+
+    if (GLOBAL(echofd) != -1) {
+        GTTY(GLOBAL(echofd), &sg);    /* get settings */
+        sg.sg_flags |= ECHO;  /* turn echo on */
+        STTY(GLOBAL(echofd), &sg);
+        GLOBAL(echofd) = -1;
+    }
+}
+
+#endif /* !CMS_MVS */
+#endif /* ?VMS */
+
+
+#if (defined(UNZIP) && !defined(FUNZIP))
+
+#ifdef ATH_BEO_UNX
+#ifdef MORE
+
+/*
+ * Get the number of lines on the output terminal.  SCO Unix apparently
+ * defines TIOCGWINSZ but doesn't support it (!M_UNIX).
+ *
+ * GRR:  will need to know width of terminal someday, too, to account for
+ *       line-wrapping.
+ */
+
+#if (defined(TIOCGWINSZ) && !defined(M_UNIX))
+
+int screensize(tt_rows, tt_cols)
+    int *tt_rows;
+    int *tt_cols;
+{
+    struct winsize wsz;
+#ifdef DEBUG_WINSZ
+    static int firsttime = TRUE;
+#endif
+
+    /* see termio(4) under, e.g., SunOS */
+    if (ioctl(1, TIOCGWINSZ, &wsz) == 0) {
+#ifdef DEBUG_WINSZ
+        if (firsttime) {
+            firsttime = FALSE;
+            fprintf(stderr, "ttyio.c screensize():  ws_row = %d\n",
+              wsz.ws_row);
+            fprintf(stderr, "ttyio.c screensize():  ws_col = %d\n",
+              wsz.ws_col);
+        }
+#endif
+        /* number of rows */
+        if (tt_rows != NULL)
+            *tt_rows = (int)((wsz.ws_row > 0) ? wsz.ws_row : 24);
+        /* number of columns */
+        if (tt_cols != NULL)
+            *tt_cols = (int)((wsz.ws_col > 0) ? wsz.ws_col : 80);
+        return 0;    /* signal success */
+    } else {         /* this happens when piping to more(1), for example */
+#ifdef DEBUG_WINSZ
+        if (firsttime) {
+            firsttime = FALSE;
+            fprintf(stderr,
+              "ttyio.c screensize():  ioctl(TIOCGWINSZ) failed\n"));
+        }
+#endif
+        /* VT-100 assumed to be minimal hardware */
+        if (tt_rows != NULL)
+            *tt_rows = 24;
+        if (tt_cols != NULL)
+            *tt_cols = 80;
+        return 1;       /* signal failure */
+    }
+}
+
+#else /* !TIOCGWINSZ: service not available, fall back to semi-bogus method */
+
+int screensize(tt_rows, tt_cols)
+    int *tt_rows;
+    int *tt_cols;
+{
+    char *envptr, *getenv();
+    int n;
+    int errstat = 0;
+
+    /* GRR:  this is overly simplistic, but don't have access to stty/gtty
+     * system anymore
+     */
+    if (tt_rows != NULL) {
+        envptr = getenv("LINES");
+        if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) {
+            /* VT-100 assumed to be minimal hardware */
+            *tt_rows = 24;
+            errstat = 1;    /* signal failure */
+        } else {
+            *tt_rows = n;
+        }
+    }
+    if (tt_cols != NULL) {
+        envptr = getenv("COLUMNS");
+        if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) {
+            *tt_cols = 80;
+            errstat = 1;    /* signal failure */
+        } else {
+            *tt_cols = n;
+        }
+    }
+    return errstat;
+}
+
+#endif /* ?(TIOCGWINSZ && !M_UNIX) */
+#endif /* MORE */
+
+
+/*
+ * Get a character from the given file descriptor without echo or newline.
+ */
+int zgetch(__G__ f)
+    __GDEF
+    int f;                      /* file descriptor from which to read */
+{
+#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
+    char oldmin, oldtim;
+#endif
+    char c;
+    struct sgttyb sg;           /* tty device structure */
+
+    GTTY(f, &sg);               /* get settings */
+#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
+    oldmin = sg.c_cc[VMIN];     /* save old values */
+    oldtim = sg.c_cc[VTIME];
+    sg.c_cc[VMIN] = 1;          /* need only one char to return read() */
+    sg.c_cc[VTIME] = 0;         /* no timeout */
+    sg.sg_flags &= ~ICANON;     /* canonical mode off */
+#else
+    sg.sg_flags |= CBREAK;      /* cbreak mode on */
+#endif
+    sg.sg_flags &= ~ECHO;       /* turn echo off, too */
+    STTY(f, &sg);               /* set cbreak mode */
+    GLOBAL(echofd) = f;         /* in case ^C hit (not perfect: still CBREAK) */
+
+    read(f, &c, 1);             /* read our character */
+
+#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
+    sg.c_cc[VMIN] = oldmin;     /* restore old values */
+    sg.c_cc[VTIME] = oldtim;
+    sg.sg_flags |= ICANON;      /* canonical mode on */
+#else
+    sg.sg_flags &= ~CBREAK;     /* cbreak mode off */
+#endif
+    sg.sg_flags |= ECHO;        /* turn echo on */
+    STTY(f, &sg);               /* restore canonical mode */
+    GLOBAL(echofd) = -1;
+
+    return (int)(uch)c;
+}
+
+
+#else /* !ATH_BEO_UNX */
+#ifndef VMS     /* VMS supplies its own variant of getch() */
+
+
+int zgetch(__G__ f)
+    __GDEF
+    int f;    /* file descriptor from which to read (must be open already) */
+{
+    char c, c2;
+
+/*---------------------------------------------------------------------------
+    Get a character from the given file descriptor without echo; can't fake
+    CBREAK mode (i.e., newline required), but can get rid of all chars up to
+    and including newline.
+  ---------------------------------------------------------------------------*/
+
+    echoff(f);
+    read(f, &c, 1);
+    if (c != '\n')
+        do {
+            read(f, &c2, 1);   /* throw away all other chars up thru newline */
+        } while (c2 != '\n');
+    echon();
+    return (int)c;
+}
+
+#endif /* !VMS */
+#endif /* ?ATH_BEO_UNX */
+
+#endif /* UNZIP && !FUNZIP */
+#endif /* !HAVE_WORKING_GETCH */
+
+
+#if CRYPT                       /* getp() is only used with full encryption */
+
+/*
+ * Simple compile-time check for source compatibility between
+ * zcrypt and ttyio:
+ */
+#if (!defined(CR_MAJORVER) || (CR_MAJORVER < 2) || (CR_MINORVER < 7))
+   error:  This Info-ZIP tool requires zcrypt 2.7 or later.
+#endif
+
+/*
+ * Get a password of length n-1 or less into *p using the prompt *m.
+ * The entered password is not echoed.
+ */
+
+#ifdef HAVE_WORKING_GETCH
+/*
+ * For the AMIGA, getch() is defined as Agetch(), which is in
+ * amiga/filedate.c; SAS/C 6.x provides a getch(), but since Agetch()
+ * uses the infrastructure that is already in place in filedate.c, it is
+ * smaller.  With this function, echoff() and echon() are not needed.
+ *
+ * For the MAC, a non-echo macgetch() function is defined in the MacOS
+ * specific sources which uses the event handling mechanism of the
+ * desktop window manager to get a character from the keyboard.
+ *
+ * For the other systems in this section, a non-echo getch() function
+ * is either contained the C runtime library (conio package), or getch()
+ * is defined as an alias for a similar system specific RTL function.
+ */
+
+#ifndef WINDLL   /* WINDLL does not support a console interface */
+#ifndef QDOS     /* QDOS supplies a variant of this function */
+
+/* This is the getp() function for all systems (with TTY type user interface)
+ * that supply a working `non-echo' getch() function for "raw" console input.
+ */
+char *getp(__G__ m, p, n)
+    __GDEF
+    ZCONST char *m;             /* prompt for password */
+    char *p;                    /* return value: line input */
+    int n;                      /* bytes available in p[] */
+{
+    char c;                     /* one-byte buffer for read() to use */
+    int i;                      /* number of characters input */
+    char *w;                    /* warning on retry */
+
+    /* get password */
+    w = "";
+    do {
+        fputs(w, stderr);       /* warning if back again */
+        fputs(m, stderr);       /* display prompt and flush */
+        fflush(stderr);
+        i = 0;
+        do {                    /* read line, keeping first n characters */
+            if ((c = (char)getch()) == '\r')
+                c = '\n';       /* until user hits CR */
+            if (c == 8 || c == 127) {
+                if (i > 0) i--; /* the `backspace' and `del' keys works */
+            }
+            else if (i < n)
+                p[i++] = c;     /* truncate past n */
+        } while (c != '\n');
+        PUTC('\n', stderr);  fflush(stderr);
+        w = "(line too long--try again)\n";
+    } while (p[i-1] != '\n');
+    p[i-1] = 0;                 /* terminate at newline */
+
+    return p;                   /* return pointer to password */
+
+} /* end function getp() */
+
+#endif /* !QDOS */
+#endif /* !WINDLL */
+
+
+#else /* !HAVE_WORKING_GETCH */
+
+
+#if (defined(ATH_BEO_UNX) || defined(__MINT__))
+
+#ifndef _PATH_TTY
+#  ifdef __MINT__
+#    define _PATH_TTY ttyname(2)
+#  else
+#    define _PATH_TTY "/dev/tty"
+#  endif
+#endif
+
+char *getp(__G__ m, p, n)
+    __GDEF
+    ZCONST char *m;             /* prompt for password */
+    char *p;                    /* return value: line input */
+    int n;                      /* bytes available in p[] */
+{
+    char c;                     /* one-byte buffer for read() to use */
+    int i;                      /* number of characters input */
+    char *w;                    /* warning on retry */
+    int f;                      /* file descriptor for tty device */
+
+#ifdef PASSWD_FROM_STDIN
+    /* Read from stdin. This is unsafe if the password is stored on disk. */
+    f = 0;
+#else
+    /* turn off echo on tty */
+
+    if ((f = open(_PATH_TTY, 0)) == -1)
+        return NULL;
+#endif
+    /* get password */
+    w = "";
+    do {
+        fputs(w, stderr);       /* warning if back again */
+        fputs(m, stderr);       /* prompt */
+        fflush(stderr);
+        i = 0;
+        echoff(f);
+        do {                    /* read line, keeping n */
+            read(f, &c, 1);
+            if (i < n)
+                p[i++] = c;
+        } while (c != '\n');
+        echon();
+        PUTC('\n', stderr);  fflush(stderr);
+        w = "(line too long--try again)\n";
+    } while (p[i-1] != '\n');
+    p[i-1] = 0;                 /* terminate at newline */
+
+#ifndef PASSWD_FROM_STDIN
+    close(f);
+#endif
+
+    return p;                   /* return pointer to password */
+
+} /* end function getp() */
+
+#endif /* ATH_BEO_UNX || __MINT__ */
+
+
+
+#if (defined(VMS) || defined(CMS_MVS))
+
+char *getp(__G__ m, p, n)
+    __GDEF
+    ZCONST char *m;             /* prompt for password */
+    char *p;                    /* return value: line input */
+    int n;                      /* bytes available in p[] */
+{
+    char c;                     /* one-byte buffer for read() to use */
+    int i;                      /* number of characters input */
+    char *w;                    /* warning on retry */
+    FILE *f;                    /* file structure for SYS$COMMAND device */
+
+#ifdef PASSWD_FROM_STDIN
+    f = stdin;
+#else
+    if ((f = fopen(ctermid(NULL), "r")) == NULL)
+        return NULL;
+#endif
+
+    /* get password */
+    fflush(stdout);
+    w = "";
+    do {
+        if (*w)                 /* bug: VMS apparently adds \n to NULL fputs */
+            fputs(w, stderr);   /* warning if back again */
+        fputs(m, stderr);       /* prompt */
+        fflush(stderr);
+        i = 0;
+        echoff(f);
+        do {                    /* read line, keeping n */
+            if ((c = (char)getc(f)) == '\r')
+                c = '\n';
+            if (i < n)
+                p[i++] = c;
+        } while (c != '\n');
+        echon();
+        PUTC('\n', stderr);  fflush(stderr);
+        w = "(line too long--try again)\n";
+    } while (p[i-1] != '\n');
+    p[i-1] = 0;                 /* terminate at newline */
+#ifndef PASSWD_FROM_STDIN
+    fclose(f);
+#endif
+
+    return p;                   /* return pointer to password */
+
+} /* end function getp() */
+
+#endif /* VMS || CMS_MVS */
+#endif /* ?HAVE_WORKING_GETCH */
+#endif /* CRYPT */
+#endif /* CRYPT || (UNZIP && !FUNZIP) */
diff --git a/ttyio.h b/ttyio.h
new file mode 100644 (file)
index 0000000..df6a4ed
--- /dev/null
+++ b/ttyio.h
@@ -0,0 +1,229 @@
+/*
+  ttyio.h - Zip 3
+
+  Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2005-Feb-10 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+   ttyio.h
+ */
+
+#ifndef __ttyio_h   /* don't include more than once */
+#define __ttyio_h
+
+#ifndef __crypt_h
+#  include "crypt.h"  /* ensure that encryption header file has been seen */
+#endif
+
+#if (CRYPT || (defined(UNZIP) && !defined(FUNZIP)))
+/*
+ * Non-echo keyboard/console input support is needed and enabled.
+ */
+
+#ifndef __G         /* UnZip only, for now (DLL stuff) */
+#  define __G
+#  define __G__
+#  define __GDEF
+#  define __GPRO    void
+#  define __GPRO__
+#endif
+
+#ifndef ZCONST      /* UnZip only (until have configure script like Zip) */
+#  define ZCONST const
+#endif
+
+#if (defined(MSDOS) || defined(OS2) || defined(WIN32))
+#  ifndef DOS_OS2_W32
+#    define DOS_OS2_W32
+#  endif
+#endif
+
+#if (defined(DOS_OS2_W32) || defined(__human68k__))
+#  ifndef DOS_H68_OS2_W32
+#    define DOS_H68_OS2_W32
+#  endif
+#endif
+
+#if (defined(DOS_OS2_W32) || defined(FLEXOS))
+#  ifndef DOS_FLX_OS2_W32
+#    define DOS_FLX_OS2_W32
+#  endif
+#endif
+
+#if (defined(DOS_H68_OS2_W32) || defined(FLEXOS))
+#  ifndef DOS_FLX_H68_OS2_W32
+#    define DOS_FLX_H68_OS2_W32
+#  endif
+#endif
+
+#if (defined(__ATHEOS__) || defined(__BEOS__) || defined(UNIX))
+#  ifndef ATH_BEO_UNX
+#    define ATH_BEO_UNX
+#  endif
+#endif
+
+#if (defined(VM_CMS) || defined(MVS))
+#  ifndef CMS_MVS
+#    define CMS_MVS
+#  endif
+#endif
+
+
+/* Function prototypes */
+
+/* The following systems supply a `non-echo' character input function "getch()"
+ * (or an alias) and do not need the echoff() / echon() function pair.
+ */
+#ifdef AMIGA
+#  define echoff(f)
+#  define echon()
+#  define getch() Agetch()
+#  define HAVE_WORKING_GETCH
+#endif /* AMIGA */
+
+#ifdef ATARI
+#  define echoff(f)
+#  define echon()
+#  include <osbind.h>
+#  define getch() (Cnecin() & 0x000000ff)
+#  define HAVE_WORKING_GETCH
+#endif
+
+#ifdef MACOS
+#  define echoff(f)
+#  define echon()
+#  define getch() macgetch()
+#  define HAVE_WORKING_GETCH
+#endif
+
+#ifdef NLM
+#  define echoff(f)
+#  define echon()
+#  define HAVE_WORKING_GETCH
+#endif
+
+#ifdef QDOS
+#  define echoff(f)
+#  define echon()
+#  define HAVE_WORKING_GETCH
+#endif
+
+#ifdef RISCOS
+#  define echoff(f)
+#  define echon()
+#  define getch() SWI_OS_ReadC()
+#  define HAVE_WORKING_GETCH
+#endif
+
+#ifdef DOS_H68_OS2_W32
+#  define echoff(f)
+#  define echon()
+#  ifdef WIN32
+#    ifndef getch
+#      define getch() getch_win32()
+#    endif
+#  else /* !WIN32 */
+#    ifdef __EMX__
+#      ifndef getch
+#        define getch() _read_kbd(0, 1, 0)
+#      endif
+#    else /* !__EMX__ */
+#      ifdef __GO32__
+#        include <pc.h>
+#        define getch() getkey()
+#      else /* !__GO32__ */
+#        include <conio.h>
+#      endif /* ?__GO32__ */
+#    endif /* ?__EMX__ */
+#  endif /* ?WIN32 */
+#  define HAVE_WORKING_GETCH
+#endif /* DOS_H68_OS2_W32 */
+
+#ifdef FLEXOS
+#  define echoff(f)
+#  define echon()
+#  define getch() getchar() /* not correct, but may not be on a console */
+#  define HAVE_WORKING_GETCH
+#endif
+
+/* For VM/CMS and MVS, we do not (yet) have any support to switch terminal
+ * input echo on and off. The following "fake" definitions allow inclusion
+ * of crypt support and UnZip's "pause prompting" features, but without
+ * any echo suppression.
+ */
+#ifdef CMS_MVS
+#  define echoff(f)
+#  define echon()
+#endif
+
+#ifdef TANDEM
+#  define echoff(f)
+#  define echon()
+#  define getch() zgetch() /* defined in TANDEMC */
+#  define HAVE_WORKING_GETCH
+#endif
+
+/* The THEOS C runtime library supplies the function conmask() to toggle
+ * terminal input echo on (conmask("e")) and off (conmask("n")).  But,
+ * since THEOS C RTL also contains a working non-echo getch() function,
+ * the echo toggles are not needed.
+ */
+#ifdef THEOS
+#  define echoff(f)
+#  define echon()
+#  define HAVE_WORKING_GETCH
+#endif
+
+/* VMS has a single echo() function in ttyio.c to toggle terminal
+ * input echo on and off.
+ */
+#ifdef VMS
+#  define echoff(f)  echo(0)
+#  define echon()    echo(1)
+#  define getch()    tt_getch()
+#  define FGETCH(f)  tt_getch()
+   int echo OF((int));
+   int tt_getch OF((void));
+#endif
+
+/* For all other systems, ttyio.c supplies the two functions Echoff() and
+ * Echon() for suppressing and (re)enabling console input echo.
+ */
+#ifndef echoff
+#  define echoff(f)  Echoff(__G__ f)
+#  define echon()    Echon(__G)
+   void Echoff OF((__GPRO__ int f));
+   void Echon OF((__GPRO));
+#endif
+
+/* this stuff is used by MORE and also now by the ctrl-S code; fileio.c only */
+#if (defined(UNZIP) && !defined(FUNZIP))
+#  ifdef HAVE_WORKING_GETCH
+#    define FGETCH(f)  getch()
+#  endif
+#  ifndef FGETCH
+     /* default for all systems where no getch()-like function is available */
+     int zgetch OF((__GPRO__ int f));
+#    define FGETCH(f)  zgetch(__G__ f)
+#  endif
+#endif /* UNZIP && !FUNZIP */
+
+#if (CRYPT && !defined(WINDLL))
+   char *getp OF((__GPRO__ ZCONST char *m, char *p, int n));
+#endif
+
+#else /* !(CRYPT || (UNZIP && !FUNZIP)) */
+
+/*
+ * No need for non-echo keyboard/console input; provide dummy definitions.
+ */
+#define echoff(f)
+#define echon()
+
+#endif /* ?(CRYPT || (UNZIP && !FUNZIP)) */
+
+#endif /* !__ttyio_h */
diff --git a/unix/Makefile b/unix/Makefile
new file mode 100644 (file)
index 0000000..abd0c44
--- /dev/null
@@ -0,0 +1,329 @@
+# Makefile for Zip, ZipNote, ZipCloak and ZipSplit
+
+# what you can make ...
+all:
+       @echo ''
+       @echo 'Make what?  You must say what system to make Zip for--e.g.'
+       @echo '"make generic".'
+       @echo 'Choices: generic, generic_gcc, att6300nodir,'
+       @echo 'coherent, cray_v3, cygwin, lynx, minix, os390,'
+       @echo 'qnx, qnxnto, solaris, solaris_gcc'
+       @echo 'Try first "make -f unix/Makefile generic" as'
+       @echo 'it should autodetect and set the proper flags.'
+       @echo 'To make the manuals use "make zipsman" after Zip is made.'
+       @echo 'See the files INSTALL and zip.txt for more information.'
+       @echo ''
+
+list:   all
+
+#MAKE = make -f unix/Makefile
+MAKEF = -f unix/Makefile
+SHELL = /bin/sh
+LN = ln -s
+
+# (to use the GNU compiler, change cc to gcc in CC)
+CC = cc
+BIND = $(CC)
+AS = $(CC) -c
+CPP = /lib/cpp
+E =
+
+# probably can change this to 'install' if you have it
+INSTALL_PROGRAM = cp
+# probably can change this to 'install -d' if you have it
+# XXX NextStep 3.3 and Openstep 4.x don't know about -p !
+INSTALL_D = mkdir -p
+CHMOD = chmod
+BINFLAGS = 755
+MANFLAGS = 644
+
+# target directories - where to install executables and man pages to
+prefix = /usr/local
+BINDIR = $(prefix)/bin
+MANEXT=1
+MANDIR = $(prefix)/man/man$(MANEXT)
+ZIPMANUAL = zip.txt
+ZIPMANUALcloak = zipcloak.txt
+ZIPMANUALnote = zipnote.txt
+ZIPMANUALsplit = zipsplit.txt
+ZIPMANUALs = zip.txt zipcloak.txt zipnote.txt zipsplit.txt
+PKGDIR = IZzip
+VERSION = Version 3.0
+
+# Our bzip2 directory
+IZ_OUR_BZIP2_DIR = bzip2
+
+# flags
+#   CFLAGS    flags for C compile
+#   LFLAGS1   flags after output file spec, before obj file list
+#   LFLAGS2   flags after obj file list (libraries, etc)
+CFLAGS_NOOPT = -I. -DUNIX $(LOCAL_ZIP)
+CFLAGS = -O2 $(CFLAGS_NOOPT)
+LFLAGS1 =
+LFLAGS2 = -s
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crypt.o ttyio.o \
+       unix.o crc32.o zbz2err.o
+OBJI = deflate.o trees.o
+OBJA =
+OCRCU8 =
+OCRCTB = crc32_.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o unix_.o $(OCRCU8)
+OBJN = zipnote.o  $(OBJU)
+OBJC = zipcloak.o $(OBJU) $(OCRCTB) crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h unix/osdep.h
+
+# suffix rules
+.SUFFIXES:
+.SUFFIXES: _.o .o .c .doc .1
+.c_.o:
+       $(CC) -c $(CFLAGS) -DUTIL -o $@ $<
+
+.c.o:
+       $(CC) -c $(CFLAGS) $<
+
+.1.doc:
+       nroff -man $< | col -bx | uniq > $@
+
+# rules for zip, zipnote, zipcloak, zipsplit, and the Zip MANUALs.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o zipup.o zipfile.o fileio.o crc32.o crypt.o: crc32.h
+zipcloak.o zipfile_.o fileio_.o crc32_.o crypt_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: unix/zipup.h
+
+match.o: match.S
+       $(CPP) match.S > _match.s
+       $(AS) _match.s
+       mv _match.o match.o
+       rm -f _match.s
+
+crc_i386.o: crc_i386.S
+       $(CPP) crc_i386.S > _crc_i386.s
+       $(AS) _crc_i386.s
+       mv _crc_i386.o crc_i386.o
+       rm -f _crc_i386.s
+
+unix.o: unix/unix.c
+       $(CC) -c $(CFLAGS) unix/unix.c
+
+unix_.o: unix/unix.c
+       $(CC) -c $(CFLAGS) -DUTIL -o $@ unix/unix.c
+
+ZIPS = zip$E zipcloak$E zipnote$E zipsplit$E
+
+zips: $(ZIPS)
+zipsman: $(ZIPS) $(ZIPMANUALs)
+
+zip$E: $(OBJZ) $(OBJI) $(OBJA) $(LIB_BZ)
+       $(BIND) -o zip$E $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote$E: $(OBJN)
+       $(BIND) -o zipnote$E $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak$E: $(OBJC) $(OCRCTB)
+       $(BIND) -o zipcloak$E $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit$E: $(OBJS)
+       $(BIND) -o zipsplit$E $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+$(ZIPMANUAL): man/zip.1
+       nroff -man man/zip.1 | col -bx | uniq > $(ZIPMANUAL)
+
+$(ZIPMANUALcloak): man/zipcloak.1
+       nroff -man man/zipcloak.1 | col -bx | uniq > $(ZIPMANUALcloak)
+
+$(ZIPMANUALnote): man/zipnote.1
+       nroff -man man/zipnote.1 | col -bx | uniq > $(ZIPMANUALnote)
+
+$(ZIPMANUALsplit): man/zipsplit.1
+       nroff -man man/zipsplit.1 | col -bx | uniq > $(ZIPMANUALsplit)
+
+
+# bzip2 object library
+
+$(IZ_OUR_BZIP2_DIR)/libbz2.a : $(IZ_OUR_BZIP2_DIR)/Makefile
+       @echo "Building bzip2 object library..."
+       ( cd $(IZ_OUR_BZIP2_DIR); \
+         $(MAKE) CC="$(CC_BZ)" CFLAGS="$(CFLAGS_BZ)" libbz2.a )
+       @echo "   bzip2 object library created."
+
+
+# install
+install:        $(ZIPS)
+       -$(INSTALL_D) $(BINDIR)
+       $(INSTALL_PROGRAM) $(ZIPS) $(BINDIR)
+       -cd $(BINDIR); $(CHMOD) $(BINFLAGS) $(ZIPS)
+       -$(INSTALL_D) $(MANDIR)
+       $(INSTALL_PROGRAM) man/zip.1 $(MANDIR)/zip.$(MANEXT)
+       $(CHMOD) $(MANFLAGS) $(MANDIR)/zip.$(MANEXT)
+       $(INSTALL_PROGRAM) man/zipcloak.1 $(MANDIR)/zipcloak.$(MANEXT)
+       $(CHMOD) $(MANFLAGS) $(MANDIR)/zipcloak.$(MANEXT)
+       $(INSTALL_PROGRAM) man/zipnote.1 $(MANDIR)/zipnote.$(MANEXT)
+       $(CHMOD) $(MANFLAGS) $(MANDIR)/zipnote.$(MANEXT)
+       $(INSTALL_PROGRAM) man/zipsplit.1 $(MANDIR)/zipsplit.$(MANEXT)
+       $(CHMOD) $(MANFLAGS) $(MANDIR)/zipsplit.$(MANEXT)
+
+uninstall:
+       -cd $(BINDIR); rm -f $(ZIPS)
+       -cd $(MANDIR); rm -f \
+        zip.$(MANEXT) zipcloak.$(MANEXT) zipnote.$(MANEXT) zipsplit.$(MANEXT)
+
+
+flags:  unix/configure
+       sh unix/configure "${CC}" "${CFLAGS_NOOPT}" "${IZ_BZIP2}"
+
+# These symbols, when #defined using -D have these effects on compilation:
+# ZMEM                  - includes C language versions of memset(), memcpy(),
+#                         and memcmp() (util.c).
+# HAVE_DIRENT_H         - use <dirent.h> instead of <sys/dir.h>
+# NODIR                 - for 3B1, which has neither getdents() nor opendir().
+# HAVE_NDIR_H           - use <ndir.h> (unix/unix.c).
+# HAVE_SYS_DIR_H        - use <sys/dir.h>
+# HAVE_SYS_NDIR_H       - use <sys/ndir.h>
+# UTIL                  - select routines for utilities (note, cloak, split)
+# NO_RMDIR              - remove directories using a system("rmdir ...") call.
+# NO_PROTO              - cannot handle ANSI prototypes
+# NO_CONST              - cannot handle ANSI const
+# NO_LARGE_FILE_SUPPORT - do not enable Large File support even if available.
+# NO_ZIP64_SUPPORT      - do not enable Zip64 archive support even if available.
+# NO_UNICODE_SUPPORT    - do not enable Unicode support even if available.
+# NO_BZIP2_SUPPORT      - do not compile in bzip2 code even if available.
+
+#               Generic targets:
+
+generic: flags
+       eval $(MAKE) $(MAKEF) zips `cat flags`
+
+generic_gcc:
+       $(MAKE) $(MAKEF) generic CC=gcc CPP="gcc -E"
+
+# AT&T 6300 PLUS (don't know yet how to allocate 64K bytes):
+att6300nodir:
+       $(MAKE) $(MAKEF) zips LFLAGS1="-Ml -s" \
+       CFLAGS="-DUNIX -I. -O -Ml -DNO_RMDIR -DDYN_ALLOC -DMEDIUM_MEM \
+-DWSIZE=16384 -DNO_STDLIB_H -DNO_STDDEF_H -DNO_RENAME \
+-DNO_MKTIME -DNO_SIZE_T -DNO_VOID -DNO_PROTO -DNO_DIR \
+-DNO_CONST -DHAVE_TERMIO_H" \
+       "LFLAGS2="
+
+# Coherent (AS definition not needed for gcc)
+coherent:
+       $(MAKE) $(MAKEF) zips CFLAGS="-DUNIX -I. -O -DDIRENT -DASMV" \
+        AS="as -gx" OBJA=match.o
+
+# Cray Unicos 6.1, Standard C compiler 3.0 (all routines except trees.c
+# may be compiled with vector3; internal compiler bug in 3.0.2.3 and
+# earlier requires vector2 for trees.c)
+cray_v3:
+       $(MAKE) $(MAKEF) zips CC="scc" \
+               CFLAGS="-DUNIX -I. -O -h vector2 -h scalar3 -DHAVE_DIRENT_H"
+
+# Cygwin
+cygwin:
+       $(MAKE) $(MAKEF) generic CC="gcc" CPP="gcc -E" EXE=".exe"
+
+# LynxOS
+lynx:
+       $(MAKE) $(MAKEF) generic CC=gcc CPP="gcc -E" CFLAGS="$(CFLAGS) \
+        -DNO_UNDERLINE -DLynx -DLYNX LFLAGS2="$LFLAGS2 -lc_p"
+
+# MINIX 1.5.10 with Bruce Evans 386 patches and gcc/GNU make
+minix:
+       $(MAKE) $(MAKEF) zips CFLAGS="-DUNIX -I. -O -DDIRENT -DMINIX" CC=gcc
+       chmem =262144 zip
+
+# IBM OS/390 (formerly MVS) compiled under "OpenEdition" shell
+# You can make the zip executable with IBM's make, but you will
+# get errors dealing with the _.o targets for the other executables
+# (zipcloak, etc).  GNU make will build all the executables.
+# If you have GNU make in your path as gmake, you can uncomment
+# the following, but it shouldn't be needed:
+#MAKE = gmake
+
+os390:
+       $(MAKE) $(MAKEF) zips CFLAGS="$(CF) -I. -DUNIX -DOS390 -DEBCDIC \
+        -DSYSV -DNO_PARAM_H" LFLAGS2=""
+
+# QNX is "special" because out /bin/sh is ksh and it doesn't grok the
+# configure script properly, generating a bad flags file.  D'oh! [cjh]
+#
+# QNX/Neutrino is "special" because you don't have any native development
+# tools yet.  Set ARCH to "x86", "ppcbe", "ppcle", "mipsbe", or "mipsle"
+# to produce x86, PowerPC (big- or little-endian) and MIPS (big-
+# or little-endian) using gcc. [cjh]
+qnx:
+       $(MAKE) $(MAKEF) zips LN=ln CC=cc CFLAGS="-DUNIX -I. -O \
+        -DHAVE_DIRENT_H -DHAVE_TERMIOS_H -DNO_MKTEMP"
+
+qnxnto:
+       @if [ "$(ARCH)" = "" ] ; then \
+               echo "You didn't set ARCH; I'll assume you meant ARCH=x86..." ; \
+               echo "" ; \
+               $(MAKE) $(MAKEF) zips LN=ln CC="qcc -Vgcc_ntox86" \
+                       CFLAGS="-g -DUNIX -I. -O -DHAVE_DIRENT_H -DHAVE_TERMIOS_H -DNO_MKTEMP" \
+                       LFLAGS2=-g ; \
+       else \
+               echo "Making zip for $(ARCH)..." ; \
+               echo "" ; \
+               $(MAKE) $(MAKEF) zips LN=ln CC="qcc -Vgcc_nto$(ARCH)" \
+                       CFLAGS="-g -DUNIX -I. -O -DHAVE_DIRENT_H -DHAVE_TERMIOS_H -DNO_MKTEMP" \
+                       LFLAGS2=-g ; \
+       fi
+
+# Solaris:  Generic, plus generation of installable package.
+solaris:       generic svr4package
+
+# Solaris with GCC: generic_gcc, plus generation of installable package
+solaris_gcc:   generic_gcc svr4package
+
+# Package generation interface (by JBush). Originally tested under Sun Solaris.
+# Other SVr4s may be very similar, and could possibly use this.
+# Note:  Expects version info to be stored in VERSION macro variable.
+# See "README" under ./unix/Packaging
+svr4package:
+       @echo "Creating SVR4 package for Unix ..."
+       -@rm -rf ./$(PKGDIR) ./$(PKGDIR)_`uname -p`.pkg
+       -@sed -e "s/.VERSION./$(VERSION)/g" \
+             -e "s/.PSTAMP./$(LOGNAME)_`date | tr  ' ' '_'`/g" \
+             -e "s/.ARCH./Solaris_`uname -rp | tr ' ' ','`/g" \
+             ./unix/Packaging/pkginfo.in > ./unix/Packaging/pkginfo
+       -@sed -e "s/.ARCH./`uname -p`/g" \
+             ./unix/Packaging/preinstall.in > ./unix/Packaging/preinstall
+       /usr/bin/pkgmk -d . -b . -r . -f ./unix/Packaging/prototype $(PKGDIR)
+       /usr/bin/pkgtrans -o -s . $(PKGDIR)_`uname -p`.pkg $(PKGDIR)
+       @echo " "
+       @echo "To install, copy $(PKGDIR)_`uname -p`.pkg to the target system, and"
+       @echo "issue the command (as root):  pkgadd -d $(PKGDIR)_`uname -p`.pkg"
+       @echo " "
+
+# make a distribution
+dist:  $(ZIPMANUAL)
+       eval zip -r9 zip`sed -e '/VERSION/!d' -e 's/.*"\(.*\)".*/\1/' \
+                         -e 's/[.]//g' -e 's/ .*//g' -e q revision.h` *
+
+# clean up after making stuff and installing it
+clean:
+       rm -f *.o $(ZIPS) flags
+       rm -rf $(PKGDIR)
+
+clean_bzip2 :
+       @if test -f "$(IZ_OUR_BZIP2_DIR)/Makefile"; then \
+         ( cd $(IZ_OUR_BZIP2_DIR); make clean ); \
+       else \
+          if test -z "$(IZ_OUR_BZIP2_DIR)"; then \
+           echo "No bzip2 directory (\"IZ_OUR_BZIP2_DIR\") specified."; \
+         else \
+           echo "No bzip2 make file found: $(IZ_OUR_BZIP2_DIR)/Makefile."; \
+         fi; \
+       fi
+
+clean_exe :
+       rm -f $(ZIPS)
+#
diff --git a/unix/Packaging/README b/unix/Packaging/README
new file mode 100644 (file)
index 0000000..6b2a451
--- /dev/null
@@ -0,0 +1,44 @@
+Solaris packaging
+-----------------
+
+To generate a Solaris package for Info-ZIP zip utilities,
+first see the top level INSTALL and README files.  Do a
+"make solaris", which will automatically build two Solaris
+installable package files for the package, IZzip.
+
+   IZzip     -- Solaris installable package in directory format.
+   IZzip_$(arch).pkg -- Solaris installable package in "stream" format.
+
+   Where:  $(arch) := system architecture, currently i386, sparc, or ppc.
+                      (use "uname -p" to determine)
+
+The ".pkg" file is a single file datastream that can be compressed
+and/or ftp'd.  This is the recommended form, because all required
+files are resident in the archive, and it is easily distributed.
+
+To install, simply:
+
+    1)  copy the package to the target system's /tmp directory.
+    2)  login or su to root
+    3)  pkgadd -d /tmp/IZzip_$(arch).pkg
+    4)  add /opt/Info-ZIP/IZzip/bin to PATH
+    5)  add /opt/Info-ZIP/IZzip/man to MANPATH
+
+This works for both SPARC and x86.
+
+Ongoing maintenance:
+
+  Keep the files, "prototype" and "pkginfo.in" up to date.
+  Observe variable substitutions made by "Makefile".
+  See manpages for pkginfo(1), pkginfo(4), pkgmk(1), pkgproto(1)
+
+Variations:
+
+  If you wish the base directory to be set to something other than
+  /opt/Info-ZIP, change the setting BASEDIR in pkginfo.in and
+  re-run the make.
+
+
+-John Bush (John.Bush@East.Sun.COM)
+ July 20, 1996
+
diff --git a/unix/Packaging/pkginfo.in b/unix/Packaging/pkginfo.in
new file mode 100644 (file)
index 0000000..c31395d
--- /dev/null
@@ -0,0 +1,13 @@
+PKG=IZzip
+NAME=Info-ZIP Zip Utilities
+CATEGORY=application
+VENDOR=Info-ZIP
+EMAIL=http://info-zip.org/zip-bug.html
+HOTLINE=http://info-zip.org/zip-bug.html
+DESC=Copyrighted FREEWARE.  See README, WHERE, and docs in pkg's doc dir.
+CLASSES=none
+BASEDIR=/opt/Info-ZIP
+#BASEDIR=/usr/local
+VERSION=".VERSION."
+PSTAMP=".PSTAMP."
+ARCH=".ARCH."
diff --git a/unix/Packaging/postinstall b/unix/Packaging/postinstall
new file mode 100644 (file)
index 0000000..086ec26
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# Info-ZIP Zip post-installation script.
+#
+# Last revised: 2007-09-29 SMS.  Zip 3.0.
+#
+# Post installation script (simply inform installer about PATH etc)
+#
+echo ''
+echo 'Installation is complete.  Users should adjust their environment'
+echo 'variables to include these directories:'
+echo "   PATH:    ${BASEDIR}/${PKG}/bin"
+echo "   MANPATH: ${BASEDIR}/${PKG}/man"
+echo ''
+echo "Commands like the following may be added to a user's shell start-up"
+echo 'file (.cshrc, .login, .profile, ...) to do this:'
+echo ''
+echo '   For a Bourne-like shell:'
+echo "      PATH=\"\${PATH}:${BASEDIR}/${PKG}/bin\""
+echo "      MANPATH=\"\${MANPATH}:${BASEDIR}/${PKG}/man\""
+echo '      export PATH MANPATH'
+echo ''
+echo '   For a C shell:'
+echo "      setenv PATH \"\${PATH}:${BASEDIR}/${PKG}/bin\""
+echo "      setenv MANPATH \"\${MANPATH}:${BASEDIR}/${PKG}/man\""
+echo ''
+echo "See the files under ${BASEDIR}/${PKG}/doc for more information."
+echo ''
+exit 0
diff --git a/unix/Packaging/preinstall.in b/unix/Packaging/preinstall.in
new file mode 100644 (file)
index 0000000..de1961b
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# Info-ZIP Zip pre-installation script.
+#
+# Last revised: 2007-09-29 SMS.  Zip 3.0.
+#
+# pkgadd should set a good PATH, but just in case, ...
+PATH="/sbin:/usr/bin:${PATH}"
+export PATH
+echo ''
+echo 'Please report problems to Info-ZIP using:'
+echo ''
+echo '      http://info-zip.org/zip-bug.html'
+echo ''
+arch=`uname -p`
+if [ "arch_${arch}" != "arch_.ARCH." ]; then
+   echo "This product MUST be installed on a Solaris \".ARCH.\" system."
+   echo "This system appears to have \"${arch}\" architecture, not \".ARCH.\"."
+   echo "Please install the version for the \".ARCH.\" architecture."
+   echo 'Aborting installation...'
+   returncode=1
+else
+   echo "Installing on \".ARCH.\" architecture..."
+   returncode=0
+fi
+echo ''
+sleep 4
+exit ${returncode:-1}
+#
diff --git a/unix/Packaging/prototype b/unix/Packaging/prototype
new file mode 100644 (file)
index 0000000..002eaf6
--- /dev/null
@@ -0,0 +1,29 @@
+d none $BASEDIR 0755 root bin
+d none $PKG 0755 root bin
+d none $PKG/doc 0755 root bin
+f none $PKG/doc/BUGS=BUGS 0644 root bin
+f none $PKG/doc/CHANGES=CHANGES 0644 root bin
+f none $PKG/doc/INSTALL=INSTALL 0644 root bin
+f none $PKG/doc/LICENSE=LICENSE 0644 root bin
+f none $PKG/doc/README=README 0644 root bin
+f none $PKG/doc/TODO=TODO 0644 root bin
+f none $PKG/doc/USexport.msg=USexport.msg 0644 root bin
+f none $PKG/doc/WHATSNEW=WHATSNEW 0644 root bin
+f none $PKG/doc/WHERE=WHERE 0644 root bin
+f none $PKG/doc/zip.txt=zip.txt 0644 root bin
+d none $PKG/man 0755 root bin
+d none $PKG/man/man1 0755 root bin
+f none $PKG/man/man1/zip.1=man/zip.1 0644 root bin
+f none $PKG/man/man1/zipcloak.1=man/zipcloak.1 0644 root bin
+f none $PKG/man/man1/zipnote.1=man/zipnote.1 0644 root bin
+f none $PKG/man/man1/zipsplit.1=man/zipsplit.1 0644 root bin
+d none $PKG/bin 0755 root bin
+f none $PKG/bin/zip=zip 0755 root bin
+f none $PKG/bin/zipcloak=zipcloak 0755 root bin
+f none $PKG/bin/zipnote=zipnote 0755 root bin
+f none $PKG/bin/zipsplit=zipsplit 0755 root bin
+i README
+i pkginfo
+i prototype
+i preinstall
+i postinstall
diff --git a/unix/README.OS390 b/unix/README.OS390
new file mode 100644 (file)
index 0000000..6fef92b
--- /dev/null
@@ -0,0 +1,85 @@
+
+OS/390 is IBM's follow-on to MVS and includes a POSIX, XOPEN,
+XPG4, build environment, a Unix-style filesystem (called HFS), and
+a POSIX (Born) shell.  This port uses this environment and is a fairly
+straight-forward port of ZIP's Unix port - but uses the existing EBCDIC
+code.  This port does not work with non-HFS (traditional MVS)
+filesystems.
+
+I believe all my changes are isolated with #ifdef's.
+
+Here's some text which might be useful for an OS390 README or
+the manual.
+
+ZIP for OS390 HFS datasets
+--------------------------
+Allows you to create ZIP archives from the OS/390 OpenEdition
+command prompt.  This port uses standard Unix-style I/O routines
+and only works with HFS files.
+
+Usage
+-----
+By default, ZIP does not perform character-set translation, but has
+options to make it easy to convert text files to be compatible with
+other systems
+  zip   zipfile list         # add the files in 'list' to archive 'zipfile'
+  zip -a zipfile list        # same as above, but translate files to ASCII
+  zip -al zipfile list       # same as above, translate linefeeds to DOS style
+  zip -all zipfile list      # same as '-a', translate linefeeds to UNIX style
+
+Build process
+-------------
+Assuming GNU make is available in your path and is called "gmake" (See
+the  notes on Makefile changes below) and a C compiler is available as
+"cc",  then type
+  gmake -f unix/Makefile MAKE=gmake os390
+
+If GNU make is not available, the existing makefile can create zip, but will
+error on the other executable (zipsplit, zipcloak, zipnote) if you type
+  make -f unix/Makefile os390
+
+Overview of Changes
+-------------------
+The OS/390 port is treated as a variant of the Unix port.  EBCDIC support
+was already implemented for CMS/MVS-batch ports.  The specific changes I
+made are summarized below.
+
+unix/Makefile - zip uses a unusual _.o target which IBM's make can't handle.
+Since the Makefile has a macro called MAKE that is used for a recursive
+call to make, I changed the MACRO to call "gmake" - GNU's make - which
+can handle the _.o target.  If you don't have GNU make, you can
+workaround by manually applying symlinks from whatever.c to whatever_.c.
+Alternatively, the whatever_.o files could be explicitely added for os390.
+
+I added an os390 target with appropriate defines.
+
+zipup.c - added code (#ifdef OS390) to convert test to ASCII if -a flag
+was set.
+
+zip.c - changed logic which always used DOS-style newlines when -a was
+set to be consistent with other port (DOS newlines if -l option)
+
+zipfile.c - miscellaneous changes to force storing file names and
+descriptions in ASCII in the zip directory. This makes zip files
+portable  across all platforms. This in turn meant names did not
+need to be translated when displaying messages.
+
+zip.h - strtoasc was missing a closing parenthesis.
+
+ebcdic.h - changed translation table to be consistent with current IBM
+recommendations - exact same changes to ebcdic.h as in my unzip port.
+
+tailor.h - define huge/far/near to be empty
+
+unix/unix.c - substantial changes to deal with mode flags.  Under
+the current XOPEN standards, some of the traditional unix file mode
+bits need not be in fixed locations, but standard access macros must be
+available to access the values.  The old unix.c code just picked up these
+values and saved them as-is where unzip interpreted them.  Existing
+Unix system provided the macros for XOPEN compliance, but left the flags
+in their traditional locations.  OS/390 has a brand new filesystem which
+is XOPEN compliant without revealing the positions of these flags.
+To create the bitmask in the same format unzip expects, the macros are
+tested one-by-one to set the appropriate bits.  This same logic should
+work on any XOPEN system, but takes more instructions (I did test this
+logic on Linux).
diff --git a/unix/configure b/unix/configure
new file mode 100644 (file)
index 0000000..73ba803
--- /dev/null
@@ -0,0 +1,695 @@
+:
+#!/bin/sh -x
+# The above : is necessary on some buggy systems.
+
+# configure: Guess values for system-dependent variables
+# Output the flag definitions to the file "flags".
+#
+# Parameters: $1 = $CC, $2 = $CFLAGS, $3 = $IZ_BZIP2
+#
+# This file is typically called from Makefile rather than executed
+# from the command line.
+#
+# To construct zip automatically using this file, type
+# "make -f unix/Makefile generic".
+# If this fails, then type "make list" to get a list of special targets.
+
+trap "rm -f conftest* core a.out; exit 1" 1 2 3 15
+
+CC=${1-cc}
+CFLAGS=${2-"-I. -DUNIX"}
+LFLAGS1=''
+LFLAGS2=''
+LN="ln -s"
+
+CFLAGS_OPT=''
+
+# bzip2
+IZ_BZIP2=${3-}
+CFLAGS_BZ=''
+
+
+echo 'Check C compiler type (optimization options)'
+# Sun C?
+cat > conftest.c << _EOF_
+int main()
+{
+#ifndef __SUNPRO_C
+   bad code
+#endif
+   return 0;
+}
+_EOF_
+$CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null
+if test $? -eq 0; then
+  CFLAGS_OPT='-xO3'
+  echo "  Sun C ($CFLAGS_OPT)"
+else
+  # Tru64 DEC/Compaq/HP C?
+  cat > conftest.c << _EOF_
+int main()
+{
+#ifndef __DECC
+   bad code
+#endif
+   return 0;
+}
+_EOF_
+  $CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null
+  if test $? -eq 0; then
+    CFLAGS_OPT='-O3'
+    echo "  DEC C ($CFLAGS_OPT)"
+  else
+    # HP-UX HP C?
+    cat > conftest.c << _EOF_
+int main()
+{
+#ifdef __GNUC__
+   bad code
+#endif
+#ifndef __hpux
+   bad code
+#endif
+   return 0;
+}
+_EOF_
+    $CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null
+    if test $? -eq 0; then
+      # HP-UX, not GCC.  Lame bundled or real ANSI compiler?
+      CFLAGS_OPT_TRY="+O3 +Onolimit"
+      $CC $CFLAGS $CFLAGS_OPT_TRY -c conftest.c 2>&1 | \
+       grep '(Bundled)' > /dev/null
+      if test $? -ne 0; then
+        CFLAGS_OPT="$CFLAGS_OPT_TRY"
+        echo "  HP-UX ANSI C ($CFLAGS_OPT)"
+      else
+        echo '  HP-UX Bundled C (no opt)'
+      fi
+    else
+      # GNU C?
+      cat > conftest.c << _EOF_
+int main()
+{
+#ifndef __GNUC__
+   bad code
+#endif
+   return 0;
+}
+_EOF_
+      $CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null
+      if test $? -eq 0; then
+        CFLAGS_OPT='-O3'
+        echo "  GNU C ($CFLAGS_OPT)"
+        # Special Mac OS X shared library "ld" option?
+        if test ` uname -s 2> /dev/null ` = 'Darwin'; then
+          lf='-Wl,-search_paths_first'
+          $CC $CFLAGS $lf conftest.c > /dev/null 2>/dev/null
+          if test $? -eq 0; then
+            LFLAGS2="${LFLAGS2} ${lf}"
+          fi
+          rm -f conftest
+        fi
+      else
+        CFLAGS_OPT='-O'
+        echo "  Other-unknown C ($CFLAGS_OPT)"
+      fi
+    fi
+  fi
+fi
+
+# optimization flags
+if test -n "${CFLAGS_OPT}"; then
+  CFLAGS="${CFLAGS} ${CFLAGS_OPT}"
+  CFLAGS_BZ="${CFLAGS_BZ} ${CFLAGS_OPT}"
+fi
+
+
+# bzip2
+
+echo "Check bzip2 support"
+CC_BZ="${CC}"
+LIB_BZ=''
+if test -n "${IZ_BZIP2}"; then
+  echo "  Check for bzip2 compiled library in IZ_BZIP2 (${IZ_BZIP2})"
+  if test -f "${IZ_BZIP2}/libbz2.a"; then
+#
+#   A bzip2 library built with BZ_NO_STDIO should have an
+#   unresolved external, "bz_internal_error".  The default,
+#   full-function library will not mention it.
+#
+    nm ${IZ_BZIP2}/libbz2.a | grep bz_internal_error > /dev/null
+    if test $? -eq 0; then
+      echo "    Found bzip2 BZ_NO_STDIO library, ${IZ_BZIP2}/libbz2.a"
+    else
+      echo "    Found bzip2 library, ${IZ_BZIP2}/libbz2.a,"
+      echo "      but library not compiled with BZ_NO_STDIO"
+      echo "    WARNING:  We recommend using a bzip2 library compiled"
+      echo "      with BZ_NO_STDIO defined for proper error handling"
+      echo "    Please see the Zip installation instructions in bzip2/install.txt"
+      echo "    Continuing anyway with standard bzip2 library..."
+    fi
+    if test -f "${IZ_BZIP2}/bzlib.h"; then
+      CFLAGS="${CFLAGS} -I${IZ_BZIP2} -DBZIP2_SUPPORT"
+      LFLAGS2="${LFLAGS2} -L${IZ_BZIP2} -lbz2"
+      echo "-- Found bzip2 library - linking in bzip2"
+    else
+      echo "    ${IZ_BZIP2}/bzlib.h not found"
+      echo "-- Since IZ_BZIP2 defined, skipping OS and bzip2 dir checks - no bzip2"
+    fi
+  else
+    echo "    ${IZ_BZIP2}/libbz2.a not found"
+    echo "-- Since IZ_BZIP2 defined, skipping OS and bzip2 checks - no bzip2"
+  fi
+else
+  echo "  Check for bzip2 in bzip2 directory"
+  IZ_BZIP2=bzip2
+  if test -f "${IZ_BZIP2}/libbz2.a"; then
+    nm ${IZ_BZIP2}/libbz2.a | grep bz_internal_error > /dev/null
+    if test $? -eq 0; then
+      echo "    Found bzip2 BZ_NO_STDIO library in bzip2 directory"
+    else
+      echo "    Found bzip2 library in bzip2 directory,"
+      echo "      but not built with the BZ_NO_STDIO option"
+      echo "    WARNING:  We recommend using a bzip2 library compiled"
+      echo "      with BZ_NO_STDIO defined for proper error handling"
+      echo "    Please see the Zip installation instructions"
+      echo "    Continuing anyway with standard bzip2 library..."
+    fi
+  fi
+  if test -f "bzip2/bzlib.h" -a -f "bzip2/libbz2.a"; then
+    CFLAGS="${CFLAGS} -I${IZ_BZIP2} -DBZIP2_SUPPORT"
+    LFLAGS2="${LFLAGS2} -Lbzip2 -lbz2"
+    echo "-- Found bzip2 library - linking in bzip2"
+  else
+    if test -f "bzip2/bzlib.c" -a -f "bzip2/bzlib.h"; then
+      echo "-- No library, but found bzip2 source in bzip2 directory"
+      echo "-- Will try to build bzip2 library from source and link in"
+#
+# Arrange to build a BZ_NO_STDIO bzip2 object library using the
+# same compiler and optimization options as used for Zip, and
+# to compile and link Zip with bzip2.
+#
+      CFLAGS_BZ="${CFLAGS_BZ} -DBZ_NO_STDIO"
+      LIB_BZ="bzip2/libbz2.a"
+      CFLAGS="${CFLAGS} -Ibzip2 -DBZIP2_SUPPORT"
+      LFLAGS2="${LFLAGS2} -Lbzip2 -lbz2"
+    else
+      echo "  Check if OS already has bzip2 library installed"
+      cat > conftest.c << _EOF_
+#include "bzlib.h"
+int main()
+{
+  bz_stream strm;
+  BZ2_bzCompressEnd(&strm);
+  return 0;
+}
+_EOF_
+      $CC $CFLAGS -o conftest conftest.c -lbz2 > /dev/null 2>/dev/null
+      if test $? -eq 0; then
+        echo "-- OS supports bzip2 - linking in bzip2"
+        CFLAGS="${CFLAGS} -DBZIP2_SUPPORT"
+        LFLAGS2="${LFLAGS2} -lbz2"
+      else
+        echo "-- Either bzlib.h or libbz2.a not found - no bzip2"
+      fi
+    fi
+  fi
+fi
+
+
+echo Check for the C preprocessor
+# on SVR4, cc -E does not produce correct assembler files. Need /lib/cpp.
+CPP="${CC} -E"
+# solaris as(1) needs -P, maybe others as well ?
+[ -f /usr/ccs/lib/cpp ] && CPP="/usr/ccs/lib/cpp -P"
+[ -f /usr/lib/cpp ] && CPP=/usr/lib/cpp
+[ -f /lib/cpp ] && CPP=/lib/cpp
+[ -f /usr/bin/cpp ] && CPP=/usr/bin/cpp
+[ -f /xenix ] && CPP="${CC} -E"
+[ -f /lynx.os ] && CPP="${CC} -E"
+
+echo "#include <stdio.h>" > conftest.c
+$CPP conftest.c >/dev/null 2>/dev/null || CPP="${CC} -E"
+
+
+echo Check if we can use asm code
+OBJA=""
+OCRCU8=""
+if eval "$CPP match.S > _match.s 2>/dev/null"; then
+  if test ! -s _match.s || grep error < _match.s > /dev/null; then
+    :
+  elif eval "$CC -c _match.s >/dev/null 2>/dev/null" && [ -f _match.o ]; then
+    CFLAGS="${CFLAGS} -DASMV"
+    OBJA="match.o"
+    echo "int foo() { return 0;}" > conftest.c
+    $CC -c conftest.c >/dev/null 2>/dev/null
+    echo Check if compiler generates underlines
+    nm conftest.o | grep "(^|[^_])foo" >/dev/null 2>/dev/null
+    [ $? -eq 0 ] && CPP="${CPP} -DNO_UNDERLINE"
+    if eval "$CPP crc_i386.S > _crc_i386.s 2>/dev/null"; then
+      if eval "$CC -c _crc_i386.s >/dev/null 2>/dev/null" && [ -f _crc_i386.o ]
+      then
+        OBJA="$OBJA crc_i386.o"
+        OCRCU8="crc_i386.o"
+        CFLAGS="${CFLAGS} -DASM_CRC"
+      fi
+    fi
+  fi
+fi
+rm -f _match.s _match.o _crc_i386.s _crc_i386.o
+
+
+# ANSI options for compilers that don't have __STDC__ defined by default
+# Currently HPUX, pyramid, Dynix, AIX, OSF/1 and ultrix
+
+echo Check for ANSI options
+cat > conftest.c << _EOF_
+int main()
+{
+#ifndef __STDC__
+   forget it
+#endif
+   return 0;
+}
+_EOF_
+$CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null
+if [ $? -ne 0 ]; then
+  for OPT in -Ae -Xa -qlanglvl=ansi -std1 -std
+  do
+    $CC $CFLAGS $OPT -c conftest.c > /dev/null 2>/dev/null
+    [ $? -eq 0 ] && CFLAGS="${CFLAGS} ${OPT}" && break
+  done
+fi
+
+
+echo Check for prototypes
+echo "int main(int argc, char *argv[]) { return 0; }" > conftest.c
+$CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_PROTO"
+
+# const check currently handles mips cc and non ANSI compilers.
+# does it need more ?
+echo Check the handling of const
+cat > conftest.c << _EOF_
+typedef int charset[2];
+int main()
+{
+  const charset x;
+  const char *foo;
+  return 0;
+}
+_EOF_
+$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_CONST"
+
+
+echo Check for time_t
+cat > conftest.c << _EOF_
+#include <sys/types.h>
+#include <time.h>
+int main()
+{
+  time_t t;
+  return 0;
+}
+_EOF_
+$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_TIME_T"
+
+
+echo Check for size_t
+cat > conftest.c << _EOF_
+#include <sys/types.h>
+int main()
+{
+  size_t s;
+  return 0;
+}
+_EOF_
+$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_SIZE_T"
+
+
+echo Check for off_t
+cat > conftest.c << _EOF_
+#include <sys/types.h>
+int main()
+{
+  off_t s;
+  return 0;
+}
+_EOF_
+$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_OFF_T"
+
+
+echo Check size of UIDs and GIDs
+echo "(Now zip stores variable size UIDs/GIDs using a new extra field.  This"
+echo " tests if this OS uses 16-bit UIDs/GIDs and so if the old 16-bit storage"
+echo " should also be used for backward compatibility.)"
+# Added 2008-04-15 CS
+cat > conftest.c << _EOF_
+# define _LARGEFILE_SOURCE          /* some OSes need this for fseeko */
+# define _LARGEFILE64_SOURCE
+# define _FILE_OFFSET_BITS 64       /* select default interface as 64 bit */
+# define _LARGE_FILES               /* some OSes need this for 64-bit off_t */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+int main()
+{
+  struct stat s;
+
+  printf("  s.st_uid is %u bytes\n", sizeof(s.st_uid));
+  printf("  s.st_gid is %u bytes\n", sizeof(s.st_gid));
+
+  /* see if have 16-bit UID */
+  if (sizeof(s.st_uid) != 2) {
+    return 1;
+  }
+  /* see if have 16-bit GID */
+  if (sizeof(s.st_gid) != 2) {
+    return 2;
+  }
+  return 3;
+}
+_EOF_
+# compile it
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+if [ $? -ne 0 ]; then
+  echo -- UID/GID test failed on compile - disabling old 16-bit UID/GID support
+  CFLAGS="${CFLAGS} -DUIDGID_NOT_16BIT"
+else
+# run it
+  ./conftest
+  r=$?
+  if [ $r -eq 1 ]; then
+    echo -- UID not 2 bytes - disabling old 16-bit UID/GID support
+    CFLAGS="${CFLAGS} -DUIDGID_NOT_16BIT"
+  elif [ $r -eq 2 ]; then
+    echo -- GID not 2 bytes - disabling old 16-bit UID/GID support
+    CFLAGS="${CFLAGS} -DUIDGID_NOT_16BIT"
+  elif [ $r -eq 3 ]; then
+    echo -- 16-bit UIDs and GIDs - keeping old 16-bit UID/GID support
+  else
+    echo -- test failed - conftest returned $r - disabling old 16-bit UID/GID support
+    CFLAGS="${CFLAGS} -DUIDGID_NOT_16BIT"
+  fi
+fi
+
+
+# Now we set the 64-bit file environment and check the size of off_t
+# Added 11/4/2003 EG
+# Revised 8/12/2004 EG
+
+echo Check for Large File Support
+cat > conftest.c << _EOF_
+# define _LARGEFILE_SOURCE       /* some OSes need this for fseeko */
+# define _LARGEFILE64_SOURCE
+# define _FILE_OFFSET_BITS 64       /* select default interface as 64 bit */
+# define _LARGE_FILES        /* some OSes need this for 64-bit off_t */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+int main()
+{
+  off_t offset;
+  struct stat s;
+  /* see if have 64-bit off_t */
+  if (sizeof(offset) < 8)
+    return 1;
+  printf("  off_t is %d bytes\n", sizeof(off_t));
+  /* see if have 64-bit stat */
+  if (sizeof(s.st_size) < 8) {
+    printf("  s.st_size is %d bytes\n", sizeof(s.st_size));
+    return 2;
+  }
+  return 3;
+}
+_EOF_
+# compile it
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+if [ $? -ne 0 ]; then
+  echo -- no Large File Support
+else
+# run it
+  ./conftest
+  r=$?
+  if [ $r -eq 1 ]; then
+    echo -- no Large File Support - no 64-bit off_t
+  elif [ $r -eq 2 ]; then
+    echo -- no Large File Support - no 64-bit stat
+  elif [ $r -eq 3 ]; then
+    echo -- yes we have Large File Support!
+    CFLAGS="${CFLAGS} -DLARGE_FILE_SUPPORT"
+  else
+    echo -- no Large File Support - conftest returned $r
+  fi
+fi
+
+
+# Check for wide char for Unicode support
+# Added 11/24/2005 EG
+
+echo Check for wide char support
+cat > conftest.c << _EOF_
+#include <stdlib.h>
+#include <stdio.h>
+int main()
+{
+  int wsize;
+  wchar_t *wide_string;
+
+  if ((wide_string = (wchar_t *)malloc(4 * sizeof(wchar_t))) == NULL) {
+    return 0;
+  }
+  /* get wide string */
+  wsize = mbstowcs(wide_string, "foo", 3);
+  wide_string[wsize] = (wchar_t) NULL;
+  return 1;
+}
+_EOF_
+# compile it
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+# OCRCU8 is used by all utilities if Unicode is enabled
+# OCRCTB is only used by zipcloak
+if [ $? -ne 0 ]; then
+  echo -- no Unicode support
+  OCRCU8=""
+  OCRCTB="crc32_.o"
+else
+# have wide char support
+  echo -- have wchar_t - enabling Unicode support
+  CFLAGS="${CFLAGS} -DUNICODE_SUPPORT"
+  OCRCU8="crc32_.o ${OCRCU8}"
+  OCRCTB=""
+fi
+
+
+# from configure 2.4i (Onno) 12/5/04
+
+echo Check for gcc no-builtin flag
+# -fno-builtin since version 2
+cat > conftest.c << _EOF_
+int main()
+{
+#if __GNUC__ >= 2
+   return 0;
+#else
+   forget it
+#endif
+}
+_EOF_
+$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null
+[ $? -eq 0 ] && BFLAG="-fno-builtin"
+
+
+# Check for missing functions
+# add NO_'function_name' to flags if missing
+
+for func in rmdir strchr strrchr rename mktemp mktime mkstemp
+do
+  echo Check for $func
+  echo "int main(){ $func(); return 0; }" > conftest.c
+  $CC $BFLAG -o conftest conftest.c >/dev/null 2>/dev/null
+  [ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_`echo $func | tr '[a-z]' '[A-Z]'`"
+done
+
+
+echo Check for memset
+echo "int main(){ char k; memset(&k,0,0); return 0; }" > conftest.c
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DZMEM"
+
+
+echo Check for memmove
+cat > conftest.c << _EOF_
+#include <string.h>
+int main() { int a; int b = 0; memmove( &a, &b, sizeof( a)); return a; }
+_EOF_
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNEED_MEMMOVE"
+
+
+echo Check for strerror
+cat > conftest.c << _EOF_
+#include <string.h>
+int main() { strerror( 0); return 0; }
+_EOF_
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNEED_STRERROR"
+
+echo Check for errno declaration
+cat > conftest.c << _EOF_
+#include <errno.h>
+main()
+{
+  errno = 0;
+  return 0;
+}
+_EOF_
+$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_ERRNO"
+
+
+echo Check for directory libraries
+cat > conftest.c << _EOF_
+int main() { return closedir(opendir(".")); }
+_EOF_
+
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+if [ $? -ne 0 ]; then
+  OPT=""
+  for lib in ndir dir ucb bsd BSD PW x dirent
+  do
+    $CC -o conftest conftest.c -l$lib >/dev/null 2>/dev/null
+    [ $? -eq 0 ] && OPT=-l$lib && break
+  done
+  if [ ${OPT} ]; then
+    LFLAGS2="${LFLAGS2} ${OPT}"
+  else
+    CFLAGS="${CFLAGS} -DNO_DIR"
+  fi
+fi
+
+
+# Dynix/ptx 1.3 needed this
+
+echo Check for readlink
+echo "int main(){ return readlink(); }" > conftest.c
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+if [ $? -ne 0 ]; then
+  $CC -o conftest conftest.c -lseq >/dev/null 2>/dev/null
+  [ $? -eq 0 ] && LFLAGS2="${LFLAGS2} -lseq"
+fi
+
+
+echo Check for directory include file
+OPT=""
+for inc in dirent.h sys/ndir.h ndir.h sys/dir.h
+do
+   echo "#include <$inc>" > conftest.c
+   $CPP conftest.c > /dev/null 2>/dev/null
+   [ $? -eq 0 ] && OPT="-DHAVE_`echo $inc | tr '[a-z]./' '[A-Z]__'`" && break
+done
+CFLAGS="${CFLAGS} ${OPT}"
+
+
+echo Check for nonexistent include files
+for inc in stdlib.h stddef.h unistd.h fcntl.h string.h
+do
+   echo "#include <$inc>" > conftest.c
+   $CPP conftest.c >/dev/null 2>/dev/null
+   [ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_`echo $inc | tr '[a-z]./' '[A-Z]__'`"
+done
+
+
+echo Check for term I/O include file
+OPT=""
+for inc in termios.h termio.h sgtty.h
+do
+   echo "#include <$inc>" > conftest.c
+   $CPP conftest.c > /dev/null 2>/dev/null
+   [ $? -eq 0 ] && OPT="-DHAVE_`echo $inc | tr '[a-z]./' '[A-Z]__'`" && break
+done
+CFLAGS="${CFLAGS} ${OPT}"
+
+
+# needed for AIX (and others ?) when mmap is used
+
+echo Check for valloc
+cat > conftest.c << _EOF_
+main()
+{
+#ifdef MMAP
+    valloc();
+#endif
+}
+_EOF_
+$CC ${CFLAGS} -c conftest.c > /dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_VALLOC"
+
+
+echo Check for /usr/local/bin and /usr/local/man
+BINDIR=$HOME/bin
+[ -d /usr/local/bin ] && BINDIR=/usr/local/bin
+
+MANDIR=manl
+[ -d /usr/man/manl ]       && MANDIR=/usr/man/manl
+[ -d /usr/local/man/manl ] && MANDIR=/usr/local/man/manl
+[ -d /usr/local/man/man1 ] && MANDIR=/usr/local/man/man1
+
+
+echo Check for OS-specific flags
+if [ -f /usr/bin/hostinfo ]; then
+  if /usr/bin/hostinfo | grep NeXT > /dev/null; then
+    CFLAGS="${CFLAGS} -posix"
+    LFLAGS1="${LFLAGS1} -posix -object"
+  fi
+# XXX ATT6300, Cray
+elif [ -f /xenix ]; then
+  if uname -p | grep 286 > /dev/null; then
+    CFLAGS="${CFLAGS} -LARGE -Mel2 -DMEDIUM_MEM -DWSIZE=16384 -DNO_VOID"
+    LFLAGS1="${LFLAGS1} -LARGE -Mel2"
+  fi
+elif uname -X >/dev/null 2>/dev/null; then
+# SCO shared library check
+  echo "int main() { return 0;}" > conftest.c
+  $CC -o conftest conftest.c -lc_s -nointl >/dev/null 2> /dev/null
+  [ $? -eq 0 ] && LFLAGS2="-lc_s -nointl"
+else
+  SYSTEM=`uname -s 2>/dev/null` || SYSTEM="unknown"
+  echo "int main() { return 0;}" > conftest.c
+  case $SYSTEM in
+     OSF1|ULTRIX)
+        echo Check for -Olimit option
+        $CC ${CFLAGS} -Olimit 1000 -o conftest conftest.c >/dev/null 2>/dev/null
+        [ $? -eq 0 ] && CFLAGS="${CFLAGS} -Olimit 1000"
+        ;;
+###     HP-UX)
+###        echo Check for +Onolimit option
+###        $CC ${CFLAGS} +Onolimit -o conftest conftest.c >/dev/null 2>/dev/null
+###        [ $? -eq 0 ] && CFLAGS="${CFLAGS} +Onolimit"
+###        ;;
+###     SunOS)
+###        CFLAGS="${CFLAGS} -D_FILE_OFFSET_BITS=64"
+###        ;;
+  esac
+fi
+
+
+echo Check for symbolic links
+ln -s /dev/null null > /dev/null 2>/dev/null || LN=ln
+
+
+rm -f a.out conftest.c conftest.o conftest null
+
+echo CC=\"${CC}\" CFLAGS=\"${CFLAGS}\"  CPP=\"${CPP}\" OBJA=\"${OBJA}\" \
+       OCRCU8=\"${OCRCU8}\" OCRCTB=\"${OCRCTB}\" \
+       BINDIR=${BINDIR} MANDIR=${MANDIR} LFLAGS1=\"${LFLAGS1}\" \
+       LFLAGS2=\"${LFLAGS2}\" LN=\"${LN}\" \
+       CC_BZ=\"${CC_BZ}\" CFLAGS_BZ=\"${CFLAGS_BZ}\" \
+       IZ_BZIP2=\"${IZ_BZIP2}\" LIB_BZ=\"${LIB_BZ}\" > flags
+
diff --git a/unix/osdep.h b/unix/osdep.h
new file mode 100644 (file)
index 0000000..10f8ee9
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+  unix/osdep.h - Zip 3
+
+  Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2005-Feb-10 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+#ifdef NO_LARGE_FILE_SUPPORT
+# ifdef LARGE_FILE_SUPPORT
+#  undef LARGE_FILE_SUPPORT
+# endif
+#endif
+
+#ifdef LARGE_FILE_SUPPORT
+  /* 64-bit Large File Support */
+
+  /* The following Large File Summit (LFS) defines turn on large file support on
+     Linux (probably 2.4 or later kernel) and many other unixen */
+
+# define _LARGEFILE_SOURCE      /* some OSes need this for fseeko */
+# define _LARGEFILE64_SOURCE
+# define _FILE_OFFSET_BITS 64   /* select default interface as 64 bit */
+# define _LARGE_FILES           /* some OSes need this for 64-bit off_t */
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* printf format size prefix for zoff_t values */
+#ifdef LARGE_FILE_SUPPORT
+# define ZOFF_T_FORMAT_SIZE_PREFIX "ll"
+#else
+# define ZOFF_T_FORMAT_SIZE_PREFIX "l"
+#endif
+
+#ifdef NO_OFF_T
+  typedef long zoff_t;
+  typedef unsigned long uzoff_t;
+#else
+  typedef off_t zoff_t;
+# if defined(LARGE_FILE_SUPPORT) && !(defined(__alpha) && defined(__osf__))
+  typedef unsigned long long uzoff_t;
+# else
+  typedef unsigned long uzoff_t;
+# endif
+#endif
+  typedef struct stat z_stat;
+
+
+/* Automatically set ZIP64_SUPPORT if LFS */
+
+#ifdef LARGE_FILE_SUPPORT
+# ifndef NO_ZIP64_SUPPORT
+#   ifndef ZIP64_SUPPORT
+#     define ZIP64_SUPPORT
+#   endif
+# else
+#   ifdef ZIP64_SUPPORT
+#     undef ZIP64_SUPPORT
+#   endif
+# endif
+#endif
+
+
+/* Process files in binary mode */
+#if defined(__DJGPP__) || defined(__CYGWIN__)
+#  define FOPR "rb"
+#  define FOPM "r+b"
+#  define FOPW "wb"
+#endif
+
+
+/* Enable the "UT" extra field (time info) */
+#if !defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME)
+#  define USE_EF_UT_TIME
+#endif
diff --git a/unix/unix.c b/unix/unix.c
new file mode 100644 (file)
index 0000000..f4d655d
--- /dev/null
@@ -0,0 +1,1100 @@
+/*
+  unix/unix.c - Zip 3
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#ifndef UTIL    /* the companion #endif is a bit of ways down ... */
+
+#include <time.h>
+
+#if defined(MINIX) || defined(__mpexl)
+#  ifdef S_IWRITE
+#    undef S_IWRITE
+#  endif /* S_IWRITE */
+#  define S_IWRITE S_IWUSR
+#endif /* MINIX */
+
+#if (!defined(S_IWRITE) && defined(S_IWUSR))
+#  define S_IWRITE S_IWUSR
+#endif
+
+#if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
+#  include <dirent.h>
+#else /* !HAVE_DIRENT_H */
+#  ifdef HAVE_NDIR_H
+#    include <ndir.h>
+#  endif /* HAVE_NDIR_H */
+#  ifdef HAVE_SYS_NDIR_H
+#    include <sys/ndir.h>
+#  endif /* HAVE_SYS_NDIR_H */
+#  ifdef HAVE_SYS_DIR_H
+#    include <sys/dir.h>
+#  endif /* HAVE_SYS_DIR_H */
+#  ifndef dirent
+#    define dirent direct
+#  endif
+#endif /* HAVE_DIRENT_H || _POSIX_VERSION */
+
+#define PAD 0
+#define PATH_END '/'
+
+/* Library functions not in (most) header files */
+
+#ifdef _POSIX_VERSION
+#  include <utime.h>
+#else
+   int utime OF((char *, time_t *));
+#endif
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Local functions */
+local char *readd OF((DIR *));
+
+
+#ifdef NO_DIR                    /* for AT&T 3B1 */
+#include <sys/dir.h>
+#ifndef dirent
+#  define dirent direct
+#endif
+typedef FILE DIR;
+/*
+**  Apparently originally by Rich Salz.
+**  Cleaned up and modified by James W. Birdsall.
+*/
+
+#define opendir(path) fopen(path, "r")
+
+struct dirent *readdir(dirp)
+DIR *dirp;
+{
+  static struct dirent entry;
+
+  if (dirp == NULL)
+    return NULL;
+  for (;;)
+    if (fread (&entry, sizeof (struct dirent), 1, dirp) == 0)
+      return NULL;
+    else if (entry.d_ino)
+      return (&entry);
+} /* end of readdir() */
+
+#define closedir(dirp) fclose(dirp)
+#endif /* NO_DIR */
+
+
+local char *readd(d)
+DIR *d;                 /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+   no more entries or an error occurs. */
+{
+  struct dirent *e;
+
+  e = readdir(d);
+  return e == NULL ? (char *) NULL : e->d_name;
+}
+
+int procname(n, caseflag)
+char *n;                /* name to process */
+int caseflag;           /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  DIR *d;               /* directory stream from opendir() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  z_stat s;             /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (LSSTAT(n, &s))
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+#ifdef OS390
+  if (S_ISREG(s.st_mode) || S_ISLNK(s.st_mode))
+#else
+#  ifdef S_IFLNK
+  if ((s.st_mode & S_IFREG) == S_IFREG || (s.st_mode & S_IFLNK) == S_IFLNK)
+#  else
+  if ((s.st_mode & S_IFREG) == S_IFREG)
+#  endif
+#endif
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0, caseflag)) != ZE_OK)
+      return m;
+  }
+#ifdef OS390
+  else if (S_ISDIR(s.st_mode))
+#else
+  else if ((s.st_mode & S_IFDIR) == S_IFDIR)
+#endif
+  {
+    /* Add trailing / to the directory name */
+    if ((p = malloc(strlen(n)+2)) == NULL)
+      return ZE_MEM;
+    if (strcmp(n, ".") == 0) {
+      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      strcpy(p, n);
+      a = p + strlen(p);
+      if (a[-1] != '/')
+        strcpy(a, "/");
+      if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+        free((zvoid *)p);
+        return m;
+      }
+    }
+    /* recurse into directory */
+    if (recurse && (d = opendir(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if (strcmp(e, ".") && strcmp(e, ".."))
+        {
+          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+          {
+            closedir(d);
+            free((zvoid *)p);
+            return ZE_MEM;
+          }
+          strcat(strcpy(a, p), e);
+          if ((m = procname(a, caseflag)) != ZE_OK)   /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", a);
+            else
+              ziperr(m, a);
+          }
+          free((zvoid *)a);
+        }
+      }
+      closedir(d);
+    }
+    free((zvoid *)p);
+  } /* (s.st_mode & S_IFDIR) */
+#ifdef OS390
+  else if (S_ISFIFO(s.st_mode))
+#else
+  else if ((s.st_mode & S_IFIFO) == S_IFIFO)
+#endif
+  {
+    if (allow_fifo) {
+      /* FIFO (Named Pipe) - handle as normal file */
+      /* add or remove name of FIFO */
+      /* zip will stop if FIFO is open and wait for pipe to be fed and closed */
+      if (noisy) zipwarn("Reading FIFO (Named Pipe): ", n);
+      if ((m = newname(n, 0, caseflag)) != ZE_OK)
+        return m;
+    } else {
+      zipwarn("ignoring FIFO (Named Pipe) - use -FI to read: ", n);
+      return ZE_OK;
+    }
+  } /* S_IFIFO */
+  else
+    zipwarn("ignoring special file: ", n);
+  return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x;                /* external file name */
+int isdir;              /* input: x is a directory */
+int *pdosflag;          /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t = NULL;       /* shortened name */
+  int dosflag;
+
+  dosflag = dosify;     /* default for non-DOS and non-OS/2 */
+
+  /* Find starting point in name before doing malloc */
+  /* Strip "//host/share/" part of a UNC name */
+  if (!strncmp(x,"//",2) && (x[2] != '\0' && x[2] != '/')) {
+    n = x + 2;
+    while (*n != '\0' && *n != '/')
+      n++;              /* strip host name */
+    if (*n != '\0') {
+      n++;
+      while (*n != '\0' && *n != '/')
+        n++;            /* strip `share' name */
+    }
+    if (*n != '\0')
+      t = n + 1;
+  } else
+      t = x;
+  while (*t == '/')
+    t++;                /* strip leading '/' chars to get a relative path */
+  while (*t == '.' && t[1] == '/')
+    t += 2;             /* strip redundant leading "./" sections */
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+  if (!pathput)
+    t = last(t, PATH_END);
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL)
+    return NULL;
+  strcpy(n, t);
+
+  if (dosify)
+    msname(n);
+
+#ifdef EBCDIC
+  strtoasc(n, n);       /* here because msname() needs native coding */
+#endif
+
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+
+  if (isdir) return n;  /* avoid warning on unused variable */
+  return n;
+}
+
+char *in2ex(n)
+char *n;                /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+    return NULL;
+#ifdef EBCDIC
+  strtoebc(x, n);
+#else
+  strcpy(x, n);
+#endif
+  return x;
+}
+
+/*
+ * XXX use ztimbuf in both POSIX and non POSIX cases ?
+ */
+void stamp(f, d)
+char *f;                /* name of file to change */
+ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+#ifdef _POSIX_VERSION
+  struct utimbuf u;     /* argument for utime()  const ?? */
+#else
+  time_t u[2];          /* argument for utime() */
+#endif
+
+  /* Convert DOS time to time_t format in u */
+#ifdef _POSIX_VERSION
+  u.actime = u.modtime = dos2unixtime(d);
+  utime(f, &u);
+#else
+  u[0] = u[1] = dos2unixtime(d);
+  utime(f, u);
+#endif
+
+}
+
+ulg filetime(f, a, n, t)
+  char *f;                /* name of file to get info on */
+  ulg *a;                 /* return value: file attributes */
+  zoff_t *n;              /* return value: file size */
+  iztimes *t;             /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  z_stat s;         /* results of stat() */
+  /* converted to pointer from using FNMAX - 11/8/04 EG */
+  char *name;
+  int len = strlen(f);
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+  if (strcmp(f, "-") == 0) {
+    if (zfstat(fileno(stdin), &s) != 0) {
+      free(name);
+      error("fstat(stdin)");
+    }
+  }
+  else if (LSSTAT(name, &s) != 0) {
+    /* Accept about any file kind including directories
+     * (stored with trailing / with -r option)
+     */
+    free(name);
+    return 0;
+  }
+  free(name);
+
+  if (a != NULL) {
+#ifndef OS390
+    *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+#else
+/*
+**  The following defines are copied from the unizip source and represent the
+**  legacy Unix mode flags.  These fixed bit masks are no longer required
+**  by XOPEN standards - the S_IS### macros being the new recommended method.
+**  The approach here of setting the legacy flags by testing the macros should
+**  work under any _XOPEN_SOURCE environment (and will just rebuild the same bit
+**  mask), but is required if the legacy bit flags differ from legacy Unix.
+*/
+#define UNX_IFDIR      0040000     /* Unix directory */
+#define UNX_IFREG      0100000     /* Unix regular file */
+#define UNX_IFSOCK     0140000     /* Unix socket (BSD, not SysV or Amiga) */
+#define UNX_IFLNK      0120000     /* Unix symbolic link (not SysV, Amiga) */
+#define UNX_IFBLK      0060000     /* Unix block special       (not Amiga) */
+#define UNX_IFCHR      0020000     /* Unix character special   (not Amiga) */
+#define UNX_IFIFO      0010000     /* Unix fifo    (BCC, not MSC or Amiga) */
+    {
+    mode_t legacy_modes;
+
+    /* Initialize with permission bits--which are not implementation-optional */
+    legacy_modes = s.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX);
+    if (S_ISDIR(s.st_mode))
+      legacy_modes |= UNX_IFDIR;
+    if (S_ISREG(s.st_mode))
+      legacy_modes |= UNX_IFREG;
+    if (S_ISLNK(s.st_mode))
+      legacy_modes |= UNX_IFLNK;
+    if (S_ISBLK(s.st_mode))
+      legacy_modes |= UNX_IFBLK;
+    if (S_ISCHR(s.st_mode))
+      legacy_modes |= UNX_IFCHR;
+    if (S_ISFIFO(s.st_mode))
+      legacy_modes |= UNX_IFIFO;
+    if (S_ISSOCK(s.st_mode))
+      legacy_modes |= UNX_IFSOCK;
+    *a = ((ulg)legacy_modes << 16) | !(s.st_mode & S_IWRITE);
+    }
+#endif
+    if ((s.st_mode & S_IFMT) == S_IFDIR) {
+      *a |= MSDOS_DIR_ATTR;
+    }
+  }
+  if (n != NULL)
+    *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = t->mtime;   /* best guess, (s.st_ctime: last status change!!) */
+  }
+  return unix2dostime(&s.st_mtime);
+}
+
+
+#ifndef QLZIP /* QLZIP Unix2QDOS cross-Zip supplies an extended variant */
+
+int set_new_unix_extra_field(z, s)
+  struct zlist far *z;
+  z_stat *s;
+  /* New unix extra field.
+     Currently only UIDs and GIDs are stored. */
+{
+  int uid_size;
+  int gid_size;
+  int ef_data_size;
+  char *extra;
+  char *cextra;
+  ulg id;
+  int b;
+
+  uid_size = sizeof(s->st_uid);
+  gid_size = sizeof(s->st_gid);
+
+/* New extra field
+   tag       (2 bytes)
+   size      (2 bytes)
+   version   (1 byte)
+   uid_size  (1 byte - size in bytes)
+   uid       (variable)
+   gid_size  (1 byte - size in bytes)
+   gid       (variable)
+ */
+   
+  ef_data_size = 1 + 1 + uid_size + 1 + gid_size;
+
+  if ((extra = (char *)malloc(z->ext + 4 + ef_data_size)) == NULL)
+    return ZE_MEM;
+  if ((cextra = (char *)malloc(z->ext + 4 + ef_data_size)) == NULL)
+    return ZE_MEM;
+
+  if (z->ext)
+    memcpy(extra, z->extra, z->ext);
+  if (z->cext)
+    memcpy(cextra, z->cextra, z->cext);
+
+  free(z->extra);
+  z->extra = extra;
+  free(z->cextra);
+  z->cextra = cextra;
+
+  z->extra[z->ext + 0] = 'u';
+  z->extra[z->ext + 1] = 'x';
+  z->extra[z->ext + 2] = (char)ef_data_size;     /* length of data part */
+  z->extra[z->ext + 3] = 0;
+  z->extra[z->ext + 4] = 1;                      /* version */
+
+  /* UID */
+  z->extra[z->ext + 5] = (char)(uid_size);       /* uid size in bytes */
+  b = 6;
+  id = (ulg)(s->st_uid);
+  z->extra[z->ext + b] = (char)(id & 0xFF);
+  if (uid_size > 1) {
+    b++;
+    id = id >> 8;
+    z->extra[z->ext + b] = (char)(id & 0xFF);
+    if (uid_size > 2) {
+      b++;
+      id = id >> 8;
+      z->extra[z->ext + b] = (char)(id & 0xFF);
+      b++;
+      id = id >> 8;
+      z->extra[z->ext + b] = (char)(id & 0xFF);
+      if (uid_size == 8) {
+        b++;
+        id = id >> 8;
+        z->extra[z->ext + b] = (char)(id & 0xFF);
+        b++;
+        id = id >> 8;
+        z->extra[z->ext + b] = (char)(id & 0xFF);
+        b++;
+        id = id >> 8;
+        z->extra[z->ext + b] = (char)(id & 0xFF);
+        b++;
+        id = id >> 8;
+        z->extra[z->ext + b] = (char)(id & 0xFF);
+      }
+    }
+  }
+
+  /* GID */
+  b++;
+  z->extra[z->ext + b] = (char)(gid_size);       /* gid size in bytes */
+  b++;
+  id = (ulg)(s->st_gid);
+  z->extra[z->ext + b] = (char)(id & 0xFF);
+  if (gid_size > 1) {
+    b++;
+    id = id >> 8;
+    z->extra[z->ext + b] = (char)(id & 0xFF);
+    if (gid_size > 2) {
+      b++;
+      id = id >> 8;
+      z->extra[z->ext + b] = (char)(id & 0xFF);
+      b++;
+      id = id >> 8;
+      z->extra[z->ext + b] = (char)(id & 0xFF);
+      if (gid_size == 8) {
+        b++;
+        id = id >> 8;
+        z->extra[z->ext + b] = (char)(id & 0xFF);
+        b++;
+        id = id >> 8;
+        z->extra[z->ext + b] = (char)(id & 0xFF);
+        b++;
+        id = id >> 8;
+        z->extra[z->ext + b] = (char)(id & 0xFF);
+        b++;
+        id = id >> 8;
+        z->extra[z->ext + b] = (char)(id & 0xFF);
+      }
+    }
+  }
+
+  /* copy local extra field to central directory extra field */
+  memcpy((z->cextra) + z->cext, (z->extra) + z->ext, 4 + ef_data_size);
+
+  z->ext = z->ext + 4 + ef_data_size;
+  z->cext = z->cext + 4 + ef_data_size;
+
+  return ZE_OK;
+}
+
+
+int set_extra_field(z, z_utim)
+  struct zlist far *z;
+  iztimes *z_utim;
+  /* store full data in local header but just modification time stamp info
+     in central header */
+{
+  z_stat s;
+  char *name;
+  int len = strlen(z->name);
+
+  /* For the full sized UT local field including the UID/GID fields, we
+   * have to stat the file again. */
+
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "set_extra_field");
+  }
+  strcpy(name, z->name);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+  if (LSSTAT(name, &s)) {
+    free(name);
+    return ZE_OPEN;
+  }
+  free(name);
+
+#define EB_L_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(2))
+#define EB_C_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(1))
+
+/* The flag UIDGID_NOT_16BIT should be set by the pre-compile configuration
+   script when it detects st_uid or st_gid sizes differing from 16-bit.
+ */
+#ifndef UIDGID_NOT_16BIT
+  /* The following "second-level" check for st_uid and st_gid members being
+     16-bit wide is only added as a safety precaution in case the "first-level"
+     check failed to define the UIDGID_NOT_16BIT symbol.
+     The first-level check should have been implemented in the automatic
+     compile configuration process.
+   */
+# ifdef UIDGID_ARE_16B
+#  undef UIDGID_ARE_16B
+# endif
+  /* The following expression is a compile-time constant and should (hopefully)
+     get optimized away by any sufficiently intelligent compiler!
+   */
+# define UIDGID_ARE_16B  (sizeof(s.st_uid) == 2 && sizeof(s.st_gid) == 2)
+
+# define EB_L_UX2_SIZE   (EB_HEADSIZE + EB_UX2_MINLEN)
+# define EB_C_UX2_SIZE   EB_HEADSIZE
+# define EF_L_UNIX_SIZE  (EB_L_UT_SIZE + (UIDGID_ARE_16B ? EB_L_UX2_SIZE : 0))
+# define EF_C_UNIX_SIZE  (EB_C_UT_SIZE + (UIDGID_ARE_16B ? EB_C_UX2_SIZE : 0))
+#else
+# define EF_L_UNIX_SIZE EB_L_UT_SIZE
+# define EF_C_UNIX_SIZE EB_C_UT_SIZE
+#endif /* !UIDGID_NOT_16BIT */
+
+  if ((z->extra = (char *)malloc(EF_L_UNIX_SIZE)) == NULL)
+    return ZE_MEM;
+  if ((z->cextra = (char *)malloc(EF_C_UNIX_SIZE)) == NULL)
+    return ZE_MEM;
+
+  z->extra[0]  = 'U';
+  z->extra[1]  = 'T';
+  z->extra[2]  = (char)EB_UT_LEN(2);    /* length of data part of local e.f. */
+  z->extra[3]  = 0;
+  z->extra[4]  = EB_UT_FL_MTIME | EB_UT_FL_ATIME;    /* st_ctime != creation */
+  z->extra[5]  = (char)(s.st_mtime);
+  z->extra[6]  = (char)(s.st_mtime >> 8);
+  z->extra[7]  = (char)(s.st_mtime >> 16);
+  z->extra[8]  = (char)(s.st_mtime >> 24);
+  z->extra[9]  = (char)(s.st_atime);
+  z->extra[10] = (char)(s.st_atime >> 8);
+  z->extra[11] = (char)(s.st_atime >> 16);
+  z->extra[12] = (char)(s.st_atime >> 24);
+
+#ifndef UIDGID_NOT_16BIT
+  /* Only store the UID and GID in the old Ux extra field if the runtime
+     system provides them in 16-bit wide variables.  */
+  if (UIDGID_ARE_16B) {
+    z->extra[13] = 'U';
+    z->extra[14] = 'x';
+    z->extra[15] = (char)EB_UX2_MINLEN; /* length of data part of local e.f. */
+    z->extra[16] = 0;
+    z->extra[17] = (char)(s.st_uid);
+    z->extra[18] = (char)(s.st_uid >> 8);
+    z->extra[19] = (char)(s.st_gid);
+    z->extra[20] = (char)(s.st_gid >> 8);
+  }
+#endif /* !UIDGID_NOT_16BIT */
+
+  z->ext = EF_L_UNIX_SIZE;
+
+  memcpy(z->cextra, z->extra, EB_C_UT_SIZE);
+  z->cextra[EB_LEN] = (char)EB_UT_LEN(1);
+#ifndef UIDGID_NOT_16BIT
+  if (UIDGID_ARE_16B) {
+    /* Copy header of Ux extra field from local to central */
+    memcpy(z->cextra+EB_C_UT_SIZE, z->extra+EB_L_UT_SIZE, EB_C_UX2_SIZE);
+    z->cextra[EB_LEN+EB_C_UT_SIZE] = 0;
+  }
+#endif
+  z->cext = EF_C_UNIX_SIZE;
+
+#if 0  /* UID/GID presence is now signaled by central EF_IZUNIX2 field ! */
+  /* lower-middle external-attribute byte (unused until now):
+   *   high bit        => (have GMT mod/acc times) >>> NO LONGER USED! <<<
+   *   second-high bit => have Unix UID/GID info
+   * NOTE: The high bit was NEVER used in any official Info-ZIP release,
+   *       but its future use should be avoided (if possible), since it
+   *       was used as "GMT mod/acc times local extra field" flags in Zip beta
+   *       versions 2.0j up to 2.0v, for about 1.5 years.
+   */
+  z->atx |= 0x4000;
+#endif /* never */
+
+  /* new unix extra field */
+  set_new_unix_extra_field(z, &s);
+
+  return ZE_OK;
+}
+
+#endif /* !QLZIP */
+
+
+int deletedir(d)
+char *d;                /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+   Return the result of rmdir(), delete(), or system().
+   For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
+ */
+{
+# ifdef NO_RMDIR
+    /* code from Greg Roelofs, who horked it from Mark Edwards (unzip) */
+    int r, len;
+    char *s;              /* malloc'd string for system command */
+
+    len = strlen(d);
+    if ((s = malloc(len + 34)) == NULL)
+      return 127;
+
+    sprintf(s, "IFS=\" \t\n\" /bin/rmdir %s 2>/dev/null", d);
+    r = system(s);
+    free(s);
+    return r;
+# else /* !NO_RMDIR */
+    return rmdir(d);
+# endif /* ?NO_RMDIR */
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__386BSD__) || \
+    defined(__OpenBSD__) || defined(__bsdi__)
+#include <sys/param.h> /* for the BSD define */
+/* if we have something newer than NET/2 we'll use uname(3) */
+#if (BSD > 199103)
+#include <sys/utsname.h>
+#endif /* BSD > 199103 */
+#endif /* __{Net,Free,Open,386}BSD__ || __bsdi__ */
+
+void version_local()
+{
+#ifdef __GNUC__
+#  ifdef NX_CURRENT_COMPILER_RELEASE
+    char compiler_name[80];
+#  endif
+#else
+#  if (defined( __SUNPRO_C))
+    char compiler_name[33];
+#  else
+#    if (defined( __HP_cc) || defined( __IBMC__))
+    char compiler_name[33];
+#    else
+#      if (defined( __DECC_VER))
+    char compiler_name[33];
+    int compiler_typ;
+#      else
+#        if ((defined(CRAY) || defined(cray)) && defined(_RELEASE))
+    char compiler_name[40];
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef BSD
+# if (BSD > 199103)
+    struct utsname u;
+    char os_name[40];
+# else
+# if defined(__NETBSD__))
+    static ZCONST char *netbsd[] = { "_ALPHA", "", "A", "B" };
+    char os_name[40];
+# endif /* __NETBSD__ */
+# endif /* BSD > 199103 */
+#else /* !BSD */
+#if ((defined(CRAY) || defined(cray)) && defined(_UNICOS))
+    char os_name[40];
+#endif /* (CRAY && defined(_UNICOS)) */
+#endif /* ?BSD */
+
+/* Define the compiler name and version string */
+#ifdef __GNUC__
+#  ifdef NX_CURRENT_COMPILER_RELEASE
+    sprintf(compiler_name, "NeXT DevKit %d.%02d (gcc " __VERSION__ ")",
+     NX_CURRENT_COMPILER_RELEASE/100, NX_CURRENT_COMPILER_RELEASE%100);
+#    define COMPILER_NAME compiler_name
+#  else
+#    define COMPILER_NAME "gcc " __VERSION__
+#  endif
+#else /* !__GNUC__ */
+#  if defined(__SUNPRO_C)
+    sprintf( compiler_name, "Sun C version %x", __SUNPRO_C);
+#    define COMPILER_NAME compiler_name
+#  else
+#    if (defined( __HP_cc))
+    if ((__HP_cc% 100) == 0)
+    {
+      sprintf( compiler_name, "HP C version A.%02d.%02d",
+       (__HP_cc/ 10000), ((__HP_cc% 10000)/ 100));
+    }
+    else
+    {
+      sprintf( compiler_name, "HP C version A.%02d.%02d.%02d",
+       (__HP_cc/ 10000), ((__HP_cc% 10000)/ 100), (__HP_cc% 100));
+    }
+#      define COMPILER_NAME compiler_name
+#    else
+#      if (defined( __DECC_VER))
+    sprintf( compiler_name, "DEC C version %c%d.%d-%03d",
+     ((compiler_typ = (__DECC_VER / 10000) % 10) == 6 ? 'T' :
+     (compiler_typ == 8 ? 'S' : 'V')),
+     __DECC_VER / 10000000,
+     (__DECC_VER % 10000000) / 100000, __DECC_VER % 1000);
+#        define COMPILER_NAME compiler_name
+#      else
+#        if ((defined(CRAY) || defined(cray)) && defined(_RELEASE))
+    sprintf(compiler_name, "cc version %d", _RELEASE);
+#          define COMPILER_NAME compiler_name
+#        else
+#          ifdef __IBMC__
+    sprintf( compiler_name, "IBM C version %d.%d.%d",
+     (__IBMC__/ 100), ((__IBMC__/ 10)% 10), (__IBMC__% 10));
+#            define COMPILER_NAME compiler_name
+#          else
+#            ifdef __VERSION__
+#              define COMPILER_NAME "cc " __VERSION__
+#            else
+#              define COMPILER_NAME "cc "
+#            endif
+#          endif
+#        endif
+#      endif
+#    endif
+#  endif
+#endif /* ?__GNUC__ */
+
+
+/* Define the name to use for the OS we're compiling on */
+#if defined(sgi) || defined(__sgi)
+#  define OS_NAME "Silicon Graphics IRIX"
+#else
+#ifdef sun
+#  ifdef sparc
+#    ifdef __SVR4
+#      define OS_NAME "Sun SPARC/Solaris"
+#    else /* may or may not be SunOS */
+#      define OS_NAME "Sun SPARC"
+#    endif
+#  else
+#  if defined(sun386) || defined(i386)
+#    define OS_NAME "Sun 386i"
+#  else
+#  if defined(mc68020) || defined(__mc68020__)
+#    define OS_NAME "Sun 3"
+#  else /* mc68010 or mc68000:  Sun 2 or earlier */
+#    define OS_NAME "Sun 2"
+#  endif
+#  endif
+#  endif
+#else
+#ifdef __hpux
+#  define OS_NAME "HP-UX"
+#else
+#ifdef __osf__
+#  define OS_NAME "DEC OSF/1"
+#else
+#ifdef _AIX
+#  define OS_NAME "IBM AIX"
+#else
+#ifdef aiws
+#  define OS_NAME "IBM RT/AIX"
+#else
+#if defined(CRAY) || defined(cray)
+#  ifdef _UNICOS
+    sprintf(os_name, "Cray UNICOS release %d", _UNICOS);
+#    define OS_NAME os_name
+#  else
+#    define OS_NAME "Cray UNICOS"
+#  endif
+#else
+#if defined(uts) || defined(UTS)
+#  define OS_NAME "Amdahl UTS"
+#else
+#ifdef NeXT
+#  ifdef mc68000
+#    define OS_NAME "NeXTStep/black"
+#  else
+#    define OS_NAME "NeXTStep for Intel"
+#  endif
+#else
+#if defined(linux) || defined(__linux__)
+#  ifdef __ELF__
+#    define OS_NAME "Linux ELF"
+#  else
+#    define OS_NAME "Linux a.out"
+#  endif
+#else
+#ifdef MINIX
+#  define OS_NAME "Minix"
+#else
+#ifdef M_UNIX
+#  define OS_NAME "SCO Unix"
+#else
+#ifdef M_XENIX
+#  define OS_NAME "SCO Xenix"
+#else
+#ifdef BSD
+# if (BSD > 199103)
+#    define OS_NAME os_name
+    uname(&u);
+    sprintf(os_name, "%s %s", u.sysname, u.release);
+# else
+# ifdef __NetBSD__
+#   define OS_NAME os_name
+#   ifdef NetBSD0_8
+      sprintf(os_name, "NetBSD 0.8%s", netbsd[NetBSD0_8]);
+#   else
+#   ifdef NetBSD0_9
+      sprintf(os_name, "NetBSD 0.9%s", netbsd[NetBSD0_9]);
+#   else
+#   ifdef NetBSD1_0
+      sprintf(os_name, "NetBSD 1.0%s", netbsd[NetBSD1_0]);
+#   endif /* NetBSD1_0 */
+#   endif /* NetBSD0_9 */
+#   endif /* NetBSD0_8 */
+# else
+# ifdef __FreeBSD__
+#    define OS_NAME "FreeBSD 1.x"
+# else
+# ifdef __bsdi__
+#    define OS_NAME "BSD/386 1.0"
+# else
+# ifdef __386BSD__
+#    define OS_NAME "386BSD"
+# else
+#    define OS_NAME "Unknown BSD"
+# endif /* __386BSD__ */
+# endif /* __bsdi__ */
+# endif /* FreeBSD */
+# endif /* NetBSD */
+# endif /* BSD > 199103 */
+#else
+#ifdef __CYGWIN__
+#  define OS_NAME "Cygwin"
+#else
+#if defined(i686) || defined(__i686) || defined(__i686__)
+#  define OS_NAME "Intel 686"
+#else
+#if defined(i586) || defined(__i586) || defined(__i586__)
+#  define OS_NAME "Intel 586"
+#else
+#if defined(i486) || defined(__i486) || defined(__i486__)
+#  define OS_NAME "Intel 486"
+#else
+#if defined(i386) || defined(__i386) || defined(__i386__)
+#  define OS_NAME "Intel 386"
+#else
+#ifdef pyr
+#  define OS_NAME "Pyramid"
+#else
+#if defined(ultrix) || defined(__ultrix)
+#  if defined(mips) || defined(__mips)
+#    define OS_NAME "DEC/MIPS"
+#  else
+#  if defined(vax) || defined(__vax)
+#    define OS_NAME "DEC/VAX"
+#  else /* __alpha? */
+#    define OS_NAME "DEC/Alpha"
+#  endif
+#  endif
+#else
+#ifdef gould
+#  define OS_NAME "Gould"
+#else
+#ifdef MTS
+#  define OS_NAME "MTS"
+#else
+#ifdef __convexc__
+#  define OS_NAME "Convex"
+#else
+#ifdef __QNX__
+#  define OS_NAME "QNX 4"
+#else
+#ifdef __QNXNTO__
+#  define OS_NAME "QNX Neutrino"
+#else
+#ifdef __APPLE__
+#  ifdef __i386__
+#    define OS_NAME "Mac OS X Intel"
+#  else /* __i386__ */
+#    ifdef __ppc__
+#      define OS_NAME "Mac OS X PowerPC"
+#    else /* __ppc__ */
+#      ifdef __ppc64__
+#        define OS_NAME "Mac OS X PowerPC64"
+#      else /* __ppc64__ */
+#        define OS_NAME "Mac OS X"
+#      endif /* __ppc64__ */
+#    endif /* __ppc__ */
+#  endif /* __i386__ */
+#else
+#  define OS_NAME "Unknown"
+#endif /* Apple */
+#endif /* QNX Neutrino */
+#endif /* QNX 4 */
+#endif /* Convex */
+#endif /* MTS */
+#endif /* Gould */
+#endif /* DEC */
+#endif /* Pyramid */
+#endif /* 386 */
+#endif /* 486 */
+#endif /* 586 */
+#endif /* 686 */
+#endif /* Cygwin */
+#endif /* BSD */
+#endif /* SCO Xenix */
+#endif /* SCO Unix */
+#endif /* Minix */
+#endif /* Linux */
+#endif /* NeXT */
+#endif /* Amdahl */
+#endif /* Cray */
+#endif /* RT/AIX */
+#endif /* AIX */
+#endif /* OSF/1 */
+#endif /* HP-UX */
+#endif /* Sun */
+#endif /* SGI */
+
+
+/* Define the compile date string */
+#ifdef __DATE__
+#  define COMPILE_DATE " on " __DATE__
+#else
+#  define COMPILE_DATE ""
+#endif
+
+    printf("Compiled with %s for Unix (%s)%s.\n\n",
+           COMPILER_NAME, OS_NAME, COMPILE_DATE);
+
+} /* end function version_local() */
+
+
+/* 2006-03-23 SMS.
+ * Emergency replacement for strerror().  (Useful on SunOS 4.*.)
+ * Enable by specifying "LOCAL_UNZIP=-DNEED_STRERROR=1" on the "make"
+ * command line.
+ */
+
+#ifdef NEED_STRERROR
+
+char *strerror( err)
+  int err;
+{
+    extern char *sys_errlist[];
+    extern int sys_nerr;
+
+    static char no_msg[ 64];
+
+    if ((err >= 0) && (err < sys_nerr))
+    {
+        return sys_errlist[ err];
+    }
+    else
+    {
+        sprintf( no_msg, "(no message, code = %d.)", err);
+        return no_msg;
+    }
+}
+
+#endif /* def NEED_STRERROR */
+
+
+/* 2006-03-23 SMS.
+ * Emergency replacement for memmove().  (Useful on SunOS 4.*.)
+ * Enable by specifying "LOCAL_UNZIP=-DNEED_MEMMOVE=1" on the "make"
+ * command line.
+ */
+
+#ifdef NEED_MEMMOVE
+
+/* memmove.c -- copy memory.
+   Copy LENGTH bytes from SOURCE to DEST.  Does not null-terminate.
+   In the public domain.
+   By David MacKenzie <djm@gnu.ai.mit.edu>.
+   Adjusted by SMS.
+*/
+
+void *memmove(dest0, source0, length)
+  void *dest0;
+  void const *source0;
+  size_t length;
+{
+    char *dest = dest0;
+    char const *source = source0;
+    if (source < dest)
+        /* Moving from low mem to hi mem; start at end.  */
+        for (source += length, dest += length; length; --length)
+            *--dest = *--source;
+    else if (source != dest)
+    {
+        /* Moving from hi mem to low mem; start at beginning.  */
+        for (; length; --length)
+            *dest++ = *source++;
+    }
+    return dest0;
+}
+
+#endif /* def NEED_MEMMOVE */
diff --git a/unix/zipup.h b/unix/zipup.h
new file mode 100644 (file)
index 0000000..0fc3f89
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+  unix/zipup.h - Zip 3
+
+  Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2005-Feb-10 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+#  define O_RDONLY 0
+#endif
+#ifndef O_BINARY
+#  define O_BINARY 0
+#endif
+#define fhow (O_RDONLY|O_BINARY)
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/util.c b/util.c
new file mode 100644 (file)
index 0000000..73317da
--- /dev/null
+++ b/util.c
@@ -0,0 +1,1450 @@
+/*
+  util.c
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  util.c by Mark Adler.
+ */
+#define __UTIL_C
+
+#include "zip.h"
+#include "ebcdic.h"
+#include <ctype.h>
+
+#ifdef MSDOS16
+#  include <dos.h>
+#endif
+
+#ifdef NO_MKTIME
+#  ifndef IZ_MKTIME_ONLY
+#    define IZ_MKTIME_ONLY      /* only mktime() related code is pulled in */
+#  endif
+#  include "timezone.c"
+#endif
+
+uch upper[256], lower[256];
+/* Country-dependent case map table */
+
+
+#ifndef UTIL /* UTIL picks out namecmp code (all utils) */
+
+/* RISC OS uses # as its single-character wildcard */
+#ifdef RISCOS
+#  define WILDCHR_SINGLE '#'
+#  define WILDCHR_MULTI  '*'
+#  define DIRSEP_CHR '.'
+#endif
+
+#ifdef VMS
+#  define WILDCHR_SINGLE '%'
+#  define WILDCHR_MULTI  '*'
+#  define DIRSEP_CHR '.'
+#endif
+
+#ifndef WILDCHR_SINGLE
+#  define WILDCHR_SINGLE '?'
+#endif
+#ifndef WILDCHR_MULTI
+#  define WILDCHR_MULTI '*'
+#endif
+#ifndef DIRSEP_CHR
+#  define DIRSEP_CHR '/'
+#endif
+
+/* Local functions */
+local int recmatch OF((ZCONST char *, ZCONST char *, int));
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+  local long recmatchw OF((ZCONST wchar_t *, ZCONST wchar_t *, int));
+#endif
+local int count_args OF((char *s));
+
+#ifdef MSDOS16
+  local unsigned ident OF((unsigned chr));
+#endif
+
+#ifndef HAVE_FSEEKABLE
+
+/* 2004-11-12 SMS.
+   Changed to use z*o() functions, and ftell() test from >= 0 to != -1.
+   This solves problems with negative 32-bit offsets, even on small-file
+   products.
+*/
+int fseekable( fp)
+FILE *fp;
+{
+    zoff_t x;
+
+    return (fp == NULL ||
+     ((zfseeko( fp, ((zoff_t) -1), SEEK_CUR) == 0) &&   /* Seek ok. */
+     ((x = zftello( fp)) != ((zoff_t) -1)) &&           /* Tell ok. */
+     (zfseeko( fp, ((zoff_t) 1), SEEK_CUR) == 0) &&     /* Seek ok. */
+     (zftello( fp) == x+ 1)));                          /* Tells agree. */
+}
+#endif /* HAVE_FSEEKABLE */
+
+
+char *isshexp(p)
+char *p;                /* candidate sh expression */
+/* If p is a sh expression, a pointer to the first special character is
+   returned.  Otherwise, NULL is returned. */
+{
+  for (; *p; INCSTR(p))
+    if (*p == '\\' && *(p+1))
+      p++;
+#ifdef VMS
+    else if (*p == WILDCHR_SINGLE || *p == WILDCHR_MULTI)
+#else /* !VMS */
+    else if (*p == WILDCHR_SINGLE || *p == WILDCHR_MULTI || *p == '[')
+#endif /* ?VMS */
+      return p;
+  return NULL;
+}
+
+#ifdef UNICODE_SUPPORT
+# ifdef WIN32
+
+wchar_t *isshexpw(pw)
+  wchar_t *pw;          /* candidate sh expression */
+/* If pw is a sh expression, a pointer to the first special character is
+   returned.  Otherwise, NULL is returned. */
+{
+  for (; *pw; pw++)
+    if (*pw == (wchar_t)'\\' && *(pw+1))
+      pw++;
+    else if (*pw == (wchar_t)WILDCHR_SINGLE || *pw == (wchar_t)WILDCHR_MULTI ||
+             *pw == (wchar_t)'[')
+      return pw;
+  return NULL;
+}
+
+# endif
+#endif
+
+
+#ifdef UNICODE_SUPPORT
+# ifdef WIN32
+
+local long recmatchw(pw, sw, cs)
+ZCONST wchar_t *pw;     /* sh pattern to match */
+ZCONST wchar_t *sw;     /* string to match it to */
+int cs;                 /* flag: force case-sensitive matching */
+/* Recursively compare the sh pattern p with the string s and return 1 if
+   they match, and 0 or 2 if they don't or if there is a syntax error in the
+   pattern.  This routine recurses on itself no deeper than the number of
+   characters in the pattern. */
+{
+  long c;               /* pattern char or start of range in [-] loop */
+  /* Get first character, the pattern for new recmatch calls follows */
+
+  c = (long)*(pw++);
+
+  /* If that was the end of the pattern, match if string empty too */
+  if (c == 0)
+    return *sw == 0;
+
+  /* '?' matches any character (but not an empty string) */
+  if ((wchar_t)c == (wchar_t)WILDCHR_SINGLE) {
+    if (wild_stop_at_dir)
+      return (*sw && *sw != (wchar_t)DIRSEP_CHR) ? recmatchw(pw, sw + 1, cs) : 0;
+    else
+      return *sw ? recmatchw(pw, sw + 1, cs) : 0;
+  }
+
+  /* WILDCHR_MULTI ('*') matches any number of characters, including zero */
+  if (!no_wild && (wchar_t)c == (wchar_t)WILDCHR_MULTI)
+  {
+    if (wild_stop_at_dir) {
+      /* Check for an immediately following WILDCHR_MULTI */
+      if (*pw != (wchar_t)WILDCHR_MULTI) {
+        /* Single WILDCHR_MULTI ('*'): this doesn't match slashes */
+        for (; *sw && *sw != (wchar_t)DIRSEP_CHR; sw++)
+          if ((c = recmatchw(pw, sw, cs)) != 0)
+            return c;
+        /* end of pattern: matched if at end of string, else continue */
+        if (*pw == 0)
+          return (*sw == 0);
+        /* continue to match if at DIRSEP_CHR in pattern, else give up */
+        return (*pw == (wchar_t)DIRSEP_CHR || (*pw == (wchar_t)'\\' &&
+                pw[1] == (wchar_t)DIRSEP_CHR))
+               ? recmatchw(pw, sw, cs) : 2;
+      }
+      /* Two consecutive WILDCHR_MULTI ("**"): this matches DIRSEP_CHR ('/') */
+      pw++;        /* move p past the second WILDCHR_MULTI */
+      /* continue with the normal non-WILD_STOP_AT_DIR code */
+    } /* wild_stop_at_dir */
+
+    /* Not wild_stop_at_dir */
+    if (*pw == 0)
+      return 1;
+    if (!isshexpw((wchar_t *)pw))
+    {
+      /* optimization for rest of pattern being a literal string */
+
+      /* optimization to handle patterns like *.txt */
+      /* if the first char in the pattern is '*' and there */
+      /* are no other shell expression chars, i.e. a literal string */
+      /* then just compare the literal string at the end */
+
+      ZCONST wchar_t *swrest;
+
+      swrest = sw + (wcslen(sw) - wcslen(pw));
+      if (swrest - sw < 0)
+        /* remaining literal string from pattern is longer than rest of
+           test string, there can't be a match
+         */
+        return 0;
+      else
+        /* compare the remaining literal pattern string with the last bytes
+           of the test string to check for a match */
+        return ((cs ? wcscmp(pw, swrest) : _wcsicmp(pw, swrest)) == 0);
+    }
+    else
+    {
+      /* pattern contains more wildcards, continue with recursion... */
+      for (; *sw; sw++)
+        if ((c = recmatchw(pw, sw, cs)) != 0)
+          return c;
+      return 2;           /* 2 means give up--shmatch will return false */
+    }
+  }
+
+  /* Parse and process the list of characters and ranges in brackets */
+  if (!no_wild && allow_regex && (wchar_t)c == '[')
+  {
+    int e;              /* flag true if next char to be taken literally */
+    ZCONST wchar_t *qw; /* pointer to end of [-] group */
+    int r;              /* flag true to match anything but the range */
+
+    if (*sw == 0)                        /* need a character to match */
+      return 0;
+    pw += (r = (*pw == (wchar_t)'!' || *pw == (wchar_t)'^')); /* see if reverse */
+    for (qw = pw, e = 0; *qw; qw++)         /* find closing bracket */
+      if (e)
+        e = 0;
+      else
+        if (*qw == (wchar_t)'\\')
+          e = 1;
+        else if (*qw == (wchar_t)']')
+          break;
+    if (*qw != (wchar_t)']')                      /* nothing matches if bad syntax */
+      return 0;
+    for (c = 0, e = *pw == (wchar_t)'-'; pw < qw; pw++)      /* go through the list */
+    {
+      if (e == 0 && *pw == (wchar_t)'\\')         /* set escape flag if \ */
+        e = 1;
+      else if (e == 0 && *pw == (wchar_t)'-')     /* set start of range if - */
+        c = *(pw-1);
+      else
+      {
+        wchar_t cc = (cs ? *sw : towupper(*sw));
+        wchar_t uc = (wchar_t) c;
+
+        if (*(pw+1) != (wchar_t)'-')
+          for (uc = uc ? uc : *pw; cc <= *pw; uc++)
+            /* compare range */
+            if ((cs ? uc : towupper(uc)) == cc)
+              return r ? 0 : recmatchw(qw + 1, sw + 1, cs);
+        c = e = 0;                      /* clear range, escape flags */
+      }
+    }
+    return r ? recmatchw(qw + 1, sw + 1, cs) : 0;
+                                        /* bracket match failed */
+  }
+
+  /* If escape ('\'), just compare next character */
+  if (!no_wild && (wchar_t)c == (wchar_t)'\\')
+    if ((c = *pw++) == '\0')            /* if \ at end, then syntax error */
+      return 0;
+
+  /* Just a character--compare it */
+  return (cs ? (wchar_t)c == *sw : towupper((wchar_t)c) == towupper(*sw)) ?
+          recmatchw(pw, sw + 1, cs) : 0;
+}
+
+# endif
+#endif
+
+
+local int recmatch(p, s, cs)
+ZCONST char *p;         /* sh pattern to match */
+ZCONST char *s;         /* string to match it to */
+int cs;                 /* flag: force case-sensitive matching */
+/* Recursively compare the sh pattern p with the string s and return 1 if
+   they match, and 0 or 2 if they don't or if there is a syntax error in the
+   pattern.  This routine recurses on itself no deeper than the number of
+   characters in the pattern. */
+{
+  int c;                /* pattern char or start of range in [-] loop */
+  /* Get first character, the pattern for new recmatch calls follows */
+
+  /* This fix provided by akt@m5.dion.ne.jp for Japanese.
+     See 21 July 2006 mail.
+     It only applies when p is pointing to a doublebyte character and
+     things like / and wildcards are not doublebyte.  This probably
+     should not be needed. */
+
+#ifdef _MBCS
+  if (CLEN(p) == 2) {
+    if (CLEN(s) == 2) {
+      return (*p == *s && *(p+1) == *(s+1)) ?
+        recmatch(p + 2, s + 2, cs) : 0;
+    } else {
+      return 0;
+    }
+  }
+#endif /* ?_MBCS */
+
+  c = *POSTINCSTR(p);
+
+  /* If that was the end of the pattern, match if string empty too */
+  if (c == 0)
+    return *s == 0;
+
+  /* '?' (or '%' or '#') matches any character (but not an empty string) */
+  if (c == WILDCHR_SINGLE) {
+    if (wild_stop_at_dir)
+      return (*s && *s != DIRSEP_CHR) ? recmatch(p, s + CLEN(s), cs) : 0;
+    else
+      return *s ? recmatch(p, s + CLEN(s), cs) : 0;
+  }
+
+  /* WILDCHR_MULTI ('*') matches any number of characters, including zero */
+#ifdef AMIGA
+  if (!no_wild && c == '#' && *p == '?')            /* "#?" is Amiga-ese for "*" */
+    c = WILDCHR_MULTI, p++;
+#endif /* AMIGA */
+  if (!no_wild && c == WILDCHR_MULTI)
+  {
+    if (wild_stop_at_dir) {
+      /* Check for an immediately following WILDCHR_MULTI */
+# ifdef AMIGA
+      if ((c = p[0]) == '#' && p[1] == '?') /* "#?" is Amiga-ese for "*" */
+        c = WILDCHR_MULTI, p++;
+      if (c != WILDCHR_MULTI) {
+# else /* !AMIGA */
+      if (*p != WILDCHR_MULTI) {
+# endif /* ?AMIGA */
+        /* Single WILDCHR_MULTI ('*'): this doesn't match slashes */
+        for (; *s && *s != DIRSEP_CHR; INCSTR(s))
+          if ((c = recmatch(p, s, cs)) != 0)
+            return c;
+        /* end of pattern: matched if at end of string, else continue */
+        if (*p == 0)
+          return (*s == 0);
+        /* continue to match if at DIRSEP_CHR in pattern, else give up */
+        return (*p == DIRSEP_CHR || (*p == '\\' && p[1] == DIRSEP_CHR))
+               ? recmatch(p, s, cs) : 2;
+      }
+      /* Two consecutive WILDCHR_MULTI ("**"): this matches DIRSEP_CHR ('/') */
+      p++;        /* move p past the second WILDCHR_MULTI */
+      /* continue with the normal non-WILD_STOP_AT_DIR code */
+    } /* wild_stop_at_dir */
+
+    /* Not wild_stop_at_dir */
+    if (*p == 0)
+      return 1;
+    if (!isshexp((char *)p))
+    {
+      /* optimization for rest of pattern being a literal string */
+
+      /* optimization to handle patterns like *.txt */
+      /* if the first char in the pattern is '*' and there */
+      /* are no other shell expression chars, i.e. a literal string */
+      /* then just compare the literal string at the end */
+
+      ZCONST char *srest;
+
+      srest = s + (strlen(s) - strlen(p));
+      if (srest - s < 0)
+        /* remaining literal string from pattern is longer than rest of
+           test string, there can't be a match
+         */
+        return 0;
+      else
+        /* compare the remaining literal pattern string with the last bytes
+           of the test string to check for a match */
+#ifdef _MBCS
+      {
+        ZCONST char *q = s;
+
+        /* MBCS-aware code must not scan backwards into a string from
+         * the end.
+         * So, we have to move forward by character from our well-known
+         * character position s in the test string until we have advanced
+         * to the srest position.
+         */
+        while (q < srest)
+          INCSTR(q);
+        /* In case the byte *srest is a trailing byte of a multibyte
+         * character, we have actually advanced past the position (srest).
+         * For this case, the match has failed!
+         */
+        if (q != srest)
+          return 0;
+        return ((cs ? strcmp(p, q) : namecmp(p, q)) == 0);
+      }
+#else /* !_MBCS */
+        return ((cs ? strcmp(p, srest) : namecmp(p, srest)) == 0);
+#endif /* ?_MBCS */
+    }
+    else
+    {
+      /* pattern contains more wildcards, continue with recursion... */
+      for (; *s; INCSTR(s))
+        if ((c = recmatch(p, s, cs)) != 0)
+          return c;
+      return 2;           /* 2 means give up--shmatch will return false */
+    }
+  }
+
+#ifndef VMS             /* No bracket matching in VMS */
+  /* Parse and process the list of characters and ranges in brackets */
+  if (!no_wild && allow_regex && c == '[')
+  {
+    int e;              /* flag true if next char to be taken literally */
+    ZCONST char *q;     /* pointer to end of [-] group */
+    int r;              /* flag true to match anything but the range */
+
+    if (*s == 0)                        /* need a character to match */
+      return 0;
+    p += (r = (*p == '!' || *p == '^')); /* see if reverse */
+    for (q = p, e = 0; *q; q++)         /* find closing bracket */
+      if (e)
+        e = 0;
+      else
+        if (*q == '\\')
+          e = 1;
+        else if (*q == ']')
+          break;
+    if (*q != ']')                      /* nothing matches if bad syntax */
+      return 0;
+    for (c = 0, e = *p == '-'; p < q; p++)      /* go through the list */
+    {
+      if (e == 0 && *p == '\\')         /* set escape flag if \ */
+        e = 1;
+      else if (e == 0 && *p == '-')     /* set start of range if - */
+        c = *(p-1);
+      else
+      {
+        uch cc = (cs ? (uch)*s : case_map((uch)*s));
+        uch uc = (uch) c;
+        if (*(p+1) != '-')
+          for (uc = uc ? uc : (uch)*p; uc <= (uch)*p; uc++)
+            /* compare range */
+            if ((cs ? uc : case_map(uc)) == cc)
+              return r ? 0 : recmatch(q + CLEN(q), s + CLEN(s), cs);
+        c = e = 0;                      /* clear range, escape flags */
+      }
+    }
+    return r ? recmatch(q + CLEN(q), s + CLEN(s), cs) : 0;
+                                        /* bracket match failed */
+  }
+#endif /* !VMS */
+
+  /* If escape ('\'), just compare next character */
+  if (!no_wild && c == '\\')
+    if ((c = *p++) == '\0')             /* if \ at end, then syntax error */
+      return 0;
+
+#ifdef VMS
+  /* 2005-11-06 SMS.
+     Handle "..." wildcard in p with "." or "]" in s.
+  */
+  if ((c == '.') && (*p == '.') && (*(p+ CLEN( p)) == '.') &&
+   ((*s == '.') || (*s == ']')))
+  {
+    /* Match "...]" with "]".  Continue after "]" in both. */
+    if ((*(p+ 2* CLEN( p)) == ']') && (*s == ']'))
+      return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), cs);
+
+    /* Else, look for a reduced match in s, until "]" in or end of s. */
+    for (; *s && (*s != ']'); INCSTR(s))
+      if (*s == '.')
+        /* If reduced match, then continue after "..." in p, "." in s. */
+        if ((c = recmatch( (p+ CLEN( p)), s, cs)) != 0)
+          return (int)c;
+
+    /* Match "...]" with "]".  Continue after "]" in both. */
+    if ((*(p+ 2* CLEN( p)) == ']') && (*s == ']'))
+      return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), cs);
+
+    /* No reduced match.  Quit. */
+    return 2;
+  }
+
+#endif /* def VMS */
+
+  /* Just a character--compare it */
+  return (cs ? c == *s : case_map((uch)c) == case_map((uch)*s)) ?
+          recmatch(p, s + CLEN(s), cs) : 0;
+}
+
+
+int shmatch(p, s, cs)
+ZCONST char *p;         /* sh pattern to match */
+ZCONST char *s;         /* string to match it to */
+int cs;                 /* force case-sensitive match if TRUE */
+/* Compare the sh pattern p with the string s and return true if they match,
+   false if they don't or if there is a syntax error in the pattern. */
+{
+  return recmatch(p, s, cs) == 1;
+}
+
+
+#if defined(DOS) || defined(WIN32)
+
+#ifdef UNICODE_SUPPORT
+
+int dosmatchw(pw, sw, cs)
+ZCONST wchar_t *pw;     /* dos pattern to match    */
+ZCONST wchar_t *sw;     /* string to match it to   */
+int cs;                 /* force case-sensitive match if TRUE */
+/* Treat filenames without periods as having an implicit trailing period */
+{
+  wchar_t *sw1;         /* revised string to match */
+  int r;                /* result */
+
+  if (wcschr(pw, (wchar_t)'.') && !wcschr(sw, (wchar_t)'.') &&
+      ((sw1 = (wchar_t *)malloc((wcslen(sw) + 2) * sizeof(wchar_t))) != NULL))
+  {
+    wcscpy(sw1, sw);
+    wcscat(sw1, L".");
+  }
+  else
+  {
+    /* will usually be OK */
+    sw1 = (wchar_t *)sw;
+  }
+
+  r = recmatchw(pw, sw1, cs) == 1;
+  if (sw != sw1)
+    free((zvoid *)sw1);
+  return r == 1;
+}
+
+#endif
+
+/* XXX  also suitable for OS2?  Atari?  Human68K?  TOPS-20?? */
+
+int dosmatch(p, s, cs)
+ZCONST char *p;         /* dos pattern to match    */
+ZCONST char *s;         /* string to match it to   */
+int cs;                 /* force case-sensitive match if TRUE */
+/* Treat filenames without periods as having an implicit trailing period */
+{
+  char *s1;             /* revised string to match */
+  int r;                /* result */
+
+  if (strchr(p, '.') && !strchr(s, '.') &&
+      ((s1 = malloc(strlen(s) + 2)) != NULL))
+  {
+    strcpy(s1, s);
+    strcat(s1, ".");
+  }
+  else
+  {
+    /* will usually be OK */
+    s1 = (char *)s;
+  }
+
+  r = recmatch(p, s1, cs) == 1;
+  if (s != s1)
+    free((zvoid *)s1);
+  return r == 1;
+}
+
+#endif /* DOS || WIN32 */
+
+zvoid far **search(b, a, n, cmp)
+ZCONST zvoid *b;        /* pointer to value to search for */
+ZCONST zvoid far **a;   /* table of pointers to values, sorted */
+extent n;               /* number of pointers in a[] */
+int (*cmp) OF((ZCONST zvoid *, ZCONST zvoid far *)); /* comparison function */
+
+/* Search for b in the pointer list a[0..n-1] using the compare function
+   cmp(b, c) where c is an element of a[i] and cmp() returns negative if
+   *b < *c, zero if *b == *c, or positive if *b > *c.  If *b is found,
+   search returns a pointer to the entry in a[], else search() returns
+   NULL.  The nature and size of *b and *c (they can be different) are
+   left up to the cmp() function.  A binary search is used, and it is
+   assumed that the list is sorted in ascending order. */
+{
+  ZCONST zvoid far **i; /* pointer to midpoint of current range */
+  ZCONST zvoid far **l; /* pointer to lower end of current range */
+  int r;                /* result of (*cmp)() call */
+  ZCONST zvoid far **u; /* pointer to upper end of current range */
+
+  l = (ZCONST zvoid far **)a;  u = l + (n-1);
+  while (u >= l) {
+    i = l + ((unsigned)(u - l) >> 1);
+    if ((r = (*cmp)(b, (ZCONST char far *)*(struct zlist far **)i)) < 0)
+      u = i - 1;
+    else if (r > 0)
+      l = i + 1;
+    else
+      return (zvoid far **)i;
+  }
+  return NULL;          /* If b were in list, it would belong at l */
+}
+
+#endif /* !UTIL */
+
+#ifdef MSDOS16
+
+local unsigned ident(unsigned chr)
+{
+   return chr; /* in al */
+}
+
+void init_upper()
+{
+  static struct country {
+    uch ignore[18];
+    int (far *casemap)(int);
+    uch filler[16];
+  } country_info;
+
+  struct country far *info = &country_info;
+  union REGS regs;
+  struct SREGS sregs;
+  unsigned int c;
+
+  regs.x.ax = 0x3800; /* get country info */
+  regs.x.dx = FP_OFF(info);
+  sregs.ds  = FP_SEG(info);
+  intdosx(&regs, &regs, &sregs);
+  for (c = 0; c < 128; c++) {
+    upper[c] = (uch) toupper(c);
+    lower[c] = (uch) c;
+  }
+  for (; c < sizeof(upper); c++) {
+    upper[c] = (uch) (*country_info.casemap)(ident(c));
+    /* ident() required because casemap takes its parameter in al */
+    lower[c] = (uch) c;
+  }
+  for (c = 0; c < sizeof(upper); c++ ) {
+    unsigned int u = upper[c];
+    if (u != c && lower[u] == (uch) u) {
+      lower[u] = (uch)c;
+    }
+  }
+  for (c = 'A'; c <= 'Z'; c++) {
+    lower[c] = (uch) (c - 'A' + 'a');
+  }
+}
+#else /* !MSDOS16 */
+#  ifndef OS2
+
+void init_upper()
+{
+  unsigned int c;
+#if defined(ATARI) || defined(CMS_MVS)
+#include <ctype.h>
+/* this should be valid for all other platforms too.   (HD 11/11/95) */
+  for (c = 0; c< sizeof(upper); c++) {
+    upper[c] = islower(c) ? toupper(c) : c;
+    lower[c] = isupper(c) ? tolower(c) : c;
+  }
+#else
+  for (c = 0; c < sizeof(upper); c++) upper[c] = lower[c] = (uch)c;
+  for (c = 'a'; c <= 'z';        c++) upper[c] = (uch)(c - 'a' + 'A');
+  for (c = 'A'; c <= 'Z';        c++) lower[c] = (uch)(c - 'A' + 'a');
+#endif
+}
+#  endif /* !OS2 */
+
+#endif /* ?MSDOS16 */
+
+int namecmp(string1, string2)
+  ZCONST char *string1, *string2;
+/* Compare the two strings ignoring case, and correctly taking into
+ * account national language characters. For operating systems with
+ * case sensitive file names, this function is equivalent to strcmp.
+ */
+{
+  int d;
+
+  for (;;)
+  {
+    d = (int) (uch) case_map(*string1)
+      - (int) (uch) case_map(*string2);
+
+    if (d || *string1 == 0 || *string2 == 0)
+      return d;
+
+    string1++;
+    string2++;
+  }
+}
+
+#ifdef EBCDIC
+char *strtoasc(char *str1, ZCONST char *str2)
+{
+  char *old;
+  old = str1;
+  while (*str1++ = (char)ascii[(uch)(*str2++)]);
+  return old;
+}
+
+char *strtoebc(char *str1, ZCONST char *str2)
+{
+  char *old;
+  old = str1;
+  while (*str1++ = (char)ebcdic[(uch)(*str2++)]);
+  return old;
+}
+
+char *memtoasc(char *mem1, ZCONST char *mem2, unsigned len)
+{
+  char *old;
+  old = mem1;
+  while (len--)
+     *mem1++ = (char)ascii[(uch)(*mem2++)];
+  return old;
+}
+
+char *memtoebc(char *mem1, ZCONST char *mem2, unsigned len)
+{
+  char *old;
+  old = mem1;
+  while (len--)
+     *mem1++ = (char)ebcdic[(uch)(*mem2++)];
+  return old;
+}
+#endif /* EBCDIC */
+
+#ifdef IZ_ISO2OEM_ARRAY
+char *str_iso_to_oem(dst, src)
+  ZCONST char *src;
+  char *dst;
+{
+  char *dest_start = dst;
+  while (*dst++ = (char)iso2oem[(uch)(*src++)]);
+  return dest_start;
+}
+#endif
+
+#ifdef IZ_OEM2ISO_ARRAY
+char *str_oem_to_iso(dst, src)
+  ZCONST char *src;
+  char *dst;
+{
+  char *dest_start = dst;
+  while (*dst++ = (char)oem2iso[(uch)(*src++)]);
+  return dest_start;
+}
+#endif
+
+
+
+/* DBCS support for Info-ZIP's zip  (mainly for japanese (-: )
+ * by Yoshioka Tsuneo (QWF00133@nifty.ne.jp,tsuneo-y@is.aist-nara.ac.jp)
+ * This code is public domain!   Date: 1998/12/20
+ */
+#ifdef _MBCS
+
+char *___tmp_ptr;
+
+int lastchar(ptr)
+    ZCONST char *ptr;
+{
+    ZCONST char *oldptr = ptr;
+    while(*ptr != '\0'){
+        oldptr = ptr;
+        INCSTR(ptr);
+    }
+    return (int)(unsigned)*oldptr;
+}
+
+unsigned char *zmbschr(str, c)
+    ZCONST unsigned char *str;
+    unsigned int c;
+{
+    while(*str != '\0'){
+        if (*str == c) {return (unsigned char *)str;}
+        INCSTR(str);
+    }
+    return NULL;
+}
+
+unsigned char *zmbsrchr(str, c)
+    ZCONST unsigned char *str;
+    unsigned int c;
+{
+    unsigned char *match = NULL;
+    while(*str != '\0'){
+        if (*str == c) {match = (unsigned char*)str;}
+        INCSTR(str);
+    }
+    return match;
+}
+#endif /* _MBCS */
+
+
+
+#ifndef UTIL
+
+/*****************************************************************
+ | envargs - add default options from environment to command line
+ |----------------------------------------------------------------
+ | Author: Bill Davidsen, original 10/13/91, revised 23 Oct 1991.
+ | This program is in the public domain.
+ |----------------------------------------------------------------
+ | Minor program notes:
+ |  1. Yes, the indirection is a tad complex
+ |  2. Parenthesis were added where not needed in some cases
+ |     to make the action of the code less obscure.
+ ****************************************************************/
+
+void envargs(Pargc, Pargv, envstr, envstr2)
+    int *Pargc;
+    char ***Pargv;
+    char *envstr;
+    char *envstr2;
+{
+    char *envptr;                     /* value returned by getenv */
+    char *bufptr;                     /* copy of env info */
+    int argc;                         /* internal arg count */
+    register int ch;                  /* spare temp value */
+    char **argv;                      /* internal arg vector */
+    char **argvect;                   /* copy of vector address */
+
+    /* see if anything in the environment */
+    envptr = getenv(envstr);
+    if (envptr != NULL)                                /* usual var */
+        while (isspace((uch)*envptr))      /* we must discard leading spaces */
+            envptr++;
+    if (envptr == NULL || *envptr == '\0')
+        if ((envptr = getenv(envstr2)) != NULL)                 /* alternate */
+            while (isspace((uch)*envptr))
+                envptr++;
+    if (envptr == NULL || *envptr == '\0')
+        return;
+
+    /* count the args so we can allocate room for them */
+    argc = count_args(envptr);
+    bufptr = malloc(1 + strlen(envptr));
+    if (bufptr == NULL)
+        ziperr(ZE_MEM, "Can't get memory for arguments");
+    strcpy(bufptr, envptr);
+
+    /* allocate a vector large enough for all args */
+    argv = (char **)malloc((argc + *Pargc + 1) * sizeof(char *));
+    if (argv == NULL) {
+        free(bufptr);
+        ziperr(ZE_MEM, "Can't get memory for arguments");
+    }
+    argvect = argv;
+
+    /* copy the program name first, that's always true */
+    *(argv++) = *((*Pargv)++);
+
+    /* copy the environment args first, may be changed */
+    do {
+#if defined(AMIGA) || defined(UNIX)
+        if (*bufptr == '"') {
+            char *argstart = ++bufptr;
+            *(argv++) = argstart;
+            for (ch = *bufptr; ch != '\0' && ch != '\"';
+                 ch = *PREINCSTR(bufptr))
+                if (ch == '\\' && bufptr[1] != '\0')
+                    ++bufptr;               /* skip to char after backslash */
+            if (ch != '\0')                       /* overwrite trailing '"' */
+                *(bufptr++) = '\0';
+
+            /* remove escape characters */
+            while ((argstart = MBSCHR(argstart, '\\')) != NULL) {
+                strcpy(argstart, argstart + 1);
+                if (*argstart)
+                    ++argstart;
+            }
+        } else {
+            *(argv++) = bufptr;
+            while ((ch = *bufptr) != '\0' && !isspace((uch)ch)) INCSTR(bufptr);
+            if (ch != '\0') *(bufptr++) = '\0';
+        }
+#else
+#  ifdef WIN32
+        /* We do not support backslash-quoting of quotes in quoted */
+        /* strings under Win32, because backslashes are directory  */
+        /* separators and double quotes are illegal in filenames.  */
+        if (*bufptr == '"') {
+            *(argv++) = ++bufptr;
+            while ((ch = *bufptr) != '\0' && ch != '\"') INCSTR(bufptr);
+            if (ch != '\0') *(bufptr++) = '\0';
+        } else {
+            *(argv++) = bufptr;
+            while ((ch = *bufptr) != '\0' && !isspace((uch)ch)) INCSTR(bufptr);
+            if (ch != '\0') *(bufptr++) = '\0';
+        }
+#  else
+        *(argv++) = bufptr;
+        while ((ch = *bufptr) != '\0' && !isspace((uch)ch)) INCSTR(bufptr);
+        if (ch != '\0') *(bufptr++) = '\0';
+#  endif
+#endif /* ?(AMIGA || UNIX) */
+        while ((ch = *bufptr) != '\0' && isspace((uch)ch)) INCSTR(bufptr);
+    } while (ch);
+
+    /* now save old argc and copy in the old args */
+    argc += *Pargc;
+    while (--(*Pargc)) *(argv++) = *((*Pargv)++);
+
+    /* finally, add a NULL after the last arg, like UNIX */
+    *argv = NULL;
+
+    /* save the values and return */
+    *Pargv = argvect;
+    *Pargc = argc;
+}
+
+local int count_args(s)
+char *s;
+{
+    int count = 0;
+    char ch;
+
+    do {
+        /* count and skip args */
+        ++count;
+#if defined(AMIGA) || defined(UNIX)
+        if (*s == '\"') {
+            for (ch = *PREINCSTR(s); ch != '\0' && ch != '\"';
+                 ch = *PREINCSTR(s))
+                if (ch == '\\' && s[1] != '\0')
+                    INCSTR(s);
+            if (*s) INCSTR(s);  /* trailing quote */
+        } else
+            while ((ch = *s) != '\0' && !isspace((uch)ch)) INCSTR(s);
+#else
+#  ifdef WIN32
+        if (*s == '\"') {
+            ++s;                /* leading quote */
+            while ((ch = *s) != '\0' && ch != '\"') INCSTR(s);
+            if (*s) INCSTR(s);  /* trailing quote */
+        } else
+            while ((ch = *s) != '\0' && !isspace((uch)ch)) INCSTR(s);
+#  else
+        while ((ch = *s) != '\0' && !isspace((uch)ch)) INCSTR(s);
+#  endif
+#endif /* ?(AMIGA || UNIX) */
+        while ((ch = *s) != '\0' && isspace((uch)ch)) INCSTR(s);
+    } while (ch);
+
+    return(count);
+}
+
+
+
+/* Extended argument processing -- by Rich Wales
+ * This function currently deals only with the MKS shell, but could be
+ * extended later to understand other conventions.
+ *
+ * void expand_args(int *argcp, char ***argvp)
+ *
+ *    Substitutes the extended command line argument list produced by
+ *    the MKS Korn Shell in place of the command line info from DOS.
+ *
+ *    The MKS shell gets around DOS's 128-byte limit on the length of
+ *    a command line by passing the "real" command line in the envi-
+ *    ronment.  The "real" arguments are flagged by prepending a tilde
+ *    (~) to each one.
+ *
+ *    This "expand_args" routine creates a new argument list by scanning
+ *    the environment from the beginning, looking for strings begin-
+ *    ning with a tilde character.  The new list replaces the original
+ *    "argv" (pointed to by "argvp"), and the number of arguments
+ *    in the new list replaces the original "argc" (pointed to by
+ *    "argcp").
+ */
+void expand_args(argcp, argvp)
+      int *argcp;
+      char ***argvp;
+{
+#ifdef DOS
+
+/* Do NEVER include (re)definiton of `environ' variable with any version
+   of MSC or BORLAND/Turbo C. These compilers supply an incompatible
+   definition in <stdlib.h>.  */
+#if defined(__GO32__) || defined(__EMX__)
+      extern char **environ;          /* environment */
+#endif /* __GO32__ || __EMX__ */
+      char        **envp;             /* pointer into environment */
+      char        **newargv;          /* new argument list */
+      char        **argp;             /* pointer into new arg list */
+      int           newargc;          /* new argument count */
+
+      /* sanity check */
+      if (environ == NULL
+          || argcp == NULL
+          || argvp == NULL || *argvp == NULL)
+              return;
+      /* find out how many environment arguments there are */
+      for (envp = environ, newargc = 0;
+           *envp != NULL && (*envp)[0] == '~';
+           envp++, newargc++) ;
+      if (newargc == 0)
+              return;                 /* no environment arguments */
+      /* set up new argument list */
+      newargv = (char **) malloc(sizeof(char **) * (newargc+1));
+      if (newargv == NULL)
+              return;                 /* malloc failed */
+      for (argp = newargv, envp = environ;
+           *envp != NULL && (*envp)[0] == '~';
+           *argp++ = &(*envp++)[1]) ;
+      *argp = NULL;                   /* null-terminate the list */
+      /* substitute new argument list in place of old one */
+      *argcp = newargc;
+      *argvp = newargv;
+#else /* !DOS */
+      if (argcp || argvp) return;
+#endif /* ?DOS */
+}
+
+
+/* Fast routine for detection of plain text
+ * (ASCII or an ASCII-compatible extension such as ISO-8859, UTF-8, etc.)
+ * Author: Cosmin Truta.
+ * See "proginfo/txtvsbin.txt" for more information.
+ *
+ * This function returns the same result as set_file_type() in "trees.c".
+ * Unlike in set_file_type(), however, the speed depends on the buffer size,
+ * so the optimal implementation is different.
+ */
+int is_text_buf(buf_ptr, buf_size)
+    ZCONST char *buf_ptr;
+    unsigned buf_size;
+{
+    int result = 0;
+    unsigned i;
+    unsigned char c;
+
+    for (i = 0; i < buf_size; ++i)
+    {
+        c = (unsigned char)buf_ptr[i];
+        if (c >= 32)    /* speed up the loop by checking this first */
+            result = 1; /* white-listed character found; keep looping */
+        else            /* speed up the loop by inlining the following check */
+        if ((c <= 6) || (c >= 14 && c <= 25) || (c >= 28 && c <= 31))
+            return 0;   /* black-listed character found; stop */
+    }
+
+    return result;
+}
+
+#endif /* UTIL */
+
+
+#ifdef DEBUGNAMES
+#undef free
+int Free(x)
+void *x;
+{
+    if (x == (void *) 0xdeadbeef)
+        exit(-1);
+    free(x);
+    return 0;
+}
+
+int printnames()
+{
+     struct zlist far *z;
+
+     for (z = zfiles; z != NULL; z = z->nxt)
+           fprintf(mesg, "%s %s %s %p %p %p %08x %08x %08x\n",
+                            z->name, z->zname, z->iname,
+                            z->name, z->zname, z->iname,
+                            *((int *) z->name), *((int *) z->zname),
+                            *((int *) z->iname));
+     return 0;
+}
+
+#endif /* DEBUGNAMES */
+
+
+/* Below is used to format zoff_t values, which can be either long or long long
+   depending on if LARGE FILES are supported.  Function provided by SMS.
+   10/17/04 EG */
+
+/* 2004-12-01 SMS.
+ * Brought in fancy fzofft() from UnZip.
+ */
+
+/* This implementation assumes that no more than FZOFF_NUM values will be
+   needed in any printf using it.  */
+
+/* zip_fzofft(): Format a zoff_t value in a cylindrical buffer set.
+   This version renamed from fzofft because of name conflict in unzip
+   when combined in WiZ. */
+
+/* 2004-12-19 SMS.
+ * I still claim than the smart move would have been to disable one or
+ * the other instance with #if for Wiz.  But fine.  We'll change the
+ * name.
+ */
+
+/* This is likely not thread safe.  Needs to be done without static storage.
+   12/29/04 EG */
+
+/* zip_fzofft(): Format a zoff_t value in a cylindrical buffer set. */
+
+#define FZOFFT_NUM 4            /* Number of chambers. */
+#define FZOFFT_LEN 24           /* Number of characters/chamber. */
+
+
+/* Format a zoff_t value in a cylindrical buffer set. */
+
+char *zip_fzofft( val, pre, post)
+  zoff_t val;
+  char *pre;
+  char *post;
+{
+    /* Storage cylinder. */
+    static char fzofft_buf[ FZOFFT_NUM][ FZOFFT_LEN];
+    static int fzofft_index = 0;
+
+    /* Temporary format string storage. */
+    static char fmt[ 16] = "%";
+
+    /* Assemble the format string. */
+    fmt[ 1] = '\0';             /* Start after initial "%". */
+    if (pre == FZOFFT_HEX_WID)  /* Special hex width. */
+    {
+        strcat( fmt, FZOFFT_HEX_WID_VALUE);
+    }
+    else if (pre == FZOFFT_HEX_DOT_WID) /* Special hex ".width". */
+    {
+        strcat( fmt, ".");
+        strcat( fmt, FZOFFT_HEX_WID_VALUE);
+    }
+    else if (pre != NULL)       /* Caller's prefix (width). */
+    {
+        strcat( fmt, pre);
+    }
+
+    strcat( fmt, FZOFFT_FMT);   /* Long or long-long or whatever. */
+
+    if (post == NULL)
+        strcat( fmt, "d");      /* Default radix = decimal. */
+    else
+        strcat( fmt, post);     /* Caller's radix. */
+
+    /* Advance the cylinder. */
+    fzofft_index = (fzofft_index+ 1)% FZOFFT_NUM;
+
+    /* Write into the current chamber. */
+    sprintf( fzofft_buf[ fzofft_index], fmt, val);
+
+    /* Return a pointer to this chamber. */
+    return fzofft_buf[ fzofft_index];
+}
+
+
+/* Format a uzoff_t value in a cylindrical buffer set. */
+/* Added to support uzoff_t type.  12/29/04 */
+
+char *zip_fuzofft( val, pre, post)
+  uzoff_t val;
+  char *pre;
+  char *post;
+{
+    /* Storage cylinder. */
+    static char fuzofft_buf[ FZOFFT_NUM][ FZOFFT_LEN];
+    static int fuzofft_index = 0;
+
+    /* Temporary format string storage. */
+    static char fmt[ 16] = "%";
+
+    /* Assemble the format string. */
+    fmt[ 1] = '\0';             /* Start after initial "%". */
+    if (pre == FZOFFT_HEX_WID)  /* Special hex width. */
+    {
+        strcat( fmt, FZOFFT_HEX_WID_VALUE);
+    }
+    else if (pre == FZOFFT_HEX_DOT_WID) /* Special hex ".width". */
+    {
+        strcat( fmt, ".");
+        strcat( fmt, FZOFFT_HEX_WID_VALUE);
+    }
+    else if (pre != NULL)       /* Caller's prefix (width). */
+    {
+        strcat( fmt, pre);
+    }
+
+    strcat( fmt, FZOFFT_FMT);   /* Long or long-long or whatever. */
+
+    if (post == NULL)
+        strcat( fmt, "u");      /* Default radix = decimal. */
+    else
+        strcat( fmt, post);     /* Caller's radix. */
+
+    /* Advance the cylinder. */
+    fuzofft_index = (fuzofft_index+ 1)% FZOFFT_NUM;
+
+    /* Write into the current chamber. */
+    sprintf( fuzofft_buf[ fuzofft_index], fmt, val);
+
+    /* Return a pointer to this chamber. */
+    return fuzofft_buf[ fuzofft_index];
+}
+
+
+/* Display number to mesg stream
+   5/15/05 EG */
+
+int DisplayNumString(file, i)
+  FILE *file;
+  uzoff_t i;
+{
+  char tempstrg[100];
+  int j;
+  char *s = tempstrg;
+
+  WriteNumString(i, tempstrg);
+  /* skip spaces */
+  for (j = 0; j < 3; j++) {
+    if (*s != ' ') break;
+    s++;
+  }
+  fprintf(file, "%s", s);
+
+  return 0;
+}
+
+/* Read numbers with trailing size multiplier (like 10M) and return number.
+   10/30/04 EG */
+
+uzoff_t ReadNumString( numstring )
+  char *numstring;
+{
+  zoff_t num = 0;
+  char multchar = ' ';
+  int i;
+  uzoff_t mult = 1;
+
+  /* check if valid number (currently no negatives) */
+  if (numstring == NULL) {
+    zipwarn("Unable to read empty number in ReadNumString", "");
+    return (uzoff_t)-1;
+  }
+  if (numstring[0] < '0' || numstring[0] > '9') {
+    zipwarn("Unable to read number (must start with digit): ", numstring);
+    return (uzoff_t)-1;
+  }
+  if (strlen(numstring) > 8) {
+    zipwarn("Number too long to read (8 characters max): ", numstring);
+    return (uzoff_t)-1;
+  }
+
+  /* get the number part */
+  num = atoi(numstring);
+
+  /* find trailing multiplier */
+  for (i = 0; numstring[i] && isdigit(numstring[i]); i++) ;
+
+  /* return if no multiplier */
+  if (numstring[i] == '\0') {
+    return (uzoff_t)num;
+  }
+
+  /* nothing follows multiplier */
+  if (numstring[i + 1]) {
+    return (uzoff_t)-1;
+  }
+
+  /* get multiplier */
+  multchar = toupper(numstring[i]);
+
+  if (multchar == 'K') {
+    mult <<= 10;
+  } else if (multchar == 'M') {
+    mult <<= 20;
+  } else if (multchar == 'G') {
+    mult <<= 30;
+#ifdef LARGE_FILE_SUPPORT
+  } else if (multchar == 'T') {
+    mult <<= 40;
+#endif
+  } else {
+    return (uzoff_t)-1;
+  }
+
+  return (uzoff_t)num * mult;
+}
+
+
+/* Write the number as a string with a multiplier (like 10M) to outstring.
+   Always writes no more than 3 digits followed maybe by a multiplier and
+   returns the characters written or -1 if error.
+   10/30/04 EG */
+
+int WriteNumString( num, outstring )
+  uzoff_t num;
+  char *outstring;
+{
+  int mult;
+  int written = 0;
+  int i;
+  int j;
+  char digits[4];
+  int dig;
+
+  *outstring = '\0';
+
+  /* shift number 1 K until less than 10000 */
+  for (mult = 0; num >= 10240; mult++) {
+    num >>= 10;
+  }
+
+  /* write digits as "    0" */
+  for (i = 1; i < 4; i++) {
+    digits[i] = ' ';
+  }
+  digits[0] = '0';
+
+  if (num >= 1000) {
+    i = 3;
+    num *= 10;
+    num >>= 10;
+    mult++;
+    digits[0] = (char) (num % 10) + '0';
+    digits[1] = '.';
+    digits[2] = (char) (num / 10) + '0';
+  } else {
+    for (i = 0; num; i++) {
+      dig = (int) (num % 10);
+      num /= 10;
+      digits[i] = dig + '0';
+    }
+  }
+  if (i == 0) i = 1;
+  for (j = i; j > 0; j--) {
+    *outstring = digits[j - 1];
+    outstring++;
+    written++;
+  }
+
+  /* output multiplier */
+  if (mult == 0) {
+  } else if (mult == 1) {
+    *outstring = 'K';
+    outstring++;
+    written++;
+  } else if (mult == 2) {
+    *outstring = 'M';
+    outstring++;
+    written++;
+  } else if (mult == 3) {
+    *outstring = 'G';
+    outstring++;
+    written++;
+  } else if (mult == 4) {
+    *outstring = 'T';
+    outstring++;
+    written++;
+  } else {
+    *outstring = '?';
+    outstring++;
+    written++;
+  }
+
+  *outstring = '\0';
+
+  return written;
+}
+
+
+#if 0 /* not used anywhere, should get removed by next release... */
+
+/* Apply the Adler-16 checksum to a set of bytes.
+ * Use this function as you would use crc32():
+ * - First call this function by passing a NULL pointer instead of buf
+ *   OR initialize the checksum register with ADLERVAL_INITIAL.
+ * - Iteratively call this function for each buffer fragment.
+ * This function returns the updated checksum.
+ *
+ * IN assertion: chksum is a valid Adler-16 checksum:
+ *    (chksum & 0xffU) < ADLER16_BASE && ((chksum >> 8) & 0xffU) < ADLER16_BASE
+ *
+ * Author: Cosmin Truta.
+ * See "proginfo/adler16.txt" for more information.
+ */
+
+#define ADLER16_BASE 251        /* The largest prime smaller than 256 */
+
+unsigned int adler16(chksum, buf, len)
+    unsigned int chksum;
+    ZCONST uch *buf;
+    extent len;
+{
+    unsigned int sum1 = chksum & 0xff;
+    unsigned int sum2 = (chksum >> 8) & 0xff;
+    extent i;
+
+    Assert((sum1 < ADLER16_BASE) && (sum2 < ADLER16_BASE),
+           "adler16: invalid checksum");
+
+    if (buf == NULL)
+        return 1;
+
+    for (i = 0; i < len; ++i)
+    {
+        sum1 += buf[i];
+        if (sum1 >= ADLER16_BASE) /* this is faster than modulo ADLER16_BASE */
+            sum1 -= ADLER16_BASE;
+        sum2 += sum1;
+        if (sum2 >= ADLER16_BASE) /* ditto */
+            sum2 -= ADLER16_BASE;
+    }
+
+    return (sum2 << 8) | sum1;
+}
+
+#endif /* 0, not used anywhere */
+
+
+/* returns true if abbrev is abbreviation for matchstring */
+int abbrevmatch (matchstring, abbrev, case_sensitive, minmatch)
+  char *matchstring;
+  char *abbrev;
+  int case_sensitive;
+  int minmatch;
+{
+  int cnt = 0;
+  char *m;
+  char *a;
+
+  m = matchstring;
+  a = abbrev;
+
+  for (; *m && *a; m++, a++) {
+    cnt++;
+    if (case_sensitive) {
+      if (*m != *a) {
+        /* mismatch */
+        return 0;
+      }
+    } else {
+      if (toupper(*m) != toupper(*a)) {
+        /* mismatch */
+        return 0;
+      }
+    }
+  }
+  if (cnt < minmatch) {
+    /* not big enough string */
+    return 0;
+  }
+  if (*a != '\0') {
+    /* abbreviation longer than match string */
+    return 0;
+  }
+  /* either abbreviation or match */
+  return 1;
+}
diff --git a/vms/NOTES.TXT b/vms/NOTES.TXT
new file mode 100644 (file)
index 0000000..4f94ec3
--- /dev/null
@@ -0,0 +1,382 @@
+      VMS Notes for Info-ZIP Zip 3.0 and UnZip 6.0
+      ============================================
+
+   This document describes some VMS-specific behavior and implementation
+details of the Info-ZIP Zip and UnZip programs.
+
+   Last modified: 2008-04-10.
+
+
+   Command-line Case
+   -----------------
+
+   Zip and UnZip now include code which can preserve the case of
+command-line parameters and options, which obviates quoting upper-case
+options like "-V" or "-Z".  This works on non-VAX systems with a
+sufficiently recent C RTL, and SET PROCESS /PARSE_STYLE = EXTENDED.
+(Sufficiently recent here means __CRTL_VER >= 70301000, which includes
+VMS V7.3-1 with a C Run Time Library ECO, or V7.3-2 or newer.)   This
+code uses the decc$feature_set_value() function to enable the
+DECC$ARGV_PARSE_STYLE feature.  There is a small range of C RTL versions
+where this function is unavailable, but where manually setting the
+logical name DECC$ARGV_PARSE_STYLE to "ENABLE" will work.   HELP CRTL
+leads to some additional information on these features.
+
+
+   File Name Case (ODS5)
+   ---------------------
+
+   In general, Zip 3.0 and UnZip 6.0 should handle file name case (and
+extended file names) in reasonable ways on ODS5 disks.
+
+   Zip offers a variety of "-C" (/PRESERVE_CASE) options to control how
+case is handled when adding files to an archive.  The default settings
+("-C2-", /PRESERVE_CASE = NOODS2, down-case ODS2 file names; "-C5",
+/PRESERVE_CASE = ODS5, preserve case of ODS5 file names) should be
+consistent with previous Zip versions for files on ODS2 disks, and
+reasonable for files on ODS5 disks.
+
+   UnZip should preserve case when it extracts to an ODS5 destination
+disk (unless "-2" (/ODS2) is specified).  (Note that previous UnZip
+versions, including version 5.52, did not properly preserve case for
+directories, which were always up-cased.)
+
+   The Zip and UnZip builders should work properly on ODS2 and ODS5
+disks, with old (pre-ODS5) and new (case-conscious) versions of MMS (or
+MMK).  All testing was done with SET PROCESS /CASE_LOOKUP = BLIND. 
+Various problems may be expected with /CASE_LOOKUP = SENSITIVE.
+
+   For consistency, the builders should always create product files
+(.OBJ, .EXE, .HLB, and so on) with upper-case names, whether the build
+is done on an ODS2 or ODS5 disk.  Note, however, that in a world with
+both ODS2 and ODS5 disks, and old and new Zip and UnZip versions, it's
+possible to encounter lower-case product file names.  For example, a VMS
+binary kit could be created on an ODS2 disk, and a Zip archive created
+from that (using Zip 2.x, or Zip 3.x with default settings).  Such a Zip
+archive would contain down-cased names for those product files, and
+those lower-case names would then normally be preserved when UnZip was
+used to extract that archive onto an ODS5 destination.  Normally, things
+will work regardless of such case changes, but there may be some
+untested combinations of unexpected name cases and quirky MMS (or MMK)
+behavior, where something goes wrong.  Complaints are always welcome,
+but it may not be possible to get everything to work as expected with
+every version of VMS, MMS (or MMK), Zip, and UnZip, on every file
+system.
+
+   It might help matters if _all_ VMS binary kits were produced on ODS5
+disks, and packaged using (case-preserving) Zip version 3.x, but this
+would certainly be different from the way things have been done before,
+and maintaining control over this process is essentially impossible.
+
+
+   Symbolic Links (ODS5)
+   ---------------------
+
+   VMS V8.3 offers support for symbolic links (symlinks) on ODS5 disks.
+In previous Zip and UnZip versions, the generic code for symlinks was
+disabled, and there was no VMS-specific code for symlinks.  Now, by
+default, Zip and UnZip attempt to support symlinks wherever the C
+headers and C run-time library include the functions needed for symlink
+support.  This means non-VAX systems with __CRTL_VER >= 70301000, so
+this includes VMS V7.3-1 and up, and thus symlink-capable Zip and UnZip
+programs may be built on systems which do not themselves offer symlink
+support.  (Various run-time failures may be expected if symlinks are
+encountered on pre-V8.3 systems, either in a file system or in a Zip
+archive.)
+
+   Symlink support can be disabled at build-time, if desired, by
+defining the C macro NO_SYMLINKS.  (See comments in the builder
+regarding LOCAL_UNZIP or LOCAL_ZIP, as appropriate.)  For example, using
+MMS to build UnZip:
+
+      MMS /DESCRIP = [.VMS] /MACRO = ("LOCAL_UNZIP=NO_SYMLINKS=1")
+
+or, using the command procedure to build Zip:
+
+      LOCAL_ZIP == "NO_SYMLINKS=1"
+      @ [.VMS]BUILD_ZIP.COM
+      DELETE /SYMBOL /GLOBAL LOCAL_ZIP
+
+   The Zip "-v" (/VERBOSE) report should include SYMLINK_SUPPORT in its
+list of "Zip special compilation options" if Zip was built with symlink
+support.  Currently, UnZip is less convenient, but searching the UnZip
+executable (or EXTRACT.OBJ) for "symlink" should fail if symlink support
+is missing (or succeed if it's present):
+
+      $ SEARCH /NOOUTPUT UNZIP.EXE SYMLINK      ! No symlink support.
+      %SEARCH-I-NOMATCHES, no strings matched
+or:
+      $ SEARCH /NOOUTPUT EXTRACT.OBJ SYMLINK    ! Symlink support.
+      $ SHOW SYMBOL $STATUS
+        $STATUS == "%X00000001"
+
+
+   File I/O Performance
+   --------------------
+
+   When compiled using DEC/Compaq/HP C (not GNU C or VAX C), the Zip and
+UnZip file I/O code now includes access callback functions which are
+used to try to set some RMS parameters to non-default values, with the
+intention of improving file I/O speed.  This affects reading an archive
+file in UnZip and writing one in Zip.  (Reading and writing the
+individual data files are handled in more exotic ways, making these
+parameters less important for them.)
+
+   Currently, the built-in default parameters enable read-ahead and
+write-behind, using a multi-buffer count of 2, and a multi-block count
+of 127 (the maximum).  For writing the archive, the default extend
+quantity is 16384 blocks (8MB), with truncation enabled.  This
+combination is believed to be, at worst, fairly harmless for most
+situations, and, in most cases, to provide a substantial speed
+improvement, especially with large archives.
+
+   This code allows SET RMS_DEFAULT parameters to override the built-in
+default values.  On some old VMS versions, sys$getjpi() can not provide
+the SET RMS_DEFAULT values, and in this situation, the callback function
+will not try to use its improved parameter values.  Users on such old
+VMS versions who seek improved I/O speed may wish to bypass this check,
+which requires changing the code in the get_rms_defaults() function in
+[.VMS]VMS.C.  The "-vv" (/VERBOSE = MORE) option on both programs
+enables diagnostic messages which show the operation of the callback
+function.  A message showing a failure status from sys$getjpi()
+indicates this problem.
+
+   Sample results (UnZip shown, Zip similar):
+
+   VMS VAX V5.4, VAX C.  Callback code disabled, no messages:
+      WIMP $ unzip -tvv TESTMAKE.ZIP
+      Archive:  SYS$SYSDEVICE:[UTILITY.SOURCE.ZIP.UNZIP60C]TESTMAKE.ZIP;1
+      [...]
+
+   VMS VAX V5.5-2, DEC C.  SYS$GETJPI() fails (%SYSTEM-F-BADPARAM):
+      WEAK $ unzip -tvv TESTMAKE.ZIP
+      Get RMS defaults.  getjpi sts = %x00000014.
+      Archive:  DUA1:[UTILITY.SOURCE.ZIP.UNZIP60C]TESTMAKE.ZIP;1
+      [...]
+
+   VMS VAX V7.3, DEC/Compaq C.  Callback code works:
+      WUSS $ unzip -tvv TESTMAKE.ZIP
+      Get RMS defaults.  getjpi sts = %x00000001.
+                     Default: deq =      0, mbc =   0, mbf =   0.
+      Open callback.  ID = 1, deq =  16384, mbc = 127, mbf =   2.
+      Archive:  ALP$DKA0:[UTILITY.SOURCE.ZIP.UNZIP60C]TESTMAKE.ZIP;1
+      [...]
+
+   VMSV5.5-2 is too old.  V7.3 is new enough.  Anyone with more precise
+information is invited to contribute it.
+
+   Users who find other parameter sets more beneficial, or who find
+particular problems with this set are welcome to comment.
+
+   In this version, as in previous versions, when UnZip expands a -V
+archive, it allocates the entire extent of a data file before writing
+any of its data.  In some previous versions, this could cause the
+destination disk to be locked for a considerable time (minutes), if
+highwater marking was enabled on that disk.  Now, the FAB SQO
+("sequential access only") flag (or equivalent) is set, which prevents
+this troublesome disk locking.
+
+   In some previous versions, when UnZip expanded a non-V archive, it
+did no pre-allocation, and used the default extension quantity.  This
+could slow file creation significantly for large files.  Now, space for
+extracted files is pre-allocated, and the same SQO ("sequential access
+only") flag is set, as with a -V archive.
+
+
+   Changes to the "-V" (/VMS) Option
+   ---------------------------------
+
+   The intent of the "-V" (/VMS) option was to store VMS file attributes
+in a Zip archive, allowing UnZip to extract an exact copy of a file on a
+VMS system, including all its VMS attributes.
+
+   In Zip before version 2.31, using the "-V" (/VMS) option created an
+archive which usually contained data from beyond the EOF (End-of-File)
+marker in a data file, but generally not all the disk blocks allocated
+for the file.  When extracted on a VMS system, the result was usually
+acceptable (because the data from beyond the EOF marker were usually
+ignored).  However, when extracted on a non-VMS system, the resulting
+file was usually corrupted by being NUL-padded to the next larger 16KB
+multiple in size.
+
+   Now (Zip 2.31 and later), with "-V" (/VMS), Zip truncates a data file
+at EOF, and portable-format files (Stream_LF, fixed-512) should be
+extracted properly on a non-VMS system.  On a VMS system, well-formed
+files (that is, those with no valid data beyond EOF) should also be
+restored correctly.
+
+   With the new "-VV" (/VMS = ALL) option, the archive includes all
+allocated blocks for the file (including those beyond EOF).  When
+extracted on a VMS system, the original file should be reproduced with
+as much fidelity as possible, but on a non-VMS system, most files will
+be seen as corrupt because of the data from beyond EOF.
+
+
+   Changes to Program Exit Status Values
+   -------------------------------------
+
+   Zip and UnZip exit with 32-bit VMS status values which are formed
+from their internal OS-independent status values.  In previous program
+versions, this was done by converting the internal success code (0) into
+%x00000001 (SS$_NORMAL), and converting the other internal warning and
+error codes using an artificial control/facility code, 0x7FFF (which
+includes some reserved bits), and a severity value which was determined
+according to rules specified in the VMS-specific exit function.
+Curiously, the internal status codes were left-shifted by 4 bits instead
+of 3, so all the resulting VMS message codes (bits 13:3) were even.
+
+   Zip and UnZip now have facility names and codes assigned by HP
+(UnZip: IZ_UNZIP, 1954; Zip: IZ_ZIP, 1955).  Now, by default, the
+programs exit with standard 32-bit VMS status values which differ from
+the old ones in several ways: The official facility code is used, and
+the facility-specific bit is set.  (For compatibility with older
+versions, the internal status codes are still left-shifted by 4 bits. 
+This also makes it easier to extract the internal status code from a
+hexadecimal representation of the VMS status code.)  The builders also
+create non-executable message files (UNZIP_MSG.EXE and ZIP_MSG.EXE) so
+that, after a suitable SET MESSAGE command, the program messages will be
+available from DCL.  For example:
+
+      $ SET MESSAGE dev:[dir]ZIP_MSG.EXE
+      $ ZIP FRED.ZIP no_such_file
+        zip warning: name not matched: no_such_file
+
+      zip error: Nothing to do!
+      (dev:[dir]FRED.ZIP;)
+
+      ALP $ WRITE SYS$OUTPUT F$MESSAGE( $STATUS)
+      %IZ_ZIP-W-NONE, Nothing to do
+
+The message files may be copied into SYS$MESSAGE to make them generally
+available, although this could cause some confusion if multiple versions
+of the programs are used on the system, and their error message source
+files differ.  Each different destination directory will get its own
+UNZIP_MSG.EXE or ZIP_MSG.EXE ([.ALPHA], [.ALPHAL], [.VAX], and so on),
+but all of the same-architecture files are equivalent to each other.
+That is, on an Alpha system, any of the [.ALPHA*]ZIP_MSG.EXE files could
+be used; on an IA64 system, any of the [.IA64*]ZIP_MSG.EXE files could
+be used; and on a VAX system, any of the [.VAX*]ZIP_MSG.EXE files could
+be used.  (Similar for UNZIP_MSG.EXE, of course.)
+
+   If desired, the programs may be built to use the old exit status values
+by defining a C macro with the old facility value:
+"CTL_FAC_IZ_UNZIP=0x7FFF" (UnZip) or "CTL_FAC_IZ_ZIP=0x7FFF" (Zip).
+(See comments in the builder regarding LOCAL_UNZIP or LOCAL_ZIP, as
+appropriate.)  This will maintain compatibility with older program
+versions, but will make the programs incompatible with the new error
+message files.
+
+
+   VMS File Attribute Schemes
+   --------------------------
+
+   Zip's "-V" (/VMS) option causes VMS file attributes to be stored in
+an archive.  Since Zip version 2.2 (released in 1996), Zip has, by
+default, stored VMS file attributes using a scheme ("PK") which is
+compatible with the one used by PKWARE in their PKZIP product.  Before
+that, a different scheme ("IM") was used.  UnZip versions before 5.2
+support only the older IM scheme, but since UnZip version 5.2, both
+schemes have been supported by UnZip.
+
+   The IM scheme has not been well tested recently, but it is still
+available.  Some problems were seen when the IM scheme was used with
+symbolic links on VMS V8.3.  Details on how build Zip to use the IM
+scheme instead of the PK scheme are included in comments in the main
+builder files.  Look for VMS_IM_EXTRA in [.VMS]BUILD_ZIP.COM or IM in
+[.VMS]DESCRIP.MMS.
+
+   The "special compilation options" section of a "zip -v" ("zip
+/verbose") report should show either VMS_PK_EXTRA or VMS_IM_EXTRA,
+according to how Zip was built.
+
+
+   UTC Date-Times
+   --------------
+
+   Zip archives traditionally include local (MS-DOS compatible)
+date-time information for files.  Since Zip version 2.1, it has also
+been possible to store UTC date-time information in the archive, and
+since UnZip version 5.2, UnZip has been able to use this UTC date-time
+information when extracting files.
+
+   On VMS, support in the C run-time environment for UTC became
+available with VMS V7.0.  UTC support in Zip and UnZip is automatically
+enabled at compile time, if it is available on the system where the code
+is compiled (__CRTL_VER >= 70000000).  It may be disabled at compile
+time by defining the C macro NO_EF_UT_TIME.  Details on how build Zip
+and UnZip with additional C macros defined are included in comments in
+the main builder files.  Look for LOCAL_[UN]ZIP in
+[.VMS]BUILD_[UN]ZIP.COM or in [.VMS]DESCRIP.MMS.  For example, using MMS
+to build UnZip:
+
+      MMS /DESCRIP = [.VMS] /MACRO = ("LOCAL_UNZIP=NO_EF_UT_TIME=1")
+
+or, using the command procedure to build Zip:
+
+      LOCAL_ZIP == "NO_EF_UT_TIME=1"
+      @ [.VMS]BUILD_ZIP.COM
+      DELETE /SYMBOL /GLOBAL LOCAL_ZIP
+
+   The "special compilation options" section of a "zip -v" ("zip
+/verbose") or "unzip -v" ("unzip /verbose") report should show
+USE_EF_UT_TIME if the program was built with UTC support.
+
+
+   Building with the LIST option using MMK or MMS
+   ----------------------------------------------
+
+   Currently, building with MMK or MMS using the LIST option (as in
+"/MACRO = LIST=1") may cause a failure for some old versions of the DEC
+C compiler.  The LIST option currently adds "/show = (all, nomessages)"
+to the CC command line, and some old DEC C compilers do not support the
+"nomessages" keyword.  When VAX C is used, this keyword is omitted, but
+the builder does not distinguish between the various DEC/Compaq/HP C
+versions.  The work-arounds are to use BUILD_[UN]ZIP.COM, or edit
+[.VMS]DESCRIP_SRC.MMS to remove the troublesome keyword.
+
+
+   GNU C
+   -----
+
+   Zip and UnZip have been built using GNU C (VAX) version 2.3, mostly
+for fun, but serious users are encouraged to report any interest in
+continuing this activity.  The GNU C 2.3 header files were missing some
+things, including definitions of SEEK_CUR, SEEK_END, and SEEK_SET.  The
+VMS-specific code now expects to find unixio.h and unixlib.h, which were
+absent from the GNU C 2.3 distribution.
+
+   To work around these difficulties, the Zip and UnZip kits include
+some emergency replacement unixio.h and unixlib.h files which appear to
+work for these programs, at least.  To install them, use commands like
+the following:
+
+      COPY [.VMS]UNIXIO_GCC.H GNU_CC_INCLUDE:[000000]UNIXIO.H
+      COPY [.VMS]UNIXLIB_GCC.H GNU_CC_INCLUDE:[000000]UNIXLIB.H
+      SET PROTECTION W:RE GNU_CC_INCLUDE:[000000]UNIXIO.H, UNIXLIB.H
+
+   There may be an error in the GNU C header file ATRDEF.H which can
+cause Zip to fail, when making a "-V" archive, with a spurious "could
+not open for reading" error message, followed by more bad behavior.  It
+probably also causes trouble of some kind in UnZip.  To check the
+questionable macro definition, use a command like the following:
+
+      SEARCH GNU_CC_INCLUDE:[000000]ATRDEF.H ATR$S_JOURNAL
+
+This should show something equivalent to this:
+
+      #define ATR$S_JOURNAL           0x001
+
+If you see "0x002" (or equivalent) instead of "0x001" (or equivalent),
+then this value must be corrected in the file before building Zip or
+UnZip.
+
+   You may also see several warnings from the compiler caused by other
+defects in the GNU C header files, such as:
+
+<various>: warning: passing arg 4 of `qsort' from incompatible pointer type
+
+[...]rab.h:134: warning: unnamed struct/union that defines no instances
+[...]rab.h:143: warning: unnamed struct/union that defines no instances
+
+These warnings appear to be harmless.
+
diff --git a/vms/VMS_ZIP.RNH b/vms/VMS_ZIP.RNH
new file mode 100644 (file)
index 0000000..183ceea
--- /dev/null
@@ -0,0 +1,1467 @@
+.!
+.!  File:       ZIP.RNH
+.!
+.!  Author:     Hunter Goatley
+.!
+.!  Date:       October 22, 1991
+.!
+.!  Description:
+.!
+.!      RUNOFF source file for portable ZIP on-line help for VMS.
+.!      Adapted from MANUAL, distributed with ZIP.
+.!
+.!      To build:       $ RUNOFF ZIP.RNH
+.!                      $ LIBR/HELP/INSERT libr ZIP
+.!
+.!  Modification history:
+.!
+.!      Hunter Goatley          22-OCT-1991 20:45
+.!              Genesis.
+.!      Jean-loup Gailly        25 March 92
+.!              Adaptation to zip 1.6.
+.!      Igor Mandrichenko       9-JUN-1992
+.!              Added explanation of -V option.
+.!      Jean-loup Gailly        14 June 92
+.!              Adaptation to zip 1.8.
+.!      Jean-loup Gailly        20 Aug 92
+.!              Adaptation to zip 1.9.
+.!      Jean-loup Gailly        31 Aug 93
+.!              Adaptation to zip 2.0.
+.!      Christian Spieler       20 Sep 93
+.!              Adaptation to zip 2.0 and OpenVMS completed.
+.!      Christian Spieler       05 Dec 95
+.!              Adaptation to zip 2.1, new options.
+.!      Christian Spieler       20 Jan 96
+.!              Changed -L and -v descriptions.
+.!      Christian Spieler       11 Feb 96
+.!              Added -X option.
+.!      Onno van der Linden,
+.!      Christian Spieler       13 Mar 96
+.!              Removed -ee option.
+.!      Christian Spieler       09 Feb 96
+.!              Updated copyright notice, Zip version.
+.!      Christian Spieler       21 Jul 97
+.!              Added -P, -R, -i@, -x@ and -tt options, modified for Zip 2.2.
+.!      Christian Spieler       14 Oct 97
+.!              unified spelling of "Info-ZIP", final cleanups for 2.2.
+.!      Steven Schweda          10 May 2007
+.!              General update for version 3.0.
+.!      Ed Gordon               12 May 2007
+.!              Minor updates for version 3.0.
+.!
+.noflags
+.lm4 .rm72
+.indent -4
+1 ZIP
+.br
+Zip is a compression and file packaging utility for several operating
+systems, including UNIX, VMS,  MSDOS, OS/2, Windows 9x/NT/XP, Minix, Atari,
+Macintosh, Amiga, and Acorn RISC OS.  It is analogous to a combination of
+tar and compress and is compatible with PKZIP (Phil Katz's ZIP) for
+MSDOS systems.
+.sk
+Zip is useful for packaging a set of files for distribution, for
+archiving files, and for saving disk space by temporarily compressing
+unused files or directories.  A companion program, UnZip, unpacks Zip
+archives.
+.sk
+For brief help on Zip or UnZip, run the program without specifying any
+parameters on the command line.
+.sk
+This description covers the Zip program which uses a UNIX-style command
+line.  A separate program is available which provides a VMS-style CLI
+command line, and it has its own documentation.  Refer to the Zip
+installation instructions for details.
+.sk
+Format
+.sk;.lm+2;.literal
+ZIP [-options] archive inpath inpath ...
+.end literal;.lm-2
+.!------------------------------------------------------------------------------
+.indent -4
+2 Basic_Usage
+.br
+Format
+.sk;.lm+2;.literal
+ZIP [-options] archive inpath inpath ...
+.end literal;.lm-2
+.sk
+The default action of Zip is to add or replace entries in "archive" from
+the list of "inpath" file specifications, which can include directories
+and file names with VMS-style wildcards, or the special name -@ to read
+file specifications from SYS$INPUT (stdin).
+.sk
+With SET PROCESS /PARSE_STYLE = EXTENDED (available on recent non-VAX
+systems), Zip preserves the case of the command line.  Otherwise, mixed-
+or upper-case options and arguments must be quoted.  For example,
+"-V".  Examples in this document generally do not show this quotation,
+so VAX and /PARSE_STYLE = TRADITIONAL users (that is, troglodytes) will
+need to add quotation where needed when working with these examples.
+.sk
+General
+.sk
+Zip reads one or more files, compresses the data (normally), and stores
+the compressed information into a single Zip archive file, along with
+information about each file (name, path, date and time of last
+modification, protection, and check information to verify file
+integrity).  On a VMS system, Zip can also save VMS/RMS file attributes,
+allowing UnZip to restore the files without loss of important file
+attributes.  Zip can pack an entire directory structure into a Zip
+archive with a single command.
+.sk
+Compression
+.sk
+Compression ratios of 2:1 to 3:1 are common for text files.  Zip has one
+standard compression method ("deflate") and can also store files without
+compression.  Zip (and UnZip) may be built with optional support for the
+bzip2 compression method.  Then, the user may select bzip2 compression
+instead of the default "deflate" method.  Zip automatically chooses
+simple storage over compression for a file, if the specified compression
+method does not actually compress the data in that file.
+.sk
+Compatibility
+.sk
+Zip and UnZip can work with archives produced by PKZIP (supporting most
+PKZIP features up to PKZIP version 4.6), and PKZIP and PKUNZIP can work
+with archives produced by Zip (with some exceptions, notably streamed
+archives, but recent changes in the .ZIP file standard may facilitate
+better compatibility).  Zip version 3.0 is compatible with PKZIP 2.04
+and also supports the Zip64 extensions of PKZIP 4.5 which allows
+archives as well as files to exceed the previous 2 GB limit (4 GB in
+some cases).  Zip also supports bzip2 compression if the bzip2 library
+is included when Zip is built.  Note that PKUNZIP 1.10 cannot extract
+files produced by PKZIP 2.04 or Zip 3.0.  You must use PKUNZIP 2.04g or
+UnZip 5.0p1 (or later versions) to extract them.
+.sk
+Large Archives and Zip64
+.sk
+Where the operating system and C run-time support allow, Zip 3.0 and
+UnZip 6.0 (and later versions) support large files (input and archive),
+using the Zip64 extensions to the original .ZIP file format.  On VMS,
+this genarally means non-VAX systems with VMS V7.2 or later (perhaps
+requiring a C RTL ECO before VMS V7.3-2).
+.sk
+Zip automatically uses the Zip64 extensions when a file larger than 2 GB
+is added to an archive, an archive containing a Zip64 entry is updated
+(if the resulting archive still needs Zip64), the size of the archive
+will exceed 4 GB, or when the number of entries in the archive will
+exceed about 64K.  Zip64 is also used for archives streamed to a
+non-seekable output device.  You must use a 4.5 compatible UnZip to
+extract files using the Zip64 extensions such as UnZip 6.0 or later.
+.sk
+In addition, streamed archives, entries encrypted with standard
+encryption, or split archives created with the pause option may not be
+compatible with PKZIP as data descriptors are used, and PKZIP at the 
+time of this writing does not support data descriptors (but recent
+changes in the PKWare published .ZIP file standard now include some
+support for the data descriptor format Zip uses).
+.!------------------------------------------------------------------------------
+.indent -4
+2 More_Usage
+.br
+Here is a very simple example of Zip use:
+.sk;.indent 10;
+$ zip stuff.zip *.*
+.sk
+This will create the Zip archive "stuff.zip" (assuming it does not
+already exist) and put all the (non-directory) files (";0") from the
+current default directory into "stuff.zip" in a compressed form.  The
+archive is opened using a default file specification of
+"SYS$DISK:[].zip", so specifying "stuff" as the archive name would also
+create (or use an existing) "stuff.zip", but specifying "stuff.other"
+would give you that name.  In general, Zip doesn't care about the type
+in the file specification, but for split archives (archives split over
+multiple files), the user should normally specify a type-less name,
+because Zip will normally generate sequentially numbered types ".z01",
+".z02", and so on for the early splits, and then the required ".zip" for
+the last split.  These file types are required by the Zip standard for
+split archives.
+.sk
+Standard VMS wildcard expansion ($SEARCH) is used to interpret the
+"inpath" file and directory specifications, like the "*.*" in this
+example.
+.sk
+On VMS, the most natural way to archive an entire directory tree is to
+use a directory-depth wildcard ("[...]").  For example:
+.sk;.indent 10
+zip foo [...]*.*
+.sk
+This will create the file "foo.zip" containing all the files (";0") and
+directories in and below the current default directory.  A more
+UNIX-like way to do this would be to use the -r (--recurse-paths)
+option:
+.sk;.indent 10
+$ zip -r foo *.*
+.sk
+Zip avoids including its own output files when selecting files to
+include in the archive, so it should be safe, as in this case, to create
+the archive in the same drectory as the input files.
+.sk
+One or more specific files, directories, or subdirectories may also be
+specified:
+.lm +10;.literal
+zip foo.zip readme.txt [www...]*.* [.ftp...]*.* -
+ [.src]*.h [.src]*.c
+.end literal;.lm -10
+.sk
+For security reasons, paths in Zip archives are always stored as
+relative paths, so some care is needed when creating an archive so that
+it will create the intended directory structure when UnZip is used to
+unpack it.
+.sk
+To use -r with a specific directory, the name of the directory file
+itself must be specified:
+.sk;.indent 10
+zip -r foo.zip [000000]www.dir ftp.dir
+.sk
+You may want to make an archive that contains the files in [.foo], but not
+record the directory name, "foo".  You can use the -j (junk path) option
+to leave off the path:
+.sk;.indent 10
+$ zip -j foo [.foo]*.*
+.sk
+If you are short on disk space, you might not have enough room to hold
+both the original directory and the corresponding compressed Zip
+archive.  In this case, you can create the archive in steps, and use the
+-m option.  For example, if [.foo] contains the subdirectories [.tom],
+[.dick], and [.harry], you could:
+.sk
+.lm +10;.literal
+zip -m foo [.foo.tom...]*.*
+zip -m foo [.foo.dick...]*.*
+zip -m foo [.foo.harry...]*.*
+.end literal;.lm -10
+.sk
+The first command would create foo.zip, and the next two would add to
+it.  The -m option means "move", and it will cause Zip to delete all
+files added to the archive after making or updating foo.zip.  No
+deletions will be done until the Zip operation has completed with no
+errors.  This option is obviously dangerous and should be used with
+care, but it does reduce the need for free disk space.  When -m is
+used, the -T option is recommended and will test the resulting archive
+before deleting the input files.
+.sk
+If a file specification list is too long to fit conveniently on the Zip
+command line, the -@ option can be used to cause Zip to read a list of
+file specifications from SYS$INPUT (stdin).  If a DCL command procedure
+is used, the names can be specified in the procedure:
+.sk;
+.lm +10;.literal
+$ zip foo -@
+$ deck
+file_spec_1
+file_spec_2
+file_spec_3
+$ eod
+.end literal;.lm -10
+.sk
+The file specifications can also be put into a separate file, and fed
+into Zip by explicitly defining SYS$INPUT, or by using PIPE.  For
+example, with the list in foo.zfl:
+.sk;
+.lm +10;.literal
+$ define /user_mode sys$input foo.zfl
+$ zip foo -@
+.end literal;.lm -10;
+or:
+.lm +10;.literal
+$ pipe type foo.zfl | zip foo -@
+.end literal;.lm -10
+.sk
+If Zip is not able to read a file, it issues a warning but continues.
+See the -MM option for more on how Zip handles patterns that are not
+matched and files that are not readable.  If some files were skipped, a
+warning is issued at the end of the Zip operation noting how many files
+were read and how many skipped.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Comments
+.br
+One-line comments may be included in the archive for each file added,
+using the -c (--entry-comments) option.  File operations (adding,
+updating) are done first, and the user is then prompted for a one-line
+comment for each file added or updated.  Enter the comment followed by
+<Return>, or just <Return> for no comment.
+.sk
+A single multi-line comment may be included for the archive as a whole,
+using the -z (--archive-comment) option.  UnZip (including UnZip SFX)
+will display this comment when it expands the archive.  The comment is
+read from SYS$INPUT (stdin), and is terminated by the usual end-of-file
+character, CTRL/Z.  As usual, in a DCL command procedure, these data can
+be included in-line in the procedure, or a user may DEFINE SYS$INPUT to
+a file to get the comment from that file.  Where supported, the DCL PIPE
+command can also be used to redirect SYS$INPUT from a file.
+.sk
+Note that -z (--archive-comment) and -@ (read file specifications from
+SYS$INPUT (stdin)) can't be used together (successfully).
+.!------------------------------------------------------------------------------
+.indent -4
+2 Compression
+.br
+Zip can archive files with or without compression.  The standard
+compression method ("deflate") is compatible with all UnZip versions
+(except really old ones that only understand the "store" method). 
+Current Zip and UnZip versions may be built with optional support for
+the bzip2 compression method.  (The bzip2 method can compress better,
+especially when compressing smaller files, but uses more CPU time, and
+requires an UnZip which includes the optional bzip2 support.  See the
+installation instructions for details on adding bzip2 compression
+support at build time.)
+.sk
+Numeric compression level options control the effort put into data
+compression, with -1 being the fastest, and -9 giving the most
+compression.
+.sk
+Compression control options:
+.sk;.lm +10;.literal
+-Z mthd                      use compress method "mthd",
+--compression-method mthd    "bzip2" or "deflate" (default)
+
+-0  (--store)                no compression
+-1  (--compress-1)           compression level 1
+-2  (--compress-2)           compression level 2
+-3  (--compress-3)           compression level 3
+-4  (--compress-4)           compression level 4
+-5  (--compress-5)           compression level 5
+-6  (--compress-6)           compression level 6
+-7  (--compress-7)           compression level 7
+-8  (--compress-8)           compression level 8
+-9  (--compress-9)           compression level 9
+.end literal;.lm -10
+.sk
+Normally, a file which is already compressed will not be compressed much 
+further (if at all) by Zip, and trying to do it can waste considerable
+CPU time.  Zip can suppress compression on files with particular types,
+specified as a colon- or semi-colon-separated list of file types:
+.sk;.indent 10
+-n type1[:type2[...]]  (--suffixes type1[:type2[...]])
+.sk
+For example:
+.sk;.indent 10
+zip -n .bz2:.gz:.jpeg:.jpg:.mp3:.zip foo [.foo]*.*
+.sk
+will put everything (";0") from [.foo] into foo.zip, but will store any
+files that end in .bz2, .gz, .jpeg, .jpg, .mp3, or .zip, without trying
+to compress them.
+.sk
+The default type list is .Z:.zip:.zoo:.arc:.lzh:.arj, and the comparison
+is case-insensitive.
+.sk
+-9 (--compress-9) will override -n (--suffixes), causing compression to
+be attempted for all files.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Encryption
+.br
+Zip offers optional encryption, using a method which by modern standards
+is generally considered to be weak.
+.sk;.literal
+-e  --encrypt
+.end literal;.br
+Encrypt new or updated archive entries using a password which is
+supplied by the user interactively on the terminal in response to a
+prompt.  (The password will not be echoed.)  If SYS$COMMAND is not a
+terminal, Zip will exit with an error.  The password is verified before
+being accepted.
+.sk;.literal
+-P password  --password password
+.end literal;.br
+Use "password" to encrypt new or updated archive entries (if any). 
+USING -P IS INSECURE!   Many multi-user operating systems provide ways
+for any user (or a privileged user) to see the current command line of
+any other user.  Even on more secure systems, there is always the threat
+of over-the-shoulder peeking.  Storing the plaintext password as part of 
+a command line in a command procedure is even less secure.  Whenever
+possible, use the non-echoing, interactive password entry method.
+.sk
+Because standard Zip encryption is weak, where security is truly
+important, use a strong encryption program, such as Pretty Good Privacy
+(PGP) or GNU Privacy Guard (GnuPG), on an archive instead of standard
+Zip encryption.  A stronger encryption method, such as AES, is planned
+for Zip 3.1.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Exit_Status
+.br
+On VMS, Zip's UNIX-style exit values are mapped into VMS-style status
+codes with facility code 1955 = %x7A3, and with the inhibit-message
+(%x10000000) and facility-specific (%x00008000) bits set:
+.sk
+.literal
+   %x17A38001                        normal exit
+   %x17A38000+ 16* Zip_error_code    warnings
+   %x17A38002+ 16* Zip_error_code    normal errors
+   %x17A38004+ 16* Zip_error_code    fatal errors
+.end literal
+.sk
+Note that multiplying the UNIX-style Zip error code by 16 places it
+conveniently in the hexadecimal representation of the VMS exit code,
+"__" in %x17A38__s, where "s" is the severity code.  For example, a
+truncated archive might cause Zip error code 2, which would be
+transformed into the VMS exit status %x17A38024.
+.sk
+The Zip VMS exit codes include severity values which approximate those
+defined by PKWARE, as shown in the following table:
+.literal
+
+    VMS      Zip err
+  severity    code     Error description
+ ----------+---------+----------------------------------------------
+  Success       0      Normal; no errors or warnings detected.
+  Fatal         2      Unexpected end of archive.
+  Error         3      A generic error in the  archive  format  was
+                       detected.   Processing  may  have  completed
+                       successfully anyway;  some  broken  archives
+                       created by other archivers have simple work-
+                       arounds.
+  Fatal         4      Zip was unable to allocate memory for one or
+                       more  buffers during program initialization.
+  Fatal         5      A severe error in  the  archive  format  was
+                       detected.   Processing probably failed imme-
+                       diately.
+  Error         6      Entry too large to be split with zipsplit.
+  Error         7      Invalid comment format.
+  Fatal         8      Zip -T failed or out of memory.
+  Error         9      The user aborted zip prematurely  with  con-
+                       trol-C (or equivalent).
+  Fatal        10      Zip  encountered an error while using a temp
+                       file.
+  Fatal        11      Read or seek error.
+  Warning      12      Zip has nothing to do.
+  Error        13      Missing or empty zip file.
+  Fatal        14      Error writing to a file.
+  Fatal        15      Zip was unable to create a file to write to.
+  Error        16      Bad command line parameters.
+  Error        18      Zip could not open a specified file to read.
+  Fatal        19      Zip was built with options not supported  on
+                       this system
+  Fatal        20      Attempt to read unsupported Zip64 archive
+.end literal
+.!------------------------------------------------------------------------------
+.indent -4
+2 Extra_Fields
+.br
+The .ZIP file format allows some extra data to be stored with a file in
+the archive.  For example, where local time zone information is
+available, Zip can store UTC date-time data for files.  (Look for
+USE_EF_UT_TIME in a "zip -v" report.)  On VMS, with -V or -VV, Zip will
+also store VMS-specific file attributes.  These data are packaged as
+"extra fields" in the archive.  Some extra fields are specific to a
+particular operating system (like VMS file attributes).  Large files
+(bigger than 4GB) on any OS require an extra field to hold their 64-bit
+size data.  Depending on the capabilities of the UnZip program used to
+expand the archive, these extra fields may be used or ignored when files
+are extracted from the archive.
+.sk
+Some extra fields, like UTC date-times or VMS file attributes, are
+optional.  Others, like the Zip64 extra field which holds 64-bit sizes
+for a large file, are required.
+.sk
+The -X (--strip-extra) option suppresses the saving of any optional
+extra fields in the archive.  (Thus, -X conflicts with -V or -VV.)
+.!------------------------------------------------------------------------------
+.indent -4
+2 Environment
+.br
+A user can specify default command-line options and arguments by
+defining an "environment variable" (that is, a logical name or DCL
+symbol), "ZIP_OPTS" or "ZIPOPT", to specify them.  If both "ZIP_OPTS" and
+"ZIPOPT" are specified, the definition of "ZIPOPT" prevails.
+.sk
+The C RTL function getenv() is used to sense these variables, so its
+behavior determines what happens if both a logical name and a symbol are
+defined.  As of VMS V7.3, a logical name supercedes a symbol.
+.sk
+The "zip -v" report should show the perceived settings of these
+variables.
+.!------------------------------------------------------------------------------
+.indent -4
+2 File_Names
+.br
+Zip deals with file names in the system file system and with file names
+in Zip archives.  File names in a Zip archive are stored in a UNIX-like
+path-name format.  For example, a VMS file specification like this:
+.sk;.indent 10
+[.zip30.vms]descrip.mms
+.sk
+could appear in a Zip archive as:
+.sk;.indent 10
+zip30/vms/descrip.mms
+.sk
+For security reasons, paths in Zip archives are always stored as
+relative paths, so an absolute VMS directory specification will be
+transformed to a relative path in the archive (that is, no leading "/"). 
+For example, the following absolute directory specification would give
+the same archive path as the previous (relative) example:
+.sk;.indent 10
+[zip30.vms]descrip.mms
+.sk
+Also, device names are dropped, so the following file specification
+would also give the same archive path:
+.sk;.indent 10
+sys$sysdevice:[zip30.vms]descrip.mms
+.sk
+If an archive is intended for use with PKUNZIP under MSDOS, then the -k
+(for "Katz", --DOS-names) option should be used to attempt to adjust the
+names and paths to conform to MSDOS character-set and length
+limitations, to store only the MSDOS file attributes (just the
+owner:write attribute from VMS), and to mark the entry as made under
+MSDOS (even though it wasn't).
+.sk
+Note that file specifications in the file system must be specified using
+VMS notation, but file names in an archive must be specified using the
+UNIX-like notation used in the archive.  For example, where a BACKUP
+command might look like this:
+.sk.indent 10
+$ back [.zip30...]*.* /excl = [...vms]*.c stuff.bck /save
+.sk
+a corresponding Zip command might look like this:
+.sk;.indent 10;
+$ zip stuff.zip [.zip30...]*.* -x */vms/*.c
+.sk
+because the files to be added to the Zip archive are specified using VMS
+file specifications, but the -x (--exclude) option excludes names based
+on their archive path/file names.  Options dealing with archive names
+include -R (--recurse-patterns), -d (--delete), -i (--include), -x
+(--exclude), and -U (--copy-entries).
+.sk
+Note: By default, on VMS, archive name pattern matching (-R, -d, -i, -x,
+and -U) is case sensitive, even when the file system is not case
+sensitive (or even case preserving).  This allows accurate matching of
+mixed-case names in an archive which may have been created on a system
+with a case sensitive file system, but it can involve extra effort on
+VMS, where it may be necessary to use unnatural case names (or the same
+names in multiple cases, like "*.obj *.OBJ") for this kind of pattern
+matching to give the desired behavior.  If completely case-blind pattern
+matching behavior is desired, specify the -ic (--ignore-case) option.
+.!------------------------------------------------------------------------------
+.indent -4
+3 Case
+.br
+For better compatibility with UNIX-like systems, Zip, by default,
+down-cases ODS2 file names.  For example, the following file on an ODS2
+file system:
+.sk;.indent 10
+[.ZIP30.VMS]DESCRIP.MMS
+.sk
+would appear in an archive as:
+.sk;.indent 10
+zip30/vms/descrip.mms
+.sk
+Zip versions before 3.0 down-cased all VMS file names.  Now, various
+options give the user control over these conversions:
+.sk
+.lm +10;.literal
+-C    preserve case of all file names
+-C-   down-case all file names
+-C2   preserve case of ODS2 names
+-C2-  down-case ODS2 file names (default)
+-C5   preserve case of ODS5 names (default)
+-C5-  down-case ODS5 file names
+.end literal;.lm -10
+.sk
+Case is handled differently for archive member names, which the user
+specifies with the -R, -d, -i, -x, and -U options.  By default, on VMS,
+archive name pattern matching is case sensitive, even when the file
+system is not case sensitive (or even case preserving).  This allows
+accurate matching of mixed-case names in an archive which may have been
+created on a system with a case sensitive file system, but it can
+involve extra effort on VMS, where it may be necessary to use unnatural
+case names (or the same names in multiple cases, like "*.obj *.OBJ") for
+this kind of pattern matching to give the desired behavior.  If
+completely case-blind pattern matching behavior is desired, specify the
+-ic (--ignore-case) option.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Fixing_Damage
+.br
+Two options can be used to fix a damaged Zip archive.
+.sk;.literal
+-F  --fix
+-FF  --fixfix
+.end literal;.sk
+The -F (--fix) option can be used if some portions of the archive are
+missing, but it requires a reasonably intact central directory.  The
+input archive is scanned as usual, but zip will ignore some problems. 
+The resulting archive should  be valid, but any inconsistent entries
+will be left out.
+.sk
+If the archive is too damaged or the end (where the central directory is
+situated) has been truncated, you must use -FF (--fixfix).  This is a
+change from zip 2.32, where the -F option is able to read a truncated
+archive.  The -F option now more reliably fixes archives with minor 
+damage, and the -FF option is needed to fix archives where -F and -FF
+was used before.
+.sk
+With -FF, the archive is scanned from the beginning and Zip scans for
+special signatures to identify the limits between the archive members.
+The -F option is more reliable if the archive is not too much damaged,
+so try this option first.
+.sk
+Neither option will recover archives that have been incorrectly
+transferred, such as by FTP in ASCII mode instead of binary.  After the
+repair, the -t option of UnZip may show that some files have a bad CRC.
+Such files cannot be recovered; you can remove them from the archive
+using the -d option of Zip.
+.sk
+Because of the uncertainty of the "fixing" process, it's required
+to specify an output archive, rather than risking further damage to the
+original damaged archive.  For example, to fix the damaged archive
+foo.zip,
+.sk;.indent 10
+zip -F foo --out foo_fix
+.sk
+tries to read the entries normally, copying good entries to the new 
+archive foo_fix.zip.  If this doesn't work, as when the archive is
+truncated, or if some entries are missed because of bad central
+directory entries, try -FF:
+.sk;.indent 10
+zip -FF foo --out foo_fixfix
+.sk
+and compare the resulting archive to the archive created using -F. The
+-FF option may create an inconsistent archive.  Depending on what is
+damaged, you can then use the -F option to fix that archive.
+.sk
+A split archive with missing split files can be fixed using -F if you
+have the last split of the archive (the ".zip" file).  If this file is
+missing, you must use -FF to fix the archive, which will prompt you for
+the splits you have.
+.sk
+Currently, the fix options can't recover an entry which has a bad
+checksum or is otherwise damaged.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Log_File
+.br
+Zip normally sends messages to the user's terminal, but these may be
+also directed to a log file.
+.sk;.literal
+-la  --log-append
+.end literal;.br
+Append to an existing log file.  Default is to create a new version.
+.sk;.literal
+-lf logfilepath  --logfile-path logfilepath
+.end literal;.br
+Open a logfile at the given path.  By default, a new version will be
+created, but with the -la option an existing file will be opened and the
+new log information appended to any existing information.  Only
+warnings and errors are written to the log unless the -li option is also
+given, then all information messages are also written to the log.
+.sk;.literal
+-li  --log-info
+.end literal;.br
+Include information messages, such as file names being zipped, in the
+log.  The default is to include only the command line, any warnings
+and errors, and the final status.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Modes_of_Operation
+.br
+Zip supports two distinct types of command modes, external and 
+internal.  The external modes (update, grow, and freshen) read files
+from the file system (as well as from an existing archive) while the
+internal modes (delete and copy) operate exclusively on entries in an
+existing archive.
+.sk;.literal
+-u  --update
+.end literal;.br
+Update existing entries and add new files.  If the archive does not
+exist, create it.  This is the default mode, so -u is optional.
+.sk;.literal
+-g  --grow
+.end literal;.br
+Grow (append to) the specified Zip archive, instead of creating a new
+one.  If this operation fails, Zip attempts to restore the archive to
+its original state.  If the restoration fails, the archive might become 
+corrupted.  This option is ignored when there's no existing archive or
+when at least one archive member must be updated or deleted.
+.sk;.literal
+-f  --freshen
+.end literal;.br
+Update existing entries in an existing archive.  Does not add new files
+to the archive.
+.sk;.literal
+-d  --delete
+.end literal;.br
+Delete entries from an existing archive.
+.sk;.literal
+-DF  --difference-archive
+.end literal;.br
+Create an incremental backup-style archive, where the resulting archive 
+will contain all new and changed files since the original archive was
+created.  For this to work, the input file list and current directory 
+must be the same as during the original Zip operation.
+.sk
+For example, if the existing archive was created using
+.sk;.indent 10
+zip foo_full.zip [.foo...]*.*
+.sk
+from just above the foo directory, then the command (also from just
+above the foo directory):
+.sk;.indent 10
+zip foo_full.zip [.foo...]*.* -DF -O foo_incr.zip
+.sk
+creates the archive foo_incr.zip with just the files not in foo_full.zip
+and the files where the size or date-time of the files does not match
+that in foo_full.zip.  Note that in the "zip -DF" operation, the
+original full archive is specified as the input archive, and the -O
+(--output-file) option is used to specify the new (incremental) output
+archive.
+.sk;.literal
+-FS  --filesync
+.end literal;.br
+Delete entries in the archive that do not match files on the OS.
+Normally when an archive is updated, new files are added and changed
+files are updated but files that no longer exist on the OS are not
+deleted from the archive.  This option enables deleting of entries that
+are not matched on the OS.  Enabling this option should create archives
+that are the same as new archives, but since existing entries are copied
+instead of compressed, updating an existing archive with -FS can be much
+faster than creating a new archive.  If few files are being copied from
+the old archive, it may be faster to create a new archive instead.
+.sk
+This option deletes files from the archive.  If you need to preserve the
+original archive, make a copy of the archive first, or use the  -O
+(--output) option to output the new archive to a new file.  Even though
+it's slower, creating a new archive with a new archive name is safer, 
+avoids mismatches between archive and OS paths, and is preferred.
+.sk;.literal
+-U  --copy-entries
+.end literal;.br
+Select entries in an existing archive and copy them to a new archive. 
+Copy mode is like update mode, but entries in the existing archive are
+selected by command line patterns rather than files from the file system
+and it uses the -O (--output-file) option to write the resulting archive
+to a new file rather than updating the existing archive, leaving the
+original archive unchanged.
+.sk
+Normally, when updating an archive using relative file specifications
+("[]", "[.xxx]", and so on), it helps to have the same default directory
+as when the archive was created, but this is not a strict requirement.
+.sk
+Date-time information in a Zip archive may be influenced by time zone.
+.!------------------------------------------------------------------------------
+.indent -4
+3 Examples
+.br
+When given the name of an existing archive, Zip will replace identically
+named entries in the archive or add entries for new names.  For example,
+if foo.zip exists and contains foo/file1 and foo/file2, and the
+directory [.foo] contains the files file1 and file3, then:
+.sk;.indent 10
+$ zip foo [.foo...]*.*
+.sk
+will replace foo/file1 in foo.zip and add foo/file3 to foo.zip.  After
+this, foo.zip contains foo/file1, foo/file2, and foo/file3, with foo/file2
+unchanged from before.  This is the default mode -u (update).
+.sk
+Update will add new entries to the archive and will replace
+existing entries only if the modified date of the file is more recent than
+the date recorded for that name in the archive.  For example:
+.sk;.indent 10
+$ zip -u stuff *.*
+.sk
+will add any new files in the current directory, and update any changed
+files in the archive stuff.zip.  Note that Zip will not try to pack
+stuff.zip into itself when you do this.  Zip avoids including its own
+output files when selecting files to include in the archive, so it
+should be safe, as in this case, to have the archive included in the
+list of input files.
+.sk
+A second mode, -f (freshen), like update will only
+replace entries with newer files.  Unlike update, however, it will not
+add files that are not already in the archive.  For example:
+.sk;.indent 10
+$ zip -f foo
+.sk
+Note that the -f option with no arguments freshens all the entries in the
+archive.  The same is true of -u, so "zip -u foo" and "zip -f foo" do
+the same thing.
+.sk
+When these options are used, Zip should be run from the same directory
+as when the original Zip command was run, so that the path names in the
+archive will continue to agree with the path names in the file system. 
+Normally, it's also a good idea to keep the other options the same (-V,
+-w, and the like), to keep the archive contents consistent.
+.sk
+The -t (--from-date) and -tt (--before-date) options can also be used
+with adding, updating, or freshening to restrict further the files to be
+included in the archive.  For example:
+.sk;.indent 10
+$ zip -rt 12071991 infamy [.FOO]*.*
+.sk
+will add all the files in [.FOO] and its subdirectories that were last
+modified on December 7, 1991, or later to the achive infamy.zip.  Dates
+can be in format mmddyyyy or yyyy-mm-dd.
+.sk
+Also, files can be explicitly excluded using the -x option:
+.sk;.indent 10
+$ zip -r foo [.FOO] -x *.obj
+.sk
+which will zip up the contents of [.FOO] into foo.zip but exclude all the
+files that end in ".obj".
+.sk
+The -d (delete) mode will remove entries from an
+archive.  An example might be:
+.sk;.indent 10
+$ zip -d foo foo/harry/*.* *.obj
+.sk
+which will remove all of the files that start with "foo/harry/" and all of
+the files that end with ".obj" (in any path).
+.sk
+The last mode, -U (--copy-entries), selects entries from an existing
+archive and copies them to a new archive.
+.sk;.indent 10
+$ zip -U foo *.obj --out fooobj
+.sk
+will copy all .obj entries from foo.zip and put them in the new archive
+fooobj.zip.
+.sk
+Note: By default, on VMS, archive name pattern matching (-R, -d, -i, -x,
+and -U) is case sensitive, even when the file system is not case
+sensitive (or even case preserving).  This allows accurate matching of
+mixed-case names in an archive which may have been created on a system
+with a case sensitive file system, but it can involve extra effort on
+VMS, where it may be necessary to use unnatural case names (or the same
+names in multiple cases, like "*.obj *.OBJ") for this kind of pattern
+matching to give the desired behavior.  If completely case-blind pattern
+matching behavior is desired, specify the -ic (--ignore-case) option.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Options_List
+.br
+"zip -h" provides a concise list of common command-line options.  "zip
+-h2" provides more details.  "zip -so" provides a list of all available
+options.  "zip -v" shows the program version and available features. 
+(The list below was derived from a "zip -so" listing.)
+.sk
+Short-form options begin with a single hyphen ("-").  Long-form option
+begin with a double hyphen ("--"), and may be abbreviated to any
+unambiguous shorter string.  For example:
+.lm +10;.literal
+-v
+--verbose
+--verb
+.end literal;.lm -10
+.sk
+To avoid confusion, if a negatable option contains an embedded hyphen
+("-"), then avoid abbreviating it at the hyphen if you plan to negate
+it.  For example, if an option like --some-option were abbreviated to
+--some-, the parser would consider that trailing hyphen to be part of
+the option name, rather than as a negating trailing hyphen.  This
+behavior may change in the future, to interpret the trailing hyphen in
+--some- to be negating.  (So don't do it.)
+.sk
+Some options may be negated (or modified) by appending a "-":
+.lm +10;.literal
+-la-
+--show-files-
+.end literal;.lm -10
+.sk
+Some options take a value, which may immediately follow the option, or
+be separated by a space or "=".  For example:
+.lm +10;.literal
+-ttmmddyyyy
+-tt mmddyyyy
+-tt=mmddyyyy
+.end literal;.lm -10
+.sk
+.lm -4;.literal
+ Sh  Long                Description
+----+-------------------+--------------------------------------------------
+ 0   store               store (instead of compress)
+ 1   compress-1          compress faster (-2, -3, -4, ...)
+ 9   compress-9          compress better
+ ?                       show the Zip help screen
+ @   names-stdin         read input file patterns from SYS$INPUT (1/line)
+ A   adjust-sfx          adjust self-extracting executable
+ b   temp-path  path     use "path" directory for temporary files
+ C   preserve-case       preserve case of all file names added to archive
+ C-  preserve-case-      down-case all file names added to archive
+ C2  preserve-case-2     preserve case of ODS2 names added to archive
+ C2- preserve-case-2-    down-case ODS2 file added to archive (default)
+ C5  preserve-case-5     preserve case of ODS5 names added to archive (dflt)
+ C5- preserve-case-5-    down-case ODS5 names added to archive
+ c   entry-comments      add a comment for each entry added to archive
+ D   no-dir-entries      do not add archive entries for directories
+ DF  difference-archive  difference archive: add only changed or new files
+ d   delete              delete entries in archive
+ db  display-bytes       display running byte counts
+ dc  display-counts      display running file counts
+ dd  display-dots        display progress dots for files (dflt size = 10MB)
+ dg  display-globaldots  display progress dots for archive, not each file
+ ds  dot-size   size     set progress dot interval to "size" (MB)
+ du  display-usize       display original uncompressed size for entries
+ dv  display-volume      display volume (disk) number as in_disk>out_disk
+ e   encrypt             encrypt entries, ask for password
+ F   fix                 fix mostly intact archive (try F before FF)
+ FF  fixfix              salvage what can be salvaged (not as reliable)
+ FS  filesync            remove archive entries unmatched in file system
+ f   freshen             update existing entries (only changed files)
+ fd  force-descriptors   force data descriptors as if streaming
+ fz  force-zip64         force use of Zip64 format
+ g   grow                grow existing archive (unless updating or deleting)
+ H                       show the Zip help screen
+ h   help                show the Zip help screen
+ h2  more-help           show extended Zip help
+ i   include  pat1 [pat2 [...]]  include only names matching the patterns
+ ic  ignore-case         ignore case (case-blind archive entry name matching)
+ J   junk-sfx            junk (remove) archive preamble (unzipsfx)
+ j   junk-paths          junk (don't store) directory names, only file names
+ k   DOS-names           simulate PKZIP-made archive (DOS 8.3 names)
+ L   license             show software license
+ l   to-crlf             translate end-of-lines (LF -> CRLF)
+ la  log-append          append to existing log file
+ lf  logfile-path  lfile  log to log file at lfile (default: new version)
+ li  log-info            include informational messages in log
+ ll  from-crlf           translate end-of-lines (CRLF -> LF)
+ MM  must-match          input file spec must exist (wildcards must match)
+ m   move                delete files added to archive
+ n   suffixes  sfx1[:sfx2[...]]  don't compress files with these suffixes
+ nw  no-wild             no wildcards during add or update
+ O   output-file  ozf  use "ozf" as the output archive (dflt = inp archive)
+ o   latest-time         set archive date-time to match oldest entry
+ P   password  password  encrypt with supplied "password" string
+ q   quiet               quiet operation (no info messages)
+ R   recurse-patterns    recurse into subdirs from cur dir, match names only
+ r   recurse-paths       recurse into directories from specified path pats
+ s   split-size  size    split archive at "size" (K/MB)  (0: don't split)
+ sb  split-bell          ring terminal bell at pause for split medium change
+ sc  show-command        show command line
+ sd  show-debug          show debug messages
+ sf  show-files          show files to process (only)
+ so  show-options        show list of all command-line options
+ sp  split-pause         pause to select split destination(s)
+ sv  split-verbose       be verbose about creating splits
+ T   test                test archive integrity (runs UnZip -T)
+ t   from-date  mmddyyyy  only do files since (at or after) "mmddyyyy"
+ tt  before-date  mmddyyyy  only do files before "mmddyyyy"
+ u   update              update changed files, add new files (default mode)
+ V   VMS-portable        save VMS file attributes
+ VV  VMS-specific        save VMS file attributes and all allocated blocks
+ v   verbose             verbose messages (print version info if only arg)
+ w   VMS-versions        save VMS version numbers in archive
+ ww  VMS-dot-versions    save VMS version numbers as ".nnn", not ";nnn"
+ X   strip-extra         strip all but critical extra fields
+ X-  strip-extra-        keep all extra fields
+ x   exclude  pat1 [pat2 [...]]  exclude all names matching the patterns
+ Z   compression-method mthd  use compress method "mthd" (bzip2 or deflate)
+ z   archive-comment     ask for archive comment
+.end literal;.lm +4
+.!------------------------------------------------------------------------------
+.indent -4
+2 Miscellaneous_Options
+.sk;.literal
+-D  --no-dir-entries
+.end literal;.br
+Do not create entries in the archive for directories.  By default,
+directory entries are added to an archive, so that their attributes can
+be saved in the archive.  When an archive is created using -D, UnZip
+will still create directories as needed (subject to user control), but
+they will get the default attributes (date-time, permissions, ...) on
+the destination system, rather than their original atributes.
+.sk;.literal
+-MM  --must-match
+.end literal;.br
+All input patterns must match at least one file and all input files 
+found must be readable.  Normally when an input pattern does not match
+a file the "name not matched" warning is issued and when an input
+file has been found but later is missing or not readable a "missing or
+not readable" warning is issued.  In either case Zip continues
+creating the archive, with missing or unreadable new files being skipped 
+and files already in the archive remaining unchanged.  After the
+archive is created, if any files were not readable zip returns the OPEN
+error code (18 on most systems) instead of the normal success return (0
+on most systems).  With -MM, Zip exits as soon as an input pattern
+is not matched (whenever the "name not matched" warning would be issued)
+or when an input file is not readable. In either case Zip exits with
+an OPEN error and no archive is created.
+.sk
+This option is useful when a known list of files is to be zipped so any
+missing or unreadable files should result in an error.  It may be less
+useful when used with wildcards, but Zip will still exit with an error
+if any input pattern doesn't match at least  one file or if any
+matched files are unreadable.  If you want to create the archive anyway
+and only need to know if files were skipped, then don't use -MM and just
+check the exit status.  Also, a log file (see -lf (--logfile-path))
+could be useful.
+.sk;.literal
+-O out_file  --output-file out_file
+.end literal;.br
+Process the archive changes as usual, but instead of updating the
+existing archive, send the output to a new archive, "out_file".  The
+output archive specified must be a different file from the input
+archive.
+.sk
+This option can be used to create updated split archives.  It can
+also be used with -U to copy entries from an existing archive to
+a new archive.  See the EXAMPLES section below.
+.sk
+Another use is converting zip files from one split size to
+another.  For instance, to convert an archive with 700MB CD splits
+to one with 2GB DVD splits, can use:
+.sk;.indent 10
+zip -s 2g cd-split.zip --out dvd-split.zip
+.sk
+which uses copy mode.  See -U below.  Also:
+.sk;.indent 10
+zip -s 0 split.zip --out unsplit.zip
+.sk
+will convert a split archive to a single-file archive.
+.sk
+Copy mode will convert stream entries (using data descriptors and which
+may be incompatible with some unzip programs) to normal entries (which
+should be compatible with all unzip programs), except if standard
+encryption was  used.  For archives with encrypted entries, zipcloak
+will decrypt the entries and convert them to normal entries.
+.sk;.literal
+-o  --latest-time
+.end literal;.br
+Set the modification date-time of the Zip archive file to the latest
+(newest) modification date-time found among the entries in the zip
+archive.  This can be used without any other operations, if
+desired.  For example:
+.sk;.indent 10
+zip -o foo
+.sk
+will change the modification date-time of foo.zip to the latest time of
+the entries in foo.zip.
+.sk;.literal
+-q  --quiet
+.end literal;.br
+Quiet mode.  Eliminates informational messages and comment prompts. 
+This mode may be useful in command procedures, or if the Zip operation
+is being performed as a background task ("$ spawn/nowait zip -q foo
+*.c").
+.sk
+.sk;.literal
+-T  --test
+.end literal;.br
+Test the integrity of a zip archive (the new one, if -O (--output-file)
+is specified).  If the check fails, the old zip file is unchanged  and
+(with the -m option) no input files are removed.
+.sk
+Implementation
+.br
+"zip -T" actually runs an "unzip -t" command to do the testing, so UnZip
+must be installed properly for this to work.
+.sk;.literal
+-TT unzip_cmd  --unzip-command unzip_cmd
+.end literal;.br
+Specify the actual UnZip command, "unzip_cmd" (normally a DCL symbol) to
+use for "zip -T".  This can be useful if multiple versions of UnZip are
+installed on a system, and the default DCL symbol "UNZIP" would run the
+wrong one (or the logical name DCL$PATH would lead to the wrong one).
+.sk
+In "unzip_cmd", the string "{}" is replaced by the temporary name of the
+archive to be tested, otherwise the name of the archive is appended
+to the end of the command.  The exit status is checked for success severity.
+.sk;.literal
+-v  --verbose
+.end literal;.br
+Verbose mode or print diagnostic version info.
+.sk
+Normally, when applied to real operations, this option enables the 
+display of a progress indicator during compression (see -dd for more on
+dots) and requests verbose diagnostic info about archive structure
+oddities.
+.sk
+When -v is the only command line argument, a diagnostic report is
+displayed, showing:
+.lm +3;.br;.indent -2
+o Copyright and other legal notices
+.br;.indent -2
+o Program name, version, and release date
+.br;.indent -2
+o Pointers to Info-ZIP FTP and Web sites
+.br;.indent -2
+o Program build information (compiler type and version, OS version, and
+the compilation date
+.br;.indent -2
+o Optional features enabled at compile-time
+.br;.indent -2
+o Environment variable definitions (ZIP_OPTS, ZIPOPT)
+.lm -3;.br
+.sk
+This information should be included in bug reports.
+.sk;.literal
+-y  --symlinks
+.end literal;.br
+Store symbolic links as such in the Zip archive, instead of compressing
+and storing the file referred to by the link.  A symbolic link normally
+requires less storage than the actual file, both in the archive, and on
+the destination file system.
+.sk
+On VMS, symbolic links are supported on ODS5 disks where the C RTL
+supports symbolic links.  Full support for symbolic links seems to
+require VMS V8.3, but a Zip program supporting symbolic links may be
+built on VMS V7.3-2.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Progress_Display
+.br
+Various options control the display of progress messages during Zip
+operation.
+.sk;.literal
+-db  --display-bytes
+.end literal;.br
+Display running byte counts showing the bytes processed and the bytes to
+go.
+.sk;.literal
+-dc  --display-counts
+.end literal;.br
+Display running count of entries processed and entries to go.
+.sk;.literal
+-dd  --display-dots
+.end literal;.br
+Display dots while each entry is processed (except on ports that have 
+their own progress indicator).  See -ds below for setting dot size.  The
+default is a dot every 10 MB of input file processed.  The -v
+(--verbose) option also displays dots and used to at a higher rate than
+this (at the same rate as in previous versions of Zip) but this rate has
+been changed to the new 10 MB default, and is also controlled by -ds.
+.sk;.literal
+-dg  --display-globaldots
+.end literal;.br
+Display progress dots for the archive instead of for each file.  The
+command
+.sk;.indent 10
+zip -qdgds 10m
+.sk
+will turn off most output except dots every 10 MB.
+.sk;.literal
+-ds size  --dot-size size
+.end literal;.br
+Set amount of input file processed for each dot displayed.  See -dd to
+enable displaying dots.  Setting this option implies -dd.  "size" is in
+the format "nm" where n is a number and m is a multiplier.  Currently
+"m" can be k (KB), m (MB), g (GB), or t (TB), so if "n" is 100 and "m"
+is k, "size" would be 100k which is 100KB.  The default is 10MB.
+.sk
+The -v (--verbose) option also displays dots and used to default to a
+higher rate than this (at the same rate as in previous versions of Zip)
+but now the default is 10 MB and the -v dots are also controlled by this
+option.  A "size" of 0 turns dots off.
+.sk
+This option does not control the dots from the "Scanning files" message 
+as Zip scans for input files.  The dot size for that is fixed at 2
+seconds or a fixed number of entries, whichever is longer.
+.sk;.literal
+-du  --display-usize
+.end literal;.br
+Display the uncompressed size of each entry.
+.sk;.literal
+-dv  --display-volume
+.end literal;.br
+Display the volume (disk) number each entry is being written to.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Self_Extracting_Archives
+.br
+A self-extracting archive (SFX) comprises a normal Zip archive appended
+to a special UnZip program (such as UNZIPSFX.EXE) for the intended
+target system.
+.sk
+The UnZip distribution includes a VMS command procedure,
+[,vms]makesfx.com, which can be used directly or adapted to create an
+SFX archive from a normal Zip archive.
+.sk
+The .ZIP file format includes offsets to data structures in the archive,
+and these offsets are measured from the start of the archive file. 
+Appending an archive to an UnZip SFX executable effectively moves the
+start of the archive file.  That makes the original offsets wrong, and
+that will cause the UnZip SFX program to emit warning messages when it
+tries to unpack the archive.  Zip -A can be used to adjust these offsets
+in a self-extracting archive.  For example, to adjust the offsets in
+foo.sfx_exe:
+.sk;.indent 10
+zip -A foo.sfx_exe
+.sk
+Similarly, the UnZip SFX program can be removed from a self-extracting
+archive (and the offsets in the archive restored) using the -J
+(--junk-sfx) option.  For example:
+.sk;.indent 10
+zip -J foo.sfx_exe
+.sk
+Note that a self-extracting archive contains a normal Zip archive, and a
+normal UnZip program can be used to expand it in the normal way.  You
+may get a warning about extra bytes at the beginning of the archive (the
+UnZip SFX program), but UnZip should work properly after that.  This
+allows data in a self-extracting archive to be accessed on any system,
+not just the target system where its embedded UnZip SFX program runs.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Split_Archives
+.br
+Beginning with version 3.0, Zip supports split archives.  A split
+archive is one which is divided into multiple files, usually to allow it
+to be stored on multiple storage media (floppy diskettes, CD-ROMs, or
+the like) when a single medium would be too small to contain the whole
+archive.  (Note that split archives are not just unitary archives split
+into pieces, as the .ZIP file format includes offsets to data structures
+in the archive, and for a split archive these are based on the start of
+each split, not on the start of the whole archive.  Concatenating the
+pieces will invalidate these offsets, but UnZip can usually deal with
+it.  Zip will usually refuse to process such a spliced archive unless
+the -FF fix option is used to fix the offsets.)
+.sk
+For a split archive with, say, 20 split files, the files are typically
+named ARCHIVE.z01, ARCHIVE.z02, ..., ARCHIVE.z19, ARCHIVE.zip, where
+"ARCHIVE" is the archive name specified by the user on the Zip command
+line.  Note that the last split file is the ".zip" file.  In contrast,
+"spanned" archives are the original multi-disk archive generally
+requiring floppy disks and using volume labels to store disk numbers. 
+Zip supports split archives but not spanned archives, though a procedure
+exists for converting split archives of the right size to spanned
+archives.  The reverse is also true, where each file of a spanned
+archive can be copied in order to files with the above names to create a
+split archive.
+.!------------------------------------------------------------------------------
+.indent -4
+3 Options
+.br
+Use "-s size" to create a split archive (and to set the split size). 
+The size is given as a number followed optionally by a multiplier suffix
+of k (KB), m (MB, the default if no suffix is specified), g (GB), or t
+(TB).  (All are powers of 1024, not 1000).  64K is the minimum split
+size.  For example, the following command could be used to create a
+split archive called "foo" from the contents of the "bar" directory with
+splits of 670MB, which might be useful for burning on CDs:
+.sk;.indent 10
+zip -s 670m foo [.bar...]*.*
+.sk
+Using -s without -sp as above creates all the splits in the directory
+specified by "foo", in this case the current default directory.  This 
+split mode updates the splits as the archive is being created, requiring
+all splits to remain writable, but creates split archives that are
+readable by any UnZip that supports split archives.  See -sp below for
+enabling split pause mode which allows splits to be written directly to
+removable media.
+.sk
+The -sv option can be used to enable verbose splitting and display
+details of how the splitting is being done.  The -sb option can be used
+to ring the terminal bell when Zip pauses for the next split
+destination.
+.sk
+The -sp option can be used to pause Zip between splits to allow 
+changing removable media, for example, but read the descriptions and
+warnings for both -s and -sp below.
+.sk
+Though Zip does not update split archives, Zip provides the option
+-O (--output-file) to allow split archives to be updated and saved in a
+new archive.  For example:
+.sk;.indent 10
+zip inarchive.zip foo.c bar.c -O outarchive.zip
+.sk
+reads archive inarchive.zip, even if split, adds the files foo.c and
+bar.c, and writes the resulting archive to outarchive.zip.  If
+inarchive.zip is split, then outarchive.zip defaults to the same split
+size.  Be aware that outarchive.zip and any split files that are created
+with it are always overwritten without warning.  This may be changed in 
+the future.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Temporary_Files
+.br
+When creating a new archive or normally when changing an existing
+archive, Zip will write a temporary file in the archive destination
+directory ("ZIxxxxxxxx", where "xxxxxxxx" is the hexadecimal process ID)
+with the new contents.  Then, if and when the Zip job has completed with
+no errors, it will rename the temporary file to the specified archive
+name (replacing the old archive, if any).
+.sk
+You can use the -b (--temp-path) option to specify a different path
+(device and/or directory) for the temporary file, but specifying a
+different device will force Zip to copy the temporary file to its final
+destination instead of simply renaming it, and that copying will take
+more time than renaming, especially for a large archive.  For example:
+.sk;.indent 10
+$ zip -b disk$scratch:[tmp] stuff *
+.sk
+will cause Zip to put its temporary files in the directory
+"disk$scratch:[tmp]", copying the temporary file back to the current
+directory as stuff.zip when it's complete.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Text_Files
+.br
+Zip offers some options to help deal with line endings in text files. 
+These may have limited utility on VMS.
+.sk;.literal
+-l  --to-crlf
+.end literal;.br
+Translate the UNIX end-of-line character LF (CR on MAC) into the MSDOS
+convention CR-LF.  This option should not be used on binary files.  This
+option can be used on UNIX if the Zip file is intended for PKUNZIP under
+MSDOS.  If the input files already contain CR-LF, this option adds an
+extra CR.  This ensure that "unzip -a" on Unix will get back an exact
+copy of the original file, to undo the effect of "zip -l".  See -ll
+below for the binary checks.
+.sk;.literal
+-ll  --from-crlf
+.end literal;.br
+Translate the MSDOS end-of-line CR LF into UNIX LF (CR on MAC).  This
+option should not be used on binary files.  This option can be used on
+MSDOS if the Zip archive is intended for UnZip under UNIX.
+.sk
+For both -l and -ll, if the file is converted and the file is later
+determined to be binary, a warning is issued and the file is probably
+corrupted.  If Zip with -l or -ll detects binary (non-text) in the first
+buffer read from a file, it issues a warning and skips line-ending
+conversion on the file, avoiding corruption.  This check seems to catch
+all binary files tested, but the original check remains and if a
+converted file is later determined to be binary, that warning is still
+issued.  The algorithm now being used for binary detection should allow
+line-ending conversion of text files in UTF-8 and similar encodings.
+.!------------------------------------------------------------------------------
+.indent -4
+2 VMS_Specifics
+.br
+VMS File Attributes
+.sk;.literal
+-V  --VMS-portable
+-VV --VMS-specific
+.end literal;.br
+The -V and -VV options cause Zip to store VMS file atributes (such as
+file organization, record format, carriage control, and so on) in
+VMS-specific "extra fields" in an archive along with the usual data. 
+These extra fields are ignored on non-VMS systems, but on a VMS system,
+they allow UnZip to restore the files with their VMS attributes intact.
+.sk
+With -V, Zip ignores any data in the file after the end-of-file (EOF)
+point (defined by FAT$L_EFBLK and FAT$W_FFBYTE), which works well for
+well-formed files (that is, those with no valid data beyond EOF). 
+Portable-format files (Stream_LF, fixed-512) archived with -V should be
+extracted properly on a non-VMS system.  Files with more complex
+structures, such as indexed files and files with embedded byte counts
+or other such data may be of limited use on other systems.  (UnZip on
+non-VMS systems may be able to extract various VMS-format text files,
+however.)
+.sk
+With -VV, Zip processes all allocated blocks for the file (including
+those beyond EOF).  When extracted on a VMS system, the original file
+should be reproduced with as much fidelity as possible, but on a non-VMS
+system, most files will be seen as corrupt because of the data from
+beyond EOF.
+.sk
+VMS File Version Numbers
+.sk;.literal
+-w  --VMS-versions
+-ww  --VMS-dot-versions
+.end literal;.br
+By default, for compatibility with non-VMS systems, Zip strips VMS file
+version numbers from the names stored in an archive.  The -w
+(--VMS-versions) option causes Zip to retain file version numbers on
+names in an archive. Without -w, a version number wildcard (";*") can
+cause errors when multiple versions of a single file are treated as
+multiple files with the same name.
+.sk
+For better compatibility with non-VMS systems where semi-colons are less
+popular in file names, the -ww (--VMS-dot-versions) option stores the
+file version numbers with a dot (".nnn") instead of a semi-colon
+(";nnn").
+.!------------------------------------------------------------------------------
+.indent -4
+2 Copyright_and_License
+.br
+Zip has an option to display its copyright and license.
+.sk;.literal
+-L  --license
+.end literal;.br
+The license is reproduced below.
+.sk.lm +3
+This is version 2007-Mar-4 of the Info-ZIP license. The definitive
+version of this document should be available at
+ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely and a copy
+at http://www.info-zip.org/pub/infozip/license.html.
+.lm -3;.sk
+--------------------------------------------------------
+.sk
+Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+.sk
+For the purposes of this copyright and license, "Info-ZIP" is defined as
+the following set of individuals:
+.sk;.lm +3
+     Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
+     Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth,
+     Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,
+     David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,
+     Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,
+     Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda,
+     Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren,
+     Rich Wales, Mike White.
+.lm -3;.sk
+This software is provided "as is," without warranty of any kind, express
+or implied.  In no event shall Info-ZIP or its contributors be held
+liable for any direct, indirect, incidental, special or consequential
+damages arising out of the use of or inability to use this software.
+.sk
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the above disclaimer and the following restrictions:
+.sk;.lm +7;.indent -4
+    1. Redistributions of source code (in whole or in part) must retain
+       the above copyright notice, definition, disclaimer, and this list
+       of conditions.
+.sk;.indent -4
+    2. Redistributions in binary form (compiled executables and libraries)
+       must reproduce the above copyright notice, definition, disclaimer,
+       and this list of conditions in documentation and/or other materials
+       provided with the distribution.  The sole exception to this condition
+       is redistribution of a standard UnZipSFX binary (including SFXWiz) as
+       part of a self-extracting archive; that is permitted without inclusion
+       of this license, as long as the normal SFX banner has not been removed
+       from the binary or disabled.
+.sk;.indent -4
+    3. Altered versions -- including, but not limited to, ports to new operating
+       systems, existing ports with new graphical interfaces, versions with
+       modified or added functionality, and dynamic, shared, or static library
+       versions not from Info-ZIP -- must be plainly marked as such and must not
+       be misrepresented as being the original source or, if binaries,
+       compiled from the original source.  Such altered versions also must not
+       be misrepresented as being Info-ZIP releases -- including, but not
+       limited to, labeling of the altered versions with the names "Info-ZIP"
+       (or any variation thereof, including, but not limited to, different
+       capitalizations), "Pocket UnZip," "WiZ" or "MacZip" without the
+       explicit permission of Info-ZIP.  Such altered versions are further
+       prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP
+       e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP
+       will provide support for the altered versions.
+.sk;.indent -4
+       4. Info-ZIP retains the right to use the names "Info-ZIP", "Zip",
+       "UnZip", "UnZipSFX", "WiZ", "Pocket UnZip", "Pocket Zip", and
+       "MacZip" for its own source and binary releases.
+.lm -7;.sk
+.!------------------------------------------------------------------------------
+.indent -4
+2 Acknowledgements
+.br
+       Thanks to R. P. Byrne for his Shrink.Pas program, which
+       inspired this project, and from which the shrink algorithm
+       was stolen; to Phil Katz for placing in the public domain
+       the zip file format, compression format, and .ZIP filename
+       extension, and for accepting minor changes to the file
+       format; to Steve Burg for clarifications on the deflate
+       format; to Haruhiko Okumura and Leonid Broukhis for providing
+        some useful ideas for the compression algorithm; to
+       Keith Petersen, Rich Wales, Hunter Goatley and Mark Adler
+       for providing a mailing list and ftp site for the Info-ZIP
+       group to use; and most importantly, to the Info-ZIP group
+       itself (listed in the file infozip.who) without whose
+       tireless testing and bug-fixing efforts a portable zip
+       would not have been possible.  Finally we should thank
+       (blame) the first Info-ZIP moderator, David Kirschbaum,
+       for getting us into this mess in the first place.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Bugs
+.br
+All bug reports, patches, or suggestions should go to zip-bugs via the
+web site contact form at http://www.Info-ZIP.org.  Patches should be
+sent as unified or context diffs only (diff -u or diff -c).
+.sk
+Any bug report should include the Zip version, any special compilation
+options (see "zip -v" report), the host system type and operating system
+version, and any other relevant information (compiler version, lunar
+phase, ...).  
+.!------------------------------------------------------------------------------
diff --git a/vms/build_zip.com b/vms/build_zip.com
new file mode 100644 (file)
index 0000000..7bbe13d
--- /dev/null
@@ -0,0 +1,690 @@
+$! BUILD_ZIP.COM
+$!
+$!     Build procedure for VMS versions of Zip.
+$!
+$!     last revised:  2007-03-15  SMS.
+$!
+$!     Command arguments:
+$!     - suppress help file processing: "NOHELP"
+$!     - suppress message file processing: "NOMSG"
+$!     - select link-only: "LINK"
+$!     - select compiler environment: "VAXC", "DECC", "GNUC"
+$!     - select large-file support: "LARGE"
+$!     - select compiler listings: "LIST"  Note that the whole argument
+$!       is added to the compiler command, so more elaborate options
+$!       like "LIST/SHOW=ALL" (quoted or space-free) may be specified.
+$!     - supply additional compiler options: "CCOPTS=xxx"  Allows the
+$!       user to add compiler command options like /ARCHITECTURE or
+$!       /[NO]OPTIMIZE.  For example, CCOPTS=/ARCH=HOST/OPTI=TUNE=HOST
+$!       or CCOPTS=/DEBUG/NOOPTI.  These options must be quoted or
+$!       space-free.
+$!     - supply additional linker options: "LINKOPTS=xxx"  Allows the
+$!       user to add linker command options like /DEBUG or /MAP.  For
+$!       example: LINKOPTS=/DEBUG or LINKOPTS=/MAP/CROSS.  These options
+$!       must be quoted or space-free.  Default is
+$!       LINKOPTS=/NOTRACEBACK, but if the user specifies a LINKOPTS
+$!       string, /NOTRACEBACK will not be included unless specified by
+$!       the user.
+$!     - select installation of CLI interface version of zip:
+$!       "VMSCLI" or "CLI"
+$!     - force installation of UNIX interface version of zip
+$!       (override LOCAL_ZIP environment): "NOVMSCLI" or "NOCLI"
+$!     - select BZIP2 support: "IZ_BZIP2=dev:[dir]", where "dev:[dir]"
+$!       (or a suitable logical name) tells where to find "bzlib.h".
+$!       The BZIP2 object library (LIBBZ2_NS.OLB) is expected to be in
+$!       a "[.dest]" directory under that one ("dev:[dir.ALPHAL]", for
+$!       example), or in that directory itself.
+$!
+$!     To specify additional options, define the global symbol
+$!     LOCAL_ZIP as a comma-separated list of the C macros to be
+$!     defined, and then run BUILD_ZIP.COM.  For example:
+$!
+$!             $ LOCAL_ZIP == "VMS_IM_EXTRA"
+$!             $ @ [.VMS]BUILD_ZIP.COM
+$!
+$!     Valid VMS-specific options include VMS_PK_EXTRA and VMS_IM_EXTRA. 
+$!     See the INSTALL file for other options.  (VMS_PK_EXTRA is the
+$!     default.)
+$!
+$!     If editing this procedure to set LOCAL_ZIP, be sure to use only
+$!     one "=", to avoid affecting other procedures.  For example:
+$!             $ LOCAL_ZIP = "VMS_IM_EXTRA"
+$!
+$!     Note: This command procedure always generates both the "default"
+$!     Zip having the UNIX style command interface and the "VMSCLI" Zip
+$!     having the CLI compatible command interface.  There is no need to
+$!     add "VMSCLI" to the LOCAL_ZIP symbol.  (The only effect of
+$!     "VMSCLI" now is the selection of the CLI style Zip executable in
+$!     the foreign command definition.)
+$!
+$!
+$ on error then goto error
+$ on control_y then goto error
+$ OLD_VERIFY = f$verify( 0)
+$!
+$ edit := edit                  ! override customized edit commands
+$ say := write sys$output
+$!
+$!##################### Read settings from environment ########################
+$!
+$ if (f$type( LOCAL_ZIP) .eqs. "")
+$ then
+$     LOCAL_ZIP = ""
+$ else  ! Trim blanks and append comma if missing
+$     LOCAL_ZIP = f$edit( LOCAL_ZIP, "TRIM")
+$     if (f$extract( f$length( LOCAL_ZIP)- 1, 1, LOCAL_ZIP) .nes. ",")
+$     then
+$         LOCAL_ZIP = LOCAL_ZIP + ","
+$     endif
+$ endif
+$!
+$! Check for the presence of "VMSCLI" in LOCAL_ZIP.  If yes, we will
+$! define the foreign command for "zip" to use the executable
+$! containing the CLI interface.
+$!
+$ len_local_zip = f$length( LOCAL_ZIP)
+$!
+$ pos_cli = f$locate( "VMSCLI", LOCAL_ZIP)
+$ if (pos_cli .ne. len_local_zip)
+$ then
+$     CLI_IS_DEFAULT = 1
+$     ! Remove "VMSCLI" macro from LOCAL_ZIP. The Zip executable
+$     ! including the CLI interface is now created unconditionally.
+$     LOCAL_ZIP = f$extract( 0, pos_cli, LOCAL_ZIP)+ -
+       f$extract( pos_cli+7, len_local_zip- (pos_cli+ 7), LOCAL_ZIP)
+$ else
+$     CLI_IS_DEFAULT = 0
+$ endif
+$ delete /symbol /local pos_cli
+$!
+$! Check for the presence of "VMS_IM_EXTRA" in LOCAL_ZIP.  If yes, we
+$! will (later) add "I" to the destination directory name.
+$!
+$ desti = ""
+$ pos_im = f$locate( "VMS_IM_EXTRA", LOCAL_ZIP)
+$ if (pos_im .ne. len_local_zip)
+$ then
+$    desti = "I"
+$ endif
+$!
+$ delete /symbol /local len_local_zip
+$!
+$!##################### Customizing section #############################
+$!
+$ zipx_unx = "ZIP"
+$ zipx_cli = "ZIP_CLI"
+$!
+$ CCOPTS = ""
+$ IZ_BZIP2 = ""
+$ LINKOPTS = "/notraceback"
+$ LINK_ONLY = 0
+$ LISTING = " /nolist"
+$ LARGE_FILE = 0
+$ MAKE_HELP = 1
+$ MAKE_MSG = 1
+$ MAY_USE_DECC = 1
+$ MAY_USE_GNUC = 0
+$!
+$! Process command line parameters requesting optional features.
+$!
+$ arg_cnt = 1
+$ argloop:
+$     current_arg_name = "P''arg_cnt'"
+$     curr_arg = f$edit( 'current_arg_name', "UPCASE")
+$     if (curr_arg .eqs. "") then goto argloop_out
+$!
+$     if (f$extract( 0, 5, curr_arg) .eqs. "CCOPT")
+$     then
+$         opts = f$edit( curr_arg, "COLLAPSE")
+$         eq = f$locate( "=", opts)
+$         CCOPTS = f$extract( (eq+ 1), 1000, opts)
+$         goto argloop_end
+$     endif
+$!
+$     if f$extract( 0, 7, curr_arg) .eqs. "IZ_BZIP"
+$     then
+$         opts = f$edit( curr_arg, "COLLAPSE")
+$         eq = f$locate( "=", opts)
+$         IZ_BZIP2 = f$extract( (eq+ 1), 1000, opts)
+$         goto argloop_end
+$     endif
+$!
+$     if (f$extract( 0, 5, curr_arg) .eqs. "LARGE")
+$     then
+$         LARGE_FILE = 1
+$         goto argloop_end
+$     endif
+$!
+$     if (f$extract( 0, 7, curr_arg) .eqs. "LINKOPT")
+$     then
+$         opts = f$edit( curr_arg, "COLLAPSE")
+$         eq = f$locate( "=", opts)
+$         LINKOPTS = f$extract( (eq+ 1), 1000, opts)
+$         goto argloop_end
+$     endif
+$!
+$! Note: LINK test must follow LINKOPTS test.
+$!
+$     if (f$extract( 0, 4, curr_arg) .eqs. "LINK")
+$     then
+$         LINK_ONLY = 1
+$         goto argloop_end
+$     endif
+$!
+$     if (f$extract( 0, 4, curr_arg) .eqs. "LIST")
+$     then
+$         LISTING = "/''curr_arg'"      ! But see below for mods.
+$         goto argloop_end
+$     endif
+$!
+$     if (curr_arg .eqs. "NOHELP")
+$     then
+$         MAKE_HELP = 0
+$         goto argloop_end
+$     endif
+$!
+$     if (curr_arg .eqs. "NOMSG")
+$     then
+$         MAKE_MSG = 0
+$         goto argloop_end
+$     endif
+$!
+$     if (curr_arg .eqs. "VAXC")
+$     then
+$         MAY_USE_DECC = 0
+$         MAY_USE_GNUC = 0
+$         goto argloop_end
+$     endif
+$!
+$     if (curr_arg .eqs. "DECC")
+$     then
+$         MAY_USE_DECC = 1
+$         MAY_USE_GNUC = 0
+$         goto argloop_end
+$     endif
+$!
+$     if (curr_arg .eqs. "GNUC")
+$     then
+$         MAY_USE_DECC = 0
+$         MAY_USE_GNUC = 1
+$         goto argloop_end
+$     endif
+$!
+$     if ((curr_arg .eqs. "VMSCLI") .or. (curr_arg .eqs. "CLI"))
+$     then
+$         CLI_IS_DEFAULT = 1
+$         goto argloop_end
+$     endif
+$!
+$     if ((curr_arg .eqs. "NOVMSCLI") .or. (curr_arg .eqs. "NOCLI"))
+$     then
+$         CLI_IS_DEFAULT = 0
+$         goto argloop_end
+$     endif
+$!
+$     say "Unrecognized command-line option: ''curr_arg'"
+$     goto error
+$!
+$     argloop_end:
+$     arg_cnt = arg_cnt + 1
+$ goto argloop
+$ argloop_out:
+$!
+$ if (CLI_IS_DEFAULT)
+$ then
+$     ZIPEXEC = zipx_cli
+$ else
+$     ZIPEXEC = zipx_unx
+$ endif
+$!
+$!#######################################################################
+$!
+$! Find out current disk, directory, compiler and options
+$!
+$ workdir = f$environment( "default")
+$ here = f$parse( workdir, , , "device")+ f$parse( workdir, , , "directory")
+$!
+$! Sense the host architecture (Alpha, Itanium, or VAX).
+$!
+$ if (f$getsyi( "HW_MODEL") .lt. 1024)
+$ then
+$     arch = "VAX"
+$ else
+$     if (f$getsyi( "ARCH_TYPE") .eq. 2)
+$     then
+$         arch = "ALPHA"
+$     else
+$         if (f$getsyi( "ARCH_TYPE") .eq. 3)
+$         then
+$             arch = "IA64"
+$         else
+$             arch = "unknown_arch"
+$         endif
+$     endif
+$ endif
+$!
+$ dest = arch
+$ cmpl = "DEC/Compaq/HP C"
+$ opts = ""
+$ if (arch .nes. "VAX")
+$ then
+$     HAVE_DECC_VAX = 0
+$     USE_DECC_VAX = 0
+$!
+$     if (MAY_USE_GNUC)
+$     then
+$         say "GNU C is not supported for ''arch'."
+$         say "You must use DEC/Compaq/HP C to build Zip."
+$         goto error
+$     endif
+$!
+$     if (.not. MAY_USE_DECC)
+$     then
+$         say "VAX C is not supported for ''arch'."
+$         say "You must use DEC/Compaq/HP C to build Zip."
+$         goto error
+$     endif
+$!
+$     cc = "cc /standard = relax /prefix = all /ansi"
+$     defs = "''LOCAL_ZIP' VMS"
+$     if (LARGE_FILE .ne. 0)
+$     then
+$         defs = "LARGE_FILE_SUPPORT, ''defs'"
+$     endif
+$ else
+$     if (LARGE_FILE .ne. 0)
+$     then
+$        say "LARGE_FILE_SUPPORT is not available on VAX."
+$        LARGE_FILE = 0
+$     endif
+$     HAVE_DECC_VAX = (f$search( "SYS$SYSTEM:DECC$COMPILER.EXE") .nes. "")
+$     HAVE_VAXC_VAX = (f$search( "SYS$SYSTEM:VAXC.EXE") .nes. "")
+$     MAY_HAVE_GNUC = (f$trnlnm( "GNU_CC") .nes. "")
+$     if (HAVE_DECC_VAX .and. MAY_USE_DECC)
+$     then
+$         ! We use DECC:
+$         USE_DECC_VAX = 1
+$         cc = "cc /decc /prefix = all"
+$         defs = "''LOCAL_ZIP' VMS"
+$     else
+$         ! We use VAXC (or GNU C):
+$         USE_DECC_VAX = 0
+$         defs = "''LOCAL_ZIP' VMS"
+$         if ((.not. HAVE_VAXC_VAX .and. MAY_HAVE_GNUC) .or. MAY_USE_GNUC)
+$         then
+$             cc = "gcc"
+$             opts = "GNU_CC:[000000]GCCLIB.OLB /LIBRARY,"
+$             dest = "''dest'G"
+$             cmpl = "GNU C"
+$         else
+$             if (HAVE_DECC_VAX)
+$             then
+$                 cc = "cc /vaxc"
+$             else
+$                 cc = "cc"
+$             endif
+$             dest = "''dest'V"
+$             cmpl = "VAC C"
+$         endif
+$         opts = "''opts' SYS$DISK:[.''dest']VAXCSHR.OPT /OPTIONS,"
+$     endif
+$ endif
+$!
+$! Change the destination directory, according to the VMS_IM_EXTRA and
+$! large-file options.  Set the bzip2 directory.
+$!
+$ dest = dest+ desti
+$ seek_bz = arch
+$ if (LARGE_FILE .ne. 0)
+$ then
+$     dest = dest+ "L"
+$     seek_bz = seek_bz+ "L"
+$ endif
+$!
+$! If BZIP2 support was selected, find the object library.
+$! Complain if things fail.
+$!
+$ cc_incl = "[]"
+$ incl_bzip2_m = ""
+$ lib_bzip2_opts = ""
+$ if (IZ_BZIP2 .nes. "")
+$ then
+$     bz2_olb = "LIBBZ2_NS.OLB"
+$     define incl_bzip2 'IZ_BZIP2'
+$     defs = "''defs', BZIP2_SUPPORT"
+$     @ [.VMS]FIND_BZIP2_LIB.COM 'IZ_BZIP2' 'seek_bz' 'bz2_olb' lib_bzip2
+$     if (f$trnlnm( "lib_bzip2") .eqs. "")
+$     then
+$         say "Can't find BZIP2 object library.  Can't link."
+$         goto error
+$     else
+$         say "BZIP2 dir = ''f$trnlnm( "lib_bzip2")'"
+$         incl_bzip2_m = ", ZBZ2ERR"
+$         lib_bzip2_opts = "lib_bzip2:''bz2_olb' /library, "
+$         cc_incl = cc_incl+ ", [.VMS]"
+$     endif
+$ endif
+$!
+$! Reveal the plan.  If compiling, set some compiler options.
+$!
+$ if (LINK_ONLY)
+$ then
+$     say "Linking on ''arch' for ''cmpl'."
+$ else
+$     say "Compiling on ''arch' using ''cmpl'."
+$!
+$     DEF_UNX = "/define = (''defs')"
+$     DEF_CLI = "/define = (''defs', VMSCLI)"
+$     DEF_UTIL = "/define = (''defs', UTIL)"
+$ endif
+$!
+$! If [.'dest'] does not exist, either complain (link-only) or make it.
+$!
+$ if (f$search( "''dest'.DIR;1") .eqs. "")
+$ then
+$     if (LINK_ONLY)
+$     then
+$         say "Can't find directory ""[.''dest']"".  Can't link."
+$         goto error
+$     else
+$         create /directory [.'dest']
+$     endif
+$ endif
+$!
+$ if (.not. LINK_ONLY)
+$ then
+$!
+$! Arrange to get arch-specific list file placement, if LISTING, and if
+$! the user didn't specify a particular "/LIST =" destination.
+$!
+$     L = f$edit( LISTING, "COLLAPSE")
+$     if ((f$extract( 0, 5, L) .eqs. "/LIST") .and. -
+       (f$extract( 4, 1, L) .nes. "="))
+$     then
+$         LISTING = " /LIST = [.''dest']"+ f$extract( 5, 1000, LISTING)
+$     endif
+$!
+$! Define compiler command.
+$!
+$     cc = cc+ " /include = (''cc_incl')"+ LISTING+ CCOPTS
+$!
+$ endif
+$!
+$! Define linker command.
+$!
+$ link = "link ''LINKOPTS'"
+$!
+$! Make a VAXCRTL options file for GNU C or VAC C, if needed.
+$!
+$ if ((opts .nes. "") .and. -
+   (f$locate( "VAXCSHR", f$edit( opts, "UPCASE")) .lt. f$length( opts)) .and. -
+   (f$search( "[.''dest']VAXCSHR.OPT") .eqs. ""))
+$ then
+$     open /write opt_file_ln [.'dest']VAXCSHR.OPT
+$     write opt_file_ln "SYS$SHARE:VAXCRTL.EXE /SHARE"
+$     close opt_file_ln
+$ endif
+$!
+$! Show interesting facts.
+$!
+$ say "   architecture = ''arch' (destination = [.''dest'])"
+$ if (.not. LINK_ONLY)
+$ then
+$     say "   cc = ''cc'"
+$ endif
+$ say "   link = ''link'"
+$ if (.not. MAKE_HELP)
+$ then
+$     say "   Not making new help files."
+$ endif
+$ say ""
+$ if (.not. MAKE_MSG)
+$ then
+$     say "   Not making new message files."
+$ endif
+$ say ""
+$!
+$ tmp = f$verify( 1)    ! Turn echo on to see what's happening.
+$!
+$!-------------------------------- Zip section -------------------------------
+$!
+$ if (.not. LINK_ONLY)
+$ then
+$!
+$! Process the help file, if desired.
+$!
+$     if (MAKE_HELP)
+$     then
+$         runoff /out = ZIP.HLP [.VMS]VMS_ZIP.RNH
+$     endif
+$!
+$! Process the message file, if desired.
+$!
+$     if (MAKE_MSG)
+$     then
+$!
+$! Create the message source file first, if it's not found.
+$!
+$         if (f$search( "[.VMS]ZIP_MSG.MSG") .eqs. "")
+$         then
+$             cc /include = [] /object = [.'dest']VMS_MSG_GEN.OBJ -
+               [.VMS]VMS_MSG_GEN.C
+$             link /executable = [.'dest']VMS_MSG_GEN.EXE -
+               [.'dest']VMS_MSG_GEN.OBJ
+$             create /fdl = [.VMS]STREAM_LF.FDL [.VMS]ZIP_MSG.MSG
+$             define /user_mode sys$output [.VMS]ZIP_MSG.MSG
+$             run [.'dest']VMS_MSG_GEN.EXE
+$             purge [.VMS]ZIP_MSG.MSG
+$             delete [.'dest']VMS_MSG_GEN.EXE;*, -
+               [.'dest']VMS_MSG_GEN.OBJ;*
+$         endif
+$!
+$         message /object = [.'dest']ZIP_MSG.OBJ /nosymbols -
+           [.VMS]ZIP_MSG.MSG
+$         link /shareable = [.'dest']ZIP_MSG.EXE [.'dest']ZIP_MSG.OBJ
+$     endif
+$!
+$! Compile the sources.
+$!
+$     cc 'DEF_UNX' /object = [.'dest']ZIP.OBJ ZIP.C
+$     cc 'DEF_UNX' /object = [.'dest']CRC32.OBJ CRC32.C
+$     cc 'DEF_UNX' /object = [.'dest']CRYPT.OBJ CRYPT.C
+$     cc 'DEF_UNX' /object = [.'dest']DEFLATE.OBJ DEFLATE.C
+$     cc 'DEF_UNX' /object = [.'dest']FILEIO.OBJ FILEIO.C
+$     cc 'DEF_UNX' /object = [.'dest']GLOBALS.OBJ GLOBALS.C
+$     cc 'DEF_UNX' /object = [.'dest']TREES.OBJ TREES.C
+$     cc 'DEF_UNX' /object = [.'dest']TTYIO.OBJ TTYIO.C
+$     cc 'DEF_UNX' /object = [.'dest']UTIL.OBJ UTIL.C
+$     cc 'DEF_UNX' /object = [.'dest']ZBZ2ERR.OBJ ZBZ2ERR.C
+$     cc 'DEF_UNX' /object = [.'dest']ZIPFILE.OBJ ZIPFILE.C
+$     cc 'DEF_UNX' /object = [.'dest']ZIPUP.OBJ ZIPUP.C
+$     cc /include = [] 'DEF_UNX' /object = [.'dest']VMS.OBJ -
+       [.VMS]VMS.C
+$     cc /include = [] 'DEF_UNX' /object = [.'dest']VMSMUNCH.OBJ -
+       [.VMS]VMSMUNCH.C
+$     cc /include = [] 'DEF_UNX' /object = [.'dest']VMSZIP.OBJ -
+       [.VMS]VMSZIP.C
+$!
+$! Create the object library.
+$!
+$     if (f$search( "[.''dest']ZIP.OLB") .eqs. "") then -
+       libr /object /create [.'dest']ZIP.OLB
+$!
+$     libr /object /replace [.'dest']ZIP.OLB -
+       [.'dest']CRC32.OBJ, -
+       [.'dest']CRYPT.OBJ, -
+       [.'dest']DEFLATE.OBJ, -
+       [.'dest']FILEIO.OBJ, -
+       [.'dest']GLOBALS.OBJ, -
+       [.'dest']TREES.OBJ, -
+       [.'dest']TTYIO.OBJ, -
+       [.'dest']UTIL.OBJ, -
+       [.'dest']ZBZ2ERR.OBJ, -
+       [.'dest']ZIPFILE.OBJ, -
+       [.'dest']ZIPUP.OBJ, -
+       [.'dest']VMS.OBJ, -
+       [.'dest']VMSMUNCH.OBJ, -
+       [.'dest']VMSZIP.OBJ
+$!
+$ endif
+$!
+$! Link the executable.
+$!
+$ link /executable = [.'dest']'ZIPX_UNX'.EXE -
+   [.'dest']ZIP.OBJ, -
+   [.'dest']ZIP.OLB /include = (GLOBALS 'incl_bzip2_m') /library, -
+   'lib_bzip2_opts' -
+   'opts' -
+   SYS$DISK:[.VMS]ZIP.OPT /options
+$!
+$!------------------------ Zip (CLI interface) section -----------------------
+$!
+$ if (.not. LINK_ONLY)
+$ then
+$!
+$! Process the CLI help file, if desired.
+$!
+$     if (MAKE_HELP)
+$     then
+$         set default [.VMS]
+$         edit /tpu /nosection /nodisplay /command = cvthelp.tpu -
+           zip_cli.help
+$         set default [-]
+$         runoff /output = ZIP_CLI.HLP [.VMS]ZIP_CLI.RNH
+$     endif
+$!
+$! Compile the CLI sources.
+$!
+$     cc 'DEF_CLI' /object = [.'dest']ZIPCLI.OBJ ZIP.C
+$     cc /include = [] 'DEF_CLI' /object = [.'dest']CMDLINE.OBJ -
+       [.VMS]CMDLINE.C
+$!
+$! Create the command definition object file.
+$!
+$     set command /object = [.'dest']ZIP_CLI.OBJ [.VMS]ZIP_CLI.CLD
+$!
+$! Create the CLI object library.
+$!
+$     if (f$search( "[.''dest']ZIPCLI.OLB") .eqs. "") then -
+       libr /object /create [.'dest']ZIPCLI.OLB
+$!
+$     libr /object /replace [.'dest']ZIPCLI.OLB -
+       [.'dest']ZIPCLI.OBJ, -
+       [.'dest']CMDLINE.OBJ, -
+       [.'dest']ZIP_CLI.OBJ
+$!
+$ endif
+$!
+$! Link the CLI executable.
+$!
+$ link /executable = [.'dest']'ZIPX_CLI'.EXE -
+   [.'dest']ZIPCLI.OBJ, -
+   [.'dest']ZIPCLI.OLB /library, -
+   [.'dest']ZIP.OLB /include = (GLOBALS 'incl_bzip2_m') /library, -
+   'lib_bzip2_opts' -
+   'opts' -
+   SYS$DISK:[.VMS]ZIP.OPT /options
+$!
+$!--------------------------- Zip utilities section --------------------------
+$!
+$ if (.not. LINK_ONLY)
+$ then
+$!
+$! Compile the variant Zip utilities library sources.
+$!
+$     cc 'DEF_UTIL' /object = [.'dest']CRC32_.OBJ CRC32.C
+$     cc 'DEF_UTIL' /object = [.'dest']CRYPT_.OBJ CRYPT.C
+$     cc 'DEF_UTIL' /object = [.'dest']FILEIO_.OBJ FILEIO.C
+$     cc 'DEF_UTIL' /object = [.'dest']UTIL_.OBJ UTIL.C
+$     cc 'DEF_UTIL' /object = [.'dest']ZIPFILE_.OBJ ZIPFILE.C
+$     cc 'DEF_UTIL' /include = [] /object = [.'dest']VMS_.OBJ [.VMS]VMS.C
+$!
+$! Create the Zip utilities object library.
+$!
+$     if f$search( "[.''dest']ZIPUTILS.OLB") .eqs. "" then -
+       libr /object /create [.'dest']ZIPUTILS.OLB
+$!
+$     libr /object /replace [.'dest']ZIPUTILS.OLB -
+       [.'dest']CRC32_.OBJ, -
+       [.'dest']CRYPT_.OBJ, -
+       [.'dest']FILEIO_.OBJ, -
+       [.'dest']GLOBALS.OBJ, -
+       [.'dest']TTYIO.OBJ, -
+       [.'dest']UTIL_.OBJ, -
+       [.'dest']ZIPFILE_.OBJ, -
+       [.'dest']VMS_.OBJ, -
+       [.'dest']VMSMUNCH.OBJ
+$!
+$! Compile the Zip utilities main program sources.
+$!
+$     cc 'DEF_UTIL' /object = [.'dest']ZIPCLOAK.OBJ ZIPCLOAK.C
+$     cc 'DEF_UTIL' /object = [.'dest']ZIPNOTE.OBJ ZIPNOTE.C
+$     cc 'DEF_UTIL' /object = [.'dest']ZIPSPLIT.OBJ ZIPSPLIT.C
+$!
+$ endif
+$!
+$! Link the Zip utilities executables.
+$!
+$ link /executable = [.'dest']ZIPCLOAK.EXE -
+   [.'dest']ZIPCLOAK.OBJ, -
+   [.'dest']ZIPUTILS.OLB /include = (GLOBALS) /library, -
+   'opts' -
+   SYS$DISK:[.VMS]ZIP.OPT /options
+$!
+$ link /executable = [.'dest']ZIPNOTE.EXE -
+   [.'dest']ZIPNOTE.OBJ, -
+   [.'dest']ZIPUTILS.OLB /include = (GLOBALS) /library, -
+   'opts' -
+   SYS$DISK:[.VMS]ZIP.OPT /OPTIONS
+$!
+$ LINK /EXECUTABLE = [.'DEST']ZIPSPLIT.EXE -
+   [.'DEST']ZIPSPLIT.OBJ, -
+   [.'DEST']ZIPUTILS.OLB /INCLUDE = (globals) /LIBRARY, -
+   'opts' -
+   SYS$DISK:[.VMS]ZIP.OPT /options
+$!
+$!----------------------- Logical name removal section -----------------------
+$!
+$ if (IZ_BZIP2 .nes. "")
+$ then
+$     if (f$trnlnm( "incl_bzip2", "LNM$PROCESS_TABLE") .nes. "")
+$     then
+$         deassign incl_bzip2
+$     endif
+$     if (f$trnlnm( "lib_bzip2", "LNM$PROCESS_TABLE") .nes. "")
+$     then
+$         deassign lib_bzip2
+$     endif
+$ endif
+$!
+$!------------------------------ Symbols section -----------------------------
+$!
+$ there = here- "]"+ ".''dest']"
+$!
+$! Define the foreign command symbols.  Similar commands may be useful
+$! in SYS$MANAGER:SYLOGIN.COM and/or users' LOGIN.COM.
+$!
+$ zip      == "$''there'''ZIPEXEC'.exe"
+$ zipcloak == "$''there'zipcloak.exe"
+$ zipnote  == "$''there'zipnote.exe"
+$ zipsplit == "$''there'zipsplit.exe"
+$!
+$! Restore the original default directory and DCL verify status.
+$!
+$ error:
+$!
+$ if (f$type( here) .nes. "")
+$ then
+$     if (here .nes. "")
+$     then
+$         set default 'here'
+$     endif
+$ endif
+$!
+$ if (f$type( OLD_VERIFY) .nes. "")
+$ then
+$     tmp = f$verify( OLD_VERIFY)
+$ endif
+$!
+$ exit
+$!
diff --git a/vms/bzlib.h b/vms/bzlib.h
new file mode 100644 (file)
index 0000000..20488ea
--- /dev/null
@@ -0,0 +1,21 @@
+/* 2007-01-13 SMS.
+ * VMS-specific BZLIB.H jacket header file to ensure compatibility with
+ * BZIP2 code compiled using /NAMES = AS_IS.
+ *
+ * The logical name INCL_BZIP2 must point to the BZIP2 source directory.
+ *
+ * A "names as_is" prototype for bz_internal_error() is included for the
+ * same reason.  See bzip2 "bzlib_private.h".  Note that this "names
+ * as_is" prototype must be the first to be read by the compiler, but
+ * one or more other prototypes (perhaps with the default "names"
+ * attributes) should cause no trouble.
+ */
+
+#pragma names save
+#pragma names as_is
+
+#include "INCL_BZIP2:BZLIB.H"
+
+extern void bz_internal_error ( int errcode );
+
+#pragma names restore
diff --git a/vms/cmdline.c b/vms/cmdline.c
new file mode 100644 (file)
index 0000000..9816bd5
--- /dev/null
@@ -0,0 +1,1802 @@
+/*
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/*
+   Test procedure:
+
+   Compile and link (in [.VMS] directory):
+
+      define vms SYS$DISK:[]
+      set command /object ZIP_CLI.CLD
+      cc /define = (TEST, VMSCLI) /include = [-] CMDLINE
+      link link CMDLINE.OBJ, ZIP_CLI.OBJ
+
+   Run:
+
+      exec*ute == "$SYS$DISK:[]'"
+      exec cmdline [options ...]
+
+*/
+
+/* 2004-12-13 SMS.
+ * Disabled the module name macro to accommodate old GNU C which didn't
+ * obey the directive, and thus confused MMS/MMK where the object
+ * library dependencies need to have the correct module name.
+ */
+#if 0
+# define module_name VMS_ZIP_CMDLINE
+# define module_ident "02-006"
+#endif /* 0 */
+
+/*
+**
+**  Facility:   ZIP
+**
+**  Module:     VMS_ZIP_CMDLINE
+**
+**  Author:     Hunter Goatley <goathunter@MadGoat.com>
+**
+**  Date:       July 30, 1993
+**
+**  Abstract:   Routines to handle a VMS CLI interface for Zip.  The CLI
+**              command line is parsed and a new argc/argv are built and
+**              returned to Zip.
+**
+**  Modified by:
+**
+**      02-007          Steven Schweda          09-FEB-2005
+**              Added /PRESERVE_CASE.
+**      02-006          Onno van der Linden,
+**                      Christian Spieler       07-JUL-1998 23:03
+**              Support GNU CC 2.8 on Alpha AXP (vers-num unchanged).
+**      02-006          Johnny Lee              25-JUN-1998 07:40
+**              Fixed typo (superfluous ';') (vers-num unchanged).
+**      02-006          Christian Spieler       12-SEP-1997 23:17
+**              Fixed bugs in /BEFORE and /SINCE handlers (vers-num unchanged).
+**      02-006          Christian Spieler       12-JUL-1997 02:05
+**              Complete revision of the argv strings construction.
+**              Added handling of "-P pwd", "-R", "-i@file", "-x@file" options.
+**      02-005          Patrick Ellis           09-MAY-1996 22:25
+**              Show UNIX style help screen when UNIX style options are used.
+**      02-004          Onno van der Linden,
+**                      Christian Spieler       13-APR-1996 20:05
+**              Removed /ENCRYPT=VERIFY ("-ee" option).
+**      02-003          Christian Spieler       11-FEB-1996 23:05
+**              Added handling of /EXTRAFIELDS qualifier ("-X" option).
+**      02-002          Christian Spieler       09-JAN-1996 22:25
+**              Added "#include crypt.h", corrected typo.
+**      02-001          Christian Spieler       04-DEC-1995 16:00
+**              Fixed compilation in DEC CC's ANSI mode.
+**      02-000          Christian Spieler       10-OCT-1995 17:54
+**              Modified for Zip v2.1, added several new options.
+**      01-000          Hunter Goatley          30-JUL-1993 07:54
+**              Original version (for Zip v1.9p1).
+**
+*/
+
+\f
+/* 2004-12-13 SMS.
+ * Disabled the module name macro to accommodate old GNU C which didn't
+ * obey the directive, and thus confused MMS/MMK where the object
+ * library dependencies need to have the correct module name.
+ */
+#if 0
+# if defined(__DECC) || defined(__GNUC__)
+#  pragma module module_name module_ident
+# else
+#  module module_name module_ident
+# endif
+#endif /* 0 */
+
+/* Accomodation for /NAMES = AS_IS with old header files. */
+
+#define lib$establish LIB$ESTABLISH
+#define lib$get_foreign LIB$GET_FOREIGN
+#define lib$get_input LIB$GET_INPUT
+#define lib$sig_to_ret LIB$SIG_TO_RET
+#define ots$cvt_tu_l OTS$CVT_TU_L
+#define str$concat STR$CONCAT
+#define str$find_first_substring STR$FIND_FIRST_SUBSTRING
+#define str$free1_dx STR$FREE1_DX
+
+#include "zip.h"
+#ifndef TEST
+#include "crypt.h"      /* for VMSCLI_help() */
+#include "revision.h"   /* for VMSCLI_help() */
+#endif /* !TEST */
+
+#include <ssdef.h>
+#include <descrip.h>
+#include <climsgdef.h>
+#include <clidef.h>
+#include <lib$routines.h>
+#include <ots$routines.h>
+#include <str$routines.h>
+
+#ifndef CLI$_COMMA
+globalvalue CLI$_COMMA;
+#endif
+
+/*
+**  "Macro" to initialize a dynamic string descriptor.
+*/
+#define init_dyndesc(dsc) {\
+        dsc.dsc$w_length = 0;\
+        dsc.dsc$b_dtype = DSC$K_DTYPE_T;\
+        dsc.dsc$b_class = DSC$K_CLASS_D;\
+        dsc.dsc$a_pointer = NULL;}
+
+/*
+**  Memory allocation step for argv string buffer.
+*/
+#define ARGBSIZE_UNIT 256
+
+/*
+**  Memory reallocation macro for argv string buffer.
+*/
+#define CHECK_BUFFER_ALLOCATION(buf, reserved, requested) { \
+    if ((requested) > (reserved)) { \
+        char *save_buf = (buf); \
+        (reserved) += ARGBSIZE_UNIT; \
+        if (((buf) = (char *) realloc((buf), (reserved))) == NULL) { \
+            if (save_buf != NULL) free(save_buf); \
+            return (SS$_INSFMEM); \
+        } \
+    } \
+}
+
+/*
+**  Define descriptors for all of the CLI parameters and qualifiers.
+*/
+$DESCRIPTOR(cli_delete,         "DELETE");              /* -d */
+$DESCRIPTOR(cli_freshen,        "FRESHEN");             /* -f */
+$DESCRIPTOR(cli_move,           "MOVE");                /* -m */
+$DESCRIPTOR(cli_update,         "UPDATE");              /* -u */
+$DESCRIPTOR(cli_exclude,        "EXCLUDE");             /* -x */
+$DESCRIPTOR(cli_include,        "INCLUDE");             /* -i */
+$DESCRIPTOR(cli_exlist,         "EXLIST");              /* -x@ */
+$DESCRIPTOR(cli_inlist,         "INLIST");              /* -i@ */
+$DESCRIPTOR(cli_adjust,         "ADJUST_OFFSETS");      /* -A */
+$DESCRIPTOR(cli_append,         "APPEND");              /* -g */
+$DESCRIPTOR(cli_batch,          "BATCH");               /* -@ */
+$DESCRIPTOR(cli_before,         "BEFORE");              /* -tt */
+$DESCRIPTOR(cli_comments,       "COMMENTS");            /* -c,-z */
+$DESCRIPTOR(cli_comment_archive,"COMMENTS.ARCHIVE");    /* -z */
+$DESCRIPTOR(cli_comment_zipfile,"COMMENTS.ZIP_FILE");   /* -z */
+$DESCRIPTOR(cli_comment_files,  "COMMENTS.FILES");      /* -c */
+$DESCRIPTOR(cli_compression,    "COMPRESSION");         /* -Z */
+$DESCRIPTOR(cli_compression_b,  "COMPRESSION.BZIP2");   /* -Zb */
+$DESCRIPTOR(cli_compression_d,  "COMPRESSION.DEFLATE"); /* -Zd */
+$DESCRIPTOR(cli_compression_s,  "COMPRESSION.STORE");   /* -Zs */
+$DESCRIPTOR(cli_copy_entries,   "COPY_ENTRIES");        /* -U */
+$DESCRIPTOR(cli_descriptors,    "DESCRIPTORS");         /* -fd */
+$DESCRIPTOR(cli_difference,     "DIFFERENCE");          /* -DF */
+$DESCRIPTOR(cli_dirnames,       "DIRNAMES");            /* -D */
+$DESCRIPTOR(cli_display,        "DISPLAY");             /* -d? */
+$DESCRIPTOR(cli_display_bytes,  "DISPLAY.BYTES");       /* -db */
+$DESCRIPTOR(cli_display_counts, "DISPLAY.COUNTS");      /* -dc */
+$DESCRIPTOR(cli_display_dots,   "DISPLAY.DOTS");        /* -dd,-ds */
+$DESCRIPTOR(cli_display_globaldots, "DISPLAY.GLOBALDOTS"); /* -dg */
+$DESCRIPTOR(cli_display_usize,  "DISPLAY.USIZE");       /* -du */
+$DESCRIPTOR(cli_display_volume, "DISPLAY.VOLUME");      /* -dv */
+$DESCRIPTOR(cli_dot_version,    "DOT_VERSION");         /* -ww */
+$DESCRIPTOR(cli_encrypt,        "ENCRYPT");             /* -e,-P */
+$DESCRIPTOR(cli_extra_fields,   "EXTRA_FIELDS");        /* -X [/NO] */
+$DESCRIPTOR(cli_extra_fields_normal, "EXTRA_FIELDS.NORMAL"); /* no -X */
+$DESCRIPTOR(cli_extra_fields_keep, "EXTRA_FIELDS.KEEP_EXISTING"); /* -X- */
+$DESCRIPTOR(cli_filesync,       "FILESYNC");            /* -FS */
+$DESCRIPTOR(cli_fix_archive,    "FIX_ARCHIVE");         /* -F[F] */
+$DESCRIPTOR(cli_fix_normal,     "FIX_ARCHIVE.NORMAL");  /* -F */
+$DESCRIPTOR(cli_fix_full,       "FIX_ARCHIVE.FULL");    /* -FF */
+$DESCRIPTOR(cli_full_path,      "FULL_PATH");           /* -p */
+$DESCRIPTOR(cli_grow,           "GROW");                /* -g */
+$DESCRIPTOR(cli_help,           "HELP");                /* -h */
+$DESCRIPTOR(cli_help_normal,    "HELP.NORMAL");         /* -h */
+$DESCRIPTOR(cli_help_extended,  "HELP.EXTENDED");       /* -h2 */
+$DESCRIPTOR(cli_junk,           "JUNK");                /* -j */
+$DESCRIPTOR(cli_keep_version,   "KEEP_VERSION");        /* -w */
+$DESCRIPTOR(cli_latest,         "LATEST");              /* -o */
+$DESCRIPTOR(cli_level,          "LEVEL");               /* -[0-9] */
+$DESCRIPTOR(cli_license,        "LICENSE");             /* -L */
+$DESCRIPTOR(cli_log_file,       "LOG_FILE");            /* -la,-lf,-li */
+$DESCRIPTOR(cli_log_file_append, "LOG_FILE.APPEND");    /* -la */
+$DESCRIPTOR(cli_log_file_file,  "LOG_FILE.FILE");       /* -lf */
+$DESCRIPTOR(cli_log_file_info,  "LOG_FILE.INFORMATIONAL"); /* -li */
+$DESCRIPTOR(cli_must_match,     "MUST_MATCH");          /* -MM */
+$DESCRIPTOR(cli_output,         "OUTPUT");              /* -O */
+$DESCRIPTOR(cli_patt_case,      "PATTERN_CASE");        /* -ic[-] */
+$DESCRIPTOR(cli_patt_case_blind, "PATTERN_CASE.BLIND"); /* -ic */
+$DESCRIPTOR(cli_patt_case_sensitive, "PATTERN_CASE.SENSITIVE"); /* -ic- */
+$DESCRIPTOR(cli_pkzip,          "PKZIP");               /* -k */
+$DESCRIPTOR(cli_pres_case,      "PRESERVE_CASE");       /* -C */
+$DESCRIPTOR(cli_pres_case_no2,  "PRESERVE_CASE.NOODS2");/* -C2- */
+$DESCRIPTOR(cli_pres_case_no5,  "PRESERVE_CASE.NOODS5");/* -C5- */
+$DESCRIPTOR(cli_pres_case_ods2, "PRESERVE_CASE.ODS2");  /* -C2 */
+$DESCRIPTOR(cli_pres_case_ods5, "PRESERVE_CASE.ODS5");  /* -C5 */
+$DESCRIPTOR(cli_quiet,          "QUIET");               /* -q */
+$DESCRIPTOR(cli_recurse,        "RECURSE");             /* -r,-R */
+$DESCRIPTOR(cli_recurse_path,   "RECURSE.PATH");        /* -r */
+$DESCRIPTOR(cli_recurse_fnames, "RECURSE.FILENAMES");   /* -R */
+$DESCRIPTOR(cli_show,           "SHOW");                /* -s? */
+$DESCRIPTOR(cli_show_command,   "SHOW.COMMAND");        /* -sc */
+$DESCRIPTOR(cli_show_debug,     "SHOW.DEBUG");          /* -sd */
+$DESCRIPTOR(cli_show_files,     "SHOW.FILES");          /* -sf */
+$DESCRIPTOR(cli_show_options,   "SHOW.OPTIONS");        /* -so */
+$DESCRIPTOR(cli_since,          "SINCE");               /* -t */
+$DESCRIPTOR(cli_split,          "SPLIT");               /* -s,-sb,-sp,-sv */
+$DESCRIPTOR(cli_split_bell,     "SPLIT.BELL");          /* -sb */
+$DESCRIPTOR(cli_split_pause,    "SPLIT.PAUSE");         /* -sp */
+$DESCRIPTOR(cli_split_size,     "SPLIT.SIZE");          /* -s */
+$DESCRIPTOR(cli_split_verbose,  "SPLIT.VERBOSE");       /* -sv */
+$DESCRIPTOR(cli_store_types,    "STORE_TYPES");         /* -n */
+$DESCRIPTOR(cli_sverbose,       "SVERBOSE");            /* -sv */
+$DESCRIPTOR(cli_symlinks,       "SYMLINKS");            /* -y */
+$DESCRIPTOR(cli_temp_path,      "TEMP_PATH");           /* -b */
+$DESCRIPTOR(cli_test,           "TEST");                /* -T */
+$DESCRIPTOR(cli_test_unzip,     "TEST.UNZIP");          /* -TT */
+$DESCRIPTOR(cli_translate_eol,  "TRANSLATE_EOL");       /* -l[l] */
+$DESCRIPTOR(cli_transl_eol_lf,  "TRANSLATE_EOL.LF");    /* -l */
+$DESCRIPTOR(cli_transl_eol_crlf,"TRANSLATE_EOL.CRLF");  /* -ll */
+$DESCRIPTOR(cli_unsfx,          "UNSFX");               /* -J */
+$DESCRIPTOR(cli_verbose,        "VERBOSE");             /* -v (?) */
+$DESCRIPTOR(cli_verbose_normal, "VERBOSE.NORMAL");      /* -v */
+$DESCRIPTOR(cli_verbose_more,   "VERBOSE.MORE");        /* -vv */
+$DESCRIPTOR(cli_verbose_debug,  "VERBOSE.DEBUG");       /* -vvv */
+$DESCRIPTOR(cli_verbose_command,"VERBOSE.COMMAND");     /* (none) */
+$DESCRIPTOR(cli_vms,            "VMS");                 /* -V */
+$DESCRIPTOR(cli_vms_all,        "VMS.ALL");             /* -VV */
+$DESCRIPTOR(cli_wildcard,       "WILDCARD");            /* -nw */
+$DESCRIPTOR(cli_wildcard_nospan,"WILDCARD.NOSPAN");     /* -W */
+
+$DESCRIPTOR(cli_yyz,            "YYZ_ZIP");
+
+$DESCRIPTOR(cli_zip64,          "ZIP64");               /* -fz */
+$DESCRIPTOR(cli_zipfile,        "ZIPFILE");
+$DESCRIPTOR(cli_infile,         "INFILE");
+$DESCRIPTOR(zip_command,        "zip ");
+
+static int show_VMSCLI_help;
+
+#if !defined(zip_clitable)
+#  define zip_clitable ZIP_CLITABLE
+#endif
+#if defined(__DECC) || defined(__GNUC__)
+extern void *zip_clitable;
+#else
+globalref void *zip_clitable;
+#endif
+
+/* extern unsigned long LIB$GET_INPUT(void), LIB$SIG_TO_RET(void); */
+
+#ifndef __STARLET_LOADED
+#ifndef sys$bintim
+#  define sys$bintim SYS$BINTIM
+#endif
+#ifndef sys$numtim
+#  define sys$numtim SYS$NUMTIM
+#endif
+extern int sys$bintim ();
+extern int sys$numtim ();
+#endif /* !__STARLET_LOADED */
+#ifndef cli$dcl_parse
+#  define cli$dcl_parse CLI$DCL_PARSE
+#endif
+#ifndef cli$present
+#  define cli$present CLI$PRESENT
+#endif
+#ifndef cli$get_value
+#  define cli$get_value CLI$GET_VALUE
+#endif
+extern unsigned long cli$dcl_parse ();
+extern unsigned long cli$present ();
+extern unsigned long cli$get_value ();
+
+unsigned long vms_zip_cmdline (int *, char ***);
+static unsigned long get_list (struct dsc$descriptor_s *,
+                               struct dsc$descriptor_d *, int,
+                               char **, unsigned long *, unsigned long *);
+static unsigned long get_time (struct dsc$descriptor_s *qual, char *timearg);
+static unsigned long check_cli (struct dsc$descriptor_s *);
+static int verbose_command = 0;
+
+\f
+#ifdef TEST
+
+char errbuf[ FNMAX+ 81];        /* Error message buffer. */
+
+void ziperr( int c, char *h)    /* Error message display function. */
+{
+/* int c: error code from the ZE_ class */
+/* char *h: message about how it happened */
+
+printf( "%d: %s\n", c, h);
+}
+
+int
+main(int argc, char **argv)     /* Main program. */
+{
+    return (vms_zip_cmdline(&argc, &argv));
+}
+
+#endif /* def TEST */
+
+\f
+unsigned long
+vms_zip_cmdline (int *argc_p, char ***argv_p)
+{
+/*
+**  Routine:    vms_zip_cmdline
+**
+**  Function:
+**
+**      Parse the DCL command line and create a fake argv array to be
+**      handed off to Zip.
+**
+**      NOTE: the argv[] is built as we go, so all the parameters are
+**      checked in the appropriate order!!
+**
+**  Formal parameters:
+**
+**      argc_p          - Address of int to receive the new argc
+**      argv_p          - Address of char ** to receive the argv address
+**
+**  Calling sequence:
+**
+**      status = vms_zip_cmdline (&argc, &argv);
+**
+**  Returns:
+**
+**      SS$_NORMAL      - Success.
+**      SS$_INSFMEM     - A malloc() or realloc() failed
+**      SS$_ABORT       - Bad time value
+**
+*/
+    register unsigned long status;
+    char options[ 64];
+    char *the_cmd_line;                 /* buffer for argv strings */
+    unsigned long cmdl_size;            /* allocated size of buffer */
+    unsigned long cmdl_len;             /* used size of buffer */
+    char *ptr;
+    int  x, len;
+
+    int new_argc;
+    char **new_argv;
+
+    struct dsc$descriptor_d work_str;
+    struct dsc$descriptor_d foreign_cmdline;
+
+    init_dyndesc(work_str);
+    init_dyndesc(foreign_cmdline);
+
+    /*
+    **  See if the program was invoked by the CLI (SET COMMAND) or by
+    **  a foreign command definition.  Check for /YYZ_ZIP, which is a
+    **  valid default qualifier solely for this test.
+    */
+    show_VMSCLI_help = TRUE;
+    status = check_cli(&cli_yyz);
+    if (!(status & 1)) {
+        lib$get_foreign(&foreign_cmdline);
+        /*
+        **  If nothing was returned or the first character is a "-", then
+        **  assume it's a UNIX-style command and return.
+        */
+        if (foreign_cmdline.dsc$w_length == 0)
+            return (SS$_NORMAL);
+        if ((*(foreign_cmdline.dsc$a_pointer) == '-') ||
+            ((foreign_cmdline.dsc$w_length > 1) &&
+             (*(foreign_cmdline.dsc$a_pointer) == '"') &&
+             (*(foreign_cmdline.dsc$a_pointer + 1) == '-'))) {
+            show_VMSCLI_help = FALSE;
+            return (SS$_NORMAL);
+        }
+
+        str$concat(&work_str, &zip_command, &foreign_cmdline);
+        status = cli$dcl_parse(&work_str, &zip_clitable, lib$get_input,
+                        lib$get_input, 0);
+        if (!(status & 1)) return (status);
+    }
+
+    /*
+    **  There's always going to be a new_argv[] because of the image name.
+    */
+    if ((the_cmd_line = (char *) malloc(cmdl_size = ARGBSIZE_UNIT)) == NULL)
+        return (SS$_INSFMEM);
+
+    strcpy(the_cmd_line, "zip");
+    cmdl_len = sizeof("zip");
+
+    /*
+    **  First, check to see if any of the regular options were specified.
+    */
+
+    options[0] = '-';
+    ptr = &options[1];          /* Point to temporary buffer */
+
+    /*
+    **  Copy entries.
+    */
+    status = cli$present(&cli_copy_entries);
+    if (status & 1)
+        /* /COPY_ENTRIES */
+        *ptr++ = 'U';
+
+    /*
+    **  Delete the specified files from the zip file?
+    */
+    status = cli$present(&cli_delete);
+    if (status & 1)
+        /* /DELETE */
+        *ptr++ = 'd';
+
+    /*
+    **  Freshen (only changed files).
+    */
+    status = cli$present(&cli_freshen);
+    if (status & 1)
+        /* /FRESHEN */
+        *ptr++ = 'f';
+
+    /*
+    **  Delete the files once they've been added to the zip file.
+    */
+    status = cli$present(&cli_move);
+    if (status & 1)
+        /* /MOVE */
+        *ptr++ = 'm';
+
+    /*
+    **  Add changed and new files.
+    */
+    status = cli$present(&cli_update);
+    if (status & 1)
+        /* /UPDATE */
+        *ptr++ = 'u';
+
+    /*
+    **  Check for the compression level (-0 through -9).
+    */
+    status = cli$present(&cli_level);
+    if (status & 1) {
+        /* /LEVEL = value */
+
+        unsigned long binval;
+
+        status = cli$get_value(&cli_level, &work_str);
+        status = ots$cvt_tu_l(&work_str, &binval);
+        if (!(status & 1) || (binval > 9)) {
+           return (SS$_ABORT);
+        }
+        *ptr++ = binval + '0';
+    }
+
+    /*
+    **  Adjust offsets of zip archive entries.
+    */
+    status = cli$present(&cli_adjust);
+    if (status & 1)
+        /* /ADJUST_OFFSETS */
+        *ptr++ = 'A';
+
+    /*
+    **  Add comments?
+    */
+    status = cli$present(&cli_comments);
+    if (status & 1)
+    {
+        int archive_or_zip_file = 0;
+
+        if ((status = cli$present(&cli_comment_archive)) & 1)
+            /* /COMMENTS = ARCHIVE */
+            archive_or_zip_file = 1;
+        if ((status = cli$present(&cli_comment_zipfile)) & 1)
+            /* /COMMENTS = ZIP_FILE */
+            archive_or_zip_file = 1;
+        if (archive_or_zip_file != 0)
+            /* /COMMENTS = ARCHIVE */
+            *ptr++ = 'z';
+        if ((status = cli$present(&cli_comment_files)) & 1)
+            /* /COMMENTS = FILES */
+            *ptr++ = 'c';
+    }
+
+    /*
+    **  Preserve case in file names.
+    */
+#define OPT_C   "-C"            /* Preserve case all. */
+#define OPT_CN  "-C-"           /* Down-case all. */
+#define OPT_C2  "-C2"           /* Preserve case ODS2. */
+#define OPT_C2N "-C2-"          /* Down-case ODS2. */
+#define OPT_C5  "-C5"           /* Preserve case ODS5. */
+#define OPT_C5N "-C5-"          /* Down-case ODS5. */
+
+    status = cli$present( &cli_pres_case);
+    if ((status & 1) || (status == CLI$_NEGATED))
+    {
+        /* /[NO]PRESERVE_CASE */
+        char *opt;
+        int ods2 = 0;
+        int ods5 = 0;
+
+        if (status == CLI$_NEGATED)
+        {
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_CN)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_CN);
+        }
+        else
+        {
+            if (cli$present( &cli_pres_case_no2) & 1)
+            {
+                /* /PRESERVE_CASE = NOODS2 */
+                ods2 = -1;
+            }
+            if (cli$present( &cli_pres_case_no5) & 1)
+            {
+                /* /PRESERVE_CASE = NOODS5 */
+                ods5 = -1;
+            }
+            if (cli$present( &cli_pres_case_ods2) & 1)
+            {
+                /* /PRESERVE_CASE = ODS2 */
+                ods2 = 1;
+            }
+            if (cli$present( &cli_pres_case_ods5) & 1)
+            {
+                /* /PRESERVE_CASE = ODS5 */
+                ods5 = 1;
+            }
+
+            if (ods2 == ods5)
+            {
+                /* Plain "-C[-]". */
+                if (ods2 < 0)
+                    opt = OPT_CN;
+                else
+                    opt = OPT_C;
+
+                x = cmdl_len;
+                cmdl_len += strlen( opt)+ 1;
+                CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+                strcpy( &the_cmd_line[ x], opt);
+            }
+            else
+            {
+                if (ods2 != 0)
+                {
+                    /* "-C2[-]". */
+                    if (ods2 < 0)
+                        opt = OPT_C2N;
+                    else
+                        opt = OPT_C2;
+
+                    x = cmdl_len;
+                    cmdl_len += strlen( opt)+ 1;
+                    CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+                    strcpy( &the_cmd_line[ x], opt);
+                }
+
+                if (ods5 != 0)
+                {
+                    /* "-C5[-]". */
+                    if (ods5 < 0)
+                        opt = OPT_C5N;
+                    else
+                        opt = OPT_C5;
+
+                    x = cmdl_len;
+                    cmdl_len += strlen( opt)+ 1;
+                    CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+                    strcpy( &the_cmd_line[ x], opt);
+                }
+            }
+        }
+    }
+
+    /*
+    **  Pattern case sensitivity.
+    */
+#define OPT_IC  "-ic"           /* Case-insensitive pattern matching. */
+#define OPT_ICN "-ic-"          /* Case-sensitive pattern matching. */
+
+    status = cli$present( &cli_patt_case);
+    if (status & 1)
+    {
+        if (cli$present( &cli_patt_case_blind) & 1)
+        {
+            /* "-ic". */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_IC)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_IC);
+        }
+        else if (cli$present( &cli_patt_case_sensitive) & 1)
+        {
+            /* "-ic-". */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_ICN)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_ICN);
+        }
+    }
+
+    /*
+    **  Data descriptors.
+    */
+#define OPT_FD "-fd"
+
+    status = cli$present( &cli_descriptors);
+    if (status & 1)
+    {
+        /* /DESCRIPTORS */
+        x = cmdl_len;
+        cmdl_len += strlen( OPT_FD)+ 1;
+        CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+        strcpy( &the_cmd_line[ x], OPT_FD);
+    }
+
+    /*
+    **  Difference archive.  Add only new or changed files.
+    */
+#define OPT_DF   "-DF"          /* Difference archive. */
+
+    if ((status = cli$present( &cli_difference)) & 1)
+    {
+        /* /DIFFERENCE */
+        x = cmdl_len;
+        cmdl_len += strlen( OPT_DF)+ 1;
+        CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+        strcpy( &the_cmd_line[ x],  OPT_DF);
+    }
+
+    /*
+    **  Do not add/modify directory entries.
+    */
+    status = cli$present(&cli_dirnames);
+    if (!(status & 1))
+        /* /DIRNAMES */
+        *ptr++ = 'D';
+
+    /*
+    **  Encrypt?
+    */
+    status = cli$present(&cli_encrypt);
+    if (status & 1)
+        if ((status = cli$get_value(&cli_encrypt, &work_str)) & 1) {
+            /* /ENCRYPT = value */
+            x = cmdl_len;
+            cmdl_len += work_str.dsc$w_length + 4;
+            CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+            strcpy(&the_cmd_line[x], "-P");
+            strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
+                    work_str.dsc$w_length);
+            the_cmd_line[cmdl_len-1] = '\0';
+        } else {
+            /* /ENCRYPT */
+            *ptr++ = 'e';
+        }
+
+    /*
+    **  Fix the zip archive structure.
+    */
+    status = cli$present(&cli_fix_archive);
+    if (status & 1) {
+        *ptr++ = 'F';
+        /* /FIX_ARCHIVE = NORMAL */
+        if ((status = cli$present(&cli_fix_full)) & 1) {
+            /* /FIX_ARCHIVE = FULL */
+            *ptr++ = 'F';
+        }
+    }
+
+    /*
+    **  Filesync.  Delete archive entry if no such file.
+    */
+#define OPT_FS   "-FS"          /* Filesync. */
+
+    if ((status = cli$present( &cli_filesync)) & 1)
+    {
+        /* /FILESYNC */
+        x = cmdl_len;
+        cmdl_len += strlen( OPT_FS)+ 1;
+        CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+        strcpy( &the_cmd_line[ x],  OPT_FS);
+    }
+
+    /*
+    **  Append (allow growing of existing zip file).
+    */
+    status = cli$present(&cli_append);
+    if (status & 1)
+        /* /APPEND */
+        *ptr++ = 'g';
+
+    status = cli$present(&cli_grow);
+    if (status & 1)
+        /* /GROW */
+        *ptr++ = 'g';
+
+    /*
+    **  Show the help.
+    */
+#define OPT_H2 "-h2"
+
+    status = cli$present(&cli_help);
+    if (status & 1)
+    {
+        status = cli$present( &cli_help_normal);
+        if (status & 1)
+        {
+            /* /HELP [= NORMAL] */
+            *ptr++ = 'h';
+        }
+        status = cli$present( &cli_help_extended);
+        if (status & 1)
+        {
+            /* /HELP = EXTENDED */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_H2)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_H2);
+        }
+    }
+
+    /*
+    **  Junk path names (directory specs).
+    */
+    status = cli$present(&cli_junk);
+    if (status & 1)
+        /* /JUNK */
+        *ptr++ = 'j';
+
+    /*
+    **  Simulate zip file made by PKZIP.
+    */
+    status = cli$present(&cli_pkzip);
+    if (status & 1)
+        /* /KEEP_VERSION */
+        *ptr++ = 'k';
+
+    /*
+    **  Translate end-of-line.
+    */
+    status = cli$present(&cli_translate_eol);
+    if (status & 1) {
+        /* /TRANSLATE_EOL [= LF]*/
+        *ptr++ = 'l';
+        if ((status = cli$present(&cli_transl_eol_crlf)) & 1) {
+            /* /TRANSLATE_EOL = CRLF */
+            *ptr++ = 'l';
+        }
+    }
+
+    /*
+    **  Show the software license.
+    */
+    status = cli$present(&cli_license);
+    if (status & 1)
+        /* /LICENSE */
+        *ptr++ = 'L';
+
+    /*
+    **  Set zip file time to time of latest file in it.
+    */
+    status = cli$present(&cli_latest);
+    if (status & 1)
+        /* /LATEST */
+        *ptr++ = 'o';
+
+    /*
+    **  Store full path (default).
+    */
+    status = cli$present(&cli_full_path);
+    if (status == CLI$_PRESENT)
+        /* /FULL_PATH */
+        *ptr++ = 'p';
+    else if (status == CLI$_NEGATED)
+        /* /NOFULL_PATH */
+        *ptr++ = 'j';
+
+    /*
+    **  Junk Zipfile prefix (SFX stub etc.).
+    */
+    status = cli$present(&cli_unsfx);
+    if (status & 1)
+        /* /UNSFX */
+        *ptr++ = 'J';
+
+    /*
+    **  Recurse through subdirectories.
+    */
+    status = cli$present(&cli_recurse);
+    if (status & 1) {
+        if ((status = cli$present(&cli_recurse_fnames)) & 1)
+            /* /RECURSE [= PATH] */
+            *ptr++ = 'R';
+        else
+            /* /RECURSE [= FILENAMES] */
+            *ptr++ = 'r';
+    }
+
+    /*
+    **  Test Zipfile.
+    */
+    status = cli$present(&cli_test);
+    if (status & 1) {
+        /* /TEST */
+        *ptr++ = 'T';
+    }
+
+    /*
+    **  Be verbose.
+    */
+    status = cli$present(&cli_verbose);
+    if (status & 1) {
+        int i;
+        int verbo = 0;
+
+        /* /VERBOSE */
+        if ((status = cli$present(&cli_verbose_command)) & 1)
+        {
+            /* /VERBOSE = COMMAND */
+            verbose_command = 1;
+        }
+
+        /* Note that any or all of the following options may be
+           specified, and the maximum one is used.
+        */
+        if ((status = cli$present(&cli_verbose_normal)) & 1)
+            /* /VERBOSE [ = NORMAL ] */
+            verbo = 1;
+        if ((status = cli$present(&cli_verbose_more)) & 1)
+            /* /VERBOSE = MORE */
+            verbo = 2;
+        if ((status = cli$present(&cli_verbose_debug)) & 1) {
+            /* /VERBOSE = DEBUG */
+            verbo = 3;
+        }
+        for (i = 0; i < verbo; i++)
+            *ptr++ = 'v';
+    }
+
+    /*
+    **  Quiet mode.
+    **  (Quiet mode is processed after verbose, because a "-v" modifier
+    **  resets "noisy" to 1.)
+    */
+    status = cli$present(&cli_quiet);
+    if (status & 1)
+        /* /QUIET */
+        *ptr++ = 'q';
+
+    /*
+    **  Save the VMS file attributes (and all allocated blocks?).
+    */
+    status = cli$present(&cli_vms);
+    if (status & 1) {
+        /* /VMS */
+        *ptr++ = 'V';
+        if ((status = cli$present(&cli_vms_all)) & 1) {
+            /* /VMS = ALL */
+            *ptr++ = 'V';
+        }
+    }
+
+    /*
+    **  Keep the VMS version number as part of the file name when stored.
+    */
+    status = cli$present(&cli_keep_version);
+    if (status & 1)
+        /* /KEEP_VERSION */
+        *ptr++ = 'w';
+
+    /*
+    **  Store symlinks as symlinks.
+    */
+    status = cli$present(&cli_symlinks);
+    if (status & 1)
+        /* /SYMLINKS */
+        *ptr++ = 'y';
+
+    /*
+    **  `Batch' processing: read filenames to archive from stdin
+    **  or the specified file.
+    */
+    status = cli$present(&cli_batch);
+    if (status & 1) {
+        /* /BATCH */
+        status = cli$get_value(&cli_batch, &work_str);
+        if (status & 1) {
+            /* /BATCH = value */
+            work_str.dsc$a_pointer[work_str.dsc$w_length] = '\0';
+            if ((stdin = freopen(work_str.dsc$a_pointer, "r", stdin)) == NULL)
+            {
+                sprintf(errbuf, "could not open list file: %s",
+                        work_str.dsc$a_pointer);
+                ziperr(ZE_PARMS, errbuf);
+            }
+        }
+        *ptr++ = '@';
+    }
+
+    /*
+    **  Now copy the final options string to the_cmd_line.
+    */
+    len = ptr - &options[0];
+    if (len > 1) {
+        options[len] = '\0';
+        x = cmdl_len;
+        cmdl_len += len + 1;
+        CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+        strcpy(&the_cmd_line[x], options);
+    }
+
+    /*
+    **
+    **  OK.  We've done all the regular options, so check for -b (temporary
+    **  file path), -n (special suffixes), -O (output atchive file),
+    **  -t (exclude before time), -Z (compression method), zipfile,
+    **  files to zip, and exclude list.
+    **
+    */
+    status = cli$present(&cli_temp_path);
+    if (status & 1) {
+        /* /TEMP_PATH = value */
+        status = cli$get_value(&cli_temp_path, &work_str);
+        x = cmdl_len;
+        cmdl_len += work_str.dsc$w_length + 4;
+        CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+        strcpy(&the_cmd_line[x], "-b");
+        strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
+                work_str.dsc$w_length);
+        the_cmd_line[cmdl_len-1] = '\0';
+    }
+
+    status = cli$present(&cli_output);
+    if (status & 1) {
+        /* /OUTPUT = value */
+        status = cli$get_value(&cli_output, &work_str);
+        x = cmdl_len;
+        cmdl_len += work_str.dsc$w_length + 4;
+        CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+        strcpy(&the_cmd_line[x], "-O");
+        strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
+                work_str.dsc$w_length);
+        the_cmd_line[cmdl_len-1] = '\0';
+    }
+
+    /*
+    **  Handle "-db", "-dc", "-dd", "-ds".
+    */
+#define OPT_DB "-db"
+#define OPT_DC "-dc"
+#define OPT_DD "-dd"
+#define OPT_DG "-dg"
+#define OPT_DS "-ds="
+#define OPT_DU "-du"
+#define OPT_DV "-dv"
+
+    status = cli$present( &cli_display);
+    if (status & 1)
+    {
+        if ((status = cli$present( &cli_display_bytes)) & 1)
+        {
+            /* /DISPLAY = BYTES */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_DB)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_DB);
+        }
+
+        if ((status = cli$present( &cli_display_counts)) & 1)
+        {
+            /* /DISPLAY = COUNTS */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_DC)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x],  OPT_DC);
+        }
+
+        if ((status = cli$present( &cli_display_dots)) & 1)
+        {
+            /* /DISPLAY = DOTS [= value] */
+            status = cli$get_value( &cli_display_dots, &work_str);
+
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_DD)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_DD);
+
+            /* -dd[=value] now -dd -ds=value - 5/8/05 EG */
+            if (work_str.dsc$w_length > 0) {
+                x = cmdl_len;
+                cmdl_len += strlen( OPT_DS);
+                CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+                strcpy( &the_cmd_line[ x], OPT_DS);
+
+                x = cmdl_len;
+                cmdl_len += work_str.dsc$w_length+ 1;
+                CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+                strncpy( &the_cmd_line[ x],
+                 work_str.dsc$a_pointer, work_str.dsc$w_length);
+            }
+        }
+
+        if ((status = cli$present( &cli_display_globaldots)) & 1)
+        {
+            /* /DISPLAY = GLOBALDOTS */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_DG)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x],  OPT_DG);
+        }
+
+        if ((status = cli$present( &cli_display_usize)) & 1)
+        {
+            /* /DISPLAY = USIZE */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_DU)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x],  OPT_DU);
+        }
+
+        if ((status = cli$present( &cli_display_volume)) & 1)
+        {
+            /* /DISPLAY = VOLUME */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_DV)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x],  OPT_DV);
+        }
+    }
+
+    /*
+    **  Handle "-la", "-lf", "-li".
+    */
+#define OPT_LA "-la"
+#define OPT_LF "-lf"
+#define OPT_LI "-li"
+
+    status = cli$present( &cli_log_file);
+    if (status & 1)
+    {
+        /* /SHOW */
+        if ((status = cli$present( &cli_log_file_append)) & 1)
+        {
+            /* /LOG_FILE = APPEND */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_LA)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_LA);
+        }
+
+        status = cli$present(&cli_log_file_file);
+        if (status & 1) {
+            /* /LOG_FILE = FILE = file */
+            status = cli$get_value(&cli_log_file_file, &work_str);
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_LF)+ 2+ work_str.dsc$w_length;
+            CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+            strcpy(&the_cmd_line[x], OPT_LF);
+            strncpy(&the_cmd_line[x+strlen( OPT_LF)+ 1], work_str.dsc$a_pointer,
+                work_str.dsc$w_length);
+            the_cmd_line[cmdl_len-1] = '\0';
+        }
+
+        if ((status = cli$present( &cli_log_file_info)) & 1)
+        {
+            /* /LOG = INFO */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_LI)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x],  OPT_LI);
+        }
+    }
+
+    /*
+    **  Handle "-s", "-sb", "-sp", "-sv".
+    */
+#define OPT_S "-s"
+#define OPT_SB "-sb"
+#define OPT_SP "-sp"
+#define OPT_SV "-sv"
+
+    status = cli$present( &cli_split);
+    if (status & 1)
+    {
+        status = cli$present( &cli_split_bell);
+        if (status & 1)
+        {
+            /* /SPLIT = BELL */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_SB)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_SB);
+        }
+
+        status = cli$present( &cli_split_pause);
+        if (status & 1)
+        {
+            /* /SPLIT = PAUSE */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_SP)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_SP);
+        }
+
+        status = cli$present( &cli_split_size);
+        if (status & 1)
+        {
+            /* /SPLIT = SIZE = size */
+            status = cli$get_value( &cli_split_size, &work_str);
+
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_S)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_S);
+
+            x = cmdl_len;
+            cmdl_len += work_str.dsc$w_length+ 1;
+            strncpy( &the_cmd_line[ x],
+             work_str.dsc$a_pointer, work_str.dsc$w_length);
+        }
+
+        status = cli$present( &cli_split_verbose);
+        if (status & 1)
+        {
+            /* /SPLIT = VERBOSE */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_SV)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_SV);
+        }
+    }
+
+    /*
+    **  Handle "-sc", "-sd", "-sf", "-so".
+    */
+#define OPT_SC "-sc"
+#define OPT_SD "-sd"
+#define OPT_SF "-sf"
+#define OPT_SO "-so"
+
+    status = cli$present( &cli_show);
+    if (status & 1)
+    {
+        /* /SHOW */
+        if ((status = cli$present( &cli_show_command)) & 1)
+        {
+            /* /SHOW = COMMAND */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_SC)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_SC);
+        }
+
+        if ((status = cli$present( &cli_show_debug)) & 1)
+        {
+            /* /SHOW = DEBUG */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_SD)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x],  OPT_SD);
+        }
+
+        if ((status = cli$present( &cli_show_files)) & 1)
+        {
+            /* /SHOW = FILES */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_SF)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_SF);
+        }
+
+        if ((status = cli$present( &cli_show_options)) & 1)
+        {
+            /* /SHOW = OPTIONS */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_SO)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_SO);
+        }
+    }
+
+    /*
+    **  Handle "-fz".
+    */
+#define OPT_FZ "-fz"
+
+    status = cli$present( &cli_zip64);
+    if (status & 1)
+    {
+        /* /ZIP64 */
+        x = cmdl_len;
+        cmdl_len += strlen( OPT_FZ)+ 1;
+        CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+        strcpy( &the_cmd_line[ x], OPT_FZ);
+    }
+
+    /*
+    **  Handle "-nw" and "-W".
+    */
+#define OPT_NW "-nw"
+#define OPT_W "-W"
+
+    status = cli$present( &cli_wildcard);
+    if (status & 1)
+    {
+        if ((status = cli$present( &cli_wildcard_nospan)) & 1)
+        {
+            /* /WILDCARD = NOSPAN */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_W)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_W);
+        }
+    }
+    else if (status == CLI$_NEGATED)
+    {
+        /* /NOWILDCARD */
+        x = cmdl_len;
+        cmdl_len += strlen( OPT_NW)+ 1;
+        CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+        strcpy( &the_cmd_line[ x], OPT_NW);
+    }
+
+    /*
+    **  Handle "-MM".
+    */
+#define OPT_MM  "-MM"
+
+    status = cli$present( &cli_must_match);
+    if (status & 1)
+    {
+        /* /MUST_MATCH */
+        x = cmdl_len;
+        cmdl_len += strlen( OPT_MM)+ 1;
+        CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+        strcpy( &the_cmd_line[ x], OPT_MM);
+    }
+
+    /*
+    **  UnZip command for archive test.
+    */
+#define OPT_TT "-TT"
+
+    status = cli$present(&cli_test);
+    if (status & 1) {
+        /* /TEST */
+        status = cli$present(&cli_test_unzip);
+        if (status & 1) {
+            /* /TEST = UNZIP = value */
+            status = cli$get_value(&cli_test_unzip, &work_str);
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_TT)+ 2+ work_str.dsc$w_length;
+            CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+            strcpy(&the_cmd_line[x], OPT_TT);
+            strncpy(&the_cmd_line[x+strlen( OPT_TT)+ 1], work_str.dsc$a_pointer,
+                work_str.dsc$w_length);
+            the_cmd_line[cmdl_len-1] = '\0';
+        }
+    }
+
+    /*
+    **  Handle "-Z".
+    */
+#define OPT_ZB "-Zb"
+#define OPT_ZD "-Zd"
+#define OPT_ZS "-Zs"
+
+    status = cli$present( &cli_compression);
+    if (status & 1)
+    {
+        if ((status = cli$present( &cli_compression_b)) & 1)
+        {
+            /* /COMPRESSION = BZIP2 */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_ZB)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_ZB);
+        }
+
+        if ((status = cli$present( &cli_compression_d)) & 1)
+        {
+            /* /COMPRESSION = DEFLATE */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_ZD)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_ZD);
+        }
+
+        if ((status = cli$present( &cli_compression_s)) & 1)
+        {
+            /* /COMPRESSION = STORE */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_ZS)+ 1;
+            CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_ZS);
+        }
+    }
+
+    /*
+    **  Handle "-t mmddyyyy".
+    */
+    status = cli$present(&cli_since);
+    if (status & 1) {
+        /* /SINCE = value */
+        char since_time[9];
+
+        status = get_time(&cli_since, &since_time[0]);
+        if (!(status & 1)) return (status);
+
+        /*
+        **  Now let's add the option "-t mmddyyyy" to the new command line.
+        */
+        x = cmdl_len;
+        cmdl_len += (3 + 9);
+        CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+        strcpy(&the_cmd_line[x], "-t");
+        strcpy(&the_cmd_line[x+3], since_time);
+    }
+
+    /*
+    **  Handle "-tt mmddyyyy".
+    */
+    status = cli$present(&cli_before);
+    if (status & 1) {
+        /* /BEFORE = value */
+        char before_time[9];
+
+        status = get_time(&cli_before, &before_time[0]);
+        if (!(status & 1)) return (status);
+
+        /*
+        **  Now let's add the option "-tt mmddyyyy" to the new command line.
+        */
+        x = cmdl_len;
+        cmdl_len += (4 + 9);
+        CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+        strcpy(&the_cmd_line[x], "-tt");
+        strcpy(&the_cmd_line[x+4], before_time);
+    }
+
+    /*
+    **  Handle "-n suffix:suffix:...".  (File types to store only.)
+    */
+    status = cli$present(&cli_store_types);
+    if (status & 1) {
+        /* /STORE_TYPES = value_list */
+        x = cmdl_len;
+        cmdl_len += 3;
+        CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+        strcpy(&the_cmd_line[x], "-n");
+
+        status = get_list(&cli_store_types, &foreign_cmdline, ':',
+                          &the_cmd_line, &cmdl_size, &cmdl_len);
+        if (!(status & 1)) return (status);
+    }
+
+    /*
+    **  Handle "-X", keep or strip extra fields.
+    */
+#define OPT_X  "-X"
+#define OPT_XN  "-X-"
+
+    status = cli$present(&cli_extra_fields);
+    if (status & 1) {
+        /* /EXTRA_FIELDS */
+        if ((status = cli$present( &cli_extra_fields_keep)) & 1) {
+            /* /EXTRA_FIELDS = KEEP_EXISTING */
+            x = cmdl_len;
+            cmdl_len += strlen( OPT_XN)+ 1;
+            CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+            strcpy( &the_cmd_line[ x], OPT_XN);
+        }
+    }
+    else if (status == CLI$_NEGATED) {
+        /* /NOEXTRA_FIELDS */
+        x = cmdl_len;
+        cmdl_len += strlen( OPT_X)+ 1;
+        CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+        strcpy( &the_cmd_line[ x], OPT_X);
+    }
+
+    /*
+    **  Now get the specified zip file name.
+    */
+    status = cli$present(&cli_zipfile);
+    /* zipfile */
+    if (status & 1) {
+        status = cli$get_value(&cli_zipfile, &work_str);
+
+        x = cmdl_len;
+        cmdl_len += work_str.dsc$w_length + 1;
+        CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+        strncpy(&the_cmd_line[x], work_str.dsc$a_pointer,
+                work_str.dsc$w_length);
+        the_cmd_line[cmdl_len-1] = '\0';
+
+    }
+
+    /*
+    **  Run through the list of input files.
+    */
+    status = cli$present(&cli_infile);
+    if (status & 1) {
+        /* infile_list */
+        status = get_list(&cli_infile, &foreign_cmdline, '\0',
+                          &the_cmd_line, &cmdl_size, &cmdl_len);
+        if (!(status & 1)) return (status);
+    }
+
+    /*
+    **  List file containing exclude patterns present? ("-x@exclude.lst")
+    */
+    status = cli$present(&cli_exlist);
+    if (status & 1) {
+        /* /EXLIST = list */
+        status = cli$get_value(&cli_exlist, &work_str);
+        x = cmdl_len;
+        cmdl_len += work_str.dsc$w_length + 4;
+        CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+        strncpy(&the_cmd_line[x], "-x@", 3);
+        strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
+                work_str.dsc$w_length);
+        the_cmd_line[cmdl_len-1] = '\0';
+    }
+
+    /*
+    **  Any files to exclude? ("-x file file")
+    */
+    status = cli$present(&cli_exclude);
+    if (status & 1) {
+        /* /EXCLUDE = list */
+        x = cmdl_len;
+        cmdl_len += 3;
+        CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+        strcpy(&the_cmd_line[x], "-x");
+
+        status = get_list(&cli_exclude, &foreign_cmdline, '\0',
+                          &the_cmd_line, &cmdl_size, &cmdl_len);
+        if (!(status & 1)) return (status);
+    }
+
+    /*
+    **  List file containing include patterns present? ("-x@exclude.lst")
+    */
+    status = cli$present(&cli_inlist);
+    if (status & 1) {
+        /* /INLIST = list */
+        status = cli$get_value(&cli_inlist, &work_str);
+        x = cmdl_len;
+        cmdl_len += work_str.dsc$w_length + 4;
+        CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+        strncpy(&the_cmd_line[x], "-i@", 3);
+        strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
+                work_str.dsc$w_length);
+        the_cmd_line[cmdl_len-1] = '\0';
+    }
+
+    /*
+    **  Any files to include? ("-i file file")
+    */
+    status = cli$present(&cli_include);
+    if (status & 1) {
+        /* /INCLUDE = list */
+        x = cmdl_len;
+        cmdl_len += 3;
+        CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+        strcpy(&the_cmd_line[x], "-i");
+
+        status = get_list(&cli_exclude, &foreign_cmdline, '\0',
+                          &the_cmd_line, &cmdl_size, &cmdl_len);
+        if (!(status & 1)) return (status);
+    }
+
+
+    /*
+    **  We have finished collecting the strings for the argv vector,
+    **  release unused space.
+    */
+    if ((the_cmd_line = (char *) realloc(the_cmd_line, cmdl_len)) == NULL)
+        return (SS$_INSFMEM);
+
+    /*
+    **  Now that we've built our new UNIX-like command line, count the
+    **  number of args and build an argv array.
+    */
+    for (new_argc = 0, x = 0; x < cmdl_len; x++)
+        if (the_cmd_line[x] == '\0')
+            new_argc++;
+
+    /*
+    **  Allocate memory for the new argv[].  The last element of argv[]
+    **  is supposed to be NULL, so allocate enough for new_argc+1.
+    */
+    if ((new_argv = (char **) calloc(new_argc+1, sizeof(char *))) == NULL)
+        return (SS$_INSFMEM);
+
+    /*
+    **  For each option, store the address in new_argv[] and convert the
+    **  separating blanks to nulls so each argv[] string is terminated.
+    */
+    for (ptr = the_cmd_line, x = 0; x < new_argc; x++) {
+        new_argv[x] = ptr;
+        ptr += strlen(ptr) + 1;
+    }
+    new_argv[new_argc] = NULL;
+
+#if defined(TEST) || defined(DEBUG)
+    printf("new_argc    = %d\n", new_argc);
+    for (x = 0; x < new_argc; x++)
+        printf("new_argv[%d] = %s\n", x, new_argv[x]);
+#endif /* TEST || DEBUG */
+
+    /* Show the complete UNIX command line, if requested. */
+    if (verbose_command != 0)
+    {
+        printf( "   UNIX command line args (argc = %d):\n", new_argc);
+        for (x = 0; x < new_argc; x++)
+            printf( "%s\n", new_argv[ x]);
+        printf( "\n");
+    }
+
+    /*
+    **  All finished.  Return the new argc and argv[] addresses to Zip.
+    */
+    *argc_p = new_argc;
+    *argv_p = new_argv;
+
+    return (SS$_NORMAL);
+}
+
+
+\f
+static unsigned long
+get_list (struct dsc$descriptor_s *qual, struct dsc$descriptor_d *rawtail,
+          int delim, char **p_str, unsigned long *p_size, unsigned long *p_end)
+{
+/*
+**  Routine:    get_list
+**
+**  Function:   This routine runs through a comma-separated CLI list
+**              and copies the strings to the argv buffer.  The
+**              specified separation character is used to separate
+**              the strings in the argv buffer.
+**
+**              All unquoted strings are converted to lower-case.
+**
+**  Formal parameters:
+**
+**      qual    - Address of descriptor for the qualifier name
+**      rawtail - Address of descriptor for the full command line tail
+**      delim   - Character to use to separate the list items
+**      p_str   - Address of pointer pointing to output buffer (argv strings)
+**      p_size  - Address of number containing allocated size for output string
+**      p_end   - Address of number containing used length in output buf
+**
+*/
+
+    register unsigned long status;
+    struct dsc$descriptor_d work_str;
+
+    init_dyndesc(work_str);
+
+    status = cli$present(qual);
+    if (status & 1) {
+
+        unsigned long len, old_len;
+        long ind, sind;
+        int keep_case;
+        char *src, *dst; int x;
+
+        /*
+        **  Just in case the string doesn't exist yet, though it does.
+        */
+        if (*p_str == NULL) {
+            *p_size = ARGBSIZE_UNIT;
+            if ((*p_str = (char *) malloc(*p_size)) == NULL)
+                return (SS$_INSFMEM);
+            len = 0;
+        } else {
+            len = *p_end;
+        }
+
+        while ((status = cli$get_value(qual, &work_str)) & 1) {
+            old_len = len;
+            len += work_str.dsc$w_length + 1;
+            CHECK_BUFFER_ALLOCATION(*p_str, *p_size, len)
+
+            /*
+            **  Look for the filename in the original foreign command
+            **  line to see if it was originally quoted.  If so, then
+            **  don't convert it to lowercase.
+            */
+            keep_case = FALSE;
+            str$find_first_substring(rawtail, &ind, &sind, &work_str);
+            if ((ind > 1 && *(rawtail->dsc$a_pointer + ind - 2) == '"') ||
+                (ind == 0))
+                keep_case = TRUE;
+
+            /*
+            **  Copy the string to the buffer, converting to lowercase.
+            */
+            src = work_str.dsc$a_pointer;
+            dst = *p_str+old_len;
+            for (x = 0; x < work_str.dsc$w_length; x++) {
+                if (!keep_case && ((*src >= 'A') && (*src <= 'Z')))
+                    *dst++ = *src++ + 32;
+                else
+                    *dst++ = *src++;
+            }
+            if (status == CLI$_COMMA)
+                (*p_str)[len-1] = (char)delim;
+            else
+                (*p_str)[len-1] = '\0';
+        }
+        *p_end = len;
+    }
+
+    return (SS$_NORMAL);
+
+}
+
+\f
+static unsigned long
+get_time (struct dsc$descriptor_s *qual, char *timearg)
+{
+/*
+**  Routine:    get_time
+**
+**  Function:   This routine reads the argument string of the qualifier
+**              "qual" that should be a VMS syntax date-time string.  The
+**              date-time string is converted into the standard format
+**              "mmddyyyy", specifying an absolute date.  The converted
+**              string is written into the 9 bytes wide buffer "timearg".
+**
+**  Formal parameters:
+**
+**      qual    - Address of descriptor for the qualifier name
+**      timearg - Address of a buffer carrying the 8-char time string returned
+**
+*/
+
+    register unsigned long status;
+    struct dsc$descriptor_d time_str;
+    struct quadword {
+        long high;
+        long low;
+    } bintimbuf = {0,0};
+#ifdef __DECC
+#pragma member_alignment save
+#pragma nomember_alignment
+#endif  /* __DECC */
+    struct tim {
+        short year;
+        short month;
+        short day;
+        short hour;
+        short minute;
+        short second;
+        short hundred;
+    } numtimbuf;
+#ifdef __DECC
+#pragma member_alignment restore
+#endif
+
+    init_dyndesc(time_str);
+
+    status = cli$get_value(qual, &time_str);
+    /*
+    **  If a date is given, convert it to 64-bit binary.
+    */
+    if (time_str.dsc$w_length) {
+        status = sys$bintim(&time_str, &bintimbuf);
+        if (!(status & 1)) return (status);
+        str$free1_dx(&time_str);
+    }
+    /*
+    **  Now call $NUMTIM to get the month, day, and year.
+    */
+    status = sys$numtim(&numtimbuf, (bintimbuf.low ? &bintimbuf : NULL));
+    /*
+    **  Write the "mmddyyyy" string to the return buffer.
+    */
+    if (!(status & 1)) {
+        *timearg = '\0';
+    } else {
+        sprintf(timearg, "%02d%02d%04d", numtimbuf.month,
+                numtimbuf.day, numtimbuf.year);
+    }
+    return (status);
+}
+
+\f
+static unsigned long
+check_cli (struct dsc$descriptor_s *qual)
+{
+/*
+**  Routine:    check_cli
+**
+**  Function:   Check to see if a CLD was used to invoke the program.
+**
+**  Formal parameters:
+**
+**      qual    - Address of descriptor for qualifier name to check.
+**
+*/
+    lib$establish(lib$sig_to_ret);      /* Establish condition handler */
+    return (cli$present(qual));         /* Just see if something was given */
+}
+
+\f
+#ifndef TEST
+
+void VMSCLI_help(void)  /* VMSCLI version */
+/* Print help (along with license info) to stdout. */
+{
+  extent i;             /* counter for help array */
+
+  /* help array */
+  static char *text[] = {
+"Zip %s (%s). Usage: (zip :== $ dev:[dir]zip_cli.exe)",
+"zip archive[.zip] [list] [/EXCL=(xlist)] /options /modifiers",
+"  The default action is to add or replace archive entries from list, except",
+"  those in xlist. The include file list may contain the special name \"-\" to",
+"  compress standard input.  If both archive and list are omitted, Zip",
+"  compresses stdin to stdout.",
+"  Type zip -h for Unix-style flags.",
+"  Major options include:",
+"    /COPY, /DELETE, /DIFFERENCE, /FILESYNC, /FRESHEN, /GROW, /MOVE, /UPDATE,",
+"    /ADJUST_OFFSETS, /FIX_ARCHIVE[={NORMAL|FULL}], /TEST[=UNZIP=cmd], /UNSFX,",
+"  Modifiers include:",
+"    /BATCH[=list_file], /BEFORE=creation_time, /COMMENTS[={ARCHIVE|FILES}],",
+"    /EXCLUDE=(file_list), /EXLIST=file, /INCLUDE=(file_list), /INLIST=file,",
+"    /LATEST, /OUTPUT=out_archive, /SINCE=creation_time, /TEMP_PATH=directory,",
+"    /LOG_FILE=(FILE=log_file[,APPEND][,INFORMATIONAL]), /MUST_MATCH,",
+"    /PATTERN_CASE={BLIND|SENSITIVE}, /NORECURSE|/RECURSE[={PATH|FILENAMES}],",
+"    /STORE_TYPES=(type_list),",
+#if CRYPT
+"\
+    /QUIET, /VERBOSE[={MORE|DEBUG}], /[NO]DIRNAMES, /JUNK, /ENCRYPT[=\"pwd\"],\
+",
+#else /* !CRYPT */
+"    /QUIET, /VERBOSE[={MORE|DEBUG}], /[NO]DIRNAMES, /JUNK,",
+#endif /* ?CRYPT */
+"    /COMPRESSION = {BZIP2|DEFLATE|STORE}, /LEVEL=[0-9], /NOVMS|/VMS[=ALL],",
+"    /STORE_TYPES=(type_list), /[NO]PRESERVE_CASE[=([NO]ODS{2|5}[,...])],", 
+"    /[NO]PKZIP, /[NO]KEEP_VERSION, /DOT_VERSION, /TRANSLATE_EOL[={LF|CRLF}],",
+"    /DISPLAY=([BYTES][,COUNTS][,DOTS=mb_per_dot][,GLOBALDOTS][,USIZE]",
+"    [,VOLUME]), /DESCRIPTORS, /[NO]EXTRA_FIELDS, /ZIP64,",
+#ifdef S_IFLNK
+"    /SPLIT = (SIZE=ssize [,BELL] [,PAUSE] [,VERBOSE]), /SYMLINKS"
+#else /* S_IFLNK */
+"    /SPLIT = (SIZE=ssize [,BELL] [,PAUSE] [,VERBOSE])"
+#endif /* S_IFLNK [else] */
+  };
+
+  if (!show_VMSCLI_help) {
+     help();
+     return;
+  }
+
+  for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
+  {
+    printf(copyright[i], "zip");
+    putchar('\n');
+  }
+  for (i = 0; i < sizeof(text)/sizeof(char *); i++)
+  {
+    printf(text[i], VERSION, REVDATE);
+    putchar('\n');
+  }
+} /* end function VMSCLI_help() */
+
+#endif /* !TEST */
diff --git a/vms/collect_deps.com b/vms/collect_deps.com
new file mode 100644 (file)
index 0000000..349307c
--- /dev/null
@@ -0,0 +1,89 @@
+$!                                              1 December 2006.  SMS.
+$!
+$! Info-ZIP VMS accessory procedure.
+$!
+$!    For the product named by P1,
+$!    collect all source file dependencies specified by P3,
+$!    and add P4 prefix.
+$!    Convert absolute dependencies to relative from one level above P5.
+$!    P2 = output file specification.
+$!
+$! MMS /EXTENDED_SYNTAX can't easily pass a macro invocation for P4, so
+$! we remove any internal spaces which might have been added to prevent
+$! immediate evaluation of a macro invocation.
+$!
+$ prefix = f$edit( p4, "COLLAPSE")
+$!
+$ dev_lose = f$edit( f$parse( p5, , , "DEVICE", "SYNTAX_ONLY"), "UPCASE")
+$ dir_lose = f$edit( f$parse( p5, , , "DIRECTORY", "SYNTAX_ONLY"), "UPCASE")
+$ suffix = ".VMS]"
+$ suffix_loc = f$locate( suffix, dir_lose)
+$ if (suffix_loc .lt f$length( dir_lose))
+$ then
+$    dev_dir_lose = dev_lose+ dir_lose- suffix
+$ else
+$    dev_dir_lose = dev_lose+ dir_lose- "]"
+$ endif
+$!
+$! For portability, make the output file record format Stream_LF.
+$!
+$ create /fdl = sys$input 'p2'
+RECORD
+        Carriage_Control carriage_return
+        Format stream_lf
+$!
+$ open /read /write /error = end_main deps_out 'p2'
+$ on error then goto loop_main_end
+$!
+$! Include proper-inclusion-check preface.
+$!
+$ incl_macro = "INCL_"+ f$parse( p2, , , "NAME", "SYNTAX_ONLY")
+$ write deps_out "#"
+$ write deps_out "# ''p1' for VMS - MMS (or MMK) Source Dependency File."
+$ write deps_out "#"
+$ write deps_out ""
+$ write deps_out -
+   "# This description file is included by other description files.  It is"
+$ write deps_out -
+   "# not intended to be used alone.  Verify proper inclusion."
+$ write deps_out ""
+$ write deps_out ".IFDEF ''incl_macro'"
+$ write deps_out ".ELSE"
+$ write deps_out -
+   "$$$$ THIS DESCRIPTION FILE IS NOT INTENDED TO BE USED THIS WAY."
+$ write deps_out ".ENDIF"
+$ write deps_out ""
+$!
+$! Actual dependencies from individual dependency files.
+$!
+$ loop_main_top:
+$    file = f$search( p3)
+$    if (file .eqs. "") then goto loop_main_end
+$!
+$    open /read /error = end_subs deps_in 'file'
+$    loop_subs_top:
+$       read /error = loop_subs_end deps_in line
+$       line_reduced = f$edit( line, "COMPRESS, TRIM, UPCASE")
+$       colon = f$locate( " : ", line_reduced)
+$       d_d_l_loc = f$locate( dev_dir_lose, -
+         f$extract( (colon+ 3), 1000, line_reduced))
+$       if (d_d_l_loc .eq. 0)
+$       then
+$          front = f$extract( 0, (colon+ 3), line_reduced)
+$          back = f$extract( (colon+ 3+ f$length( dev_dir_lose)), -
+            1000, line_reduced)
+$          line = front+ "["+ back
+$       endif
+$       write deps_out "''prefix'"+ "''line'"
+$    goto loop_subs_top
+$!
+$    loop_subs_end:
+$    close deps_in
+$!
+$ goto loop_main_top
+$!
+$ loop_main_end:
+$ close deps_out
+$!
+$ end_main:
+$!
diff --git a/vms/cvthelp.tpu b/vms/cvthelp.tpu
new file mode 100644 (file)
index 0000000..8c60369
--- /dev/null
@@ -0,0 +1,182 @@
+!       TITLE   CVTHELP.TPU
+!       IDENT   01-001
+!
+!++
+! Copyright (c) 1990-2001 Info-ZIP.  All rights reserved.
+!
+! See the accompanying file LICENSE, version 2000-Apr-09 or later
+! (the contents of which are also included in zip.h) for terms of use.
+! If, for some reason, all these files are missing, the Info-ZIP license
+! also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+!
+!++
+!
+!  Program:     CVTHELP.TPU
+!
+!  Author:      Hunter Goatley
+!
+!  Date:        January 12, 1992
+!
+!  Purpose:     Convert .HELP files to RUNOFF .RNH files.  Substitutes
+!               RUNOFF commands for tags imbedded in the .HELP file.
+!
+!  Calling sequence:
+!
+!       $ EDIT/TPU/NOJOURNAL/NODISPLAY/COMMAND=CVTHELP file.HELP
+!
+!  Modified by:
+!
+!       01-001          Hunter Goatley            7-FEB-2001 15:40
+!               Added <NEXT> for qualifier separators.
+!
+!       01-000          Hunter Goatley           12-JAN-1992 15:15
+!               Original version.
+!
+!--
+Procedure eve_convert_help
+Local   temp
+        ,x
+        ;
+
+   qualifier_level := 0;
+   hg$substitute_topic(current_buffer, "<MAIN>", ".indent-3", "1");
+   hg$substitute_topic(current_buffer, "<QUALIFIER>", ".sk;.indent-3", "");
+   hg$substitute_topic(current_buffer, "<TOPIC>", ".indent-3", "2");
+   hg$substitute_topic(current_buffer, "<SUBTOPIC>", ".indent-3", "3");
+   hg$substitute_topic(current_buffer, "<SUBSUBTOPIC>", ".indent-3", "4");
+   hg$substitute_comment(current_buffer,"<QUALIFIERS>",".indent-3;2 Qualifiers");
+   hg$substitute_comment(current_buffer,"<PARAMETER>",".indent-2");
+   hg$substitute_comment(current_buffer,"<PTEXT>",".lm+3");
+   hg$substitute_comment(current_buffer,"<TXETP>",".lm-3");
+   hg$substitute_comment(current_buffer,"<ETEXT>",".lm+4");
+   hg$substitute_comment(current_buffer,"<TXETE>",".lm-4");
+   hg$substitute_comment(current_buffer,"<INIT>",".noflags;.lm3;.rm70");
+   hg$substitute_comment(current_buffer,"<LITERAL>",".lm+4;.literal");
+   hg$substitute_comment(current_buffer,"<LARETIL>",".end literal;.lm-4");
+   hg$substitute_comment(current_buffer,"<LITERAL0>",".literal");
+   hg$substitute_comment(current_buffer,"<0LARETIL>",".end literal");
+   hg$substitute_comment(current_buffer,"<DOT1LIST>",'.list 1,"o"');
+   hg$substitute_comment(current_buffer,"<DOT0LIST>",'.list 0,"o"');
+   hg$substitute_comment(current_buffer,"<ENTRY>",".le");
+   hg$substitute_comment(current_buffer,"<TSIL>",".end list");
+   hg$substitute_comment(current_buffer,"<CENTER>",".center");
+   hg$substitute_comment(current_buffer,"<FORMAT>",".sk;.indent2");
+   hg$substitute_comment(current_buffer,"<NOTE>",".note");
+   hg$substitute_comment(current_buffer,"<ETON>",".end note");
+   hg$substitute_comment(current_buffer, LINE_BEGIN & LINE_END,".sk");
+   hg$substitute_comment(current_buffer, LINE_BEGIN & "|", "");
+   hg$substitute_comment(current_buffer,"<NEXT>",".br");
+
+EndProcedure;           ! eve_convert_help
+
+Procedure hg$substitute_comment (the_buffer, target, new)
+Local   temp
+        ,save_pos
+        ,x
+        ;
+  on_error;
+  endon_error;
+
+  save_pos := mark(none);
+  position(beginning_of(the_buffer));
+  loop
+        x := search(target, forward);
+        exitif x = 0;
+        position (x);
+        erase_character(length(x));
+        copy_text(new);
+  endloop;
+
+  position(save_pos);
+
+EndProcedure;           ! hg$substitute_comment
+
+Procedure hg$substitute_topic (the_buffer, target, new, level)
+Local   temp
+        ,save_pos
+        ,x
+        ;
+  on_error;
+  endon_error;
+
+  save_pos := mark(none);
+  position(beginning_of(the_buffer));
+  loop
+        x := search(target, forward);
+        exitif x = 0;
+        position (x);
+        erase_character(length(x));
+        move_vertical(-1);
+        if (length(current_line) = 0)
+        then copy_text("|");
+        endif;
+        move_vertical(1);
+        copy_text(".!------------------------------------------------------");
+        split_line;
+        copy_text(new);
+        move_horizontal(-current_offset);
+        move_vertical(1);
+        if level <> "" then
+                copy_text(level + " ");
+!       else
+!           if qualifier_level = 0
+!           then
+!               copy_text("2 Qualifiers");
+!               split_line; split_line;
+!               copy_text(new); split_line;
+!               qualifier_level := 1;
+!           endif;
+        endif;
+        move_horizontal(-current_offset);
+        move_vertical(1);
+        if length(current_line) = 0
+        then
+            if (target = "<MAIN>") OR (target = "<TOPIC>")
+                OR (target = "<SUBTOPIC>") or (target = "<SUBSUBTOPIC>")
+            then copy_text(".br");
+            else copy_text(".sk");
+            endif;
+        endif;
+  endloop;
+
+  position(save_pos);
+
+EndProcedure;           ! hg$substitute_topic
+
+!===============================================================================
+Procedure tpu$init_procedure
+Local   temp
+        ,orig_filespec
+        ,f
+        ;
+
+   on_error
+   endon_error;
+
+ !Prompt user for information
+
+  orig_filespec := get_info(command_line, "file_name");
+  if orig_filespec = ""
+  then
+        message("No .HELP file given");
+        quit;
+  endif;
+  f := file_parse(orig_filespec, ".HELP");              !Add .LIS ending
+
+    ! Create a buffer and window for editing
+
+  main_buf := create_buffer ("MAIN",f);
+  set (eob_text, main_buf, "[End of buffer]");
+
+  position (beginning_of(main_buf));
+
+  eve_convert_help;
+
+  f := file_parse(orig_filespec,"","",NAME);
+
+  write_file (main_buf, f+".RNH");
+
+ quit;
+EndProcedure;           !TPU$INIT_PROCEDURE
+
+tpu$init_procedure;
diff --git a/vms/descrip.mms b/vms/descrip.mms
new file mode 100644 (file)
index 0000000..ae2bc04
--- /dev/null
@@ -0,0 +1,358 @@
+#                                               23 February 2007.  SMS.
+#
+#    Zip 3.0 for VMS - MMS (or MMK) Description File.
+#
+# Usage:
+#
+#    MMS /DESCRIP = [.VMS]DESCRIP.MMS [/MACRO = (<see_below>)] [target]
+#
+# Note that this description file must be used from the main
+# distribution directory, not from the [.VMS] subdirectory.
+#
+# Optional macros:
+#
+#    CCOPTS=xxx     Compile with CC options xxx.  For example:
+#                   CCOPTS=/ARCH=HOST
+#
+#    DBG=1          Compile with /DEBUG /NOOPTIMIZE.
+#                   Link with /DEBUG /TRACEBACK.
+#                   (Default is /NOTRACEBACK.)
+#
+#    IM=1           Use the old "IM" scheme for storing VMS/RMS file
+#                   atributes, instead of the newer "PK" scheme.
+#
+#    IZ_BZIP2=dev:[dir]  Add optional BZIP2 support.  The valus of the
+#                        MMS macro IZ_BZIP2 ("dev:[dir]", or a suitable
+#                   logical name) tells where to find "bzlib.h".  The
+#                   BZIP2 object library (LIBBZ2_NS.OLB) is expected to
+#                   be in a "[.dest]" directory under that one
+#                   ("dev:[dir.ALPHAL]", for example), or in that
+#                   directory itself.
+#
+#    LARGE=1        Enable large-file (>2GB) support.  Non-VAX only.
+#
+#    LINKOPTS=xxx   Link with LINK options xxx.  For example:
+#                   LINKOPTS=/NOINFO   
+#
+#    LIST=1         Compile with /LIST /SHOW = (ALL, NOMESSAGES).
+#                   Link with /MAP /CROSS_REFERENCE /FULL.
+#
+#    "LOCAL_ZIP=c_macro_1=value1 [, c_macro_2=value2 [...]]"
+#                   Compile with these additional C macros defined.
+#
+# VAX-specific optional macros:
+#
+#    VAXC=1         Use the VAX C compiler, assuming "CC" runs it.
+#                   (That is, DEC C is not installed, or else DEC C is
+#                   installed, but VAX C is the default.)
+#
+#    FORCE_VAXC=1   Use the VAX C compiler, assuming "CC /VAXC" runs it.
+#                   (That is, DEC C is installed, and it is the
+#                   default, but you want VAX C anyway, you fool.)
+#
+#    GNUC=1         Use the GNU C compiler.  (Seriously under-tested.)
+#
+#
+# The default target, ALL, builds the selected product executables and
+# help files.
+#
+# Other targets:
+#
+#    CLEAN      deletes architecture-specific files, but leaves any
+#               individual source dependency files and the help files.
+#
+#    CLEAN_ALL  deletes all generated files, except the main (collected)
+#               source dependency file.
+#
+#    CLEAN_EXE  deletes only the architecture-specific executables. 
+#               Handy if all you wish to do is re-link the executables.
+#
+# Example commands:
+#
+# To build the conventional small-file product using the DEC/Compaq/HP C
+# compiler (Note: DESCRIP.MMS is the default description file name.):
+#
+#    MMS /DESCRIP = [.VMS]
+#
+# To get the large-file executables (on a non-VAX system):
+#
+#    MMS /DESCRIP = [.VMS] /MACRO = (LARGE=1)
+#
+# To delete the architecture-specific generated files for this system
+# type:
+#
+#    MMS /DESCRIP = [.VMS] /MACRO = (LARGE=1) CLEAN     ! Large-file.
+# or
+#    MMS /DESCRIP = [.VMS] CLEAN                        ! Small-file.
+#
+# To build a complete small-file product for debug with compiler
+# listings and link maps:
+#
+#    MMS /DESCRIP = [.VMS] CLEAN
+#    MMS /DESCRIP = [.VMS] /MACRO = (DBG=1, LIST=1)
+#
+########################################################################
+
+# Include primary product description file.
+
+INCL_DESCRIP_SRC = 1
+.INCLUDE [.VMS]DESCRIP_SRC.MMS
+
+# Object library names.
+
+LIB_ZIP = [.$(DEST)]ZIP.OLB
+LIB_ZIPCLI = [.$(DEST)]ZIPCLI.OLB
+LIB_ZIPUTILS = [.$(DEST)]ZIPUTILS.OLB
+
+# Help file names.
+
+ZIP_HELP = ZIP.HLP ZIP_CLI.HLP
+
+# Message file names.
+
+ZIP_MSG_MSG = [.VMS]ZIP_MSG.MSG
+ZIP_MSG_EXE = [.$(DEST)]ZIP_MSG.EXE
+ZIP_MSG_OBJ = [.$(DEST)]ZIP_MSG.OBJ
+
+
+# TARGETS.
+
+# Default target, ALL.  Build All Zip executables, utility executables,
+# and help files.
+
+ALL : $(ZIP) $(ZIP_CLI) $(ZIPUTILS) $(ZIP_HELP) $(ZIP_MSG_EXE)
+       @ write sys$output "Done."
+
+# CLEAN target.  Delete the [.$(DEST)] directory and everything in it.
+
+CLEAN :
+       if (f$search( "[.$(DEST)]*.*") .nes. "") then -
+        delete /noconfirm [.$(DEST)]*.*;*
+       if (f$search( "$(DEST).DIR") .nes. "") then -
+        set protection = w:d $(DEST).DIR;*
+       if (f$search( "$(DEST).DIR") .nes. "") then -
+        delete /noconfirm $(DEST).DIR;*
+
+# CLEAN_ALL target.  Delete:
+#    The [.$(DEST)] directories and everything in them.
+#    All help-related derived files,
+#    All individual C dependency files.
+# Also mention:
+#    Comprehensive dependency file.
+
+CLEAN_ALL :
+       if (f$search( "[.ALPHA*]*.*") .nes. "") then -
+        delete /noconfirm [.ALPHA*]*.*;*
+       if (f$search( "ALPHA*.DIR", 1) .nes. "") then -
+        set protection = w:d ALPHA*.DIR;*
+       if (f$search( "ALPHA*.DIR", 2) .nes. "") then -
+        delete /noconfirm ALPHA*.DIR;*
+       if (f$search( "[.IA64*]*.*") .nes. "") then -
+        delete /noconfirm [.IA64*]*.*;*
+       if (f$search( "IA64*.DIR", 1) .nes. "") then -
+        set protection = w:d IA64*.DIR;*
+       if (f$search( "IA64*.DIR", 2) .nes. "") then -
+        delete /noconfirm IA64*.DIR;*
+       if (f$search( "[.VAX*]*.*") .nes. "") then -
+        delete /noconfirm [.VAX*]*.*;*
+       if (f$search( "VAX*.DIR", 1) .nes. "") then -
+        set protection = w:d VAX*.DIR;*
+       if (f$search( "VAX*.DIR", 2) .nes. "") then -
+        delete /noconfirm VAX*.DIR;*
+       if (f$search( "[.vms]ZIP_CLI.RNH") .nes. "") then -
+        delete /noconfirm [.vms]ZIP_CLI.RNH;*
+       if (f$search( "ZIP_CLI.HLP") .nes. "") then -
+        delete /noconfirm ZIP_CLI.HLP;*
+       if (f$search( "ZIP.HLP") .nes. "") then -
+        delete /noconfirm ZIP.HLP;*
+       if (f$search( "*.MMSD") .nes. "") then -
+        delete /noconfirm *.MMSD;*
+       if (f$search( "[.vms]*.MMSD") .nes. "") then -
+        delete /noconfirm [.vms]*.MMSD;*
+       @ write sys$output ""
+       @ write sys$output "Note:  This procedure will not"
+       @ write sys$output "   DELETE [.VMS]DESCRIP_DEPS.MMS;*"
+       @ write sys$output -
+ "You may choose to, but a recent version of MMS (V3.5 or newer?) is"
+       @ write sys$output -
+ "needed to regenerate it.  (It may also be recovered from the original"
+       @ write sys$output -
+ "distribution kit.)  See [.VMS]DESCRIP_MKDEPS.MMS for instructions on"
+       @ write sys$output -
+ "generating [.VMS]DESCRIP_DEPS.MMS."
+       @ write sys$output ""
+       @ write sys$output -
+ "It also does not delete the error message source file:"
+       @ write sys$output "   DELETE [.VMS]ZIP_MSG.MSG;*"
+       @ write sys$output -
+ "but it can regenerate it if needed."
+       @ write sys$output ""
+
+# CLEAN_EXE target.  Delete the executables in [.$(DEST)].
+
+CLEAN_EXE :
+       if (f$search( "[.$(DEST)]*.EXE") .nes. "") then -
+        delete /noconfirm [.$(DEST)]*.EXE;*
+
+
+# Object library module dependencies.
+
+$(LIB_ZIP) : $(LIB_ZIP)($(MODS_OBJS_LIB_ZIP))
+       @ write sys$output "$(MMS$TARGET) updated."
+
+$(LIB_ZIPCLI) : $(LIB_ZIPCLI)($(MODS_OBJS_LIB_ZIPCLI))
+       @ write sys$output "$(MMS$TARGET) updated."
+
+$(LIB_ZIPUTILS) : $(LIB_ZIPUTILS)($(MODS_OBJS_LIB_ZIPUTILS))
+       @ write sys$output "$(MMS$TARGET) updated."
+
+# Module ID options file.
+
+OPT_ID = SYS$DISK:[.VMS]ZIP.OPT
+
+# Default C compile rule.
+
+.C.OBJ :
+       $(CC) $(CFLAGS) $(CDEFS_UNX) $(MMS$SOURCE)
+
+
+# Normal sources in [.VMS].
+
+[.$(DEST)]VMS.OBJ : [.VMS]VMS.C
+[.$(DEST)]VMSMUNCH.OBJ : [.VMS]VMSMUNCH.C
+[.$(DEST)]VMSZIP.OBJ : [.VMS]VMSZIP.C
+
+# Command-line interface files.
+
+[.$(DEST)]CMDLINE.OBJ : [.VMS]CMDLINE.C
+       $(CC) $(CFLAGS) $(CDEFS_CLI) $(MMS$SOURCE)
+
+[.$(DEST)]ZIPCLI.OBJ : ZIP.C
+       $(CC) $(CFLAGS) $(CDEFS_CLI) $(MMS$SOURCE)
+
+[.$(DEST)]ZIP_CLI.OBJ : [.VMS]ZIP_CLI.CLD
+
+# Utility variant sources.
+
+[.$(DEST)]CRC32_.OBJ : CRC32.C
+       $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+[.$(DEST)]CRYPT_.OBJ : CRYPT.C
+       $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+[.$(DEST)]FILEIO_.OBJ : FILEIO.C
+       $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+[.$(DEST)]UTIL_.OBJ : UTIL.C
+       $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+[.$(DEST)]ZIPFILE_.OBJ : ZIPFILE.C
+       $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+[.$(DEST)]VMS_.OBJ : [.VMS]VMS.C
+       $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+# Utility main sources.
+
+[.$(DEST)]ZIPCLOAK.OBJ : ZIPCLOAK.C
+       $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+[.$(DEST)]ZIPNOTE.OBJ : ZIPNOTE.C
+       $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+[.$(DEST)]ZIPSPLIT.OBJ : ZIPSPLIT.C
+       $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+# VAX C LINK options file.
+
+.IFDEF OPT_FILE
+$(OPT_FILE) :
+        open /write opt_file_ln  $(OPT_FILE)
+        write opt_file_ln "SYS$SHARE:VAXCRTL.EXE /SHARE"
+        close opt_file_ln
+.ENDIF
+
+# Normal Zip executable.
+
+$(ZIP) : [.$(DEST)]ZIP.OBJ $(LIB_ZIP) $(OPT_FILE)
+       $(LINK) $(LINKFLAGS) $(MMS$SOURCE), -
+        $(LIB_ZIP) /include = (GLOBALS $(INCL_BZIP2_M)) /library,  -
+        $(LIB_BZIP2_OPTS) -
+        $(LFLAGS_ARCH) -
+        $(OPT_ID) /options
+
+# CLI Zip executable.
+
+$(ZIP_CLI) : [.$(DEST)]ZIPCLI.OBJ \
+             $(LIB_ZIPCLI) $(OPT_ID) $(OPT_FILE)
+       $(LINK) $(LINKFLAGS) $(MMS$SOURCE), -
+        $(LIB_ZIPCLI) /library, -
+        $(LIB_ZIP) /include = (GLOBALS $(INCL_BZIP2_M)) /library, -
+        $(LIB_BZIP2_OPTS) -
+        $(LFLAGS_ARCH) -
+        $(OPT_ID) /options
+
+# Utility executables.
+
+[.$(DEST)]ZIPCLOAK.EXE : [.$(DEST)]ZIPCLOAK.OBJ \
+                         $(LIB_ZIPUTILS) \
+                         $(OPT_ID) $(OPT_FILE)
+       $(LINK) $(LINKFLAGS) $(MMS$SOURCE), -
+        $(LIB_ZIPUTILS) /include = (GLOBALS) /library, -
+        $(LFLAGS_ARCH) -
+        $(OPT_ID) /options
+
+[.$(DEST)]ZIPNOTE.EXE : [.$(DEST)]ZIPNOTE.OBJ \
+                        $(LIB_ZIPUTILS) \
+                        $(OPT_ID) $(OPT_FILE)
+       $(LINK) $(LINKFLAGS) $(MMS$SOURCE), -
+        $(LIB_ZIPUTILS) /include = (GLOBALS) /library, -
+        $(LFLAGS_ARCH) -
+        $(OPT_ID) /options
+
+[.$(DEST)]ZIPSPLIT.EXE : [.$(DEST)]ZIPSPLIT.OBJ \
+                         $(LIB_ZIPUTILS) \
+                         $(OPT_ID) $(OPT_FILE)
+       $(LINK) $(LINKFLAGS) $(MMS$SOURCE), -
+        $(LIB_ZIPUTILS) /include = (GLOBALS) /library, -
+        $(LFLAGS_ARCH) -
+        $(OPT_ID) /options
+
+# Help files.
+
+ZIP.HLP : [.VMS]VMS_ZIP.RNH
+       runoff /output = $(MMS$TARGET) $(MMS$SOURCE)
+
+ZIP_CLI.HLP : [.VMS]ZIP_CLI.HELP [.VMS]CVTHELP.TPU
+       edit := edit
+       edit /tpu /nosection /nodisplay /command = [.VMS]CVTHELP.TPU -
+        $(MMS$SOURCE)
+       rename /noconfirm ZIP_CLI.RNH; [.VMS];
+       purge /noconfirm /nolog /keep = 1 [.VMS]ZIP_CLI.RNH
+       runoff /output = $(MMS$TARGET) [.VMS]ZIP_CLI.RNH
+
+# Message file.
+
+$(ZIP_MSG_EXE) : $(ZIP_MSG_OBJ)
+       link /shareable = $(MMS$TARGET) $(ZIP_MSG_OBJ)
+
+$(ZIP_MSG_OBJ) : $(ZIP_MSG_MSG)
+       message /object = $(MMS$TARGET) /nosymbols $(ZIP_MSG_MSG)
+
+$(ZIP_MSG_MSG) : ZIPERR.H [.VMS]STREAM_LF.FDL [.VMS]VMS_MSG_GEN.C
+       $(CC) /include = [] /object = [.$(DEST)]VMS_MSG_GEN.OBJ -
+        [.VMS]VMS_MSG_GEN.C 
+       $(LINK) /executable = [.$(DEST)]VMS_MSG_GEN.EXE -
+        $(LFLAGS_ARCH) -
+        [.$(DEST)]VMS_MSG_GEN.OBJ
+       create /fdl = [.VMS]STREAM_LF.FDL $(MMS$TARGET)
+       define /user_mode sys$output $(MMS$TARGET)
+       run [.$(DEST)]VMS_MSG_GEN.EXE
+       purge $(MMS$TARGET)
+       delete [.$(DEST)]VMS_MSG_GEN.EXE;*, [.$(DEST)]VMS_MSG_GEN.OBJ;*
+
+# Include generated source dependencies.
+
+INCL_DESCRIP_DEPS = 1
+.INCLUDE [.VMS]DESCRIP_DEPS.MMS
+
diff --git a/vms/descrip_deps.mms b/vms/descrip_deps.mms
new file mode 100644 (file)
index 0000000..cf8f9b1
--- /dev/null
@@ -0,0 +1,207 @@
+#
+# Zip for VMS - MMS (or MMK) Source Dependency File.
+#
+
+# This description file is included by other description files.  It is
+# not intended to be used alone.  Verify proper inclusion.
+
+.IFDEF INCL_DESCRIP_DEPS
+.ELSE
+$$$$ THIS DESCRIPTION FILE IS NOT INTENDED TO BE USED THIS WAY.
+.ENDIF
+
+[.$(DEST)]CRC32.OBJ : []CRC32.C
+[.$(DEST)]CRC32.OBJ : []ZIP.H
+[.$(DEST)]CRC32.OBJ : []TAILOR.H
+[.$(DEST)]CRC32.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]CRC32.OBJ : []ZIPERR.H
+[.$(DEST)]CRC32.OBJ : []CRC32.H
+[.$(DEST)]CRC32_.OBJ : []CRC32.C
+[.$(DEST)]CRC32_.OBJ : []ZIP.H
+[.$(DEST)]CRC32_.OBJ : []TAILOR.H
+[.$(DEST)]CRC32_.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]CRC32_.OBJ : []ZIPERR.H
+[.$(DEST)]CRC32_.OBJ : []CRC32.H
+[.$(DEST)]CRYPT.OBJ : []CRYPT.C
+[.$(DEST)]CRYPT.OBJ : []ZIP.H
+[.$(DEST)]CRYPT.OBJ : []TAILOR.H
+[.$(DEST)]CRYPT.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]CRYPT.OBJ : []ZIPERR.H
+[.$(DEST)]CRYPT.OBJ : []CRYPT.H
+[.$(DEST)]CRYPT.OBJ : []TTYIO.H
+[.$(DEST)]CRYPT.OBJ : []CRC32.H
+[.$(DEST)]CRYPT_.OBJ : []CRYPT.C
+[.$(DEST)]CRYPT_.OBJ : []ZIP.H
+[.$(DEST)]CRYPT_.OBJ : []TAILOR.H
+[.$(DEST)]CRYPT_.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]CRYPT_.OBJ : []ZIPERR.H
+[.$(DEST)]CRYPT_.OBJ : []CRYPT.H
+[.$(DEST)]CRYPT_.OBJ : []TTYIO.H
+[.$(DEST)]CRYPT_.OBJ : []CRC32.H
+[.$(DEST)]DEFLATE.OBJ : []DEFLATE.C
+[.$(DEST)]DEFLATE.OBJ : []ZIP.H
+[.$(DEST)]DEFLATE.OBJ : []TAILOR.H
+[.$(DEST)]DEFLATE.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]DEFLATE.OBJ : []ZIPERR.H
+[.$(DEST)]FILEIO.OBJ : []FILEIO.C
+[.$(DEST)]FILEIO.OBJ : []ZIP.H
+[.$(DEST)]FILEIO.OBJ : []TAILOR.H
+[.$(DEST)]FILEIO.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]FILEIO.OBJ : []ZIPERR.H
+[.$(DEST)]FILEIO.OBJ : []CRC32.H
+[.$(DEST)]FILEIO.OBJ : [.VMS]VMS.H
+[.$(DEST)]FILEIO_.OBJ : []FILEIO.C
+[.$(DEST)]FILEIO_.OBJ : []ZIP.H
+[.$(DEST)]FILEIO_.OBJ : []TAILOR.H
+[.$(DEST)]FILEIO_.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]FILEIO_.OBJ : []ZIPERR.H
+[.$(DEST)]FILEIO_.OBJ : []CRC32.H
+[.$(DEST)]FILEIO_.OBJ : [.VMS]VMS.H
+[.$(DEST)]GLOBALS.OBJ : []GLOBALS.C
+[.$(DEST)]GLOBALS.OBJ : []ZIP.H
+[.$(DEST)]GLOBALS.OBJ : []TAILOR.H
+[.$(DEST)]GLOBALS.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]GLOBALS.OBJ : []ZIPERR.H
+[.$(DEST)]TREES.OBJ : []TREES.C
+[.$(DEST)]TREES.OBJ : []ZIP.H
+[.$(DEST)]TREES.OBJ : []TAILOR.H
+[.$(DEST)]TREES.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]TREES.OBJ : []ZIPERR.H
+[.$(DEST)]TTYIO.OBJ : []TTYIO.C
+[.$(DEST)]TTYIO.OBJ : []ZIP.H
+[.$(DEST)]TTYIO.OBJ : []TAILOR.H
+[.$(DEST)]TTYIO.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]TTYIO.OBJ : []ZIPERR.H
+[.$(DEST)]TTYIO.OBJ : []CRYPT.H
+[.$(DEST)]TTYIO.OBJ : []TTYIO.H
+[.$(DEST)]UTIL.OBJ : []UTIL.C
+[.$(DEST)]UTIL.OBJ : []ZIP.H
+[.$(DEST)]UTIL.OBJ : []TAILOR.H
+[.$(DEST)]UTIL.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]UTIL.OBJ : []ZIPERR.H
+[.$(DEST)]UTIL.OBJ : []EBCDIC.H
+[.$(DEST)]UTIL_.OBJ : []UTIL.C
+[.$(DEST)]UTIL_.OBJ : []ZIP.H
+[.$(DEST)]UTIL_.OBJ : []TAILOR.H
+[.$(DEST)]UTIL_.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]UTIL_.OBJ : []ZIPERR.H
+[.$(DEST)]UTIL_.OBJ : []EBCDIC.H
+[.$(DEST)]ZBZ2ERR.OBJ : []ZBZ2ERR.C
+[.$(DEST)]ZBZ2ERR.OBJ : []ZIP.H
+[.$(DEST)]ZBZ2ERR.OBJ : []TAILOR.H
+[.$(DEST)]ZBZ2ERR.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZBZ2ERR.OBJ : []ZIPERR.H
+[.$(DEST)]ZIP.OBJ : []ZIP.C
+[.$(DEST)]ZIP.OBJ : []ZIP.H
+[.$(DEST)]ZIP.OBJ : []TAILOR.H
+[.$(DEST)]ZIP.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIP.OBJ : []ZIPERR.H
+[.$(DEST)]ZIP.OBJ : []REVISION.H
+[.$(DEST)]ZIP.OBJ : []CRC32.H
+[.$(DEST)]ZIP.OBJ : []CRYPT.H
+[.$(DEST)]ZIP.OBJ : []TTYIO.H
+[.$(DEST)]ZIP.OBJ : [.VMS]VMSMUNCH.H
+[.$(DEST)]ZIP.OBJ : [.VMS]VMS.H
+[.$(DEST)]ZIPCLI.OBJ : []ZIP.C
+[.$(DEST)]ZIPCLI.OBJ : []ZIP.H
+[.$(DEST)]ZIPCLI.OBJ : []TAILOR.H
+[.$(DEST)]ZIPCLI.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIPCLI.OBJ : []ZIPERR.H
+[.$(DEST)]ZIPCLI.OBJ : []REVISION.H
+[.$(DEST)]ZIPCLI.OBJ : []CRC32.H
+[.$(DEST)]ZIPCLI.OBJ : []CRYPT.H
+[.$(DEST)]ZIPCLI.OBJ : []TTYIO.H
+[.$(DEST)]ZIPCLI.OBJ : [.VMS]VMSMUNCH.H
+[.$(DEST)]ZIPCLI.OBJ : [.VMS]VMS.H
+[.$(DEST)]ZIPCLOAK.OBJ : []ZIPCLOAK.C
+[.$(DEST)]ZIPCLOAK.OBJ : []ZIP.H
+[.$(DEST)]ZIPCLOAK.OBJ : []TAILOR.H
+[.$(DEST)]ZIPCLOAK.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIPCLOAK.OBJ : []ZIPERR.H
+[.$(DEST)]ZIPCLOAK.OBJ : []REVISION.H
+[.$(DEST)]ZIPCLOAK.OBJ : []CRC32.H
+[.$(DEST)]ZIPCLOAK.OBJ : []CRYPT.H
+[.$(DEST)]ZIPCLOAK.OBJ : []TTYIO.H
+[.$(DEST)]ZIPFILE.OBJ : []ZIPFILE.C
+[.$(DEST)]ZIPFILE.OBJ : []ZIP.H
+[.$(DEST)]ZIPFILE.OBJ : []TAILOR.H
+[.$(DEST)]ZIPFILE.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIPFILE.OBJ : []ZIPERR.H
+[.$(DEST)]ZIPFILE.OBJ : []REVISION.H
+[.$(DEST)]ZIPFILE.OBJ : [.VMS]VMS.H
+[.$(DEST)]ZIPFILE.OBJ : [.VMS]VMSMUNCH.H
+[.$(DEST)]ZIPFILE.OBJ : [.VMS]VMSDEFS.H
+[.$(DEST)]ZIPFILE_.OBJ : []ZIPFILE.C
+[.$(DEST)]ZIPFILE_.OBJ : []ZIP.H
+[.$(DEST)]ZIPFILE_.OBJ : []TAILOR.H
+[.$(DEST)]ZIPFILE_.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIPFILE_.OBJ : []ZIPERR.H
+[.$(DEST)]ZIPFILE_.OBJ : []REVISION.H
+[.$(DEST)]ZIPFILE_.OBJ : [.VMS]VMS.H
+[.$(DEST)]ZIPFILE_.OBJ : [.VMS]VMSMUNCH.H
+[.$(DEST)]ZIPFILE_.OBJ : [.VMS]VMSDEFS.H
+[.$(DEST)]ZIPNOTE.OBJ : []ZIPNOTE.C
+[.$(DEST)]ZIPNOTE.OBJ : []ZIP.H
+[.$(DEST)]ZIPNOTE.OBJ : []TAILOR.H
+[.$(DEST)]ZIPNOTE.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIPNOTE.OBJ : []ZIPERR.H
+[.$(DEST)]ZIPNOTE.OBJ : []REVISION.H
+[.$(DEST)]ZIPSPLIT.OBJ : []ZIPSPLIT.C
+[.$(DEST)]ZIPSPLIT.OBJ : []ZIP.H
+[.$(DEST)]ZIPSPLIT.OBJ : []TAILOR.H
+[.$(DEST)]ZIPSPLIT.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIPSPLIT.OBJ : []ZIPERR.H
+[.$(DEST)]ZIPSPLIT.OBJ : []REVISION.H
+[.$(DEST)]ZIPUP.OBJ : []ZIPUP.C
+[.$(DEST)]ZIPUP.OBJ : []ZIP.H
+[.$(DEST)]ZIPUP.OBJ : []TAILOR.H
+[.$(DEST)]ZIPUP.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIPUP.OBJ : []ZIPERR.H
+[.$(DEST)]ZIPUP.OBJ : []REVISION.H
+[.$(DEST)]ZIPUP.OBJ : []CRC32.H
+[.$(DEST)]ZIPUP.OBJ : []CRYPT.H
+[.$(DEST)]ZIPUP.OBJ : [.VMS]ZIPUP.H
+[.$(DEST)]CMDLINE.OBJ : [.VMS]CMDLINE.C
+[.$(DEST)]CMDLINE.OBJ : []ZIP.H
+[.$(DEST)]CMDLINE.OBJ : []TAILOR.H
+[.$(DEST)]CMDLINE.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]CMDLINE.OBJ : []ZIPERR.H
+[.$(DEST)]CMDLINE.OBJ : []CRYPT.H
+[.$(DEST)]CMDLINE.OBJ : []REVISION.H
+[.$(DEST)]VMS.OBJ : [.VMS]VMS.C
+[.$(DEST)]VMS.OBJ : []ZIP.H
+[.$(DEST)]VMS.OBJ : []TAILOR.H
+[.$(DEST)]VMS.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]VMS.OBJ : []ZIPERR.H
+[.$(DEST)]VMS.OBJ : [.VMS]ZIPUP.H
+[.$(DEST)]VMS.OBJ : [.VMS]VMS_PK.C
+[.$(DEST)]VMS.OBJ : []CRC32.H
+[.$(DEST)]VMS.OBJ : [.VMS]VMS.H
+[.$(DEST)]VMS.OBJ : [.VMS]VMSDEFS.H
+[.$(DEST)]VMS.OBJ : [.VMS]VMS_IM.C
+[.$(DEST)]VMSMUNCH.OBJ : [.VMS]VMSMUNCH.C
+[.$(DEST)]VMSMUNCH.OBJ : []ZIP.H
+[.$(DEST)]VMSMUNCH.OBJ : []TAILOR.H
+[.$(DEST)]VMSMUNCH.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]VMSMUNCH.OBJ : []ZIPERR.H
+[.$(DEST)]VMSMUNCH.OBJ : [.VMS]VMS.H
+[.$(DEST)]VMSMUNCH.OBJ : [.VMS]VMSMUNCH.H
+[.$(DEST)]VMSMUNCH.OBJ : [.VMS]VMSDEFS.H
+[.$(DEST)]VMSZIP.OBJ : [.VMS]VMSZIP.C
+[.$(DEST)]VMSZIP.OBJ : []ZIP.H
+[.$(DEST)]VMSZIP.OBJ : []TAILOR.H
+[.$(DEST)]VMSZIP.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]VMSZIP.OBJ : []ZIPERR.H
+[.$(DEST)]VMSZIP.OBJ : [.VMS]VMSMUNCH.H
+[.$(DEST)]VMSZIP.OBJ : [.VMS]VMS.H
+[.$(DEST)]VMS_.OBJ : [.VMS]VMS.C
+[.$(DEST)]VMS_.OBJ : []ZIP.H
+[.$(DEST)]VMS_.OBJ : []TAILOR.H
+[.$(DEST)]VMS_.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]VMS_.OBJ : []ZIPERR.H
+[.$(DEST)]VMS_.OBJ : [.VMS]ZIPUP.H
+[.$(DEST)]VMS_.OBJ : [.VMS]VMS_PK.C
+[.$(DEST)]VMS_.OBJ : []CRC32.H
+[.$(DEST)]VMS_.OBJ : [.VMS]VMS.H
+[.$(DEST)]VMS_.OBJ : [.VMS]VMSDEFS.H
+[.$(DEST)]VMS_.OBJ : [.VMS]VMS_IM.C
diff --git a/vms/descrip_mkdeps.mms b/vms/descrip_mkdeps.mms
new file mode 100644 (file)
index 0000000..9bf5add
--- /dev/null
@@ -0,0 +1,247 @@
+#                                               1 February 2008.  SMS.
+#
+#    Zip 3.0 for VMS - MMS Dependency Description File.
+#
+#    MMS /EXTENDED_SYNTAX description file to generate a C source
+#    dependencies file.  Unsightly errors result when /EXTENDED_SYNTAX
+#    is not specified.  Typical usage:
+#
+#    $ MMS /EXTEND /DESCRIP = [.VMS]DESCRIP_MKDEPS.MMS /SKIP
+#
+# Note that this description file must be used from the main
+# distribution directory, not from the [.VMS] subdirectory.
+#
+# This description file uses these command procedures:
+#
+#    [.VMS]MOD_DEP.COM
+#    [.VMS]COLLECT_DEPS.COM
+#
+# MMK users without MMS will be unable to generate the dependencies file
+# using this description file, however there should be one supplied in
+# the kit.  If this file has been deleted, users in this predicament
+# will need to recover it from the original distribution kit.
+#
+# Note:  This dependency generation scheme assumes that the dependencies
+# do not depend on host architecture type or other such variables. 
+# Therefore, no "#include" directive in the C source itself should be
+# conditional on such variables.
+#
+# The default target is the comprehensive source dependency file,
+# DEPS_FILE = [.VMS]DESCRIP_DEPS.MMS.
+#
+# Other targets:
+#
+#    CLEAN      deletes the individual source dependency files,
+#               *.MMSD;*, but leaves the comprehensive source dependency
+#               file.
+#
+#    CLEAN_ALL  deletes all source dependency files, including the
+#               individual *.MMSD;* files and the comprehensive file,
+#               DESCRIP_DEPS.MMS.*.
+#
+
+# Required command procedures.
+
+COMS = [.VMS]MOD_DEP.COM [.VMS]COLLECT_DEPS.COM
+
+# Include the source file lists (among other data).
+
+INCL_DESCRIP_SRC = 1
+.INCLUDE [.VMS]DESCRIP_SRC.MMS
+
+# The ultimate product, a comprehensive dependency list.
+
+DEPS_FILE = [.VMS]DESCRIP_DEPS.MMS 
+
+# Detect valid qualifier and/or macro options.
+
+.IF $(FINDSTRING Skip, $(MMSQUALIFIERS)) .eq Skip
+DELETE_MMSD = 1
+.ELSIF NOSKIP
+PURGE_MMSD = 1
+.ELSE
+UNK_MMSD = 1
+.ENDIF
+
+# Dependency suffixes and rules.
+#
+# .FIRST is assumed to be used already, so the MMS qualifier/macro check
+# is included in each rule (one way or another).
+
+.SUFFIXES_BEFORE .C .MMSD
+
+.C.MMSD :
+.IF UNK_MMSD
+       @ write sys$output -
+ "   /SKIP_INTERMEDIATES is expected on the MMS command line."
+       @ write sys$output -
+ "   For normal behavior (delete .MMSD files), specify ""/SKIP""."
+       @ write sys$output -
+ "   To retain the .MMSD files, specify ""/MACRO = NOSKIP=1""."
+       @ exit %x00000004
+.ENDIF
+       $(CC) $(CFLAGS_INCL) $(MMS$SOURCE) /NOLIST /NOOBJECT -
+        /MMS_DEPENDENCIES = (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+
+# List of MMS dependency files.
+
+# In case it's not obvious...
+# To extract module name lists from object library module=object lists:
+# 1.  Transform "module=[.dest]name.OBJ" into "module=[.dest] name".
+# 2.  For [.VMS], add [.VMS] to name.
+# 3.  Delete "*]" words.
+#
+# A similar scheme works for executable lists.
+
+MODS_LIB_ZIP_N = $(FILTER-OUT *], \
+ $(PATSUBST *]*.OBJ, *] *, $(MODS_OBJS_LIB_ZIP_N)))
+
+MODS_LIB_ZIP_V = $(FILTER-OUT *], \
+ $(PATSUBST *]*.OBJ, *] [.VMS]*, $(MODS_OBJS_LIB_ZIP_V)))
+
+MODS_LIB_ZIPUTILS_N = $(FILTER-OUT *], \
+ $(PATSUBST *]*.OBJ, *] *, $(MODS_OBJS_LIB_ZIPUTILS_N)))
+
+MODS_LIB_ZIPUTILS_N_V = $(FILTER-OUT *], \
+ $(PATSUBST *]*.OBJ, *] [.VMS]*, $(MODS_OBJS_LIB_ZIPUTILS_N_V)))
+
+MODS_LIB_ZIPUTILS_U = $(FILTER-OUT *], \
+ $(PATSUBST *]*.OBJ, *] *, $(MODS_OBJS_LIB_ZIPUTILS_U)))
+
+MODS_LIB_ZIPUTILS_U_V = $(FILTER-OUT *], \
+ $(PATSUBST *]*.OBJ, *] [.VMS]*, $(MODS_OBJS_LIB_ZIPUTILS_U_V)))
+
+MODS_LIB_ZIPCLI_V = $(FILTER-OUT *], \
+ $(PATSUBST *]*.OBJ, *] [.VMS]*, $(MODS_OBJS_LIB_ZIPCLI_C_V)))
+
+MODS_ZIP = $(FILTER-OUT *], \
+ $(PATSUBST *]*.EXE, *] *, $(ZIP)))
+
+MODS_ZIPUTILS = $(FILTER-OUT *], \
+ $(PATSUBST *]*.EXE, *] *, $(ZIPUTILS)))
+
+# Complete list of C object dependency file names.
+# Note that the CLI Zip main program object file is a special case.
+
+DEPS = $(FOREACH NAME, \
+ $(MODS_LIB_ZIP_N) $(MODS_LIB_ZIP_V) \
+ $(MODS_ZIPUTILS_N) $(MODS_ZIPUTILS_N_V) \
+ $(MODS_LIB_ZIPUTILS_U) $(MODS_LIB_ZIPUTILS_U_V) \
+ $(MODS_LIB_ZIPCLI_V) \
+ $(MODS_ZIP) ZIPCLI $(MODS_ZIPUTILS), \
+ $(NAME).MMSD)
+
+# Default target is the comprehensive dependency list.
+
+$(DEPS_FILE) : $(DEPS) $(COMS)
+.IF UNK_MMSD
+       @ write sys$output -
+ "   /SKIP_INTERMEDIATES is expected on the MMS command line."
+       @ write sys$output -
+ "   For normal behavior (delete individual .MMSD files), specify ""/SKIP""."
+       @ write sys$output -
+ "   To retain the individual .MMSD files, specify ""/MACRO = NOSKIP=1""."
+       @ exit %x00000004
+.ENDIF
+#
+#       Note that the space in P3, which prevents immediate macro
+#       expansion, is removed by COLLECT_DEPS.COM.
+#
+        @[.VMS]COLLECT_DEPS.COM "Zip" -
+         "$(MMS$TARGET)" "[...]*.MMSD" "[.$ (DEST)]" $(MMSDESCRIPTION_FILE)
+        @ write sys$output -
+         "Created a new dependency file: $(MMS$TARGET)"
+.IF DELETE_MMSD
+       @ write sys$output -
+         "Deleting intermediate .MMSD files..."
+       delete /log *.MMSD;*, [.VMS]*.MMSD;*
+.ELSE
+       @ write sys$output -
+         "Purging intermediate .MMSD files..."
+       purge /log *.MMSD, [.VMS]*.MMSD
+.ENDIF
+
+# CLEAN target.  Delete the individual C dependency files.
+
+CLEAN :
+       if (f$search( "*.MMSD") .nes. "") then -
+        delete /log *.MMSD;*
+       if (f$search( "[.VMS]*.MMSD") .nes. "") then -
+        delete /log [.VMS]*.MMSD;*
+
+# CLEAN_ALL target.  Delete:
+#    The individual C dependency files.
+#    The collected source dependency file.
+
+CLEAN_ALL :
+       if (f$search( "*.MMSD") .nes. "") then -
+        delete /log *.MMSD;*
+       if (f$search( "[.VMS]*.MMSD") .nes. "") then -
+        delete /log [.VMS]*.MMSD;*
+       if (f$search( "[.VMS]DESCRIP_DEPS.MMS") .nes. "") then -
+        delete /log [.VMS]DESCRIP_DEPS.MMS;*
+
+# Explicit dependencies and rules for utility variant modules.
+#
+# The extra dependency on the normal dependency file obviates including
+# the /SKIP warning code in each rule here.
+
+CRC32_.MMSD : CRC32.C CRC32.MMSD
+       $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+         /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+         (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+       @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
+CRYPT_.MMSD : CRYPT.C CRYPT.MMSD
+       $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+         /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+         (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+       @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
+FILEIO_.MMSD : FILEIO.C FILEIO.MMSD
+       $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+         /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+         (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+       @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
+UTIL_.MMSD : UTIL.C UTIL.MMSD
+       $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+         /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+         (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+       @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
+ZIPFILE_.MMSD : ZIPFILE.C ZIPFILE.MMSD
+       $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+         /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+         (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+       @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
+[.VMS]VMS_.MMSD : [.VMS]VMS.C [.VMS]VMS.MMSD
+       $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+         /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+         (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+       @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
+ZIPCLI.MMSD : ZIP.C ZIP.MMSD
+       $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+         /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+         (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+       @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
+# Special case.  No normal (non-CLI) version.
+
+[.VMS]CMDLINE.MMSD : [.VMS]CMDLINE.C
+.IF UNK_MMSD
+       @ write sys$output -
+ "   /SKIP_INTERMEDIATES is expected on the MMS command line."
+       @ write sys$output -
+ "   For normal behavior (delete .MMSD files), specify ""/SKIP""."
+       @ write sys$output -
+ "   To retain the .MMSD files, specify ""/MACRO = NOSKIP=1""."
+       @ exit %x00000004
+.ENDIF
+       $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+         /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+         (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+       @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
diff --git a/vms/descrip_src.mms b/vms/descrip_src.mms
new file mode 100644 (file)
index 0000000..33f3281
--- /dev/null
@@ -0,0 +1,373 @@
+#                                               23 February 2007.  SMS.
+#
+#    Zip 3.0 for VMS - MMS (or MMK) Source Description File.
+#
+
+# This description file is included by other description files.  It is
+# not intended to be used alone.  Verify proper inclusion.
+
+.IFDEF INCL_DESCRIP_SRC
+.ELSE
+$$$$ THIS DESCRIPTION FILE IS NOT INTENDED TO BE USED THIS WAY.
+.ENDIF
+
+
+# Define MMK architecture macros when using MMS.
+
+.IFDEF __MMK__                  # __MMK__
+.ELSE                           # __MMK__
+ALPHA_X_ALPHA = 1
+IA64_X_IA64 = 1
+VAX_X_VAX = 1
+.IFDEF $(MMS$ARCH_NAME)_X_ALPHA     # $(MMS$ARCH_NAME)_X_ALPHA
+__ALPHA__ = 1
+.ENDIF                              # $(MMS$ARCH_NAME)_X_ALPHA
+.IFDEF $(MMS$ARCH_NAME)_X_IA64      # $(MMS$ARCH_NAME)_X_IA64
+__IA64__ = 1
+.ENDIF                              # $(MMS$ARCH_NAME)_X_IA64
+.IFDEF $(MMS$ARCH_NAME)_X_VAX       # $(MMS$ARCH_NAME)_X_VAX
+__VAX__ = 1
+.ENDIF                              # $(MMS$ARCH_NAME)_X_VAX
+.ENDIF                          # __MMK__
+
+# Combine command-line VAX C compiler macros.
+
+.IFDEF VAXC                     # VAXC
+VAXC_OR_FORCE_VAXC = 1
+.ELSE                           # VAXC
+.IFDEF FORCE_VAXC                   # FORCE_VAXC
+VAXC_OR_FORCE_VAXC = 1
+.ENDIF                              # FORCE_VAXC
+.ENDIF                          # VAXC
+
+# Analyze architecture-related and option macros.
+
+.IFDEF __ALPHA__                # __ALPHA__
+DECC = 1
+DESTM = ALPHA
+.ELSE                           # __ALPHA__
+.IFDEF __IA64__                     # __IA64__
+DECC = 1
+DESTM = IA64
+.ELSE                               # __IA64__
+.IFDEF __VAX__                          # __VAX__
+.IFDEF VAXC_OR_FORCE_VAXC                   # VAXC_OR_FORCE_VAXC
+DESTM = VAXV
+.ELSE                                       # VAXC_OR_FORCE_VAXC
+.IFDEF GNUC                                     # GNUC
+CC = GCC
+DESTM = VAXG
+.ELSE                                           # GNUC
+DECC = 1
+DESTM = VAX
+.ENDIF                                          # GNUC
+.ENDIF                                      # VAXC_OR_FORCE_VAXC
+.ELSE                                   # __VAX__
+DESTM = UNK
+UNK_DEST = 1
+.ENDIF                                  # __VAX__
+.ENDIF                              # __IA64__
+.ENDIF                          # __ALPHA__
+
+.IFDEF IM                       # IM
+DESTI = I
+.ELSE                           # IM
+DESTI =
+.ENDIF                          # IM
+
+.IFDEF LARGE                    # LARGE
+.IFDEF __VAX__                      # __VAX__
+DESTL =
+.ELSE                               # __VAX__
+DESTL = L
+.ENDIF                              # __VAX__
+.ELSE                           # LARGE
+DESTL =
+.ENDIF                          # LARGE
+
+DEST = $(DESTM)$(DESTI)$(DESTL)
+SEEK_BZ = $(DESTM)$(DESTL)
+
+# Library module name suffix for XXX_.OBJ with GNU C.
+
+.IFDEF GNUC                     # GNUC
+GCC_ = _
+.ELSE                           # GNUC
+GCC_ =
+.ENDIF                          # GNUC
+
+# Check for option problems.
+
+.IFDEF __VAX__                  # __VAX__
+.IFDEF LARGE                        # LARGE
+LARGE_VAX = 1
+.ENDIF                              # LARGE
+.IFDEF VAXC_OR_FORCE_VAXC           # VAXC_OR_FORCE_VAXC
+.IFDEF GNUC                             # GNUC
+VAX_MULTI_CMPL = 1
+.ENDIF                                  # GNUC
+.ENDIF                              # VAXC_OR_FORCE_VAXC
+.ELSE                           # __VAX__
+.IFDEF VAXC_OR_FORCE_VAXC           # VAXC_OR_FORCE_VAXC
+NON_VAX_CMPL = 1
+.ELSE                               # VAXC_OR_FORCE_VAXC
+.IFDEF GNUC                             # GNUC
+NON_VAX_CMPL = 1
+.ENDIF                                  # GNUC
+.ENDIF                              # VAXC_OR_FORCE_VAXC
+.ENDIF                          # __VAX__
+
+# Complain if warranted.  Otherwise, show destination directory.
+# Make the destination directory, if necessary.
+                               
+.IFDEF UNK_DEST                 # UNK_DEST
+.FIRST
+       @ write sys$output -
+ "   Unknown system architecture."
+.IFDEF __MMK__                      # __MMK__
+       @ write sys$output -
+ "   MMK on IA64?  Try adding ""/MACRO = __IA64__""."
+.ELSE                               # __MMK__
+       @ write sys$output -
+ "   MMS too old?  Try adding ""/MACRO = MMS$ARCH_NAME=ALPHA"","
+       @ write sys$output -
+ "   or ""/MACRO = MMS$ARCH_NAME=IA64"", or ""/MACRO = MMS$ARCH_NAME=VAX"","
+       @ write sys$output -
+ "   as appropriate.  (Or try a newer version of MMS.)"
+.ENDIF                              # __MMK__
+       @ write sys$output ""
+       I_WILL_DIE_NOW.  /$$$$INVALID$$$$
+.ELSE                           # UNK_DEST
+.IFDEF VAX_MULTI_CMPL               # VAX_MULTI_CMPL
+.FIRST
+       @ write sys$output -
+ "   Macro ""GNUC"" is incompatible with ""VAXC"" or ""FORCE_VAXC""."
+       @ write sys$output ""
+       I_WILL_DIE_NOW.  /$$$$INVALID$$$$
+.ELSE                               # VAX_MULTI_CMPL
+.IFDEF NON_VAX_CMPL                     # NON_VAX_CMPL
+.FIRST
+       @ write sys$output -
+ "   Macros ""GNUC"", ""VAXC"", and ""FORCE_VAXC"" are valid only on VAX."
+       @ write sys$output ""
+       I_WILL_DIE_NOW.  /$$$$INVALID$$$$
+.ELSE                                   # NON_VAX_CMPL
+.IFDEF LARGE_VAX                            # LARGE_VAX
+.FIRST
+       @ write sys$output -
+ "   Macro ""LARGE"" is invalid on VAX."
+       @ write sys$output ""
+       I_WILL_DIE_NOW.  /$$$$INVALID$$$$
+.ELSE                                       # LARGE_VAX
+.IFDEF IZ_BZIP2                                 # IZ_BZIP2
+CDEFS_BZ = , BZIP2_SUPPORT
+CFLAGS_INCL = /INCLUDE = ([], [.VMS])
+INCL_BZIP2_M = , ZBZ2ERR
+LIB_BZIP2_OPTS = LIB_BZIP2:LIBBZ2_NS.OLB /library,
+.FIRST
+       @ define incl_bzip2 $(IZ_BZIP2)
+       @ @[.VMS]FIND_BZIP2_LIB.COM $(IZ_BZIP2) $(SEEK_BZ) -
+          LIBBZ2_NS.OLB lib_bzip2
+       @ write sys$output ""
+       @ if (f$trnlnm( "lib_bzip2") .nes. "") then -
+          write sys$output "   BZIP2 dir: ''f$trnlnm( "lib_bzip2")'"
+       @ if (f$trnlnm( "lib_bzip2") .eqs. "") then -
+          write sys$output "   Can not find BZIP2 object library."
+       @ write sys$output ""
+       @ if (f$trnlnm( "lib_bzip2") .eqs. "") then -
+          I_WILL_DIE_NOW.  /$$$$INVALID$$$$
+       @ write sys$output "   Destination: [.$(DEST)]"
+       @ write sys$output ""
+       if (f$search( "$(DEST).DIR;1") .eqs. "") then -
+        create /directory [.$(DEST)]
+.ELSE                                           # IZ_BZIP2
+CDEFS_BZ =
+CFLAGS_INCL = /include = []
+INCL_BZIP2_M = , ZBZ2ERR
+LIB_BZIP2_OPTS =
+.FIRST
+       @ write sys$output "   Destination: [.$(DEST)]"
+       @ write sys$output ""
+       if (f$search( "$(DEST).DIR;1") .eqs. "") then -
+        create /directory [.$(DEST)]
+.ENDIF                                          # IZ_BZIP2
+.ENDIF                                      # LARGE_VAX
+.ENDIF                                  # NON_VAX_CMPL
+.ENDIF                              # VAX_MULTI_CMPL
+.ENDIF                          # UNK_DEST
+
+# DBG options.
+
+.IFDEF DBG                      # DBG
+CFLAGS_DBG = /debug /nooptimize
+LINKFLAGS_DBG = /debug /traceback
+.ELSE                           # DBG
+CFLAGS_DBG =
+LINKFLAGS_DBG = /notraceback
+.ENDIF                          # DBG
+
+# "IM" scheme for storing VMS/RMS file attributes.
+
+.IFDEF IM                       # IM
+CDEFS_IM = , VMS_IM_EXTRA
+.ELSE                           # IM
+CDEFS_IM =
+.ENDIF                          # IM
+
+# Large-file options.
+
+.IFDEF LARGE                    # LARGE
+CDEFS_LARGE = , LARGE_FILE_SUPPORT
+.ELSE                           # LARGE
+CDEFS_LARGE =
+.ENDIF                          # LARGE
+
+# C compiler defines.
+
+.IFDEF LOCAL_ZIP
+C_LOCAL_ZIP = , $(LOCAL_ZIP)
+.ELSE
+C_LOCAL_ZIP =
+.ENDIF
+
+CDEFS = VMS $(CDEFS_BZ) $(CDEFS_IM) $(CDEFS_LARGE) $(C_LOCAL_ZIP)
+
+CDEFS_UNX = /define = ($(CDEFS))
+
+CDEFS_CLI = /define = ($(CDEFS), VMSCLI)
+
+CDEFS_UTIL = /define = ($(CDEFS), UTIL)
+
+# Other C compiler options.
+
+.IFDEF DECC                             # DECC
+CFLAGS_ARCH = /decc /prefix = (all)
+.ELSE                                   # DECC
+.IFDEF FORCE_VAXC                           # FORCE_VAXC
+CFLAGS_ARCH = /vaxc
+.IFDEF VAXC                                     # VAXC
+.ELSE                                           # VAXC
+VAXC = 1
+.ENDIF                                          # VAXC
+.ELSE                                       # FORCE_VAXC
+CFLAGS_ARCH =
+.ENDIF                                      # FORCE_VAXC
+.ENDIF                                  # DECC
+
+.IFDEF VAXC_OR_FORCE_VAXC               # VAXC_OR_FORCE_VAXC
+OPT_FILE = [.$(DEST)]VAXCSHR.OPT
+LFLAGS_ARCH = $(OPT_FILE) /options, 
+.ELSE                                   # VAXC_OR_FORCE_VAXC
+.IFDEF GNUC                                 # GNUC
+OPT_FILE = [.$(DEST)]VAXCSHR.OPT
+LFLAGS_GNU = GNU_CC:[000000]GCCLIB.OLB /LIBRARY
+LFLAGS_ARCH = $(LFLAGS_GNU), SYS$DISK:$(OPT_FILE) /options, 
+.ELSE                                       # GNUC
+OPT_FILE =
+LFLAGS_ARCH =
+.ENDIF                                      # GNUC
+.ENDIF                                  # VAXC_OR_FORCE_VAXC
+
+# LIST options.
+
+.IFDEF LIST                     # LIST
+.IFDEF DECC                         # DECC
+CFLAGS_LIST = /list = $*.LIS /show = (all, nomessages)
+.ELSE                               # DECC
+CFLAGS_LIST = /list = $*.LIS /show = (all)
+.ENDIF                              # DECC
+LINKFLAGS_LIST = /map = $*.MAP /cross_reference /full
+.ELSE                           # LIST
+CFLAGS_LIST =
+LINKFLAGS_LIST =
+.ENDIF                          # LIST
+
+# Common CFLAGS and LINKFLAGS.
+
+CFLAGS = \
+ $(CFLAGS_ARCH) $(CFLAGS_DBG) $(CFLAGS_INCL) $(CFLAGS_LIST) $(CCOPTS) \
+ /object = $(MMS$TARGET)
+
+LINKFLAGS = \
+ $(LINKFLAGS_DBG) $(LINKFLAGS_LIST) $(LINKOPTS) \
+ /executable = $(MMS$TARGET)
+
+# Object library module=object lists.
+
+#    Primary object library, [].
+
+MODS_OBJS_LIB_ZIP_N = \
+ CRC32=[.$(DEST)]CRC32.OBJ \
+ CRYPT=[.$(DEST)]CRYPT.OBJ \
+ DEFLATE=[.$(DEST)]DEFLATE.OBJ \
+ FILEIO=[.$(DEST)]FILEIO.OBJ \
+ GLOBALS=[.$(DEST)]GLOBALS.OBJ \
+ TREES=[.$(DEST)]TREES.OBJ \
+ TTYIO=[.$(DEST)]TTYIO.OBJ \
+ UTIL=[.$(DEST)]UTIL.OBJ \
+ ZBZ2ERR=[.$(DEST)]ZBZ2ERR.OBJ \
+ ZIPFILE=[.$(DEST)]ZIPFILE.OBJ \
+ ZIPUP=[.$(DEST)]ZIPUP.OBJ
+
+#    Primary object library, [.VMS].
+                    
+MODS_OBJS_LIB_ZIP_V = \
+ VMS=[.$(DEST)]VMS.OBJ \
+ VMSMUNCH=[.$(DEST)]VMSMUNCH.OBJ \
+ VMSZIP=[.$(DEST)]VMSZIP.OBJ
+
+MODS_OBJS_LIB_ZIP = $(MODS_OBJS_LIB_ZIP_N) $(MODS_OBJS_LIB_ZIP_V)
+
+#    Utility object library, normal, [].
+
+MODS_OBJS_LIB_ZIPUTILS_N = \
+ GLOBALS=[.$(DEST)]GLOBALS.OBJ \
+ TTYIO=[.$(DEST)]TTYIO.OBJ
+
+#    Utility object library, variant, [].
+
+MODS_OBJS_LIB_ZIPUTILS_U = \
+ CRC32$(GCC_)=[.$(DEST)]CRC32_.OBJ \
+ CRYPT$(GCC_)=[.$(DEST)]CRYPT_.OBJ \
+ FILEIO$(GCC_)=[.$(DEST)]FILEIO_.OBJ \
+ UTIL$(GCC_)=[.$(DEST)]UTIL_.OBJ \
+ ZIPFILE$(GCC_)=[.$(DEST)]ZIPFILE_.OBJ
+
+#    Utility object library, normal, [.VMS].
+
+MODS_OBJS_LIB_ZIPUTILS_N_V = \
+ VMSMUNCH=[.$(DEST)]VMSMUNCH.OBJ
+
+#    Utility object library, variant, [.VMS].
+
+MODS_OBJS_LIB_ZIPUTILS_U_V = \
+ VMS$(GCC_)=[.$(DEST)]VMS_.OBJ
+
+MODS_OBJS_LIB_ZIPUTILS = $(MODS_OBJS_LIB_ZIPUTILS_N) \
+ $(MODS_OBJS_LIB_ZIPUTILS_U) \
+ $(MODS_OBJS_LIB_ZIPUTILS_N_V) \
+ $(MODS_OBJS_LIB_ZIPUTILS_U_V) \
+
+#    CLI object library, [.VMS].
+
+MODS_OBJS_LIB_ZIPCLI_C_V = \
+ CMDLINE=[.$(DEST)]CMDLINE.OBJ
+
+MODS_OBJS_LIB_ZIPCLI_CLD_V = \
+ ZIP_CLITABLE=[.$(DEST)]ZIP_CLI.OBJ
+
+MODS_OBJS_LIB_ZIPCLI = \
+ $(MODS_OBJS_LIB_ZIPCLI_C_V) \
+ $(MODS_OBJS_LIB_ZIPCLI_CLD_V)
+
+# Executables.
+
+ZIP = [.$(DEST)]ZIP.EXE
+
+ZIP_CLI = [.$(DEST)]ZIP_CLI.EXE
+
+ZIPUTILS = \
+ [.$(DEST)]ZIPCLOAK.EXE \
+ [.$(DEST)]ZIPNOTE.EXE \
+ [.$(DEST)]ZIPSPLIT.EXE
+
diff --git a/vms/find_bzip2_lib.com b/vms/find_bzip2_lib.com
new file mode 100644 (file)
index 0000000..21ebf7b
--- /dev/null
@@ -0,0 +1,71 @@
+$!                                              28 December 2006.  SMS.
+$!
+$! Info-ZIP VMS accessory procedure.
+$!
+$! Find the BZIP2 object library under P1, starting in the [.'P2']
+$! destination directory.  (We assume, initially, that the BZIP2
+$! directory has a destination directory structure like ours.)
+$!
+$! Set the P4 logical name to the directory where it was found.
+$! P5 and P6 may be used for qualifiers on the DEFINE command.
+$!
+$ bz_orig = p1
+$ dest = p2
+$ libbz2 = p3
+$!
+$! Remove any trailing colon, to allow logical name translation.
+$!
+$ bz_dev_dir = ""
+$ bz_base = bz_orig
+$ if (f$extract( (f$length( bz_base)- 1), 1, bz_base) .eqs. ":")
+$ then
+$     bz_base = bz_base- ":"
+$ endif
+$!
+$ bz_base_eqv = f$trnlnm( bz_base)
+$ if (bz_base_eqv .nes. "")
+$ then
+$     bz_orig = bz_base_eqv
+$     bz_base = bz_base_eqv
+$ endif
+$ bz_base = bz_base- "]"
+$!
+$! Candidate 1 = the actual analogue destination directory.
+$!
+$ bz_dev_dir_cand = bz_base+ "."+ dest+ "]"
+$ lib_cand = bz_dev_dir_cand+ libbz2
+$ if (f$search( lib_cand) .nes. "")
+$ then
+$     bz_dev_dir = bz_dev_dir_cand
+$ else
+$!
+$!     Candidate 2 = the actual analogue destination directory + "L".
+$!
+$     bz_dev_dir_cand = bz_base+ "."+ dest+ "L]"
+$     lib_cand = bz_dev_dir_cand+ libbz2
+$     if (f$search( lib_cand) .nes. "")
+$     then
+$         bz_dev_dir = bz_dev_dir_cand
+$     else
+$!
+$!         Candidate 3 = the actual user-specified directory.
+$!
+$         bz_dev_dir_cand = bz_orig
+$         lib_cand = bz_dev_dir_cand+ libbz2
+$         if (f$search( lib_cand) .nes. "")
+$         then
+$             bz_dev_dir = bz_dev_dir_cand
+$         endif
+$     endif
+$ endif
+$!
+$ if (bz_dev_dir .nes. "")
+$ then
+$     if (p4 .eqs. "")
+$     then
+$         write sys$output bz_dev_dir
+$     else
+$         define 'p5' 'p4' 'bz_dev_dir' 'p6'
+$     endif
+$ endif
+$!
diff --git a/vms/hlp_lib_next.com b/vms/hlp_lib_next.com
new file mode 100644 (file)
index 0000000..f9b14a5
--- /dev/null
@@ -0,0 +1,17 @@
+$!                                              21 November 2004.  SMS.
+$!
+$!    HLP_LIB_NEXT.COM
+$!
+$!    Find the next available HLP$LIBRARY[_*] logical name.
+$!
+$ base = "HLP$LIBRARY"
+$ candidate = base
+$ i = 0
+$!
+$ loop_top:
+$    if (i .gt. 0) then candidate = base+ "_"+ f$string( i)
+$    i = i+ 1
+$    if (f$trnlnm( candidate) .nes. "") then goto loop_top
+$!
+$ write sys$output candidate
+$!
diff --git a/vms/install_vms.txt b/vms/install_vms.txt
new file mode 100644 (file)
index 0000000..47dfebb
--- /dev/null
@@ -0,0 +1,158 @@
+
+  VMS (OpenVMS):
+
+  Building:
+
+     On VMS, two build methods are provided: a command procedure, and
+     description files for MMS or MMK.  Both methods must be run from
+     the main directory, not the [.VMS] subdirectory.
+
+     A simple build using the command procedure looks like this:
+          @ [.VMS]BUILD_ZIP.COM
+
+     A simple build using MMS or MMK looks like this:
+          MMS /DESCRIP = [.VMS]DESCRIP.MMS      ! Or, with MMK, ...
+          MMK /DESCRIP = [.VMS]DESCRIP.MMS
+
+     Various options for each build method are explained in comments in
+     the main builder file, either BUILD_ZIP.COM or DESCRIP.MMS.
+
+      Note that on non-VAX systems with VMS V7.2 or later (and with a
+      sufficiently new C compiler), Zip 3.0 can support files (both data
+      files and Zip archives) larger than 2GB.  For the greatest
+      compatibility with previous Zip versions, the builders by default
+      create old-style small-file programs.  The user must specify the
+      appropriate builder command-line option to create
+      large-file-capable programs.
+
+     Here are some more complex build examples:
+
+     o Build with the large-file option enabled (non-VAX only):
+
+          @ [.VMS]BUILD_ZIP LARGE
+       or:
+          MMS /DESC = [.VMS] /MACRO = LARGE=1
+
+     o Re-link the executables (small-file and large-file):
+
+          @ [.VMS]BUILD_ZIP LINK
+          @ [.VMS]BUILD_ZIP LARGE LINK
+       or
+          MMK /DESC = [.VMS] CLEAN_EXE  ! Deletes existing executables.
+          MMK /DESC = [.VMS]            ! Builds new executables.
+          MMK /DESC = [.VMS] /MACRO = LARGE=1 CLEAN_EXE
+          MMK /DESC = [.VMS] /MACRO = LARGE=1
+
+     o Build a large-file product from scratch, for debug, getting
+       compiler listings and link maps:
+
+          MMS /DESC = [.VMS] CLEAN
+          MMS /DESC = [.VMS] /MACRO = (DBG=1, LARGE=1. LIST=1)
+
+     On VAX, the builders attempt to cope with the various available C
+     compilers, DEC/Compaq/HP C, VAX C, or GNU C.  If DEC/Compaq/HP C is
+     not available or not desired, comments in the relevant builder file
+     explain the command-line options used to select a different
+     compiler.
+
+     By default, Zip uses the "deflate" compression method.  To add
+     support for the optional "bzip2" compression method, first obtain
+     and build the bzip2 software (http://www.bzip.org/ or, for a more
+     VMS-friendly kit, http://antinode.info/dec/sw/bzip2.html).  Then,
+     define the macro IZ_BZIP2 on the BUILD_ZIP.COM or MMS/MMK command
+     line to specify the directory where the bzip2 files may be found.
+     For example:
+
+          @ [.VMS]BUILD_ZIP LARGE -
+           IZ_BZIP2=SYS$SYSDEVICE:[UTILITY.SOURCE.BZIP2.BZIP2-1_0_3C_VMS]
+       or:
+          MMS /DESC = [.VMS] /MACRO = (LARGE=1, -
+           IZ_BZIP2=SYS$SYSDEVICE:[UTILITY.SOURCE.BZIP2.BZIP2-1_0_3C_VMS])
+
+     Note that historically, Zip has been built with the default
+     compiler option, /NAMES = UPPERCASE, while bzip2 is normally built
+     with /NAMES = AS_IS, to avoid name collisions.  With modern
+     compilers, the "#pragma names" directives in [.VMS]BZLIB.H will
+     handle these differences without user intervention.  An old
+     compiler (for example, DEC C V4.0-000) will emit complaints
+     %CC-I-UNKNOWNPRAGMA, and will mishandle the bzip2 library function
+     names, which will cause the link to fail.  To solve this problem,
+     either build the bzip2 BZ_NO_STDIO object library with /NAMES =
+     UPPERCASE, or else build Zip with /NAMES = AS_IS.  For example:
+
+          @ [.VMS]BUILD_ZIP LARGE "CCOPTS=/NAMES=AS_IS" -
+           IZ_BZIP2=SYS$SYSDEVICE:[UTILITY.SOURCE.BZIP2.BZIP2-1_0_3C_VMS]
+       or:
+          MMS /DESC = [.VMS] /MACRO = (LARGE=1, "CCOPTS=/NAMES=AS_IS", -
+           IZ_BZIP2=SYS$SYSDEVICE:[UTILITY.SOURCE.BZIP2.BZIP2-1_0_3C_VMS])
+
+     System-architecture-specific files (like objects and executables)
+     are placed in separate directories, such as [.ALPHA], [.IA64], or
+     [.VAX].  Large-file products get their own directories, [.ALPHAL]
+     or [.IA64L].  On VAX, VAX C products are placed in [.VAXV], GNU C
+     products in [.VAXG].  Each product builder announces what the
+     destination directory will be when it is run.
+
+     Common files, such as the help libraries (ZIP.HLP for the default
+     UNIX-like command-line interface, ZIP_CLI.HLP for the VMS-like
+     command-line interface), are placed in the main directory.  With a
+     mixed-architecture VMS cluster, the same main directory on a shared
+     disk may be used by all system types.  (Using the NOHELP option
+     with BUILD_ZIP.COM can keep it from making the same help files
+     repeatedly.)  Building the help files is detailed below.
+
+  Completing installation:
+
+     To complete the installation, the executables may be left in place,
+     or moved (or copied) to a convenient place.  While other methods
+     (like DCL$PATH) exist, most users define symbols to make the Zip
+     executables available as foreign commands.  These symbol definitions
+     may be placed in a user's SYS$LOGIN:LOGIN.COM, or in a more central
+     location, like SYS$MANAGER:SYLOGIN.COM.  Typical symbol definitions
+     might look like these:
+
+           ZIP :== $ dev:[dir]ZIP.EXE            ! UNIX-like command line.
+   or:
+           ZIP :== $ dev:[dir]ZIP_CLI.EXE        ! VMS-like command line.
+
+     On a non-VAX system, different symbols could be defined for the
+     small-file and large-file programs.  For example:
+
+           ZIPS  :== $ dev:[dir.ALPHA]ZIP.EXE    ! ZIPS = small-file Zip.
+           ZIP*L :== $ dev:[dir.ALPHAL]ZIP.EXE   ! ZIP[L] = large-file Zip.
+
+     The builders create help text files, ZIP.HLP and ZIP_CLI.HLP.
+     These may be incorporated into an existing help library, or a separate
+     Zip help library may be created using commands like these, using
+     either ZIP.HLP (as shown) or ZIP_CLI.HLP:
+
+           $ LIBRARY /HELP dev:[dir]existing_library.HLB ZIP.HLP
+
+           $ LIBRARY /CREATE /HELP ZIP.HLB ZIP.HLP
+
+     Zip help may then be accessed from a separate Zip help library
+     using a command like:
+
+           $ HELP /LIBRARY = device:[directory]ZIP.HLB
+
+     For greater ease, the user (or system manager) may define a
+     HLP$LIBRARY logical name to allow the HELP utility to find the Zip
+     help library automatically.  See HELP HELP /USERLIBRARY for more
+     details.   The command procedure HLP_LIB_NEXT.COM may be used to
+     determine the next available HLP$LIBRARY logical name, and could be
+     adapted to define a HLP$LIBRARY logical name for a Zip help library.
+
+     The builders also create VMS message files, ZIP_MSG.EXE, in the
+     destination directory with the program executables.  A user may
+     gain DCL access to the Zip error messages using a command like:
+
+           $ SET MESSAGE device:[directory]ZIP_MSG.EXE
+
+     For system-wide access, the system manager may move or copy this
+     file to SYS$MESSAGE, although this could cause some confusion if
+     multiple versions of Zip are used on the system, and their error
+     message source files differ.
+
+     Some further information may be found in the files
+     [.VMS]00README.TXT and [.VMS]00BINARY.VMS, though much of what's
+     there is now obsolete.
diff --git a/vms/mod_dep.com b/vms/mod_dep.com
new file mode 100644 (file)
index 0000000..bbc6d2d
--- /dev/null
@@ -0,0 +1,33 @@
+$!                                              3 March 2005.  SMS.
+$!
+$! Info-ZIP VMS accessory procedure.
+$!
+$!    Modify a dependencies file (P1), changing the object file name to
+$!    P2.
+$!    P3 = output file specification.
+$!
+$!
+$ prefix = f$edit( p3, "COLLAPSE")
+$!
+$! Strip any device:[directory] from P2.
+$!
+$ obj_name = f$parse( P2, , , "NAME", "SYNTAX_ONLY")+ -
+   f$parse( P2, , , "TYPE", "SYNTAX_ONLY")
+$!
+$ open /read /error = end_main deps_in 'p1'
+$ open /write /error = end_main deps_out 'p3'
+$ on error then goto loop_main_end
+$ loop_main_top:
+$     read /error = loop_main_end deps_in line
+$     line_reduced = f$edit( line, "COMPRESS, TRIM")
+$     colon = f$locate( " : ", line_reduced)
+$     line = obj_name+ f$extract( colon, 2000, line)
+$     write deps_out "''line'"
+$ goto loop_main_top
+$!
+$ loop_main_end:
+$ close deps_in
+$ close deps_out
+$!
+$ end_main:
+$!
diff --git a/vms/osdep.h b/vms/osdep.h
new file mode 100644 (file)
index 0000000..d7a07a4
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef VMS
+#  define VMS 1
+#endif
+
+#if (defined(__VMS_VER) && !defined(__CRTL_VER))
+#  define __CRTL_VER __VMS_VER
+#endif
+
+#if (defined(__VMS_VERSION) && !defined(VMS_VERSION))
+#  define VMS_VERSION __VMS_VERSION
+#endif
+
+#if !(defined(__DECC) || defined(__DECCXX) || defined(__GNUC__))
+     /* VAX C does not properly support the void keyword. (Only functions
+        are allowed to have the type "void".)  */
+#  ifndef NO_TYPEDEF_VOID
+#    define NO_TYPEDEF_VOID
+#  endif
+#  define NO_FCNTL_H        /* VAXC does not supply fcntl.h. */
+#endif /* VAX C */
+
+#define USE_CASE_MAP
+#define PROCNAME(n) \
+ (((action == ADD) || (action == UPDATE) || (action == FRESHEN)) ? \
+ wild(n) : procname(n, filter_match_case))
+
+/* 2004-11-09 SMS.
+   Large file support.
+*/
+#ifdef LARGE_FILE_SUPPORT
+
+#  define _LARGEFILE                   /* Define the pertinent macro. */
+
+/* LARGE_FILE_SUPPORT implies ZIP64_SUPPORT,
+   unless explicitly disabled by NO_ZIP64_SUPPORT.
+*/
+#  ifdef NO_ZIP64_SUPPORT
+#    ifdef ZIP64_SUPPORT
+#      undef ZIP64_SUPPORT
+#    endif /* def ZIP64_SUPPORT */
+#  else /* def NO_ZIP64_SUPPORT */
+#    ifndef ZIP64_SUPPORT
+#      define ZIP64_SUPPORT
+#    endif /* ndef ZIP64_SUPPORT */
+#  endif /* def NO_ZIP64_SUPPORT */
+
+#  define ZOFF_T_FORMAT_SIZE_PREFIX "ll"
+
+#else /* def LARGE_FILE_SUPPORT */
+
+#  define ZOFF_T_FORMAT_SIZE_PREFIX "l"
+
+#endif /* def LARGE_FILE_SUPPORT */
+
+/* Need _LARGEFILE for types.h. */
+
+#include <types.h>
+
+#ifdef __GNUC__
+#include <sys/types.h>
+#endif /* def __GNUC__ */
+
+/* Need types.h for off_t. */
+
+#ifdef LARGE_FILE_SUPPORT
+   typedef off_t zoff_t;
+   typedef unsigned long long uzoff_t;
+#else /* def LARGE_FILE_SUPPORT */
+   typedef long zoff_t;
+   typedef unsigned long uzoff_t;
+#endif /* def LARGE_FILE_SUPPORT */
+
+#include <stat.h>
+
+typedef struct stat z_stat;
+
+#include <unixio.h>
+
+#if defined(__GNUC__) && !defined(ZCRYPT_INTERNAL)
+#  include <unixlib.h>          /* ctermid() declaration needed in ttyio.c */
+#endif
+#ifdef ZCRYPT_INTERNAL
+#  include <unixlib.h>          /* getpid() declaration for srand seed */
+#endif
+
+#if defined(_MBCS)
+#  undef _MBCS                 /* Zip on VMS does not support MBCS */
+#endif
+
+/* VMS is run on little-endian processors with 4-byte ints:
+ * enable the optimized CRC-32 code */
+#ifdef IZ_CRC_BE_OPTIMIZ
+#  undef IZ_CRC_BE_OPTIMIZ
+#endif
+#if !defined(IZ_CRC_LE_OPTIMIZ) && !defined(NO_CRC_OPTIMIZ)
+#  define IZ_CRC_LE_OPTIMIZ
+#endif
+#if !defined(IZ_CRCOPTIM_UNFOLDTBL) && !defined(NO_CRC_OPTIMIZ)
+#  define IZ_CRCOPTIM_UNFOLDTBL
+#endif
+
+#if !defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME)
+#  if (defined(__CRTL_VER) && (__CRTL_VER >= 70000000))
+#    define USE_EF_UT_TIME
+#  endif
+#endif
+
+#if defined(VMS_PK_EXTRA) && defined(VMS_IM_EXTRA)
+#  undef VMS_IM_EXTRA                 /* PK style takes precedence */
+#endif
+#if !defined(VMS_PK_EXTRA) && !defined(VMS_IM_EXTRA)
+#  define VMS_PK_EXTRA 1              /* PK style VMS support is default */
+#endif
+
+/* 2007-02-22 SMS.
+ * <unistd.h> is needed for symbolic link functions, so use it when the
+ * symbolic link criteria are met.
+ */
+#if defined(__VAX) || __CRTL_VER < 70301000
+#  define NO_UNISTD_H
+#  define NO_SYMLINKS
+#endif /* defined(__VAX) || __CRTL_VER < 70301000 */
+
+/* 2007-02-22 SMS.  Use delete() when unlink() is not available. */
+#if defined(NO_UNISTD_H) || (__CRTL_VER < 70000000)
+#  define unlink delete
+#endif /* defined(NO_UNISTD_H) || __CRTL_VER < 70000000) */
+
+#define SSTAT vms_stat
+#define EXIT(exit_code) vms_exit(exit_code)
+#define RETURN(exit_code) return (vms_exit(exit_code), 1)
+
+
+#ifdef __DECC
+
+/* File open callback ID values. */
+
+#  define FOPM_ID 1
+#  define FOPR_ID 2
+#  define FOPW_ID 3
+
+/* File open callback ID storage. */
+
+extern int fopm_id;
+extern int fopr_id;
+extern int fopw_id;
+
+/* File open callback ID function. */
+
+extern int acc_cb();
+
+/* Option macros for zfopen().
+ * General: Stream access
+ * Output: fixed-length, 512-byte records.
+ *
+ * Callback function (DEC C only) sets deq, mbc, mbf, rah, wbh, ...
+ */
+
+#  define FOPM "r+b", "ctx=stm", "rfm=fix", "mrs=512", "acc", acc_cb, &fopm_id
+#  define FOPR "rb",  "ctx=stm", "acc", acc_cb, &fopr_id
+#  define FOPW "wb",  "ctx=stm", "rfm=fix", "mrs=512", "acc", acc_cb, &fopw_id
+
+#else /* def __DECC */ /* (So, GNU C, VAX C, ...)*/
+
+#  define FOPM "r+b", "ctx=stm", "rfm=fix", "mrs=512"
+#  define FOPR "rb",  "ctx=stm"
+#  define FOPW "wb",  "ctx=stm", "rfm=fix", "mrs=512"
+
+#endif /* def __DECC */
+
diff --git a/vms/stream_lf.fdl b/vms/stream_lf.fdl
new file mode 100644 (file)
index 0000000..ab0f907
--- /dev/null
@@ -0,0 +1,3 @@
+RECORD
+        Carriage_Control carriage_return
+        Format stream_lf
diff --git a/vms/unixio_gcc.h b/vms/unixio_gcc.h
new file mode 100644 (file)
index 0000000..05bc421
--- /dev/null
@@ -0,0 +1,27 @@
+/* 2004-12-12 SMS.
+ *
+ * Emergency replacement UNIXIO.H for GNU C, for use as needed.
+ * Install as GNU_CC_INCLUDE:[000000]UNIXIO.H
+ */
+
+#ifndef __UNIXIO_LOADED
+#define __UNIXIO_LOADED 1
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif /* ndef SEEK_SET */
+
+#ifndef SEEK_CUR
+# define SEEK_CUR 1
+#endif /* ndef SEEK_CUR */
+
+#ifndef SEEK_END
+# define SEEK_END 2
+#endif /* ndef SEEK_END */
+
+#endif  /* ndef __UNIXIO_LOADED */
+
diff --git a/vms/unixlib_gcc.h b/vms/unixlib_gcc.h
new file mode 100644 (file)
index 0000000..eda4ed9
--- /dev/null
@@ -0,0 +1,16 @@
+/* 2004-12-12 SMS.
+ *
+ * Emergency replacement UNIXLIB.H for GNU C, for use as needed.
+ * Install as GNU_CC_INCLUDE:[000000]UNIXLIB.H
+ */
+
+#ifndef __UNIXLIB_LOADED
+#define __UNIXLIB_LOADED 1
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+typedef struct stat stat_t;
+
+#endif  /* ndef __UNIXLIB_LOADED */
+
diff --git a/vms/vms.c b/vms/vms.c
new file mode 100644 (file)
index 0000000..1b194c6
--- /dev/null
+++ b/vms/vms.c
@@ -0,0 +1,1007 @@
+/*
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  vms.c (zip) by Igor Mandrichenko    Version 2.2-2
+ *
+ *  Revision history:
+ *  ...
+ *  2.2-2       18-jan-1993     I.Mandrichenko
+ *      vms_stat() added - version of stat() that handles special
+ *      case when end-of-file-block == 0
+ *
+ *  3.0         11-oct-2004     SMS
+ *      It would be nice to know why vms_stat() is needed.  If EOF can't
+ *      be trusted for a zero-length file, why trust it for any file?
+ *      Anyway, I removed the (int) cast on ->st_size, which may now be
+ *      bigger than an int, just in case this code ever does get used.
+ *      (A true zero-length file should still report zero length, even
+ *      after the long fight with RMS.)
+ *      Moved the VMS_PK_EXTRA test(s) into VMS_IM.C and VMS_PK.C to
+ *      allow more general automatic dependency generation.
+ */
+
+#ifdef VMS                      /* For VMS only ! */
+
+#define NO_ZIPUP_H              /* Prevent full inclusion of vms/zipup.h. */
+
+#include "zip.h"
+#include "zipup.h"              /* Only partial. */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <jpidef.h>
+#include <fab.h>                /* Needed only in old environments. */
+#include <nam.h>                /* Needed only in old environments. */
+#include <starlet.h>
+#include <ssdef.h>
+#include <stsdef.h>
+
+/* On VAX, define Goofy VAX Type-Cast to obviate /standard = vaxc.
+   Otherwise, lame system headers on VAX cause compiler warnings.
+   (GNU C may define vax but not __VAX.)
+*/
+#ifdef vax
+# define __VAX 1
+#endif /* def vax */
+
+#ifdef __VAX
+# define GVTC (unsigned int)
+#else /* def __VAX */
+# define GVTC
+#endif /* def __VAX */
+
+
+#ifdef UTIL
+
+/* For utilities, include only vms.h, as either of the vms_XX.c files
+ * would do.
+ */
+
+# include "vms.h"
+
+#else /* not UTIL */
+
+/* Include the `VMS attributes' preserving file-io code. We distinguish
+   between two incompatible flavours of storing VMS attributes in the
+   Zip archive:
+   a) The "PKware" style follows the extra field specification for
+      PKware's VMS Zip.
+   b) The "IM (Info-ZIP)" flavour was defined from scratch by
+      Igor Mandrichenko. This version has be used in official Info-ZIP
+      releases for several years and is known to work well.
+ */
+
+/* Note that only one of these #include directives will include any
+ * active code, depending on VMS_PK_EXTRA.  Both are included here (and
+ * tested there) to allow more general automatic dependency generation.
+ */
+
+#include "vms_pk.c"
+#include "vms_im.c"
+
+#endif /* not UTIL [else] */
+
+#ifndef ERR
+#define ERR(x) (((x)&1)==0)
+#endif
+
+#ifndef NULL
+#define NULL (void*)(0L)
+#endif
+
+int vms_stat( char *file, stat_t *s)
+{
+    int status;
+    int staterr;
+    struct FAB fab;
+    struct NAM_STRUCT nam;
+    struct XABFHC fhc;
+
+    /*
+     *  In simplest case when stat() returns "ok" and file size is
+     *  nonzero or this is directory, finish with this
+     */
+
+    if( (staterr=stat(file,s)) == 0
+        && ( s->st_size >= 0                      /* Size - ok */
+             || (s->st_mode & S_IFREG) == 0       /* Not a plain file */
+           )
+    ) return staterr;
+
+    /*
+     *  Get here to handle the special case when stat() returns
+     *  invalid file size. Use RMS to compute the size.
+     *  When EOF block is zero, set file size to its physical size.
+     *  One more case to get here is when this is remote file accessed
+     *  via DECnet.
+     */
+
+    fab = cc$rms_fab;
+    nam = CC_RMS_NAM;
+    fhc = cc$rms_xabfhc;
+    fab.FAB_NAM = &nam;
+    fab.fab$l_xab = (char*)(&fhc);
+
+#ifdef NAML$C_MAXRSS
+
+    fab.fab$l_dna = (char *) -1;    /* Using NAML for default name. */
+    fab.fab$l_fna = (char *) -1;    /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = file;
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen( file);
+
+    fab.fab$b_fac = FAB$M_GET;
+
+    status = sys$open(&fab);
+    fab.fab$l_xab = (char*)0L;
+    sys$close(&fab);
+
+    if( !ERR(status) )
+    {
+        if( fhc.xab$l_ebk > 0 )
+            s->st_size = ( fhc.xab$l_ebk-1 ) * 512 + fhc.xab$w_ffb;
+        else if( fab.fab$b_org == FAB$C_IDX
+                 || fab.fab$b_org == FAB$C_REL
+                 || fab.fab$b_org == FAB$C_HSH )
+                /* Special case, when ebk=0: save entire allocated space */
+                    s->st_size = fhc.xab$l_hbk * 512;
+        else
+            s->st_size = fhc.xab$w_ffb;
+        return 0; /* stat() success code */
+    }
+    else
+        return status;
+}
+
+
+/*
+ * 2007-01-29 SMS.
+ *
+ *  VMS Status Code Summary  (See STSDEF.H for details.)
+ *
+ *      Bits:   31:28    27:16     15:3     2:0
+ *      Field:  Control  Facility  Message  Severity
+ *
+ *  In the Control field, bits 31:29 are reserved.  Bit 28 inhibits
+ *  printing the message.  In the Facility field, bit 27 means
+ *  customer-defined (not HP-assigned, like us).  In the Message field,
+ *  bit 15 means facility-specific (which our messages are).  The
+ *  Severity codes are 0 = Warning, 1 = Success, 2 = Error, 3 = Info,
+ *  4 = Severe (fatal).
+ *
+ *  Previous versions of Info-ZIP programs used a generic ("chosen (by
+ *  experimentation)") Control+Facility code of 0x7FFF, which included
+ *  some reserved control bits, the inhibit-printing bit, and the
+ *  customer-defined bit.
+ *
+ *  HP has now assigned official Facility names and corresponding
+ *  Facility codes for the Info-ZIP products:
+ *
+ *      Facility Name    Facility Code
+ *      IZ_UNZIP         1954 = 0x7A2
+ *      IZ_ZIP           1955 = 0x7A3
+ *
+ *  Now, unless the CTL_FAC_IZ_ZIP macro is defined at build-time, we
+ *  will use the official Facility code.
+ *
+ */
+
+/* Official HP-assigned Info-ZIP Zip Facility code. */
+#define FAC_IZ_ZIP 1955   /* 0x7A3 */
+
+#ifndef CTL_FAC_IZ_ZIP
+   /*
+    * Default is inhibit-printing with the official Facility code.
+    */
+#  define CTL_FAC_IZ_ZIP ((0x1 << 12)| FAC_IZ_ZIP)
+#  define MSG_FAC_SPEC 0x8000   /* Facility-specific code. */
+#else /* ndef CTL_FAC_IZ_ZIP */
+   /* Use the user-supplied Control+Facility code for err or warn. */
+#  define OLD_STATUS
+#  ifndef MSG_FAC_SPEC          /* Old default is not Facility-specific. */
+#    define MSG_FAC_SPEC 0x0    /* Facility-specific code.  Or 0x8000. */
+#  endif /* ndef MSG_FAC_SPEC */
+#endif /* ndef CTL_FAC_IZ_ZIP [else] */
+
+
+/* Return an intelligent status/severity code. */
+
+void vms_exit(e)
+   int e;
+{
+  {
+#ifndef OLD_STATUS
+
+    /*
+     * Exit with code comprising Control, Facility, (facility-specific)
+     * Message, and Severity.
+     */
+    exit( (CTL_FAC_IZ_ZIP << 16) |              /* Facility                */
+          MSG_FAC_SPEC |                        /* Facility-specific       */
+          (e << 4) |                            /* Message code            */
+          (ziperrors[ e].severity & 0x07)       /* Severity                */
+        );
+
+#else /* ndef OLD_STATUS */
+
+    /* 2007-01-17 SMS.
+     * Defining OLD_STATUS provides the same behavior as in Zip versions
+     * before an official VMS Facility code had been assigned, which
+     * means that Success (ZE_OK) gives a status value of 1 (SS$_NORMAL)
+     * with no Facility code, while any error or warning gives a status
+     * value which includes a Facility code.  (Curiously, under the old
+     * scheme, message codes were left-shifted by 4 instead of 3,
+     * resulting in all-even message codes.)  I don't like this, but I
+     * was afraid to remove it, as someone, somewhere may be depending
+     * on it.  Define CTL_FAC_IZ_ZIP as 0x7FFF to get the old behavior.
+     * Define only OLD_STATUS to get the old behavior for Success
+     * (ZE_OK), but using the official HP-assigned Facility code for an
+     * error or warning.  Define MSG_FAC_SPEC to get the desired
+     * behavior.
+     *
+     * Exit with simple SS$_NORMAL for ZE_OK.  Otherwise, exit with code
+     * comprising Control, Facility, Message, and Severity.
+     */
+    exit(
+         (e == ZE_OK) ? SS$_NORMAL :            /* Success (others below)  */
+         ((CTL_FAC_IZ_ZIP << 16) |              /* Facility                */
+          MSG_FAC_SPEC |                        /* Facility-specific (?)   */
+          (e << 4) |                            /* Message code            */
+          (ziperrors[ e].severity & 0x07)       /* Severity                */
+         )
+        );
+
+#endif /* ndef OLD_STATUS */
+   }
+}
+
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+void version_local()
+{
+    static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+#ifdef VMS_VERSION
+    char *chrp1;
+    char *chrp2;
+    char buf[40];
+    char vms_vers[ 16];
+    int ver_maj;
+#endif
+#ifdef __DECC_VER
+    char buf2[40];
+    int  vtyp;
+#endif
+
+#ifdef VMS_VERSION
+    /* Truncate the version string at the first (trailing) space. */
+    strncpy( vms_vers, VMS_VERSION, sizeof( vms_vers));
+    chrp1 = strchr( vms_vers, ' ');
+    if (chrp1 != NULL)
+        *chrp1 = '\0';
+
+    /* Determine the major version number. */
+    ver_maj = 0;
+    chrp1 = strchr( &vms_vers[ 1], '.');
+    for (chrp2 = &vms_vers[ 1];
+     chrp2 < chrp1;
+     ver_maj = ver_maj* 10+ *(chrp2++)- '0');
+
+#endif /* def VMS_VERSION */
+
+/*  DEC C in ANSI mode does not like "#ifdef MACRO" inside another
+    macro when MACRO is equated to a value (by "#define MACRO 1").   */
+
+    printf(CompiledWith,
+
+#ifdef __GNUC__
+      "gcc ", __VERSION__,
+#else
+#  if defined(DECC) || defined(__DECC) || defined (__DECC__)
+      "DEC C",
+#    ifdef __DECC_VER
+      (sprintf(buf2, " %c%d.%d-%03d",
+               ((vtyp = (__DECC_VER / 10000) % 10) == 6 ? 'T' :
+                (vtyp == 8 ? 'S' : 'V')),
+               __DECC_VER / 10000000,
+               (__DECC_VER % 10000000) / 100000, __DECC_VER % 1000), buf2),
+#    else
+      "",
+#    endif
+#  else
+#  ifdef VAXC
+      "VAX C", "",
+#  else
+      "unknown compiler", "",
+#  endif
+#  endif
+#endif
+
+#ifdef VMS_VERSION
+#  if defined( __alpha)
+      "OpenVMS",
+      (sprintf( buf, " (%s Alpha)", vms_vers), buf),
+#  elif defined( __ia64) /* defined( __alpha) */
+      "OpenVMS",
+      (sprintf( buf, " (%s IA64)", vms_vers), buf),
+#  else /* defined( __alpha) */
+      (ver_maj >= 6) ? "OpenVMS" : "VMS",
+      (sprintf( buf, " (%s VAX)", vms_vers), buf),
+#  endif /* defined( __alpha) */
+#else
+      "VMS",
+      "",
+#endif /* def VMS_VERSION */
+
+#ifdef __DATE__
+      " on ", __DATE__
+#else
+      "", ""
+#endif
+      );
+
+} /* end function version_local() */
+
+/* 2004-10-08 SMS.
+ *
+ *       tempname() for VMS.
+ *
+ *    Generate a temporary Zip archive file name, near the actual
+ *    destination Zip archive file, or at "tempath", if specified.
+ *
+ *    Using sys$parse() is probably more work than it's worth, but it
+ *    should also be ODS5-safe.
+ *
+ *    Note that the generic method using tmpnam() (in FILEIO.C)
+ *    produces "ziXXXXXX", where "XXXXXX" is the low six digits of the
+ *    decimal representation of the process ID.  This method produces
+ *    "ZIxxxxxxxx", where "xxxxxxxx" is the (whole) eight-digit
+ *    hexadecimal representation of the process ID.  More important, it
+ *    actually uses the directory part of the argument or "tempath".
+ */
+
+
+char *tempname( char *zip)
+/* char *zip; */                /* Path name of Zip archive. */
+{
+    char *temp_name;            /* Return value. */
+    int sts;                    /* System service status. */
+
+    static int pid;             /* Process ID. */
+    static int pid_len;         /* Returned size of process ID. */
+
+    struct                      /* Item list for GETJPIW. */
+    {
+        short buf_len;          /* Buffer length. */
+        short itm_cod;          /* Item code. */
+        int *buf;               /* Buffer address. */
+        int *ret_len;           /* Returned length. */
+        int term;               /* Item list terminator. */
+    } jpi_itm_lst = { sizeof( pid), JPI$_PID, &pid, &pid_len };
+
+    /* ZI<UNIQUE> name storage. */
+    static char zip_tmp_nam[ 16] = "ZI<unique>.;";
+
+    struct FAB fab;             /* FAB structure. */
+    struct NAM_STRUCT nam;      /* NAM[L] structure. */
+
+    char exp_str[ NAM_MAXRSS+ 1];   /* Expanded name storage. */
+
+#ifdef VMS_UNIQUE_TEMP_BY_TIME
+
+    /* Use alternate time-based scheme to generate a unique temporary name. */
+    sprintf( &zip_tmp_nam[ 2], "%08X", time( NULL));
+
+#else /* def VMS_UNIQUE_TEMP_BY_TIME */
+
+    /* Use the process ID to generate a unique temporary name. */
+    sts = sys$getjpiw( 0, 0, 0, &jpi_itm_lst, 0, 0, 0);
+    sprintf( &zip_tmp_nam[ 2], "%08X", pid);
+
+#endif /* def VMS_UNIQUE_TEMP_BY_TIME */
+
+    /* Smoosh the unique temporary name against the actual Zip archive
+       name (or "tempath") to create the full temporary path name.
+       (Truncate it at the file type to remove any file type.)
+    */
+    if (tempath != NULL)        /* Use "tempath", if it's been specified. */
+        zip = tempath;
+
+    /* Initialize the FAB and NAM[L], and link the NAM[L] to the FAB. */
+    fab = cc$rms_fab;
+    nam = CC_RMS_NAM;
+    fab.FAB_NAM = &nam;
+
+    /* Point the FAB/NAM[L] fields to the actual name and default name. */
+
+#ifdef NAML$C_MAXRSS
+
+    fab.fab$l_dna = (char *) -1;    /* Using NAML for default name. */
+    fab.fab$l_fna = (char *) -1;    /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+    /* Default name = Zip archive name. */
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNA = zip;
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNS = strlen( zip);
+
+    /* File name = "ZI<unique>,;". */
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = zip_tmp_nam;
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen( zip_tmp_nam);
+
+    nam.NAM_ESA = exp_str;      /* Expanded name (result) storage. */
+    nam.NAM_ESS = NAM_MAXRSS;   /* Size of expanded name storage. */
+
+    nam.NAM_NOP = NAM_M_SYNCHK; /* Syntax-only analysis. */
+
+    temp_name = NULL;           /* Prepare for failure (unlikely). */
+    sts = sys$parse( &fab, 0, 0);       /* Parse the name(s). */
+
+    if ((sts& STS$M_SEVERITY) == STS$M_SUCCESS)
+    {
+        /* Overlay any resulting file type (typically ".ZIP") with none. */
+        strcpy( nam.NAM_L_TYPE, ".;");
+
+        /* Allocate temp name storage (as caller expects), and copy the
+           (truncated) temp name into the new location.
+        */
+        temp_name = malloc( strlen( nam.NAM_ESA)+ 1);
+
+        if (temp_name != NULL)
+        {
+            strcpy( temp_name, nam.NAM_ESA);
+        }
+    }
+    return temp_name;
+} /* tempname() for VMS. */
+
+
+/* 2005-02-17 SMS.
+ *
+ *       ziptyp() for VMS.
+ *
+ *    Generate a real Zip archive file name (exact, if it exists), using
+ *    a default file name.
+ *
+ *    2005-02-17 SMS.  Moved to here from [-]ZIPFILE.C, to segregate
+ *    better the RMS stuff.
+ *
+ *    Before 2005-02-17, if sys$parse() failed, ziptyp() returned a null
+ *    string ("&zero", where "static char zero = '\0';").  This
+ *    typically caused Zip to proceed, but then the final rename() of
+ *    the temporary archive would (silently) fail (null file name, after
+ *    all), leaving only the temporary archive file, and providing no
+ *    warning message to the victim.  Now, when sys$parse() fails,
+ *    ziptyp() returns the original string, so a later open() fails, and
+ *    a relatively informative message is provided.  (A VMS-specific
+ *    message could also be provided here, if desired.)
+ *
+ *    2005-09-16 SMS.
+ *    Changed name parsing in ziptyp() to solve a problem with a
+ *    search-list logical name device-directory spec for the zipfile.
+ *    Previously, when the zipfile did not exist (so sys$search()
+ *    failed), the expanded name was used, but as it was
+ *    post-sys$search(), it was based on the _last_ member of the search
+ *    list instead of the first.  Now, the expanded name from the
+ *    original sys$parse() (pre-sys$search()) is retained, and it is
+ *    used if sys$search() fails.  This name is based on the first
+ *    member of the search list, as a user might expect.
+ */
+
+/* Default Zip archive file spec. */
+#define DEF_DEVDIRNAM "SYS$DISK:[].zip"
+
+char *ziptyp( char *s)
+{
+    int status;
+    int exp_len;
+    struct FAB fab;
+    struct NAM_STRUCT nam;
+    char result[ NAM_MAXRSS+ 1];
+    char exp[ NAM_MAXRSS+ 1];
+    char *p;
+
+    fab = cc$rms_fab;                           /* Initialize FAB. */
+    nam = CC_RMS_NAM;                           /* Initialize NAM[L]. */
+    fab.FAB_NAM = &nam;                         /* FAB -> NAM[L] */
+
+#ifdef NAML$C_MAXRSS
+
+    fab.fab$l_dna =(char *) -1;         /* Using NAML for default name. */
+    fab.fab$l_fna = (char *) -1;        /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+    /* Argument file name and length. */
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = s;
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen( s);
+
+    /* Default file spec and length. */
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNA = DEF_DEVDIRNAM;
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNS = sizeof( DEF_DEVDIRNAM)- 1;
+
+    nam.NAM_ESA = exp;                 /* Expanded name, */
+    nam.NAM_ESS = NAM_MAXRSS;          /* storage size. */
+    nam.NAM_RSA = result;              /* Resultant name, */
+    nam.NAM_RSS = NAM_MAXRSS;          /* storage size. */
+
+    status = sys$parse(&fab);
+    if ((status & 1) == 0)
+    {
+        /* Invalid file name.  Return (re-allocated) original, and hope
+           for a later error message.
+        */
+        if ((p = malloc( strlen( s)+ 1)) != NULL )
+        {
+            strcpy( p, s);
+        }
+        return p;
+    }
+
+    /* Save expanded name length from sys$parse(). */
+    exp_len = nam.NAM_ESL;
+
+    /* Leave expanded name as-is, in case of search failure. */
+    nam.NAM_ESA = NULL;                 /* Expanded name, */
+    nam.NAM_ESS = 0;                    /* storage size. */
+
+    status = sys$search(&fab);
+    if (status & 1)
+    {   /* Zip file exists.  Use resultant (complete, exact) name. */
+        if ((p = malloc( nam.NAM_RSL+ 1)) != NULL )
+        {
+            result[ nam.NAM_RSL] = '\0';
+            strcpy( p, result);
+        }
+    }
+    else
+    {   /* New Zip file.  Use pre-search expanded name. */
+        if ((p = malloc( exp_len+ 1)) != NULL )
+        {
+            exp[ exp_len] = '\0';
+            strcpy( p, exp);
+        }
+    }
+    return p;
+} /* ziptyp() for VMS. */
+
+
+/* 2005-12-30 SMS.
+ *
+ *       vms_file_version().
+ *
+ *    Return the ";version" part of a VMS file specification.
+ */
+
+char *vms_file_version( char *s)
+{
+    int status;
+    struct FAB fab;
+    struct NAM_STRUCT nam;
+    char *p;
+
+    static char exp[ NAM_MAXRSS+ 1];    /* Expanded name storage. */
+
+
+    fab = cc$rms_fab;                   /* Initialize FAB. */
+    nam = CC_RMS_NAM;                   /* Initialize NAM[L]. */
+    fab.FAB_NAM = &nam;                 /* FAB -> NAM[L] */
+
+#ifdef NAML$C_MAXRSS
+
+    fab.fab$l_dna =(char *) -1;         /* Using NAML for default name. */
+    fab.fab$l_fna = (char *) -1;        /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+    /* Argument file name and length. */
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = s;
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen( s);
+
+    nam.NAM_ESA = exp;                 /* Expanded name, */
+    nam.NAM_ESS = NAM_MAXRSS;          /* storage size. */
+
+    nam.NAM_NOP = NAM_M_SYNCHK;        /* Syntax-only analysis. */
+
+    status = sys$parse(&fab);
+
+    if ((status & 1) == 0)
+    {
+        /* Invalid file name.  Return "". */
+        exp[ 0] = '\0';
+        p = exp;
+    }
+    else
+    {
+        /* Success.  NUL-terminate, and return a pointer to the ";" in
+           the expanded name storage buffer.
+        */
+        p = nam.NAM_L_VER;
+        p[ nam.NAM_B_VER] = '\0';
+    }
+    return p;
+} /* vms_file_version(). */
+
+
+/* 2004-11-23 SMS.
+ *
+ *       get_rms_defaults().
+ *
+ *    Get user-specified values from (DCL) SET RMS_DEFAULT.  FAB/RAB
+ *    items of particular interest are:
+ *
+ *       fab$w_deq         default extension quantity (blocks) (write).
+ *       rab$b_mbc         multi-block count.
+ *       rab$b_mbf         multi-buffer count (used with rah and wbh).
+ */
+
+#define DIAG_FLAG (verbose >= 2)
+
+/* Default RMS parameter values. */
+
+#define RMS_DEQ_DEFAULT 16384   /* About 1/4 the max (65535 blocks). */
+#define RMS_MBC_DEFAULT 127     /* The max, */
+#define RMS_MBF_DEFAULT 2       /* Enough to enable rah and wbh. */
+
+/* GETJPI item descriptor structure. */
+typedef struct
+    {
+    short buf_len;
+    short itm_cod;
+    void *buf;
+    int *ret_len;
+    } jpi_item_t;
+
+/* Durable storage */
+
+static int rms_defaults_known = 0;
+
+/* JPI item buffers. */
+static unsigned short rms_ext;
+static char rms_mbc;
+static unsigned char rms_mbf;
+
+/* Active RMS item values. */
+unsigned short rms_ext_active;
+char rms_mbc_active;
+unsigned char rms_mbf_active;
+
+/* GETJPI item lengths. */
+static int rms_ext_len;         /* Should come back 2. */
+static int rms_mbc_len;         /* Should come back 1. */
+static int rms_mbf_len;         /* Should come back 1. */
+
+/* Desperation attempts to define unknown macros.  Probably doomed.
+ * If these get used, expect sys$getjpiw() to return %x00000014 =
+ * %SYSTEM-F-BADPARAM, bad parameter value.
+ * They keep compilers with old header files quiet, though.
+ */
+#ifndef JPI$_RMS_EXTEND_SIZE
+#  define JPI$_RMS_EXTEND_SIZE 542
+#endif /* ndef JPI$_RMS_EXTEND_SIZE */
+
+#ifndef JPI$_RMS_DFMBC
+#  define JPI$_RMS_DFMBC 535
+#endif /* ndef JPI$_RMS_DFMBC */
+
+#ifndef JPI$_RMS_DFMBFSDK
+#  define JPI$_RMS_DFMBFSDK 536
+#endif /* ndef JPI$_RMS_DFMBFSDK */
+
+/* GETJPI item descriptor set. */
+
+struct
+    {
+    jpi_item_t rms_ext_itm;
+    jpi_item_t rms_mbc_itm;
+    jpi_item_t rms_mbf_itm;
+    int term;
+    } jpi_itm_lst =
+     { { 2, JPI$_RMS_EXTEND_SIZE, &rms_ext, &rms_ext_len },
+       { 1, JPI$_RMS_DFMBC, &rms_mbc, &rms_mbc_len },
+       { 1, JPI$_RMS_DFMBFSDK, &rms_mbf, &rms_mbf_len },
+       0
+     };
+
+int get_rms_defaults()
+{
+int sts;
+
+/* Get process RMS_DEFAULT values. */
+
+sts = sys$getjpiw( 0, 0, 0, &jpi_itm_lst, 0, 0, 0);
+if ((sts& STS$M_SEVERITY) != STS$M_SUCCESS)
+    {
+    /* Failed.  Don't try again. */
+    rms_defaults_known = -1;
+    }
+else
+    {
+    /* Fine, but don't come back. */
+    rms_defaults_known = 1;
+    }
+
+/* Limit the active values according to the RMS_DEFAULT values. */
+
+if (rms_defaults_known > 0)
+    {
+    /* Set the default values. */
+
+    rms_ext_active = RMS_DEQ_DEFAULT;
+    rms_mbc_active = RMS_MBC_DEFAULT;
+    rms_mbf_active = RMS_MBF_DEFAULT;
+
+    /* Default extend quantity.  Use the user value, if set. */
+    if (rms_ext > 0)
+        {
+        rms_ext_active = rms_ext;
+        }
+
+    /* Default multi-block count.  Use the user value, if set. */
+    if (rms_mbc > 0)
+        {
+        rms_mbc_active = rms_mbc;
+        }
+
+    /* Default multi-buffer count.  Use the user value, if set. */
+    if (rms_mbf > 0)
+        {
+        rms_mbf_active = rms_mbf;
+        }
+    }
+
+if (DIAG_FLAG)
+    {
+    fprintf( stderr,
+     "Get RMS defaults.  getjpi sts = %%x%08x.\n",
+     sts);
+
+    if (rms_defaults_known > 0)
+        {
+        fprintf( stderr,
+         "               Default: deq = %6d, mbc = %3d, mbf = %3d.\n",
+         rms_ext, rms_mbc, rms_mbf);
+        }
+    }
+return sts;
+}
+
+#ifdef __DECC
+
+/* 2004-11-23 SMS.
+ *
+ *       acc_cb(), access callback function for DEC C zfopen().
+ *
+ *    Set some RMS FAB/RAB items, with consideration of user-specified
+ * values from (DCL) SET RMS_DEFAULT.  Items of particular interest are:
+ *
+ *       fab$w_deq         default extension quantity (blocks).
+ *       rab$b_mbc         multi-block count.
+ *       rab$b_mbf         multi-buffer count (used with rah and wbh).
+ *
+ *    See also the FOP* macros in OSDEP.H.  Currently, no notice is
+ * taken of the caller-ID value, but options could be set differently
+ * for read versus write access.  (I assume that specifying fab$w_deq,
+ * for example, for a read-only file has no ill effects.)
+ */
+
+/* Global storage. */
+
+int fopm_id = FOPM_ID;          /* Callback id storage, modify. */
+int fopr_id = FOPR_ID;          /* Callback id storage, read. */
+int fopw_id = FOPW_ID;          /* Callback id storage, write. */
+
+int fhow_id = FHOW_ID;          /* Callback id storage, in read. */
+
+/* acc_cb() */
+
+int acc_cb( int *id_arg, struct FAB *fab, struct RAB *rab)
+{
+int sts;
+
+/* Get process RMS_DEFAULT values, if not already done. */
+if (rms_defaults_known == 0)
+    {
+    get_rms_defaults();
+    }
+
+/* If RMS_DEFAULT (and adjusted active) values are available, then set
+ * the FAB/RAB parameters.  If RMS_DEFAULT values are not available,
+ * suffer with the default parameters.
+ */
+if (rms_defaults_known > 0)
+    {
+    /* Set the FAB/RAB parameters accordingly. */
+    fab-> fab$w_deq = rms_ext_active;
+    rab-> rab$b_mbc = rms_mbc_active;
+    rab-> rab$b_mbf = rms_mbf_active;
+
+    /* Truncate at EOF on close, as we'll probably over-extend. */
+    fab-> fab$v_tef = 1;
+
+    /* If using multiple buffers, enable read-ahead and write-behind. */
+    if (rms_mbf_active > 1)
+        {
+        rab-> rab$v_rah = 1;
+        rab-> rab$v_wbh = 1;
+        }
+
+    if (DIAG_FLAG)
+        {
+        fprintf( mesg,
+         "Open callback.  ID = %d, deq = %6d, mbc = %3d, mbf = %3d.\n",
+         *id_arg, fab-> fab$w_deq, rab-> rab$b_mbc, rab-> rab$b_mbf);
+        }
+    }
+
+/* Declare success. */
+return 0;
+}
+
+#endif /* def __DECC */
+
+/*
+ * 2004-09-19 SMS.
+ *
+ *----------------------------------------------------------------------
+ *
+ *       decc_init()
+ *
+ *    On non-VAX systems, uses LIB$INITIALIZE to set a collection of C
+ *    RTL features without using the DECC$* logical name method.
+ *
+ *----------------------------------------------------------------------
+ */
+
+#ifdef __DECC
+
+#ifdef __CRTL_VER
+
+#if !defined( __VAX) && (__CRTL_VER >= 70301000)
+
+#include <unixlib.h>
+
+/*--------------------------------------------------------------------*/
+
+/* Global storage. */
+
+/*    Flag to sense if decc_init() was called. */
+
+int decc_init_done = -1;
+
+/*--------------------------------------------------------------------*/
+
+/* decc_init()
+
+      Uses LIB$INITIALIZE to set a collection of C RTL features without
+      requiring the user to define the corresponding logical names.
+*/
+
+/* Structure to hold a DECC$* feature name and its desired value. */
+
+typedef struct
+   {
+   char *name;
+   int value;
+   } decc_feat_t;
+
+/* Array of DECC$* feature names and their desired values. */
+
+decc_feat_t decc_feat_array[] = {
+
+   /* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */
+ { "DECC$ARGV_PARSE_STYLE", 1 },
+
+   /* Preserve case for file names on ODS5 disks. */
+ { "DECC$EFS_CASE_PRESERVE", 1 },
+
+   /* Enable multiple dots (and most characters) in ODS5 file names,
+      while preserving VMS-ness of ";version". */
+ { "DECC$EFS_CHARSET", 1 },
+
+   /* List terminator. */
+ { (char *)NULL, 0 } };
+
+/* LIB$INITIALIZE initialization function. */
+
+static void decc_init( void)
+{
+int feat_index;
+int feat_value;
+int feat_value_max;
+int feat_value_min;
+int i;
+int sts;
+
+/* Set the global flag to indicate that LIB$INITIALIZE worked. */
+
+decc_init_done = 1;
+
+/* Loop through all items in the decc_feat_array[]. */
+
+for (i = 0; decc_feat_array[ i].name != NULL; i++)
+   {
+   /* Get the feature index. */
+   feat_index = decc$feature_get_index( decc_feat_array[ i].name);
+   if (feat_index >= 0)
+      {
+      /* Valid item.  Collect its properties. */
+      feat_value = decc$feature_get_value( feat_index, 1);
+      feat_value_min = decc$feature_get_value( feat_index, 2);
+      feat_value_max = decc$feature_get_value( feat_index, 3);
+
+      if ((decc_feat_array[ i].value >= feat_value_min) &&
+       (decc_feat_array[ i].value <= feat_value_max))
+         {
+         /* Valid value.  Set it if necessary. */
+         if (feat_value != decc_feat_array[ i].value)
+            {
+            sts = decc$feature_set_value( feat_index,
+             1,
+             decc_feat_array[ i].value);
+            }
+         }
+      else
+         {
+         /* Invalid DECC feature value. */
+         printf( " INVALID DECC FEATURE VALUE, %d: %d <= %s <= %d.\n",
+          feat_value,
+          feat_value_min, decc_feat_array[ i].name, feat_value_max);
+         }
+      }
+   else
+      {
+      /* Invalid DECC feature name. */
+      printf( " UNKNOWN DECC FEATURE: %s.\n", decc_feat_array[ i].name);
+      }
+   }
+}
+
+/* Get "decc_init()" into a valid, loaded LIB$INITIALIZE PSECT. */
+
+#pragma nostandard
+
+/* Establish the LIB$INITIALIZE PSECTs, with proper alignment and
+   other attributes.  Note that "nopic" is significant only on VAX.
+*/
+#pragma extern_model save
+
+#pragma extern_model strict_refdef "LIB$INITIALIZ" 2, nopic, nowrt
+const int spare[ 8] = { 0 };
+
+#pragma extern_model strict_refdef "LIB$INITIALIZE" 2, nopic, nowrt
+void (*const x_decc_init)() = decc_init;
+
+#pragma extern_model restore
+
+/* Fake reference to ensure loading the LIB$INITIALIZE PSECT. */
+
+#pragma extern_model save
+
+int LIB$INITIALIZE( void);
+
+#pragma extern_model strict_refdef
+int dmy_lib$initialize = (int) LIB$INITIALIZE;
+
+#pragma extern_model restore
+
+#pragma standard
+
+#endif /* !defined( __VAX) && (__CRTL_VER >= 70301000) */
+
+#endif /* def __CRTL_VER */
+
+#endif /* def __DECC */
+
+#endif /* VMS */
diff --git a/vms/vms.h b/vms/vms.h
new file mode 100644 (file)
index 0000000..8685fdd
--- /dev/null
+++ b/vms/vms.h
@@ -0,0 +1,354 @@
+/*
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+  vms.h
+
+  Generic VMS header file for Info-ZIP's Zip and UnZip.
+
+  ---------------------------------------------------------------------------*/
+
+#ifndef __vms_h
+#define __vms_h 1
+
+#ifndef __DESCRIP_LOADED
+#include <descrip.h>
+#endif
+#ifndef __STARLET_LOADED
+#include <starlet.h>
+#endif
+#ifndef __SYIDEF_LOADED
+#include <syidef.h>
+#endif
+#ifndef __ATRDEF_LOADED
+#include <atrdef.h>
+#endif
+#ifndef __FIBDEF_LOADED
+#include <fibdef.h>
+#endif
+#ifndef __IODEF_LOADED
+#include <iodef.h>
+#endif
+#if !defined(_RMS_H) && !defined(__RMS_LOADED)
+#include <rms.h>
+#endif
+
+#define ERR(s) !((s) & 1)       /* VMS system error */
+
+#ifndef SYI$_VERSION
+#define SYI$_VERSION 4096       /* VMS 5.4 definition */
+#endif
+
+/*
+ *  Under Alpha (DEC C in VAXC mode) and under `good old' VAXC, the FIB unions
+ *  are declared as variant_unions.  DEC C (Alpha) in ANSI modes and third
+ *  party compilers which do not support `variant_union' define preprocessor
+ *  symbols to `hide' the "intermediate union/struct" names from the
+ *  programmer's API.
+ *  We check the presence of these defines and for DEC's FIBDEF.H defining
+ *  __union as variant_union to make sure we access the structure correctly.
+ */
+#define variant_union 1
+#if defined(fib$w_did) || (defined(__union) && (__union == variant_union))
+#  define FIB$W_DID     fib$w_did
+#  define FIB$W_FID     fib$w_fid
+#  define FIB$L_ACCTL   fib$l_acctl
+#  define FIB$W_EXCTL   fib$w_exctl
+#else
+#  define FIB$W_DID     fib$r_did_overlay.fib$w_did
+#  define FIB$W_FID     fib$r_fid_overlay.fib$w_fid
+#  define FIB$L_ACCTL   fib$r_acctl_overlay.fib$l_acctl
+#  define FIB$W_EXCTL   fib$r_exctl_overlay.fib$w_exctl
+#endif
+#undef variant_union
+
+
+/* 2005-02-08 SMS.  Moved NAM[L] macros here from VMS.C. */
+
+/* Define macros for use with either NAM or NAML. */
+
+#ifdef NAML$C_MAXRSS            /* NAML is available.  Use it. */
+
+#  define NAM_STRUCT NAML
+
+#  define FAB_OR_NAML( fab, nam) nam
+#  define FAB_OR_NAML_DNA naml$l_long_defname
+#  define FAB_OR_NAML_DNS naml$l_long_defname_size
+#  define FAB_OR_NAML_FNA naml$l_long_filename
+#  define FAB_OR_NAML_FNS naml$l_long_filename_size
+
+#  define CC_RMS_NAM cc$rms_naml
+#  define FAB_NAM fab$l_naml
+#  define NAM_DID naml$w_did
+#  define NAM_DVI naml$t_dvi
+#  define NAM_ESA naml$l_long_expand
+#  define NAM_ESL naml$l_long_expand_size
+#  define NAM_ESS naml$l_long_expand_alloc
+#  define NAM_FID naml$w_fid
+#  define NAM_FNB naml$l_fnb
+#  define NAM_RSA naml$l_long_result
+#  define NAM_RSL naml$l_long_result_size
+#  define NAM_RSS naml$l_long_result_alloc
+#  define NAM_MAXRSS NAML$C_MAXRSS
+#  define NAM_NOP naml$b_nop
+#  define NAM_M_EXP_DEV NAML$M_EXP_DEV
+#  define NAM_M_SYNCHK NAML$M_SYNCHK
+#  define NAM_B_DEV naml$l_long_dev_size
+#  define NAM_L_DEV naml$l_long_dev
+#  define NAM_B_DIR naml$l_long_dir_size
+#  define NAM_L_DIR naml$l_long_dir
+#  define NAM_B_NAME naml$l_long_name_size
+#  define NAM_L_NAME naml$l_long_name
+#  define NAM_B_TYPE naml$l_long_type_size
+#  define NAM_L_TYPE naml$l_long_type
+#  define NAM_B_VER naml$l_long_ver_size
+#  define NAM_L_VER naml$l_long_ver
+
+#else /* def NAML$C_MAXRSS */   /* NAML is not available.  Use NAM. */
+
+#  define NAM_STRUCT NAM
+
+#  define FAB_OR_NAML( fab, nam) fab
+#  define FAB_OR_NAML_DNA fab$l_dna
+#  define FAB_OR_NAML_DNS fab$b_dns
+#  define FAB_OR_NAML_FNA fab$l_fna
+#  define FAB_OR_NAML_FNS fab$b_fns
+
+#  define CC_RMS_NAM cc$rms_nam
+#  define FAB_NAM fab$l_nam
+#  define NAM_DID nam$w_did
+#  define NAM_DVI nam$t_dvi
+#  define NAM_ESA nam$l_esa
+#  define NAM_ESL nam$b_esl
+#  define NAM_ESS nam$b_ess
+#  define NAM_FID nam$w_fid
+#  define NAM_FNB nam$l_fnb
+#  define NAM_RSA nam$l_rsa
+#  define NAM_RSL nam$b_rsl
+#  define NAM_RSS nam$b_rss
+#  define NAM_MAXRSS NAM$C_MAXRSS
+#  define NAM_NOP nam$b_nop
+#  define NAM_M_EXP_DEV NAM$M_EXP_DEV
+#  define NAM_M_SYNCHK NAM$M_SYNCHK
+#  define NAM_B_DEV nam$b_dev
+#  define NAM_L_DEV nam$l_dev
+#  define NAM_B_DIR nam$b_dir
+#  define NAM_L_DIR nam$l_dir
+#  define NAM_B_NAME nam$b_name
+#  define NAM_L_NAME nam$l_name
+#  define NAM_B_TYPE nam$b_type
+#  define NAM_L_TYPE nam$l_type
+#  define NAM_B_VER nam$b_ver
+#  define NAM_L_VER nam$l_ver
+
+#endif /* def NAML$C_MAXRSS */
+
+
+struct EB_header    /* Common header of extra block */
+{   ush tag;
+    ush size;
+    uch data[1];
+};
+
+#ifndef EB_HEADSIZE
+#  define EB_HEADSIZE 4
+#endif
+
+/*------ Old style Info-ZIP extra field definitions -----*/
+
+#if (!defined(VAXC) && !defined(_RMS_H) && !defined(__RMS_LOADED))
+
+struct XAB {                    /* This definition may be skipped */
+    unsigned char xab$b_cod;
+    unsigned char xab$b_bln;
+    short int xabdef$$_fill_1;
+    char *xab$l_nxt;
+};
+
+#endif /* !VAXC && !_RMS_H && !__RMS_LOADED */
+
+#ifndef EB_IZVMS_BCMASK
+#  define EB_IZVMS_BCMASK   07  /* 3 bits for compression type */
+#endif
+#ifndef EB_IZVMS_BCSTOR
+#  define EB_IZVMS_BCSTOR   0   /*  Stored */
+#endif
+#ifndef EB_IZVMS_BC00
+#  define EB_IZVMS_BC00     1   /*  0byte -> 0bit compression */
+#endif
+#ifndef EB_IZVMS_BCDEFL
+#  define EB_IZVMS_BCDEFL   2   /*  Deflated */
+#endif
+
+/*
+ *  Extra record format
+ *  ===================
+ *  signature       (2 bytes)   = 'I','M'
+ *  size            (2 bytes)
+ *  block signature (4 bytes)
+ *  flags           (2 bytes)
+ *  uncomprssed size(2 bytes)
+ *  reserved        (4 bytes)
+ *  data            ((size-12) bytes)
+ *  ....
+ */
+
+struct IZ_block                 /* Extra field block header structure */
+{
+    ush sig;
+    ush size;
+    ulg bid;
+    ush flags;
+    ush length;
+    ulg reserved;
+    uch body[1];                /* The actual size is unknown */
+};
+
+/*
+ *   Extra field signature and block signatures
+ */
+
+#define IZ_SIGNATURE "IM"
+#define FABSIG  "VFAB"
+#define XALLSIG "VALL"
+#define XFHCSIG "VFHC"
+#define XDATSIG "VDAT"
+#define XRDTSIG "VRDT"
+#define XPROSIG "VPRO"
+#define XKEYSIG "VKEY"
+#define XNAMSIG "VNAM"
+#define VERSIG  "VMSV"
+
+/*
+ *   Block sizes
+ */
+
+#define FABL    (cc$rms_fab.fab$b_bln)
+#define RABL    (cc$rms_rab.rab$b_bln)
+#define XALLL   (cc$rms_xaball.xab$b_bln)
+#define XDATL   (cc$rms_xabdat.xab$b_bln)
+#define XFHCL   (cc$rms_xabfhc.xab$b_bln)
+#define XKEYL   (cc$rms_xabkey.xab$b_bln)
+#define XPROL   (cc$rms_xabpro.xab$b_bln)
+#define XRDTL   (cc$rms_xabrdt.xab$b_bln)
+#define XSUML   (cc$rms_xabsum.xab$b_bln)
+#define EXTBSL  4               /* Block signature length */
+#define RESL    8               /* Reserved 8 bytes */
+#define EXTHL   (EB_HEADSIZE+EXTBSL+RESL)
+
+typedef unsigned char byte;
+
+struct iosb
+{
+    ush status;
+    ush count;
+    ulg spec;
+};
+
+/*------------ PKWARE extra block definitions ----------*/
+
+/* Structure of PKWARE extra header */
+
+#ifdef VMS_ZIP
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __nostandard
+#endif /* __DECC || __DECCXX */
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __member_alignment __save
+#pragma __nomember_alignment
+#endif /* __DECC || __DECCXX */
+
+#ifdef VMS_ORIGINAL_PK_LAYOUT
+/*  The original order of ATR fields in the PKZIP VMS-extra field leads
+ *  to unaligned fields in the PK_info structure representing the
+ *  extra field layout.  When compiled for Alpha AXP, this results in
+ *  some performance (and code size) penalty.  It is not allowed to
+ *  apply structure padding, since this is explicitely forbidden in
+ *  the specification (APPNOTE.TXT) for the PK VMS extra field.
+ */
+typedef struct
+{
+    ush tag_ra; ush len_ra;     byte ra[ATR$S_RECATTR];
+    ush tag_uc; ush len_uc;     byte uc[ATR$S_UCHAR];
+    ush tag_jr; ush len_jr;     byte jr[ATR$S_JOURNAL];
+    ush tag_cd; ush len_cd;     byte cd[ATR$S_CREDATE];
+    ush tag_rd; ush len_rd;     byte rd[ATR$S_REVDATE];
+    ush tag_ed; ush len_ed;     byte ed[ATR$S_EXPDATE];
+    ush tag_bd; ush len_bd;     byte bd[ATR$S_BAKDATE];
+    ush tag_rn; ush len_rn;     ush  rn;
+    ush tag_ui; ush len_ui;     byte ui[ATR$S_UIC];
+    ush tag_fp; ush len_fp;     byte fp[ATR$S_FPRO];
+    ush tag_rp; ush len_rp;     byte rp[ATR$S_RPRO];
+} PK_info_t;
+#else /* !VMS_ORIGINAL_PK_LAYOUT */
+/*  The Info-ZIP support for the PK VMS extra field uses a reordered
+ *  field layout to achieve ``natural alignment'' of the PK_info structure
+ *  members whenever possible.  This rearrangement does not violate the
+ *  PK's VMS extra field specification and should not break any ``well
+ *  behaving'' (PK)Unzip utility. (`Well behaving' means that (PK)Unzip
+ *  should use the field tag to identify the ATR$ field rather than
+ *  assuming a fixed order of ATR$ fields in the PK VMS extra field.)
+ */
+typedef struct
+{
+    ush tag_ra; ush len_ra;     byte ra[ATR$S_RECATTR];
+    ush tag_uc; ush len_uc;     byte uc[ATR$S_UCHAR];
+    ush tag_cd; ush len_cd;     byte cd[ATR$S_CREDATE];
+    ush tag_rd; ush len_rd;     byte rd[ATR$S_REVDATE];
+    ush tag_ed; ush len_ed;     byte ed[ATR$S_EXPDATE];
+    ush tag_bd; ush len_bd;     byte bd[ATR$S_BAKDATE];
+    ush tag_rn; ush len_rn;     ush  rn;
+    ush tag_ui; ush len_ui;     byte ui[ATR$S_UIC];
+    ush tag_fp; ush len_fp;     byte fp[ATR$S_FPRO];
+    ush tag_rp; ush len_rp;     byte rp[ATR$S_RPRO];
+    ush tag_jr; ush len_jr;     byte jr[ATR$S_JOURNAL];
+} PK_info_t;
+#endif /* ?VMS_ORIGINAL_PK_LAYOUT */
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __member_alignment __restore
+#endif /* __DECC || __DECCXX */
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __standard
+#endif /* __DECC || __DECCXX */
+
+#endif /* VMS_ZIP */
+
+/* PKWARE "VMS" tag */
+#define PK_SIGNATURE        0x000C
+
+/* Total number of attributes to be saved */
+#define VMS_ATTR_COUNT  11
+#define VMS_MAX_ATRCNT  20
+
+struct PK_field
+{
+    ush         tag;
+    ush         size;
+    byte        value[1];
+};
+
+#define PK_FLDHDR_SIZE  4
+
+struct PK_header
+{
+    ush tag;
+    ush size;
+    ulg crc32;
+    byte data[1];
+};
+
+#define PK_HEADER_SIZE  8
+
+char *vms_file_version( char *s);
+
+#endif /* !__vms_h */
diff --git a/vms/vms_im.c b/vms/vms_im.c
new file mode 100644 (file)
index 0000000..001088b
--- /dev/null
@@ -0,0 +1,926 @@
+/*
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  vms_im.c (zip) by Igor Mandrichenko    Version 2.2-2
+ *
+ *  Revision history:
+ *  ...
+ *  2.1-1       16-feb-1993     I.Mandrichenko
+ *      Get file size from XABFHC and check bytes rest in file before
+ *      reading.
+ *  2.1-2       2-mar-1993      I.Mandrichenko
+ *      Make code more standard
+ *  2.2         21-jun-1993     I.Mandrichenko
+ *      Free all allocated space, use more static storage.
+ *      Use memcompress() from bits.c (deflation) for block compression.
+ *      To revert to old compression method #define OLD_COMPRESS
+ *  2.2-2       28-sep-1995     C.Spieler
+ *      Reorganized code for easier maintance of the two incompatible
+ *      flavours (IM style and PK style) VMS attribute support.
+ *      Generic functions (common to both flavours) are now collected
+ *      in a `wrapper' source file that includes one of the VMS attribute
+ *      handlers.
+ *  3.0         23-Oct-2004     Steven Schweda
+ *      Changed to maintain compatibility with VMS_PK.C.  Note that
+ *      reading with sys$read() prevents getting any data past EOF,
+ *      regardless of appearances.  Moved the VMS_PK_EXTRA test into
+ *      here from VMS.C to allow more general automatic dependency
+ *      generation.
+ *              17-Feb-2005     Steven Schweda
+ *      Added support for ODS5 extended names.
+ */
+
+#ifdef VMS                      /* For VMS only ! */
+
+#ifndef VMS_PK_EXTRA
+
+#define OLD_COMPRESS            /*To use old compression method define it.*/
+
+#ifdef VMS_ZIP
+#undef VMS_ZIP                  /* do NOT include PK style Zip definitions */
+#endif
+
+#include "vms.h"
+
+#ifndef __LIB$ROUTINES_LOADED
+#include <lib$routines.h>
+#endif
+
+#ifndef UTIL
+
+#define RET_ERROR 1
+#define RET_SUCCESS 0
+#define RET_EOF 0
+
+#define Kbyte 1024
+
+typedef struct XAB *xabptr;
+
+/*
+ *   Block sizes
+ */
+
+#define EXTL0   ((FABL + EXTHL)+        \
+                (XFHCL + EXTHL)+        \
+                (XPROL + EXTHL)+        \
+                (XDATL + EXTHL)+        \
+                (XRDTL + EXTHL))
+
+#ifdef OLD_COMPRESS
+#define PAD     sizeof(uch)
+#else
+#define PAD     10*sizeof(ush)          /* Two extra bytes for compr. header */
+#endif
+
+#define PAD0    (5*PAD)                 /* Reserve space for the case when
+                                         *  compression fails */
+static int _compress(uch *from, uch *to, int size);
+#ifdef DEBUG
+static void dump_rms_block(uch *p);
+#endif /* DEBUG */
+
+/********************************
+ *   Function set_extra_field   *
+ ********************************/
+/*
+ |   2004-11-11 SMS.
+ |   Changed to use separate storage for ->extra and ->cextra.  Zip64
+ |   processing may move (reallocate) one and not the other.
+ */
+
+static uch *_compress_block(register struct IZ_block *to,
+                            uch *from, int size, char *sig);
+static int get_vms_version(char *verbuf, int len);
+
+int set_extra_field(z, z_utim)
+  struct zlist far *z;
+  iztimes *z_utim;
+/*
+ *      Get file VMS file attributes and store them into extent fields.
+ *      Store VMS version also.
+ *      On error leave z intact.
+ */
+{
+    int status;
+    uch *xtra;
+    uch *cxtra;
+    uch *scan;
+    extent extra_l;
+    static struct FAB fab;
+    static struct NAM_STRUCT nam;
+    static struct XABSUM xabsum;
+    static struct XABFHC xabfhc;
+    static struct XABDAT xabdat;
+    static struct XABPRO xabpro;
+    static struct XABRDT xabrdt;
+    xabptr x = (xabptr)NULL, xab_chain = (xabptr)NULL, last_xab = (xabptr)NULL;
+    int nk, na;
+    int i;
+    int rc=RET_ERROR;
+    char verbuf[80];
+    int verlen = 0;
+
+    if (!vms_native)
+    {
+#ifdef USE_EF_UT_TIME
+       /*
+        *  A `portable' zipfile entry is created. Create an "UT" extra block
+        *  containing UNIX style modification time stamp in UTC, which helps
+        *  maintaining the `real' "last modified" time when the archive is
+        *  transfered across time zone boundaries.
+        */
+#  ifdef IZ_CHECK_TZ
+        if (!zp_tz_is_valid)
+            return ZE_OK;       /* skip silently if no valid TZ info */
+#  endif
+        if ((xtra = (uch *) malloc( EB_HEADSIZE+ EB_UT_LEN( 1))) == NULL)
+            return ZE_MEM;
+
+        if ((cxtra = (uch *) malloc( EB_HEADSIZE+ EB_UT_LEN( 1))) == NULL)
+            return ZE_MEM;
+
+        /* Fill xtra[] with data. */
+        xtra[ 0] = 'U';
+        xtra[ 1] = 'T';
+        xtra[ 2] = EB_UT_LEN(1);        /* length of data part of e.f. */
+        xtra[ 3] = 0;
+        xtra[ 4] = EB_UT_FL_MTIME;
+        xtra[ 5] = (uch) (z_utim->mtime);
+        xtra[ 6] = (uch) (z_utim->mtime >> 8);
+        xtra[ 7] = (uch) (z_utim->mtime >> 16);
+        xtra[ 8] = (uch) (z_utim->mtime >> 24);
+
+        /* Copy xtra[] data into cxtra[]. */
+        memcpy( cxtra, xtra, (EB_HEADSIZE+ EB_UT_LEN( 1)));
+
+        /* Set sizes and pointers. */
+        z->cext = z->ext = (EB_HEADSIZE+ EB_UT_LEN( 1));
+        z->extra = (char *) xtra;
+        z->cextra = (char *) cxtra;
+
+#endif /* USE_EF_UT_TIME */
+
+        return RET_SUCCESS;
+    }
+
+    /*
+     *  Initialize RMS control blocks and link them
+     */
+
+    fab =    cc$rms_fab;
+    nam =    CC_RMS_NAM;
+    xabsum = cc$rms_xabsum;
+    xabdat = cc$rms_xabdat;
+    xabfhc = cc$rms_xabfhc;
+    xabpro = cc$rms_xabpro;
+    xabrdt = cc$rms_xabrdt;
+
+    fab.FAB_NAM = &nam;
+    fab.fab$l_xab = (char*)&xabsum;
+    /*
+     *  Open the file and read summary information.
+     */
+
+#ifdef NAML$C_MAXRSS
+
+    fab.fab$l_dna = (char *) -1;    /* Using NAML for default name. */
+    fab.fab$l_fna = (char *) -1;    /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = z->name;
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen( z->name);
+
+#ifdef NAML$M_OPEN_SPECIAL
+    /* 2007-02-28 SMS.
+     * If processing symlinks as symlinks ("-y"), then $OPEN the
+     * link, not the target file.
+     *
+     * (nam.naml$v_open_special gets us the symlink itself instead of
+     * its target.  fab.fab$v_bio is necessary to allow sys$open() to
+     * work.  Without it, you get status %x0001860c, "%RMS-F-ORG,
+     * invalid file organization value".)
+     */
+    if (linkput)
+    {
+        nam.naml$v_open_special = 1;
+        fab.fab$v_bio = 1;
+    }
+#endif /* def NAML$M_OPEN_SPECIAL */
+
+    status = sys$open(&fab);
+    if (ERR(status))
+    {
+#ifdef DEBUG
+        printf("set_extra_field: sys$open for file %s:\n  error status = %d\n",
+               z->name, status);
+#endif
+        goto err_exit;
+    }
+
+    nk = xabsum.xab$b_nok;
+    na = xabsum.xab$b_noa;
+#ifdef DEBUG
+    printf("%d keys, %d alls\n", nk, na);
+#endif
+
+    /*
+     *  Allocate XABKEY and XABALL blocks and link them
+     */
+
+    xabfhc.xab$l_nxt = (char*)&xabdat;
+    xabdat.xab$l_nxt = (char*)&xabpro;
+    xabpro.xab$l_nxt = (char*)&xabrdt;
+    xabrdt.xab$l_nxt = NULL;
+
+    xab_chain = (xabptr)(&xabfhc);
+    last_xab  = (xabptr)(&xabrdt);
+
+#define INIT(ptr,size,type,init)     \
+        if ( (ptr = (type *)malloc(size)) == NULL )     \
+        {                                               \
+              printf( "set_extra_field: Insufficient memory.\n" );   \
+                      goto err_exit;                    \
+        }                                               \
+        *(ptr) = (init);
+    /*
+     *  Allocate and initialize all needed XABKEYs and XABALLs
+     */
+    for (i = 0; i < nk; i++)
+    {
+        struct XABKEY *k;
+        INIT(k, XKEYL, struct XABKEY, cc$rms_xabkey);
+        k->xab$b_ref = i;
+        if (last_xab != NULL)
+            last_xab->xab$l_nxt = (char*)k;
+        last_xab = (xabptr)k;
+    }
+    for (i = 0; i < na; i++)
+    {
+        struct XABALL *a;
+        INIT(a, XALLL, struct XABALL, cc$rms_xaball);
+        a->xab$b_aid = i;
+        if (last_xab != NULL)
+            last_xab->xab$l_nxt = (char*)a;
+        last_xab = (xabptr)a;
+    }
+
+    fab.fab$l_xab = (char*)xab_chain;
+#ifdef DEBUG
+    printf("Dump of XAB chain before $DISPLAY:\n");
+    for (x = xab_chain; x != NULL; x = x->xab$l_nxt)
+        dump_rms_block((uch *)x);
+#endif
+    /*
+     *  Get information on the file structure etc.
+     */
+    status = sys$display(&fab, 0, 0);
+    if (ERR(status))
+    {
+#ifdef DEBUG
+        printf("set_extra_field: sys$display for file %s:\n  error status = %d\n",
+               z->name, status);
+#endif
+        goto err_exit;
+    }
+
+#ifdef DEBUG
+    printf("\nDump of XAB chain after $DISPLAY:\n");
+    for (x = xab_chain; x != NULL; x = x->xab$l_nxt)
+        dump_rms_block((uch *)x);
+#endif
+
+    fab.fab$l_xab = NULL;  /* Keep XABs */
+    status = sys$close(&fab);
+    if (ERR(status))
+    {
+#ifdef DEBUG
+        printf("set_extra_field: sys$close for file %s:\n  error status = %d\n",
+               z->name, status);
+#endif
+        goto err_exit;
+    }
+
+    extra_l = EXTL0 + nk * (XKEYL + EXTHL) + na * (XALLL + EXTHL);
+#ifndef OLD_COMPRESS
+    extra_l += PAD0 + (nk+na) * PAD;
+#endif
+
+    if ( (verlen = get_vms_version(verbuf, sizeof(verbuf))) > 0 )
+    {
+        extra_l += verlen + EXTHL;
+#ifndef OLD_COMPRESS
+        extra_l += PAD;
+#endif
+    }
+
+    if ((scan = xtra = (uch *) malloc( extra_l)) == (uch*)NULL)
+    {
+#ifdef DEBUG
+        printf(
+         "set_extra_field: Insufficient memory to allocate extra L buffer\n");
+#endif
+        goto err_exit;
+    }
+
+    if ((cxtra = (uch *) malloc( extra_l)) == (uch*)NULL)
+    {
+#ifdef DEBUG
+        printf(
+         "set_extra_field: Insufficient memory to allocate extra C buffer\n");
+#endif
+        goto err_exit;
+    }
+
+    if (verlen > 0)
+        scan = _compress_block((struct IZ_block *)scan, (uch *)verbuf,
+                               verlen, VERSIG);
+
+    /*
+     *  Zero all unusable fields to improve compression
+     */
+    fab.fab$b_fns = fab.fab$b_shr = fab.fab$b_dns = fab.fab$b_fac = 0;
+    fab.fab$w_ifi = 0;
+    fab.fab$l_stv = fab.fab$l_sts = fab.fab$l_ctx = 0;
+    fab.fab$l_dna = NULL;
+    fab.fab$l_fna = NULL;
+    fab.fab$l_nam = NULL;
+#ifdef NAML$C_MAXRSS
+    fab.fab$l_naml = NULL;
+#endif /* def NAML$C_MAXRSS */
+    fab.fab$l_xab = NULL;
+
+#ifdef DEBUG
+    dump_rms_block( (uch *)&fab );
+#endif
+    scan = _compress_block((struct IZ_block *)scan, (uch *)&fab, FABL, FABSIG);
+    for (x = xab_chain; x != NULL;)
+    {
+        int bln;
+        char *sig;
+        xabptr next;
+
+        next = (xabptr)(x->xab$l_nxt);
+        x->xab$l_nxt = 0;
+
+        switch (x->xab$b_cod)
+        {
+            case XAB$C_ALL:
+                bln = XALLL;
+                sig = XALLSIG;
+                break;
+            case XAB$C_KEY:
+                bln = XKEYL;
+                sig = XKEYSIG;
+                break;
+            case XAB$C_PRO:
+                bln = XPROL;
+                sig = XPROSIG;
+                break;
+            case XAB$C_FHC:
+                bln = XFHCL;
+                sig = XFHCSIG;
+                break;
+            case XAB$C_DAT:
+                bln = XDATL;
+                sig = XDATSIG;
+                break;
+            case XAB$C_RDT:
+                bln = XRDTL;
+                sig = XRDTSIG;
+                break;
+            default:
+                bln = 0;
+                sig = 0L;
+                break;
+        }
+        if (bln > 0)
+            scan = _compress_block((struct IZ_block *)scan, (uch *)x,
+                                   bln, sig);
+        x = next;
+    }
+
+    /* Copy xtra[] data into cxtra[]. */
+    memcpy( cxtra, xtra, (scan- xtra));
+
+    /* Set sizes and pointers. */
+    z->cext = z->ext = scan- xtra;
+    z->extra = (char*) xtra;
+    z->cextra = (char*) cxtra;
+
+    rc = RET_SUCCESS;
+
+err_exit:
+    /*
+     *  Give up all allocated blocks
+     */
+    for (x = (struct XAB *)xab_chain; x != NULL; )
+    {
+        struct XAB *next;
+        next = (xabptr)(x->xab$l_nxt);
+        if (x->xab$b_cod == XAB$C_ALL || x->xab$b_cod == XAB$C_KEY)
+            free(x);
+        x = next;
+    }
+    return rc;
+}
+
+static int get_vms_version(verbuf, len)
+char *verbuf;
+int len;
+{
+    int i = SYI$_VERSION;
+    int verlen = 0;
+    struct dsc$descriptor version;
+    char *m;
+
+    version.dsc$a_pointer = verbuf;
+    version.dsc$w_length  = len - 1;
+    version.dsc$b_dtype   = DSC$K_DTYPE_B;
+    version.dsc$b_class   = DSC$K_CLASS_S;
+
+    if (ERR(lib$getsyi(&i, 0, &version, &verlen, 0, 0)) || verlen == 0)
+        return 0;
+
+    /* Cut out trailing spaces "V5.4-3   " -> "V5.4-3" */
+    for (m = verbuf + verlen, i = verlen - 1; i > 0 && verbuf[i] == ' '; --i)
+        --m;
+    *m = 0;
+
+    /* Cut out release number "V5.4-3" -> "V5.4" */
+    if ((m = strrchr(verbuf, '-')) != NULL)
+        *m = 0;
+    return strlen(verbuf) + 1;  /* Transmit ending 0 too */
+}
+
+#define CTXSIG ((ulg)('CtXx'))
+
+typedef struct user_context
+{
+    ulg sig;
+    struct FAB *fab;
+    struct NAM_STRUCT *nam;
+    struct RAB *rab;
+    uzoff_t size;
+    uzoff_t rest;
+    int status;
+} Ctx, *Ctxptr;
+
+Ctx init_ctx =
+{
+        CTXSIG,
+        NULL,
+        NULL,
+        NULL,
+        0L,
+        0L,
+        0
+};
+
+#define CTXL    sizeof(Ctx)
+#define CHECK_RAB(_r) ( (_r) != NULL &&                         \
+                        (_r) -> rab$b_bid == RAB$C_BID &&       \
+                        (_r) -> rab$b_bln == RAB$C_BLN &&       \
+                        (_r) -> rab$l_ctx != 0         &&       \
+                        (_r) -> rab$l_fab != NULL )
+
+
+#define BLOCK_BYTES 512
+
+/**************************
+ *   Function vms_open    *
+ **************************/
+struct RAB *vms_open(name)
+    char *name;
+{
+    struct FAB *fab;
+    struct NAM_STRUCT *nam;
+    struct RAB *rab;
+    struct XABFHC *fhc;
+    Ctxptr ctx;
+
+    if ((fab = (struct FAB *) malloc(FABL)) == NULL)
+        return NULL;
+
+    if ((nam =
+     (struct NAM_STRUCT *) malloc( sizeof( struct NAM_STRUCT))) == NULL)
+    {
+        free(fab);
+        return NULL;
+    }
+
+    if ((rab = (struct RAB *) malloc(RABL)) == NULL)
+    {
+        free(fab);
+        free(nam);
+        return NULL;
+    }
+
+    if ((fhc = (struct XABFHC *) malloc(XFHCL)) == (struct XABFHC *)NULL)
+    {
+        free(fab);
+        free(nam);
+        free(rab);
+        return (struct RAB *)NULL;
+    }
+    if ((ctx = (Ctxptr) malloc(CTXL)) == (Ctxptr)NULL)
+    {
+        free(fab);
+        free(nam);
+        free(rab);
+        free(fhc);
+        return (struct RAB *)NULL;
+    }
+    *fab = cc$rms_fab;
+    *nam = CC_RMS_NAM;
+    *rab = cc$rms_rab;
+    *fhc = cc$rms_xabfhc;
+
+    fab->FAB_NAM = nam;
+
+#ifdef NAML$C_MAXRSS
+
+    fab->fab$l_dna = (char *) -1;   /* Using NAML for default name. */
+    fab->fab$l_fna = (char *) -1;   /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+    FAB_OR_NAML( fab, nam)->FAB_OR_NAML_FNA = name;
+    FAB_OR_NAML( fab, nam)->FAB_OR_NAML_FNS = strlen( name);
+
+    fab->fab$b_fac = FAB$M_GET | FAB$M_BIO;
+    fab->fab$l_xab = (char*)fhc;
+
+#ifdef NAML$M_OPEN_SPECIAL
+    /* 2007-02-28 SMS.
+     * If processing symlinks as symlinks ("-y"), then $OPEN the
+     * link, not the target file.  (Note that here the required
+     * fab->fab$v_bio flag was set above.)
+     */
+    if (linkput)
+    {
+        nam->naml$v_open_special = 1;
+    }
+#endif /* def NAML$M_OPEN_SPECIAL */
+
+    if (ERR(sys$open(fab)))
+    {
+        sys$close(fab);
+        free(fab);
+        free(nam);
+        free(rab);
+        free(fhc);
+        free(ctx);
+        return (struct RAB *)NULL;
+    }
+
+    rab->rab$l_fab = fab;
+    rab->rab$l_rop = RAB$M_BIO;
+
+    if (ERR(sys$connect(rab)))
+    {
+        sys$close(fab);
+        free(fab);
+        free(nam);
+        free(rab);
+        free(ctx);
+        return (struct RAB *)NULL;
+    }
+
+    *ctx = init_ctx;
+    ctx->fab = fab;
+    ctx->nam = nam;
+    ctx->rab = rab;
+
+    if (fhc->xab$l_ebk == 0)
+    {
+        /* Only known size is all allocated blocks.
+           (This occurs with a zero-length file, for example.)
+        */
+        ctx->size =
+        ctx->rest = ((uzoff_t) fhc->xab$l_hbk)* BLOCK_BYTES;
+    }
+    else
+    {
+        /* Store normal (used) size in ->size.
+           If only one -V, store normal (used) size in ->rest.
+           If -VV, store allocated-blocks size in ->rest.
+        */
+        ctx->size =
+         (((uzoff_t) fhc->xab$l_ebk)- 1)* BLOCK_BYTES+ fhc->xab$w_ffb;
+        if (vms_native < 2)
+            ctx->rest = ctx->size;
+        else
+            ctx->rest = ((uzoff_t) fhc->xab$l_hbk)* BLOCK_BYTES;
+    }
+
+    free(fhc);
+    fab->fab$l_xab = NULL;
+    rab->rab$l_ctx = (unsigned) ctx;
+    return rab;
+}
+
+/**************************
+ *   Function vms_close   *
+ **************************/
+int vms_close(rab)
+    struct RAB *rab;
+{
+    struct FAB *fab;
+    struct NAM_STRUCT *nam;
+    Ctxptr ctx;
+
+    if (!CHECK_RAB(rab))
+        return RET_ERROR;
+    fab = (ctx = (Ctxptr)(rab->rab$l_ctx))->fab;
+    nam = (ctx = (Ctxptr)(rab->rab$l_ctx))->nam;
+    sys$close(fab);
+
+    free(fab);
+    free(nam);
+    free(rab);
+    free(ctx);
+
+    return RET_SUCCESS;
+}
+
+/**************************
+ *   Function vms_rewind  *
+ **************************/
+int vms_rewind(rab)
+    struct RAB *rab;
+{
+    Ctxptr ctx;
+
+    int status;
+    if (!CHECK_RAB(rab))
+        return RET_ERROR;
+
+    ctx = (Ctxptr) (rab->rab$l_ctx);
+    if (ERR(status = sys$rewind(rab)))
+    {
+        ctx->status = status;
+        return RET_ERROR;
+    }
+
+    ctx->status = 0;
+    ctx->rest = ctx->size;
+
+    return RET_SUCCESS;
+}
+
+
+#define KByte (2* BLOCK_BYTES)
+#define MAX_READ_BYTES (32* KByte)
+
+/**************************
+ *   Function vms_read    *
+ **************************/
+size_t vms_read(rab, buf, size)
+struct RAB *rab;
+char *buf;
+size_t size;
+/*
+ *      size must be greater or equal to 512 !
+ */
+{
+    int status;
+    Ctxptr ctx;
+
+    ctx = (Ctxptr)rab->rab$l_ctx;
+
+    if (!CHECK_RAB(rab))
+        return 0;
+
+    if (ctx -> rest == 0)
+        return 0;               /* Eof */
+
+    /* If request is smaller than a whole block, fail.
+       This really should never happen.  (assert()?)
+    */
+    if (size < BLOCK_BYTES)
+        return 0;
+
+    /* 2004-09-27 SMS.
+       Code here now resembles low-level QIO code in VMS_PK.C, but I
+       doubt that sys$read() will actually get past the official EOF.
+    */
+
+    /* Adjust request size as appropriate. */
+    if (size > MAX_READ_BYTES)
+    {
+        /* Restrict request to MAX_READ_BYTES. */
+        size = MAX_READ_BYTES;
+    }
+    else
+    {
+        /* Round odd-ball request up to the next whole block.
+           This really should never happen.  (assert()?)
+        */
+        size = (size+ BLOCK_BYTES- 1)& ~(BLOCK_BYTES- 1);
+    }
+
+    /* Reduce "size" when next (last) read would overrun the EOF,
+       but never below one byte (so we'll always get a nice EOF).
+    */
+    if (size > ctx->rest)
+        size = ctx->rest;
+    if (size == 0)
+        size = 1;
+
+    rab->rab$l_ubf = buf;
+    rab->rab$w_usz = size;
+    status = sys$read(rab);
+
+    if (!ERR(status) && rab->rab$w_rsz > 0)
+    {
+        ctx -> status = 0;
+        ctx -> rest -= rab->rab$w_rsz;
+        return rab->rab$w_rsz;
+    }
+    else
+    {
+        ctx->status = (status==RMS$_EOF ? 0:status);
+        if (status == RMS$_EOF)
+                ctx -> rest = 0;
+        return 0;
+    }
+}
+
+/**************************
+ *   Function vms_error   *
+ **************************/
+int vms_error(rab)
+    struct RAB *rab;
+{
+    if (!CHECK_RAB(rab))
+        return RET_ERROR;
+    return ((Ctxptr) (rab->rab$l_ctx))->status;
+}
+
+
+#ifdef DEBUG
+static void dump_rms_block(p)
+    uch *p;
+{
+    uch bid, len;
+    int err;
+    char *type;
+    char buf[132];
+    int i;
+
+    err = 0;
+    bid = p[0];
+    len = p[1];
+    switch (bid)
+    {
+        case FAB$C_BID:
+            type = "FAB";
+            break;
+        case XAB$C_ALL:
+            type = "xabALL";
+            break;
+        case XAB$C_KEY:
+            type = "xabKEY";
+            break;
+        case XAB$C_DAT:
+            type = "xabDAT";
+            break;
+        case XAB$C_RDT:
+            type = "xabRDT";
+            break;
+        case XAB$C_FHC:
+            type = "xabFHC";
+            break;
+        case XAB$C_PRO:
+            type = "xabPRO";
+            break;
+        default:
+            type = "Unknown";
+            err = 1;
+            break;
+    }
+    printf("Block @%08X of type %s (%d).", p, type, bid);
+    if (err)
+    {
+        printf("\n");
+        return;
+    }
+    printf(" Size = %d\n", len);
+    printf(" Offset - Hex - Dec\n");
+    for (i = 0; i < len; i += 8)
+    {
+        int j;
+
+        printf("%3d - ", i);
+        for (j = 0; j < 8; j++)
+            if (i + j < len)
+                printf("%02X ", p[i + j]);
+            else
+                printf("   ");
+        printf(" - ");
+        for (j = 0; j < 8; j++)
+            if (i + j < len)
+                printf("%03d ", p[i + j]);
+            else
+                printf("    ");
+        printf("\n");
+    }
+}
+#endif /* DEBUG */
+
+#ifdef OLD_COMPRESS
+# define BC_METHOD      EB_IZVMS_BC00
+# define        COMP_BLK(to,tos,from,froms) _compress( from,to,froms )
+#else
+# define BC_METHOD      EB_IZVMS_BCDEFL
+# define        COMP_BLK(to,tos,from,froms) memcompress(to,tos,from,froms)
+#endif
+
+static uch *_compress_block(to,from,size,sig)
+register struct IZ_block *to;
+uch *from;
+int size;
+char *sig;
+{
+        ulg cl;
+        to -> sig =  *(ush*)IZ_SIGNATURE;
+        to -> bid =       *(ulg*)(sig);
+        to -> flags =           BC_METHOD;
+        to -> length =  size;
+#ifdef DEBUG
+        printf("\nmemcompr(%d,%d,%d,%d)\n",&(to->body[0]),size+PAD,from,size);
+#endif
+        cl = COMP_BLK( &(to->body[0]), size+PAD, from, size );
+#ifdef DEBUG
+        printf("Compressed to %d\n",cl);
+#endif
+        if (cl >= size)
+        {
+                memcpy(&(to->body[0]), from, size);
+                to->flags = EB_IZVMS_BCSTOR;
+                cl = size;
+#ifdef DEBUG
+                printf("Storing block...\n");
+#endif
+        }
+        return (uch*)(to) + (to->size = cl + EXTBSL + RESL) + EB_HEADSIZE;
+}
+
+#define NBITS 32
+
+static int _compress(from,to,size)
+uch *from,*to;
+int size;
+{
+    int off=0;
+    ulg bitbuf=0;
+    int bitcnt=0;
+    int i;
+
+#define _BIT(val,len)   {                       \
+        if (bitcnt + (len) > NBITS)             \
+            while(bitcnt >= 8)                  \
+            {                                   \
+                to[off++] = (uch)bitbuf;        \
+                bitbuf >>= 8;                   \
+                bitcnt -= 8;                    \
+            }                                   \
+        bitbuf |= ((ulg)(val))<<bitcnt;         \
+        bitcnt += len;                          \
+    }
+
+#define _FLUSH  {                               \
+            while(bitcnt>0)                     \
+            {                                   \
+                to[off++] = (uch)bitbuf;        \
+                bitbuf >>= 8;                   \
+                bitcnt -= 8;                    \
+            }                                   \
+        }
+
+    for (i=0; i<size; i++)
+    {
+        if (from[i])
+        {
+                _BIT(1,1);
+                _BIT(from[i],8);
+        }
+        else
+            _BIT(0,1);
+    }
+    _FLUSH;
+    return off;
+}
+
+#endif /* !UTIL */
+
+#endif /* ndef VMS_PK_EXTRA */
+
+#endif /* VMS */
diff --git a/vms/vms_msg_gen.c b/vms/vms_msg_gen.c
new file mode 100644 (file)
index 0000000..4599cb0
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * VMS Message Source File Generator.
+ *
+ * 2007-01-29 SMS.
+ *
+ * Generates a VMS error message source file from data in "ziperr.h".
+ *
+ * On a VMS system, the standard builders should do the work.  On a
+ * non-VMS system:
+ *
+ *    cc -I. vms/vms_msg_gen.c -o vms_msg_gen
+ *    ./vms_msg_gen > vms/zip_msg.msg
+ *    rm ./vms_msg_gen
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#define GLOBALS         /* Include data for ziperrors[] in ziperr.h. */
+#include "ziperr.h"
+
+main()
+{
+    int base_prev;
+    int code_vms;
+    int code_zip;
+    int i;
+
+    char *sev_str[ 8] = {
+     "/WARNING",
+     "/SUCCESS",
+     "/ERROR",
+     "/INFORMATIONAL",
+     "/FATAL",
+     "/??????",
+     "/???????",
+     "/????????"
+    };
+
+    char *text1[] = {
+"!    VMS Error Message Source File for Zip",
+"!",
+"! Because the facility code was formally assigned by HP, the .FACILITY",
+"! directive below specifies /SYSTEM.  Because the messages are, in",
+"! general, specific to Zip, this file is not compiled with /SHARED.",
+"! For example:",
+"!",
+"!    MESSAGE /OBJECT = [.dest]ZIP_MSG.OBJ /NOSYMBOLS [.VMS]ZIP_MSG.MSG",
+"!",
+"!    LINK /SHAREABLE = [.dest]ZIP_MSG.EXE [.dest]ZIP_MSG.OBJ",
+"!",
+"!-----------------------------------------------------------------------",
+"",
+".TITLE  Info-ZIP Zip Error Messages",
+".FACILITY IZ_ZIP, 1955 /SYSTEM",
+NULL                                            /* End-of-text marker. */
+};
+
+    /* Initialize the .BASE counter. */
+    base_prev = -2;
+
+    /* Put out the header text. */
+    for (i = 0; text1[ i] != NULL; i++)
+    {
+        printf( "%s\n", text1[ i]);
+    }
+    printf( ".IDENT '%s'\n", VMS_MSG_IDENT);
+    printf( "\n");
+
+    /* Put out the error messages. */
+    for (code_zip = 0; code_zip <= ZE_MAXERR; code_zip++)
+    {
+        if ((ziperrors[ code_zip].string != NULL) &&
+         (strlen(ziperrors[ code_zip].string) != 0))
+        {
+            code_vms = 2* code_zip;     /* 4-bit left-shift, not 3. */
+            if (code_vms != base_prev+ 1)
+            {
+                printf( ".BASE %d\n", code_vms);
+            }
+            printf( "%-7s %-13s <%s>\n",
+             ziperrors[ code_zip].name,
+             sev_str[ ziperrors[ code_zip].severity & 0x07],
+             ziperrors[ code_zip].string);
+            base_prev = code_vms;
+        }
+    }
+    /* Put out the .END directive. */
+    printf( "\n");
+    printf( ".END\n");
+}
diff --git a/vms/vms_pk.c b/vms/vms_pk.c
new file mode 100644 (file)
index 0000000..9aa203d
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *    vms_pk.c  by Igor Mandrichenko
+ *
+ *    version 2.0       20-Mar-1993
+ *                      Generates PKWARE version of VMS attributes
+ *                      extra field according to appnote 2.0.
+ *                      Uses low level QIO-ACP interface.
+ *    version 2.0-1     10-Apr-1993
+ *                      Save ACLs
+ *    version 2.1       24-Aug-1993
+ *                      By default produce 0x010C extra record ID instead of
+ *                      PKWARE's 0x000C. The format is mostly compatible with
+ *                      PKWARE.
+ *                      Incompatibility (?): zip produces multiple ACE
+ *                      fields.
+ *    version 2.1-1     Clean extra fields in vms_get_attributes().
+ *                      Fixed bug with EOF.
+ *    version 2.1-2     15-Sep-1995, Chr. Spieler
+ *                      Removed extra fields cleanup from vms_get_attributes().
+ *                      This is now done in zipup.c
+ *                      Modified (according to UnZip's vms.[ch]) the fib stuff
+ *                      for DEC C (AXP,VAX) support.
+ *    version 2.2       28-Sep-1995, Chr. Spieler
+ *                      Reorganized code for easier maintance of the two
+ *                      incompatible flavours (IM style and PK style) VMS
+ *                      attribute support.  Generic functions (common to
+ *                      both flavours) are now collected in a `wrapper'
+ *                      source file that includes one of the VMS attribute
+ *                      handlers.
+ *                      Made extra block header conforming to PKware's
+ *                      specification (extra block header has a length
+ *                      of four bytes, two bytes for a signature, and two
+ *                      bytes for the length of the block excluding this
+ *                      header.
+ *    version 2.2-1     19-Oct-1995, Chr. Spieler
+ *                      Fixed bug in CRC calculation.
+ *                      Use official PK VMS extra field id.
+ *    version 2.2-2     21-Nov-1997, Chr. Spieler
+ *                      Fixed bug in vms_get_attributes() for directory
+ *                      entries (access to uninitialized ioctx record).
+ *                      Removed unused second arg for vms_open().
+ *    version 2.2-3     04-Apr-1999, Chr. Spieler
+ *                      Changed calling interface of vms_get_attributes()
+ *                      to accept a void pointer as first argument.
+ *    version 2.2-4     26-Jan-2002, Chr. Spieler
+ *                      Modified vms_read() to handle files larger than 2GByte
+ *                      (up to size limit of "unsigned long", resp. 4GByte).
+ *    version 3.0       20-Oct-2004, Steven Schweda.
+ *                      Changed vms_read() to read all the allocated
+ *                      blocks in a file, for sure.  Changed the default
+ *                      chunk size from 16K to 32K.  Changed to use the
+ *                      new typedef for the ioctx structure.  Moved the
+ *                      VMS_PK_EXTRA test into here from VMS.C to allow
+ *                      more general automatic dependency generation.
+ *                      08-Feb-2005, SMS.
+ *                      Changed to accomodate ODS5 extended file names:
+ *                      NAM structure -> NAM[L], and so on.  (VMS.H.)
+ *                      Added some should-never-appear error messages in
+ *                      vms_open().
+ */
+
+#ifdef VMS                      /* For VMS only ! */
+
+#ifdef VMS_PK_EXTRA
+
+#include <ssdef.h>
+
+#ifndef VMS_ZIP
+#define VMS_ZIP
+#endif
+
+#include "crc32.h"
+#include "vms.h"
+#include "vmsdefs.h"
+
+#ifndef ERR
+#define ERR(x) (((x)&1)==0)
+#endif
+
+#ifndef NULL
+#define NULL (void*)(0L)
+#endif
+
+#ifndef UTIL
+
+static PK_info_t PK_def_info =
+{
+        ATR$C_RECATTR,  ATR$S_RECATTR,  {0},
+        ATR$C_UCHAR,    ATR$S_UCHAR,    {0},
+        ATR$C_CREDATE,  ATR$S_CREDATE,  {0},
+        ATR$C_REVDATE,  ATR$S_REVDATE,  {0},
+        ATR$C_EXPDATE,  ATR$S_EXPDATE,  {0},
+        ATR$C_BAKDATE,  ATR$S_BAKDATE,  {0},
+        ATR$C_ASCDATES, sizeof(ush),    0,
+        ATR$C_UIC,      ATR$S_UIC,      {0},
+        ATR$C_FPRO,     ATR$S_FPRO,     {0},
+        ATR$C_RPRO,     ATR$S_RPRO,     {0},
+        ATR$C_JOURNAL,  ATR$S_JOURNAL,  {0}
+};
+
+/* File description structure for Zip low level I/O */
+typedef struct
+{
+    struct iosb         iosb;
+    long                vbn;
+    uzoff_t             size;
+    uzoff_t             rest;
+    int                 status;
+    ush                 chan;
+    ush                 chan_pad;       /* alignment member */
+    long                acllen;
+    uch                 aclbuf[ATR$S_READACL];
+    PK_info_t           PKi;
+} ioctx_t;
+
+
+/* Forward declarations of public functions: */
+ioctx_t *vms_open(char *file);
+unsigned int  vms_read(register ioctx_t *ctx,
+                       register char *buf, register unsigned int size);
+int  vms_error(ioctx_t *ctx);
+int  vms_rewind(ioctx_t *ctx);
+int  vms_get_attributes(ioctx_t *ctx, struct zlist far *z,
+                        iztimes *z_utim);
+int  vms_close(ioctx_t *ctx);
+
+
+#define BLOCK_BYTES 512
+
+
+/*---------------*
+ |  vms_open()   |
+ *---------------*
+ |  This routine opens file for reading fetching its attributes.
+ |  Returns pointer to file description structure.
+ */
+
+ioctx_t *vms_open(file)
+char *file;
+{
+    static struct atrdef        Atr[VMS_MAX_ATRCNT+1];
+    static struct NAM_STRUCT    Nam;
+    static struct fibdef        Fib;
+    static struct dsc$descriptor FibDesc =
+        {sizeof(Fib),DSC$K_DTYPE_Z,DSC$K_CLASS_S,(char *)&Fib};
+    static struct dsc$descriptor_s DevDesc =
+        {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,&Nam.NAM_DVI[1]};
+    static char EName[NAM_MAXRSS];
+    static char RName[NAM_MAXRSS];
+
+    struct FAB Fab;
+    register ioctx_t *ctx;
+    register struct fatdef *fat;
+    int status;
+    int i;
+    ulg efblk;
+    ulg hiblk;
+
+    if ( (ctx=(ioctx_t *)malloc(sizeof(ioctx_t))) == NULL )
+        return NULL;
+    ctx -> PKi = PK_def_info;
+
+#define FILL_REQ(ix,id,b)   {       \
+    Atr[ix].atr$l_addr = GVTC &(b);      \
+    Atr[ix].atr$w_type = (id);      \
+    Atr[ix].atr$w_size = sizeof(b); \
+}
+
+    FILL_REQ(0, ATR$C_RECATTR,  ctx->PKi.ra);
+    FILL_REQ(1, ATR$C_UCHAR,    ctx->PKi.uc);
+    FILL_REQ(2, ATR$C_REVDATE,  ctx->PKi.rd);
+    FILL_REQ(3, ATR$C_EXPDATE,  ctx->PKi.ed);
+    FILL_REQ(4, ATR$C_CREDATE,  ctx->PKi.cd);
+    FILL_REQ(5, ATR$C_BAKDATE,  ctx->PKi.bd);
+    FILL_REQ(6, ATR$C_ASCDATES, ctx->PKi.rn);
+    FILL_REQ(7, ATR$C_JOURNAL,  ctx->PKi.jr);
+    FILL_REQ(8, ATR$C_RPRO,     ctx->PKi.rp);
+    FILL_REQ(9, ATR$C_FPRO,     ctx->PKi.fp);
+    FILL_REQ(10,ATR$C_UIC,      ctx->PKi.ui);
+    FILL_REQ(11,ATR$C_ACLLENGTH,ctx->acllen);
+    FILL_REQ(12,ATR$C_READACL,  ctx->aclbuf);
+
+    Atr[13].atr$w_type = 0;     /* End of ATR list */
+    Atr[13].atr$w_size = 0;
+    Atr[13].atr$l_addr = GVTC NULL;
+
+    /* Initialize RMS structures.  We need a NAM[L] to retrieve the FID. */
+    Fab = cc$rms_fab;
+    Nam = CC_RMS_NAM;
+    Fab.FAB_NAM = &Nam; /* FAB has an associated NAM[L]. */
+
+#ifdef NAML$C_MAXRSS
+
+    Fab.fab$l_dna =(char *) -1;         /* Using NAML for default name. */
+    Fab.fab$l_fna = (char *) -1;        /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+    FAB_OR_NAML( Fab, Nam).FAB_OR_NAML_FNA = file ;     /* File name. */
+    FAB_OR_NAML( Fab, Nam).FAB_OR_NAML_FNS = strlen(file);
+    Nam.NAM_ESA = EName; /* expanded filename */
+    Nam.NAM_ESS = sizeof(EName);
+    Nam.NAM_RSA = RName; /* resultant filename */
+    Nam.NAM_RSS = sizeof(RName);
+
+    /* Do $PARSE and $SEARCH here. */
+    status = sys$parse(&Fab);
+
+    if (!(status & 1))
+    {
+        fprintf( stderr,
+         " vms_open(): $parse sts = %%x%08x.\n", status);
+        return NULL;
+    }
+
+#ifdef NAML$M_OPEN_SPECIAL
+    /* 2007-02-28 SMS.
+     * If processing symlinks as symlinks ("-y"), then $SEARCH for the
+     * link, not the target file.
+     */
+    if (linkput)
+    {
+        Nam.naml$v_open_special = 1;
+    }
+#endif /* def NAML$M_OPEN_SPECIAL */
+
+    /* Search for the first file.  If none, signal error. */
+    status = sys$search(&Fab);
+
+    if (!(status & 1))
+    {
+        fprintf( stderr,
+         " vms_open(): $search sts = %%x%08x.\n", status);
+        return NULL;
+    }
+
+    /* Initialize Device name length.  Note that this points into the
+       NAM[L] to get the device name filled in by the $PARSE, $SEARCH
+       services.
+    */
+    DevDesc.dsc$w_length = Nam.NAM_DVI[0];
+
+    status = sys$assign(&DevDesc,&ctx->chan,0,0);
+
+    if (!(status & 1))
+    {
+        fprintf( stderr,
+         " vms_open(): $assign sts = %%x%08x.\n", status);
+        return NULL;
+    }
+
+    /* Move the FID (and not the DID) into the FIB.
+       2005=02-08 SMS.
+       Note that only the FID is needed, not the DID, and not the file
+       name.  Setting these other items causes failures on ODS5.
+    */
+    Fib.FIB$L_ACCTL = FIB$M_NOWRITE;
+
+    for (i = 0; i < 3; i++)
+    {
+        Fib.FIB$W_FID[ i] = Nam.NAM_FID[ i];
+        Fib.FIB$W_DID[ i] = 0;
+    }
+
+    /* Use the IO$_ACCESS function to return info about the file. */
+    status = sys$qiow( 0, ctx->chan,
+     (IO$_ACCESS| IO$M_ACCESS), &ctx->iosb, 0, 0,
+     &FibDesc, 0, 0, 0, Atr, 0);
+
+    if (ERR(status) || ERR(status = ctx->iosb.status))
+    {
+        vms_close(ctx);
+        fprintf( stderr,
+         " vms_open(): $qiow (access) sts = %%x%08x, iosb sts = %%x%08x.\n",
+         status, ctx->iosb.status);
+        return NULL;
+    }
+
+    fat = (struct fatdef *)&(ctx -> PKi.ra);
+
+#define SWAPW(x)        ( (((x)>>16)&0xFFFF) + ((x)<<16) )
+
+    efblk = SWAPW(fat->fat$l_efblk);
+    hiblk = SWAPW(fat->fat$l_hiblk);
+
+    if (efblk == 0)
+    {
+        /* Only known size is all allocated blocks.
+           (This occurs with a zero-length file, for example.)
+        */
+        ctx -> size =
+        ctx -> rest = ((uzoff_t) hiblk)* BLOCK_BYTES;
+    }
+    else
+    {
+        /* Store normal (used) size in ->size.
+           If only one -V, store normal (used) size in ->rest.
+           If multiple -V, store allocated-blocks size in ->rest.
+        */
+        ctx -> size =
+         (((uzoff_t) efblk)- 1)* BLOCK_BYTES+ fat -> fat$w_ffbyte;
+
+        if (vms_native < 2)
+            ctx -> rest = ctx -> size;
+        else
+            ctx -> rest = ((uzoff_t) hiblk)* BLOCK_BYTES;
+    }
+
+    ctx -> status = SS$_NORMAL;
+    ctx -> vbn = 1;
+    return ctx;
+}
+
+
+#define KByte (2* BLOCK_BYTES)
+#define MAX_READ_BYTES (32* KByte)
+
+/*----------------*
+ |   vms_read()   |
+ *----------------*
+ |   Reads file in (multi-)block-sized chunks into the buffer.
+ |   Stops on EOF. Returns number of bytes actually read.
+ |   Note: This function makes no sense (and will error) if the buffer
+ |   size ("size") is not a multiple of the disk block size (512).
+ */
+
+size_t vms_read( ctx, buf, size)
+ioctx_t *ctx;
+char *buf;
+size_t size;
+{
+    int act_cnt;
+    uzoff_t rest_rndup;
+    int status;
+    size_t bytes_read = 0;
+
+    /* If previous read hit EOF, fail early. */
+    if (ctx -> status == SS$_ENDOFFILE)
+        return 0;               /* EOF. */
+
+    /* If no more expected to be read, fail early. */
+    if (ctx -> rest == 0)
+        return 0;               /* Effective EOF. */
+
+    /* If request is smaller than a whole block, fail.
+       This really should never happen.  (assert()?)
+    */
+    if (size < BLOCK_BYTES)
+        return 0;
+
+    /* Note that on old VMS VAX versions (like V5.5-2), QIO[W] may fail
+       with status %x0000034c (= %SYSTEM-F-IVBUFLEN, invalid buffer
+       length) when size is not a multiple of 512.  Thus the requested
+       size is boosted as needed, but the IOSB byte count returned is
+       reduced when it exceeds the actual bytes remaining (->rest).
+    */
+
+    /* Adjust request size as appropriate. */
+    if (size > MAX_READ_BYTES)
+    {
+        /* Restrict request to MAX_READ_BYTES. */
+        size = MAX_READ_BYTES;
+    }
+    else
+    {
+        /* Round odd-ball request up to the next whole block.
+           This really should never happen.  (assert()?)
+        */
+        size = (size+ BLOCK_BYTES- 1)& ~(BLOCK_BYTES- 1);
+    }
+    rest_rndup = (ctx -> rest+ BLOCK_BYTES- 1)& ~(BLOCK_BYTES- 1);
+
+    /* Read (QIOW) until error or "size" bytes have been read. */
+    do
+    {
+        /* Reduce "size" when next (last) read would overrun the EOF,
+           but never below one block (so we'll always get a nice EOF).
+        */
+        if (size > rest_rndup)
+            size = rest_rndup;
+
+        status = sys$qiow( 0, ctx->chan, IO$_READVBLK,
+            &ctx->iosb, 0, 0,
+            buf, size, ctx->vbn, 0, 0, 0);
+
+        /* If initial status was good, use final status. */
+        if ( !ERR(status) )
+                status = ctx->iosb.status;
+
+        if ( !ERR(status) || status == SS$_ENDOFFILE )
+        {
+            act_cnt = ctx->iosb.count;
+            /* Ignore whole-block boost when remainder is smaller. */
+            if (act_cnt > ctx->rest)
+            {
+                act_cnt = ctx->rest;
+                status = SS$_ENDOFFILE;
+            }
+            /* Adjust counters/pointers according to delivered bytes. */
+            size -= act_cnt;
+            buf += act_cnt;
+            bytes_read += act_cnt;
+            ctx->vbn += ctx->iosb.count/ BLOCK_BYTES;
+        }
+
+    } while ( !ERR(status) && (size > 0) );
+
+    if (!ERR(status))
+    {
+        /* Record any successful status as SS$_NORMAL. */
+        ctx -> status = SS$_NORMAL;
+    }
+    else if (status == SS$_ENDOFFILE)
+    {
+        /* Record EOF as SS$_ENDOFFILE.  (Ignore error status codes?) */
+        ctx -> status = SS$_ENDOFFILE;
+    }
+
+    /* Decrement bytes-to-read.  Return the total bytes read. */
+    ctx -> rest -= bytes_read;
+
+    return bytes_read;
+}
+
+/*-----------------*
+ |   vms_error()   |
+ *-----------------*
+ |   Returns whether last operation on the file caused an error
+ */
+
+int vms_error(ctx)
+ioctx_t *ctx;
+{   /* EOF is not actual error */
+    return ERR(ctx->status) && (ctx->status != SS$_ENDOFFILE);
+}
+
+/*------------------*
+ |   vms_rewind()   |
+ *------------------*
+ |   Rewinds file to the beginning for the next vms_read().
+ */
+
+int vms_rewind(ctx)
+ioctx_t *ctx;
+{
+    ctx -> vbn = 1;
+    ctx -> rest = ctx -> size;
+    return 0;
+}
+
+/*--------------------------*
+ |   vms_get_attributes()   |
+ *--------------------------*
+ |   Malloc a PKWARE extra field and fill with file attributes. Returns
+ |   error number of the ZE_??? class.
+ |   If the passed ioctx record "FILE *" pointer is NULL, vms_open() is
+ |   called to fetch the file attributes.
+ |   When `vms_native' is not set, a generic "UT" type timestamp extra
+ |   field is generated instead.
+ |
+ |   2004-11-11 SMS.
+ |   Changed to use separate storage for ->extra and ->cextra.  Zip64
+ |   processing may move (reallocate) one and not the other.
+ */
+
+int vms_get_attributes(ctx, z, z_utim)
+ioctx_t *ctx;           /* Internal file control structure. */
+struct zlist far *z;    /* Zip entry to compress. */
+iztimes *z_utim;
+{
+    byte    *p;
+    byte    *xtra;
+    byte    *cxtra;
+    struct  PK_header    *h;
+    extent  l;
+    int     notopened;
+
+    if ( !vms_native )
+    {
+#ifdef USE_EF_UT_TIME
+        /*
+         *  A `portable' zipfile entry is created. Create an "UT" extra block
+         *  containing UNIX style modification time stamp in UTC, which helps
+         *  maintaining the `real' "last modified" time when the archive is
+         *  transfered across time zone boundaries.
+         */
+#  ifdef IZ_CHECK_TZ
+        if (!zp_tz_is_valid)
+            return ZE_OK;       /* skip silently if no valid TZ info */
+#  endif
+
+        if ((xtra = (uch *) malloc( EB_HEADSIZE+ EB_UT_LEN( 1))) == NULL)
+            return ZE_MEM;
+
+        if ((cxtra = (uch *) malloc( EB_HEADSIZE+ EB_UT_LEN( 1))) == NULL)
+            return ZE_MEM;
+
+        /* Fill xtra[] with data. */
+        xtra[ 0] = 'U';
+        xtra[ 1] = 'T';
+        xtra[ 2] = EB_UT_LEN(1);        /* length of data part of e.f. */
+        xtra[ 3] = 0;
+        xtra[ 4] = EB_UT_FL_MTIME;
+        xtra[ 5] = (byte) (z_utim->mtime);
+        xtra[ 6] = (byte) (z_utim->mtime >> 8);
+        xtra[ 7] = (byte) (z_utim->mtime >> 16);
+        xtra[ 8] = (byte) (z_utim->mtime >> 24);
+
+        /* Copy xtra[] data into cxtra[]. */
+        memcpy( cxtra, xtra, (EB_HEADSIZE+ EB_UT_LEN( 1)));
+
+        /* Set sizes and pointers. */
+        z->cext = z->ext = (EB_HEADSIZE+ EB_UT_LEN( 1));
+        z->extra = (char*) xtra;
+        z->cextra = (char*) cxtra;
+
+#endif /* USE_EF_UT_TIME */
+
+        return ZE_OK;
+    }
+
+    notopened = (ctx == NULL);
+    if ( notopened && ((ctx = vms_open(z->name)) == NULL) )
+        return ZE_OPEN;
+
+    l = PK_HEADER_SIZE + sizeof(ctx->PKi);
+    if (ctx->acllen > 0)
+        l += PK_FLDHDR_SIZE + ctx->acllen;
+
+    if ((xtra = (uch *) malloc( l)) == NULL)
+        return ZE_MEM;
+
+    if ((cxtra = (uch *) malloc( l)) == NULL)
+        return ZE_MEM;
+
+    /* Fill xtra[] with data. */
+
+    h = (struct PK_header *) xtra;
+    h->tag = PK_SIGNATURE;
+    h->size = l - EB_HEADSIZE;
+    p = (h->data);
+
+    /* Copy default set of attributes */
+    memcpy(h->data, (char*)&(ctx->PKi), sizeof(ctx->PKi));
+    p += sizeof(ctx->PKi);
+
+    if ( ctx->acllen > 0 )
+    {
+        struct PK_field *f;
+
+        if (dosify)
+            zipwarn("file has ACL, may be incompatible with PKUNZIP","");
+
+        f = (struct PK_field *)p;
+        f->tag = ATR$C_ADDACLENT;
+        f->size = ctx->acllen;
+        memcpy((char *)&(f->value[0]), ctx->aclbuf, ctx->acllen);
+        p += PK_FLDHDR_SIZE + ctx->acllen;
+    }
+
+
+    h->crc32 = CRCVAL_INITIAL;                  /* Init CRC register */
+    h->crc32 = crc32(h->crc32, (uch *)(h->data), l - PK_HEADER_SIZE);
+
+    /* Copy xtra[] data into cxtra[]. */
+    memcpy( cxtra, xtra, l);
+
+    /* Set sizes and pointers. */
+    z->ext = z->cext = l;
+    z->extra = (char *) xtra;
+    z->cextra = (char *) cxtra;
+
+    if (notopened)              /* close "ctx", if we have opened it here */
+        vms_close(ctx);
+
+    return ZE_OK;
+}
+
+
+int vms_close(ctx)
+ioctx_t *ctx;
+{
+        sys$dassgn(ctx->chan);
+        free(ctx);
+        return 0;
+}
+
+#endif /* !_UTIL */
+
+#endif /* def VMS_PK_EXTRA */
+
+#endif /* VMS */
diff --git a/vms/vmsdefs.h b/vms/vmsdefs.h
new file mode 100644 (file)
index 0000000..73d013a
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+  vmsdefs.h
+
+  Contents of three header files from Joe
+  Meadows' FILE program.  Used by vmsmunch
+
+        06-Apr-1994     Jamie Hanrahan  jeh@cmkrnl.com
+                        Moved "contents of three header files" from
+                        VMSmunch.h to VMSdefs.h .
+
+        16-Sep-1995     Christian Spieler
+                        Added #pragma (no)member_alignment directives
+                        to achieve compatibility with DEC C and Alpha AXP
+
+        05-Oct-1995     Christian Spieler
+                        Revised fatdef, fchdef, fjndef to achieve closer
+                        compatibility with DEC's system include header files
+                        supplied with C version 4.0 and newer.
+
+        10-Oct-1995     Christian Spieler
+                        Use lowercase filenames for vms specific sources
+                        (VMSmunch.? -> vmsmunch.?, VMSdefs.h -> vmsdefs.h)
+
+        15-Dec-1995     Christian Spieler
+                        Removed the last "tabs" from the source.
+
+        24-Jun-1997     Onno van der Linden / Chr. Spieler
+                        Modifications to support the VMS port of GNU C 2.x.
+
+        27-Jul-1999     Chr. Spieler
+                        Added Info-ZIP copyright note for identification.
+
+  ---------------------------------------------------------------------------*/
+
+#ifndef __vmsdefs_h
+#define __vmsdefs_h 1
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __nostandard
+#endif /* __DECC || __DECCXX */
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __member_alignment __save
+#pragma __nomember_alignment
+#endif /* __DECC || __DECCXX */
+
+#if !(defined(__VAXC) || defined(VAXC)) || defined(__GNUC__)
+#define __struct struct
+#define __union union
+#else
+#define __struct variant_struct
+#define __union variant_union
+#endif /* !(__VAXC || VAXC) || __GNUC__ */
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/*---------------------------------------------------------------------------
+    fatdef.h
+  ---------------------------------------------------------------------------*/
+
+/* This header file was created by Joe Meadows, and is not copyrighted
+   in any way. No guarantee is made as to the accuracy of the contents
+   of this header file. This header file was last modified on Sep. 22th,
+   1987. (Modified to include this statement) */
+
+#define FAT$K_LENGTH 32
+#define FAT$C_LENGTH 32
+#define FAT$S_FATDEF 32
+
+struct fatdef {
+  __union  {
+    unsigned char fat$b_rtype;          /* record type                      */
+    __struct  {
+      unsigned fat$v_rtype : 4;         /* record type subfield             */
+      unsigned fat$v_fileorg : 4;       /* file organization                */
+    } fat$r_rtype_bits;
+  } fat$r_rtype_overlay;
+# define FAT$S_RTYPE 4
+# define FAT$V_RTYPE 0
+#   define FAT$C_UNDEFINED 0
+#   define FAT$C_FIXED 1
+#   define FAT$C_VARIABLE 2
+#   define FAT$C_VFC 3
+#   define FAT$C_STREAM 4
+#   define FAT$C_STREAMLF 5
+#   define FAT$C_STREAMCR 6
+# define FAT$S_FILEORG 4
+# define FAT$V_FILEORG 4
+#   define FAT$C_SEQUENTIAL 0
+#   define FAT$C_RELATIVE 1
+#   define FAT$C_INDEXED 2
+#   define FAT$C_DIRECT 3
+  __union  {
+    unsigned char fat$b_rattrib;        /* record attributes                */
+    __struct  {
+      unsigned fat$v_fortrancc : 1;
+      unsigned fat$v_impliedcc : 1;
+      unsigned fat$v_printcc : 1;
+      unsigned fat$v_nospan : 1;
+      unsigned fat$v_msbrcw : 1;
+    } fat$r_rattrib_bits;
+  } fat$r_rattrib_overlay;
+#   define FAT$V_FORTRANCC 0
+#   define FAT$M_FORTRANCC 1
+#   define FAT$V_IMPLIEDCC 1
+#   define FAT$M_IMPLIEDCC 2
+#   define FAT$V_PRINTCC 2
+#   define FAT$M_PRINTCC 4
+#   define FAT$V_NOSPAN 3
+#   define FAT$M_NOSPAN 8
+#   define FAT$V_MSBRCW 4
+#   define FAT$M_MSBRCW 16
+  unsigned short int fat$w_rsize;       /* record size in bytes             */
+  __union
+  {
+    unsigned long int fat$l_hiblk;      /* highest allocated VBN            */
+    __struct
+    {
+      unsigned short int fat$w_hiblkh;  /* high order word                  */
+      unsigned short int fat$w_hiblkl;  /* low order word                   */
+    } fat$r_hiblk_fields;
+  } fat$r_hiblk_overlay;
+  __union
+  {
+    unsigned long int fat$l_efblk;      /* end of file VBN                  */
+    __struct
+    {
+      unsigned short int fat$w_efblkh;  /* high order word                  */
+      unsigned short int fat$w_efblkl;  /* low order word                   */
+    } fat$r_efblk_fields;
+  } fat$r_efblk_overlay;
+  unsigned short int fat$w_ffbyte;      /* first free byte in EFBLK         */
+  unsigned char fat$b_bktsize;          /* bucket size in blocks            */
+  unsigned char fat$b_vfcsize;          /* # of control bytes in VFC record */
+  unsigned short int fat$w_maxrec;      /* maximum record size in bytes     */
+  unsigned short int fat$w_defext;      /* default extend quantity          */
+  unsigned short int fat$w_gbc;         /* global buffer count              */
+  char fat$fill[8];
+  unsigned short int fat$w_versions;
+};
+
+#if !(defined(__VAXC) || defined(VAXC)) || defined(__GNUC__)
+#define fat$b_rtype fat$r_rtype_overlay.fat$b_rtype
+#define fat$v_rtype fat$r_rtype_overlay.fat$r_rtype_bits.fat$v_rtype
+#define fat$v_fileorg fat$r_rtype_overlay.fat$r_rtype_bits.fat$v_fileorg
+#define fat$b_rattrib fat$r_rattrib_overlay.fat$b_rattrib
+#define fat$v_fortrancc fat$r_rattrib_overlay.fat$r_rattrib_bits.fat$v_fortrancc
+#define fat$v_impliedcc fat$r_rattrib_overlay.fat$r_rattrib_bits.fat$v_impliedcc
+#define fat$v_printcc fat$r_rattrib_overlay.fat$r_rattrib_bits.fat$v_printcc
+#define fat$v_nospan fat$r_rattrib_overlay.fat$r_rattrib_bits.fat$v_nospan
+#define fat$v_msbrcw fat$r_rattrib_overlay.fat$r_rattrib_bits.fat$v_msbrcw
+#define fat$l_hiblk fat$r_hiblk_overlay.fat$l_hiblk
+#define fat$w_hiblkh fat$r_hiblk_overlay.fat$r_hiblk_fields.fat$w_hiblkh
+#define fat$w_hiblkl fat$r_hiblk_overlay.fat$r_hiblk_fields.fat$w_hiblkl
+#define fat$l_efblk fat$r_efblk_overlay.fat$l_efblk
+#define fat$w_efblkh fat$r_efblk_overlay.fat$r_efblk_fields.fat$w_efblkh
+#define fat$w_efblkl fat$r_efblk_overlay.fat$r_efblk_fields.fat$w_efblkl
+#endif /* !(__VAXC || VAXC) || __GNUC__ */
+
+#define __FATDEF_LOADED 1       /* prevent inclusion of DECC's fatdef.h */
+
+/*---------------------------------------------------------------------------
+    fchdef.h
+  ---------------------------------------------------------------------------*/
+
+/* This header file was created by Joe Meadows, and is not copyrighted
+   in any way. No guarantee is made as to the accuracy of the contents
+   of this header file. This header file was last modified on Sep. 22th,
+   1987. (Modified to include this statement) */
+
+#define FCH$V_BADACL 0x00B
+#define FCH$M_BADACL (1 << FCH$V_BADACL)
+#define FCH$V_BADBLOCK 0x00E
+#define FCH$M_BADBLOCK (1 << FCH$V_BADBLOCK)
+#define FCH$V_CONTIG 0x007
+#define FCH$M_CONTIG (1 << FCH$V_CONTIG)
+#define FCH$V_CONTIGB 0x005
+#define FCH$M_CONTIGB (1 << FCH$V_CONTIGB)
+#define FCH$V_DIRECTORY 0x00D
+#define FCH$M_DIRECTORY (1 << FCH$V_DIRECTORY)
+#define FCH$V_ERASE 0x011
+#define FCH$M_ERASE (1 << FCH$V_ERASE)
+#define FCH$V_LOCKED 0x006
+#define FCH$M_LOCKED (1 << FCH$V_LOCKED)
+#define FCH$V_MARKDEL 0x00F
+#define FCH$M_MARKDEL (1 << FCH$V_MARKDEL)
+#define FCH$V_NOBACKUP 0x001
+#define FCH$M_NOBACKUP (1 << FCH$V_NOBACKUP)
+#define FCH$V_NOCHARGE 0x010
+#define FCH$M_NOCHARGE (1 << FCH$V_NOCHARGE)
+#define FCH$V_READCHECK 0x003
+#define FCH$M_READCHECK (1 << FCH$V_READCHECK)
+#define FCH$V_SPOOL 0x00C
+#define FCH$M_SPOOL (1 << FCH$V_SPOOL)
+#define FCH$V_WRITCHECK 0x004
+#define FCH$M_WRITCHECK (1 << FCH$V_WRITCHECK)
+#define FCH$V_WRITEBACK 0x002
+#define FCH$M_WRITEBACK (1 << FCH$V_WRITEBACK)
+
+struct fchdef  {
+  __union  {
+    int fch$$_fill_1;
+    __struct  {
+      unsigned fch$$_fill_31 : 8;
+      unsigned fch$v_vcc_state : 3;    /* VCC state bits              */
+      unsigned fch$$_fill_32 : 7;
+      unsigned fch$$_alm_state : 2;
+      unsigned fch$v_associated : 1;   /* ISO 9660 Associated file    */
+      unsigned fch$v_existence : 1;    /* ISO 9660 Existence file     */
+      unsigned fch$v_fill_6 : 2;
+    } fch$r_fill_1_chunks;
+    __struct  {
+      unsigned fch$v_wascontig : 1;
+      unsigned fch$v_nobackup : 1 ;
+      unsigned fch$v_writeback : 1;
+      unsigned fch$v_readcheck : 1;
+      unsigned fch$v_writcheck : 1;
+      unsigned fch$v_contigb : 1;
+      unsigned fch$v_locked : 1;
+      unsigned fch$v_contig : 1;
+      unsigned fch$$_fill_3 : 3;
+      unsigned fch$v_badacl : 1;
+      unsigned fch$v_spool : 1;
+      unsigned fch$v_directory : 1;
+      unsigned fch$v_badblock : 1;
+      unsigned fch$v_markdel : 1;
+      unsigned fch$v_nocharge : 1;
+      unsigned fch$v_erase : 1;
+      unsigned fch$$_fill_4 : 1;
+      unsigned fch$v_shelved : 1;
+      unsigned fch$v_scratch : 1;
+      unsigned fch$v_nomove : 1;
+      unsigned fch$v_noshelvable : 1;
+    } fch$r_fill_1_bits;
+  } fch$r_fch_union;
+};
+
+#if !(defined(__VAXC) || defined(VAXC)) || defined(__GNUC__)
+#define fch$v_vcc_state fch$r_fch_union.fch$r_fill_1_chunks.fch$v_vcc_state
+#define fch$v_associated fch$r_fch_union.fch$r_fill_1_chunks.fch$v_associated
+#define fch$v_existence fch$r_fch_union.fch$r_fill_1_chunks.fch$v_existence
+#define fch$v_wascontig fch$r_fch_union.fch$r_fill_1_bits.fch$v_wascontig
+#define fch$v_nobackup fch$r_fch_union.fch$r_fill_1_bits.fch$v_nobackup
+#define fch$v_writeback fch$r_fch_union.fch$r_fill_1_bits.fch$v_writeback
+#define fch$v_readcheck fch$r_fch_union.fch$r_fill_1_bits.fch$v_readcheck
+#define fch$v_writcheck fch$r_fch_union.fch$r_fill_1_bits.fch$v_writcheck
+#define fch$v_contigb fch$r_fch_union.fch$r_fill_1_bits.fch$v_contigb
+#define fch$v_locked fch$r_fch_union.fch$r_fill_1_bits.fch$v_locked
+#define fch$v_contig fch$r_fch_union.fch$r_fill_1_bits.fch$v_contig
+#define fch$v_badacl fch$r_fch_union.fch$r_fill_1_bits.fch$v_badacl
+#define fch$v_spool fch$r_fch_union.fch$r_fill_1_bits.fch$v_spool
+#define fch$v_directory fch$r_fch_union.fch$r_fill_1_bits.fch$v_directory
+#define fch$v_badblock fch$r_fch_union.fch$r_fill_1_bits.fch$v_badblock
+#define fch$v_markdel fch$r_fch_union.fch$r_fill_1_bits.fch$v_markdel
+#define fch$v_nocharge fch$r_fch_union.fch$r_fill_1_bits.fch$v_nocharge
+#define fch$v_erase fch$r_fch_union.fch$r_fill_1_bits.fch$v_erase
+#define fch$v_shelved fch$r_fch_union.fch$r_fill_1_bits.fch$v_shelved
+#define fch$v_scratch fch$r_fch_union.fch$r_fill_1_bits.fch$v_scratch
+#define fch$v_nomove fch$r_fch_union.fch$r_fill_1_bits.fch$v_nomove
+#define fch$v_noshelvable fch$r_fch_union.fch$r_fill_1_bits.fch$v_noshelvable
+#endif /* !(__VAXC || VAXC) || __GNUC__ */
+
+#define __FCHDEF_LOADED 1       /* prevent inclusion of DECC's fchdef.h */
+
+/*---------------------------------------------------------------------------
+    fjndef.h
+  ---------------------------------------------------------------------------*/
+
+/* This header file was created by Joe Meadows, and is not copyrighted
+   in any way. No guarantee is made as to the accuracy of the contents
+   of this header file. This header file was last modified on Sep. 22th,
+   1987. (Modified to include this statement) */
+
+#define FJN$M_ONLY_RU 1
+#define FJN$M_RUJNL 2
+#define FJN$M_BIJNL 4
+#define FJN$M_AIJNL 8
+#define FJN$M_ATJNL 16
+#define FJN$M_NEVER_RU 32
+#define FJN$M_JOURNAL_FILE 64
+#define FJN$S_FJNDEF 1
+struct fjndef  {
+  unsigned fjn$v_only_ru : 1;
+  unsigned fjn$v_rujnl : 1;
+  unsigned fjn$v_bijnl : 1;
+  unsigned fjn$v_aijnl : 1;
+  unsigned fjn$v_atjnl : 1;
+  unsigned fjn$v_never_ru : 1;
+  unsigned fjn$v_journal_file : 1;
+  unsigned fjn$v_fill_7 : 1;
+} ;
+
+#define __FJNDEF_LOADED 1       /* prevent inclusion of DECC's fjndef.h */
+
+/*---------------------------------------------------------------------------*/
+
+#ifdef __cplusplus
+    }
+#endif
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __member_alignment __restore
+#endif /* __DECC || __DECCXX */
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __standard
+#endif /* __DECC || __DECCXX */
+
+#endif /* !__vmsdefs_h */
diff --git a/vms/vmsmunch.c b/vms/vmsmunch.c
new file mode 100644 (file)
index 0000000..8140036
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/* 2004-12-13 SMS.
+ * Disabled the module name macro to accommodate old GNU C which didn't
+ * obey the directive, and thus confused MMS/MMK where the object
+ * library dependencies need to have the correct module name.
+ */
+#if 0
+# define module_name     VMSMUNCH
+# define module_version  "V1.3-4"
+#endif /* 0 */
+
+/*
+ *  Modified by:
+ *
+ *    v1.3.1        O.v.d.Linden, C. Spieler            04-JUL-1998 14:35
+ *            Modified check that decides on the type of definitions for
+ *            FIB$W_FID etc. to support GNU C.
+ *
+ *    v1.3          Hunter Goatley                      14-SEP-1992 08:51
+ *            Added definitions of FIB$W_FID, FIB$W_DID, and
+ *            FIB$L_ACCTL to allow for the fact that fibdef
+ *            contains variant_unions under Alpha.
+ */
+/*---------------------------------------------------------------------------
+
+  vmsmunch.c                    version 1.2                     28 Apr 1992
+
+  This routine is a blatant and unrepentent appropriation of all the nasty
+  and difficult-to-do and complicated VMS shenanigans which Joe Meadows has
+  so magnificently captured in his FILE utility.  Not only that, it's even
+  allowed! (see below).  But let it be clear at the outset that Joe did all
+  the work; yea, verily, he is truly a godlike unit.
+
+  The appropriations and modifications herein were performed primarily by
+  him known as "Cave Newt," although the Info-ZIP working group probably had
+  their fingers in it somewhere along the line.  The idea is to put the raw
+  power of Joe's original routine at the disposal of various routines used
+  by UnZip (and Zip, possibly), not least among them the utime() function.
+  Read on for details...
+
+        01-SEP-1994     Richard Levitte <levitte@e.kth.se>
+                        If one of the fields given to VMSmunch are NULL,
+                        do not update the corresponding daytime.
+
+        18-JUL-1994     Hunter Goatley <goathunter@WKU.EDU>
+                        Fixed IO$_ACCESS call.
+
+        18-Jul-1994     Richard Levitte levitte@e.kth.se
+                        Changed VMSmunch() to deassign the channel before
+                        returning when an error has occured.
+
+        02-Apr-1994     Jamie Hanrahan  jeh@cmkrnl.com
+                        Moved definition of VMStimbuf struct from here
+                        to vmsmunch.h
+  ---------------------------------------------------------------------------
+
+  Usage (i.e., "interface," in geek-speak):
+
+     int VMSmunch( char *filename, int action, char *ptr );
+
+     filename   the name of the file on which to be operated, obviously
+     action     an integer which specifies what action to take
+     ptr        pointer to any extra item which may be needed (else NULL)
+
+  The possible values for the action argument are as follows:
+
+     GET_TIMES      get the creation and revision dates of filename; ptr
+                    must point to an empty VMStimbuf struct, as defined
+                    in vmsmunch.h
+                    (with room for at least 24 characters, including term.)
+     SET_TIMES      set the creation and revision dates of filename (utime
+                    option); ptr must point to a valid VMStimbuf struct,
+                    as defined in vmsmunch.h
+     GET_RTYPE      get the record type of filename; ptr must point to an
+                    integer which, on return, is set to the type (as defined
+                    in vmsdefs.h:  FAT$C_* defines)
+     CHANGE_RTYPE   change the record type to that specified by the integer
+                    to which ptr points; save the old record type (later
+                    saves overwrite earlier ones)
+     RESTORE_RTYPE  restore the record type to the previously saved value;
+                    or, if none, set it to "fixed-length, 512-byte" record
+                    format (ptr not used)
+
+  ---------------------------------------------------------------------------
+
+  Comments from FILE.C, a utility to modify file characteristics:
+
+     Written by Joe Meadows Jr, at the Fred Hutchinson Cancer Research Center
+     BITNET: JOE@FHCRCVAX
+     PHONE: (206) 467-4970
+
+     There are no restrictions on this code, you may sell it, include it
+     with any commercial package, or feed it to a whale.. However, I would
+     appreciate it if you kept this comment in the source code so that anyone
+     receiving this code knows who to contact in case of problems. Note that
+     I do not demand this condition..
+
+  ---------------------------------------------------------------------------*/
+
+
+/* 2004-12-13 SMS.
+ * Disabled the module name macro to accommodate old GNU C which didn't
+ * obey the directive, and thus confused MMS/MMK where the object
+ * library dependencies need to have the correct module name.
+ */
+#if 0
+# if defined(__DECC) || defined(__GNUC__)
+#  pragma module module_name module_version
+# else
+#  module module_name module_version
+# endif
+#endif /* 0 */
+
+/*****************************/
+/*  Includes, Defines, etc.  */
+/*****************************/
+
+/* Accomodation for /NAMES = AS_IS with old header files. */
+
+#define sys$asctim SYS$ASCTIM
+#define sys$assign SYS$ASSIGN
+#define sys$bintim SYS$BINTIM
+#define sys$dassgn SYS$DASSGN
+#define sys$parse SYS$PARSE
+#define sys$qiow SYS$QIOW
+#define sys$search SYS$SEARCH
+
+#include "zip.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <iodef.h>
+#include <starlet.h>
+#include <fibdef.h>   /* this gets created with the c3.0 compiler */
+
+/*
+ *  Under Alpha (DEC C in VAXC mode) and under `good old' VAXC, the FIB unions
+ *  are declared as variant_unions.  DEC C (Alpha) in ANSI modes and third
+ *  party compilers which do not support `variant_union' define preprocessor
+ *  symbols to `hide' the "intermediate union/struct" names from the
+ *  programmer's API.
+ *  We check the presence of these defines and for DEC's FIBDEF.H defining
+ *  __union as variant_union to make sure we access the structure correctly.
+ */
+#if defined(fib$w_did) || (defined(__union) && (__union == variant_union))
+#  define FIB$W_DID     fib$w_did
+#  define FIB$W_FID     fib$w_fid
+#  define FIB$L_ACCTL   fib$l_acctl
+#else
+#  define FIB$W_DID     fib$r_did_overlay.fib$w_did
+#  define FIB$W_FID     fib$r_fid_overlay.fib$w_fid
+#  define FIB$L_ACCTL   fib$r_acctl_overlay.fib$l_acctl
+#endif
+
+#include "vms.h"
+#include "vmsmunch.h"  /* GET/SET_TIMES, RTYPE, etc. */
+#include "vmsdefs.h"   /* fatdef.h, etc. */
+
+static void asctim(char *time, long int binval[2]);
+static void bintim(char *time, long int binval[2]);
+
+/* from <ssdef.h> */
+#ifndef SS$_NORMAL
+#  define SS$_NORMAL    1
+#  define SS$_BADPARAM  20
+#endif
+
+
+/* On VAX, define Goofy VAX Type-Cast to obviate /standard = vaxc.
+   Otherwise, lame system headers on VAX cause compiler warnings.
+   (GNU C may define vax but not __VAX.)
+*/
+#ifdef vax
+# define __VAX 1
+#endif /* def vax */
+
+#ifdef __VAX
+# define GVTC (unsigned int)
+#else /* def __VAX */
+# define GVTC
+#endif /* def __VAX */
+
+
+/*************************/
+/*  Function VMSmunch()  */
+/*************************/
+
+int VMSmunch(
+    char  *filename,
+    int   action,
+    char  *ptr )
+{
+
+    /* original file.c variables */
+
+    static struct FAB Fab;
+    static struct NAM_STRUCT Nam;
+    static struct fibdef Fib; /* short fib */
+
+    static struct dsc$descriptor FibDesc =
+      {sizeof(Fib),DSC$K_DTYPE_Z,DSC$K_CLASS_S,(char *)&Fib};
+    static struct dsc$descriptor_s DevDesc =
+      {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,&Nam.NAM_DVI[1]};
+    static struct fatdef Fat;
+    static union {
+      struct fchdef fch;
+      long int dummy;
+    } uchar;
+    static struct fjndef jnl;
+    static long int Cdate[2],Rdate[2],Edate[2],Bdate[2];
+    static short int revisions;
+    static unsigned long uic;
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __member_alignment __save
+#pragma __nomember_alignment
+#endif /* __DECC || __DECCXX */
+    static union {
+      unsigned short int value;
+      struct {
+        unsigned system : 4;
+        unsigned owner : 4;
+        unsigned group : 4;
+        unsigned world : 4;
+      } bits;
+    } prot;
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __member_alignment __restore
+#endif /* __DECC || __DECCXX */
+
+    static struct atrdef Atr[] = {
+      {sizeof(Fat),ATR$C_RECATTR, GVTC &Fat},          /* record attributes */
+      {sizeof(uchar),ATR$C_UCHAR, GVTC &uchar},    /* File characteristics */
+      {sizeof(Cdate),ATR$C_CREDATE, GVTC &Cdate[0]},   /* Creation date */
+      {sizeof(Rdate),ATR$C_REVDATE, GVTC &Rdate[0]},   /* Revision date */
+      {sizeof(Edate),ATR$C_EXPDATE, GVTC &Edate[0]},   /* Expiration date */
+      {sizeof(Bdate),ATR$C_BAKDATE, GVTC &Bdate[0]},   /* Backup date */
+      {sizeof(revisions),ATR$C_ASCDATES, GVTC &revisions}, /* number of revs */
+      {sizeof(prot),ATR$C_FPRO, GVTC &prot},           /* file protection  */
+      {sizeof(uic),ATR$C_UIC, GVTC &uic},              /* file owner */
+      {sizeof(jnl),ATR$C_JOURNAL, GVTC &jnl},          /* journal flags */
+      {0,0,0}
+    } ;
+
+    static char EName[NAM_MAXRSS];
+    static char RName[NAM_MAXRSS];
+    static struct dsc$descriptor_s FileName =
+      {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
+    static struct dsc$descriptor_s string = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
+    static short int DevChan;
+    static short int iosb[4];
+
+    static long int i,status;
+/*  static char *retval;  */
+
+
+    /* new VMSmunch variables */
+
+    static int  old_rtype=FAT$C_FIXED;   /* storage for record type */
+
+
+
+/*---------------------------------------------------------------------------
+    Initialize attribute blocks, parse filename, resolve any wildcards, and
+    get the file info.
+  ---------------------------------------------------------------------------*/
+
+    /* Initialize RMS structures.  We need a NAM[L] to retrieve the FID. */
+    Fab = cc$rms_fab;
+    Fab.fab$l_fna = filename;
+    Fab.fab$b_fns = strlen(filename);
+    Fab.FAB_NAM = &Nam; /* FAB has an associated NAM[L]. */
+    Nam = CC_RMS_NAM;
+    Nam.NAM_ESA = EName; /* expanded filename */
+    Nam.NAM_ESS = sizeof(EName);
+    Nam.NAM_RSA = RName; /* resultant filename */
+    Nam.NAM_RSS = sizeof(RName);
+
+    /* do $PARSE and $SEARCH here */
+    status = sys$parse(&Fab);
+    if (!(status & 1)) return(status);
+
+    /* search for the first file.. If none signal error */
+    status = sys$search(&Fab);
+    if (!(status & 1)) return(status);
+
+    while (status & 1) {
+        /* initialize Device name length, note that this points into the NAM[L]
+           to get the device name filled in by the $PARSE, $SEARCH services */
+        DevDesc.dsc$w_length = Nam.NAM_DVI[0];
+
+        status = sys$assign(&DevDesc,&DevChan,0,0);
+        if (!(status & 1)) return(status);
+
+        FileName.dsc$a_pointer = Nam.NAM_L_NAME;
+        FileName.dsc$w_length = Nam.NAM_B_NAME+Nam.NAM_B_TYPE+Nam.NAM_B_VER;
+
+        /* Initialize the FIB */
+        for (i=0;i<3;i++) {
+            Fib.FIB$W_FID[i]=Nam.NAM_FID[i];
+            Fib.FIB$W_DID[i]=Nam.NAM_DID[i];
+        }
+
+        /* Use the IO$_ACCESS function to return info about the file */
+        /* Note, used this way, the file is not opened, and the expiration */
+        /* and revision dates are not modified */
+        status = sys$qiow(0,DevChan,IO$_ACCESS,&iosb,0,0,
+                          &FibDesc,&FileName,0,0,&Atr,0);
+        if (!(status & 1) || !((status = iosb[0]) & 1)) {
+            sys$dassgn(DevChan);
+            return(status);
+        }
+
+    /*-----------------------------------------------------------------------
+        We have the current information from the file:  now see what user
+        wants done with it.
+      -----------------------------------------------------------------------*/
+
+        switch (action) {
+
+          case GET_TIMES:   /* non-modifying */
+              asctim(((struct VMStimbuf *)ptr)->modtime, Cdate);
+              asctim(((struct VMStimbuf *)ptr)->actime, Rdate);
+              sys$dassgn(DevChan);
+              return RMS$_NORMAL;     /* return to user */
+              break;
+
+          case SET_TIMES:
+              if (((struct VMStimbuf *)ptr)->modtime != (char *)NULL)
+                  bintim(((struct VMStimbuf *)ptr)->modtime, Cdate);
+              if (((struct VMStimbuf *)ptr)->actime != (char *)NULL)
+                  bintim(((struct VMStimbuf *)ptr)->actime, Rdate);
+              break;
+
+          case GET_RTYPE:   /* non-modifying */
+              *(int *)ptr = Fat.fat$v_rtype;
+              sys$dassgn(DevChan);
+              return RMS$_NORMAL;     /* return to user */
+              break;
+
+          case CHANGE_RTYPE:
+              old_rtype = Fat.fat$v_rtype;              /* save current one */
+              if ((*(int *)ptr < FAT$C_UNDEFINED) ||
+                  (*(int *)ptr > FAT$C_STREAMCR))
+                  Fat.fat$v_rtype = FAT$C_STREAMLF;       /* Unix I/O happy */
+              else
+                  Fat.fat$v_rtype = *(int *)ptr;
+              break;
+
+          case RESTORE_RTYPE:
+              Fat.fat$v_rtype = old_rtype;
+              break;
+
+          default:
+              sys$dassgn(DevChan);
+              return SS$_BADPARAM;   /* anything better? */
+        }
+
+    /*-----------------------------------------------------------------------
+        Go back and write modified data to the file header.
+      -----------------------------------------------------------------------*/
+
+        /* note, part of the FIB was cleared by earlier QIOW, so reset it */
+        Fib.FIB$L_ACCTL = FIB$M_NORECORD;
+        for (i=0;i<3;i++) {
+            Fib.FIB$W_FID[i]=Nam.NAM_FID[i];
+            Fib.FIB$W_DID[i]=Nam.NAM_DID[i];
+        }
+
+        /* Use the IO$_MODIFY function to change info about the file */
+        /* Note, used this way, the file is not opened, however this would */
+        /* normally cause the expiration and revision dates to be modified. */
+        /* Using FIB$M_NORECORD prohibits this from happening. */
+        status = sys$qiow(0,DevChan,IO$_MODIFY,&iosb,0,0,
+                          &FibDesc,&FileName,0,0,&Atr,0);
+        if (!(status & 1) || !((status = iosb[0]) & 1)) {
+            sys$dassgn(DevChan);
+            return(status);
+        }
+
+        status = sys$dassgn(DevChan);
+        if (!(status & 1)) return(status);
+
+        /* look for next file, if none, no big deal.. */
+        status = sys$search(&Fab);
+    }
+    return(status);
+} /* end function VMSmunch() */
+
+
+
+
+
+/***********************/
+/*  Function asctim()  */
+/***********************/
+
+static void asctim(        /* convert 64-bit binval to string, put in time */
+    char *time,
+    long int binval[2] )
+{
+    static struct dsc$descriptor date_str={23,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
+      /* dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer */
+
+    date_str.dsc$a_pointer = time;
+    sys$asctim(0, &date_str, binval, 0);
+    time[23] = '\0';
+}
+
+
+
+
+
+/***********************/
+/*  Function bintim()  */
+/***********************/
+
+static void bintim(        /* convert time string to 64 bits, put in binval */
+    char *time,
+    long int binval[2] )
+{
+    static struct dsc$descriptor date_str={0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
+
+    date_str.dsc$w_length = strlen(time);
+    date_str.dsc$a_pointer = time;
+    sys$bintim(&date_str, binval);
+}
diff --git a/vms/vmsmunch.h b/vms/vmsmunch.h
new file mode 100644 (file)
index 0000000..458ad78
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+  vmsmunch.h
+
+  A few handy #defines, plus the contents of three header files from Joe
+  Meadows' FILE program.  Used by VMSmunch and by various routines which
+  call VMSmunch (e.g., in Zip and UnZip).
+
+        02-Apr-1994     Jamie Hanrahan  jeh@cmkrnl.com
+                        Moved definition of VMStimbuf struct from vmsmunch.c
+                        to here.
+
+        06-Apr-1994     Jamie Hanrahan  jeh@cmkrnl.com
+                        Moved "contents of three header files" (not needed by
+                        callers of vmsmunch) to VMSdefs.h .
+
+        07-Apr-1994     Richard Levitte levitte@e.kth.se
+                        Inserted a forward declaration of VMSmunch.
+
+        17-Sep-1995     Chr. Spieler    spieler@linac.ikp.physik.th-darmstadt.de
+                        Added wrapper to prevent multiple loading of this file.
+
+        10-Oct-1995     Chr. Spieler    spieler@linac.ikp.physik.th-darmstadt.de
+                        Use lowercase names for all VMS specific source files
+
+        15-Dec-1995     Chr. Spieler    spieler@linac.ikp.physik.th-darmstadt.de
+                        Removed ALL "tabs" from source file.
+
+  ---------------------------------------------------------------------------*/
+
+#ifndef __vmsmunch_h
+#define __vmsmunch_h 1
+
+#define GET_TIMES       4
+#define SET_TIMES       0
+#define GET_RTYPE       1
+#define CHANGE_RTYPE    2
+#define RESTORE_RTYPE   3
+
+struct VMStimbuf {      /* VMSmunch */
+    char *actime;       /* VMS revision date, ASCII format */
+    char *modtime;      /* VMS creation date, ASCII format */
+};
+
+extern int VMSmunch(char *filename, int action, char *ptr);
+
+#endif /* !__vmsmunch_h */
diff --git a/vms/vmszip.c b/vms/vmszip.c
new file mode 100644 (file)
index 0000000..2dae718
--- /dev/null
@@ -0,0 +1,1444 @@
+/*
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/* 2005-02-14 SMS.
+   Added some ODS5 support.
+      Use longer name structures in NAML, where available.
+      Locate special characters mindful of "^" escapes.
+      Replaced compile-time case preservation (VMS_PRESERVE_CASE macro)
+      with command-line-specified case preservation (vms_case_x
+      variables).
+   Prototyped all functions.
+   Removed "#ifndef UTIL", as no one should be compiling it that way.
+*/
+
+#include "zip.h"
+#include "vmsmunch.h"
+#include "vms.h"
+
+#include <ctype.h>
+#include <time.h>
+#include <unixlib.h>
+
+/* Judge availability of str[n]casecmp() in C RTL.
+   (Note: This must follow a "#include <decc$types.h>" in something to
+   ensure that __CRTL_VER is as defined as it will ever be.  DEC C on
+   VAX may not define it itself.)
+*/
+#ifdef __CRTL_VER
+#if __CRTL_VER >= 70000000
+#define HAVE_STRCASECMP
+#endif /* __CRTL_VER >= 70000000 */
+#endif /* def __CRTL_VER */
+
+#ifdef HAVE_STRCASECMP
+#include <strings.h>    /* str[n]casecmp() */
+#endif /* def HAVE_STRCASECMP */
+
+#include <dvidef.h>
+#include <lib$routines.h>
+#include <ssdef.h>
+#include <stsdef.h>
+#include <starlet.h>
+
+/* Directory file type with version, and its strlen(). */
+#define DIR_TYPE_VER ".DIR;1"
+#define DIR_TYPE_VER_LEN (sizeof( DIR_TYPE_VER)- 1)
+
+/* Extra malloc() space in names for cutpath().  (May have to change
+   ".FOO]" to "]FOO.DIR;1".)
+*/
+#define DIR_PAD (DIR_TYPE_VER_LEN- 1)
+
+/* Hex digit table. */
+
+char hex_digit[ 16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+/* Character property table for (re-)escaping ODS5 extended file names.
+   Note that this table ignore Unicode, and does not identify invalid
+   characters.
+
+   ODS2 valid characters: 0-9 A-Z a-z $ - _
+
+   ODS5 Invalid characters:
+      C0 control codes (0x00 to 0x1F inclusive)
+      Asterisk (*)
+      Question mark (?)
+
+   ODS5 Invalid characters only in VMS V7.2 (which no one runs, right?):
+      Double quotation marks (")
+      Backslash (\)
+      Colon (:)
+      Left angle bracket (<)
+      Right angle bracket (>)
+      Slash (/)
+      Vertical bar (|)
+
+   Characters escaped by "^":
+      SP  !  #  %  &  '  (  )  +  ,  .  ;  =  @  [  ]  ^  `  {  }  ~
+
+   Either "^_" or "^ " is accepted as a space.  Period (.) is a special
+   case.  Note that un-escaped < and > can also confuse a directory
+   spec.
+
+   Characters put out as ^xx:
+      7F (DEL)
+      80-9F (C1 control characters)
+      A0 (nonbreaking space)
+      FF (Latin small letter y diaeresis)
+
+   Other cases:
+      Unicode: "^Uxxxx", where "xxxx" is four hex digits.
+
+    Property table values:
+      Normal escape:    1
+      Space:            2
+      Dot:              4
+      Hex-hex escape:   8
+      -------------------
+      Hex digit:       64
+*/
+
+unsigned char char_prop[ 256] = {
+
+/* NUL SOH STX ETX EOT ENQ ACK BEL   BS  HT  LF  VT  FF  CR  SO  SI */
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+
+/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB  CAN  EM SUB ESC  FS  GS  RS  US */
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+
+/*  SP  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /  */
+    2,  1,  0,  1,  0,  1,  1,  1,   1,  1,  0,  1,  1,  0,  4,  0,
+
+/*  0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?  */
+   64, 64, 64, 64, 64, 64, 64, 64,  64, 64,  0,  1,  1,  1,  1,  1,
+
+/*  @   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O  */
+    1, 64, 64, 64, 64, 64, 64,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+
+/*  P   Q   R   S   T   U   V   W    X   Y   Z   [   \   ]   ^   _  */
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  1,  0,  1,  1,  0,
+
+/*  `   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o  */
+    1, 64, 64, 64, 64, 64, 64,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+
+/*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~  DEL */
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  1,  0,  1,  1,  8,
+
+    8,  8,  8,  8,  8,  8,  8,  8,   8,  8,  8,  8,  8,  8,  8,  8,
+    8,  8,  8,  8,  8,  8,  8,  8,   8,  8,  8,  8,  8,  8,  8,  8,
+    8,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  8
+};
+
+/* The C RTL from OpenVMS 7.0 and newer supplies POSIX compatible versions of
+ * opendir() et al. Thus, we have to use other names in our private code for
+ * directory scanning to prevent symbol name conflicts at link time.
+ * For now, we do not use the library supplied "dirent.h" functions, since
+ * our private implementation provides some functionality which may not be
+ * present in the library versions.  For example:
+ * ==> zopendir("DISK:[DIR.SUB1]SUB2.DIR") scans "DISK:[DIR.SUB1.SUB2]".
+ */
+
+typedef struct zdirent {
+  int d_wild;                /* flag for wildcard vs. non-wild */
+  struct FAB fab;
+  struct NAM_STRUCT nam;
+  char d_qualwildname[ NAM_MAXRSS+ 1];
+  char d_name[ NAM_MAXRSS+ 1];
+} zDIR;
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+local int relative_dir_s = 0;   /* Relative directory spec. */
+
+/* Local functions */
+local void vms_wild OF((char *, zDIR *));
+local zDIR *zopendir OF((ZCONST char *));
+local char *readd OF((zDIR *));
+local char *strlower OF((char *));
+local char *strupper OF((char *));
+
+/* 2004-09-25 SMS.
+   str[n]casecmp() replacement for old C RTL.
+   Assumes a prehistorically incompetent toupper().
+*/
+#ifndef HAVE_STRCASECMP
+
+int strncasecmp( char *s1, char *s2, size_t n)
+{
+  /* Initialization prepares for n == 0. */
+  char c1 = '\0';
+  char c2 = '\0';
+
+  while (n-- > 0)
+  {
+    /* Set c1 and c2.  Convert lower-case characters to upper-case. */
+    if (islower( c1 = *s1))
+      c1 = toupper( c1);
+
+    if (islower( c2 = *s2))
+      c2 = toupper( c2);
+
+    /* Quit at inequality or NUL. */
+    if ((c1 != c2) || (c1 == '\0'))
+      break;
+
+    s1++;
+    s2++;
+  }
+return ((unsigned int) c1- (unsigned int) c2);
+}
+
+#ifndef UINT_MAX
+#define UINT_MAX 4294967295U
+#endif
+
+#define strcasecmp( s1, s2) strncasecmp( s1, s2, UINT_MAX)
+
+#endif /* ndef HAVE_STRCASECMP */
+
+
+/* 2004-09-27 SMS.
+   eat_carets().
+
+   Delete ODS5 extended file name escape characters ("^") in the
+   original buffer.
+   Note that the current scheme does not handle all EFN cases, but it
+   could be made more complicated.
+*/
+
+local void eat_carets( char *str)
+/* char *str;      Source pointer. */
+{
+  char *strd;   /* Destination pointer. */
+  char hdgt;
+  unsigned char uchr;
+  unsigned char prop;
+
+  /* Skip ahead to the first "^", if any. */
+  while ((*str != '\0') && (*str != '^'))
+     str++;
+
+  /* If no caret was found, quit early. */
+  if (*str != '\0')
+  {
+    /* Shift characters leftward as carets are found. */
+    strd = str;
+    while (*str != '\0')
+    {
+      uchr = *str;
+      if (uchr == '^')
+      {
+        /* Found a caret.  Skip it, and check the next character. */
+        uchr = *(++str);
+        prop = char_prop[ uchr];
+        if (prop& 64)
+        {
+          /* Hex digit.  Get char code from this and next hex digit. */
+          if (uchr <= '9')
+          {
+            hdgt = uchr- '0';           /* '0' - '9' -> 0 - 9. */
+          }
+          else
+          {
+            hdgt = ((uchr- 'A')& 7)+ 10;    /* [Aa] - [Ff] -> 10 - 15. */
+          }
+          hdgt <<= 4;                   /* X16. */
+          uchr = *(++str);              /* Next char must be hex digit. */
+          if (uchr <= '9')
+          {
+            uchr = hdgt+ uchr- '0';
+          }
+          else
+          {
+            uchr = hdgt+ ((uchr- 'A')& 15)+ 10;
+          }
+        }
+        else if (uchr == '_')
+        {
+          /* Convert escaped "_" to " ". */
+          uchr = ' ';
+        }
+        else if (uchr == '/')
+        {
+          /* Convert escaped "/" (invalid Zip) to "?" (invalid VMS). */
+          uchr = '?';
+        }
+        /* Else, not a hex digit.  Must be a simple escaped character
+           (or Unicode, which is not yet handled here).
+        */
+      }
+      /* Else, not a caret.  Use as-is. */
+      *strd = uchr;
+
+      /* Advance destination and source pointers. */
+      strd++;
+      str++;
+    }
+    /* Terminate the destination string. */
+    *strd = '\0';
+  }
+}
+
+
+/* 2007-05-22 SMS.
+ * explicit_dev().
+ *
+ * Determine if an explicit device name is present in a (VMS) file
+ * specification.
+ */
+local int explicit_dev( char *file_spec)
+{
+  int sts;
+  struct FAB fab;               /* FAB. */
+  struct NAM_STRUCT nam;        /* NAM[L]. */
+
+  /* Initialize the FAB and NAM[L], and link the NAM[L] to the FAB. */
+  nam = CC_RMS_NAM;
+  fab = cc$rms_fab;
+  fab.FAB_NAM = &nam;
+
+  /* Point the FAB/NAM[L] fields to the actual name and default name. */
+
+#ifdef NAML$C_MAXRSS
+
+  fab.fab$l_dna = (char *) -1;  /* Using NAML for default name. */
+  fab.fab$l_fna = (char *) -1;  /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+  /* File name. */
+  FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = file_spec;
+  FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen( file_spec);
+
+  nam.NAM_NOP = NAM_M_SYNCHK;   /* Syntax-only analysis. */
+  sts = sys$parse( &fab, 0, 0); /* Parse the file spec. */
+
+  /* Device found = $PARSE success and "device was explicit" flag. */
+  return (((sts& STS$M_SEVERITY) == STS$M_SUCCESS) &&
+   ((nam.NAM_FNB& NAM_M_EXP_DEV) != 0));
+}
+
+
+/* 2005-02-04 SMS.
+   find_dir().
+
+   Find directory boundaries in an ODS2 or ODS5 file spec.
+   Returns length (zero if no directory, negative if error),
+   and sets "start" argument to first character (typically "[") location.
+
+   No one will care about the details, but the return values are:
+
+       0  No dir.
+      -2  [, no end.              -3  <, no end.
+      -4  [, multiple start.      -5  <, multiple start.
+      -8  ], no start.            -9  >, no start.
+     -16  ], wrong end.          -17  >, wrong end.
+     -32  ], multiple end.       -33  >, multiple end.
+
+   Note that the current scheme handles only simple EFN cases, but it
+   could be made more complicated.
+*/
+int find_dir( char *file_spec, char **start)
+{
+  char *cp;
+  char chr;
+
+  char *end_tmp = NULL;
+  char *start_tmp = NULL;
+  int lenth = 0;
+
+  for (cp = file_spec; cp < file_spec+ strlen( file_spec); cp++)
+  {
+    chr = *cp;
+    if (chr == '^')
+    {
+      /* Skip ODS5 extended name escaped characters. */
+      cp++;
+      /* If escaped char is a hex digit, skip the second hex digit, too. */
+      if (char_prop[ (unsigned char) *cp]& 64)
+        cp++;
+    }
+    else if (chr == '[')
+    {
+      /* Found start. */
+      if (start_tmp == NULL)
+      {
+        /* First time.  Record start location. */
+        start_tmp = cp;
+        /* Error if no end. */
+        lenth = -2;
+      }
+      else
+      {
+        /* Multiple start characters.  */
+        lenth = -4;
+        break;
+      }
+    }
+    else if (chr == '<')
+    {
+      /* Found start. */
+      if (start_tmp == NULL)
+      {
+        /* First time.  Record start location. */
+        start_tmp = cp;
+        /* Error if no end. */
+        lenth = -3;
+      }
+      else
+      {
+        /* Multiple start characters.  */
+        lenth = -5;
+        break;
+      }
+    }
+    else if (chr == ']')
+    {
+      /* Found end. */
+      if (end_tmp == NULL)
+      {
+        /* First time. */
+        if (lenth == 0)
+        {
+          /* End without start. */
+          lenth = -8;
+          break;
+        }
+        else if (lenth != -2)
+        {
+          /* Wrong kind of end. */
+          lenth = -16;
+          break;
+        }
+        /* End ok.  Record end location. */
+        end_tmp = cp;
+        lenth = end_tmp+ 1- start_tmp;
+        /* Could break here, ignoring excessive end characters. */
+      }
+      else
+      {
+        /* Multiple end characters. */
+        lenth = -32;
+        break;
+      }
+    }
+    else if (chr == '>')
+    {
+      /* Found end. */
+      if (end_tmp == NULL)
+      {
+        /* First time. */
+        if (lenth == 0)
+        {
+          /* End without start. */
+          lenth = -9;
+          break;
+        }
+        else if (lenth != -3)
+        {
+          /* Wrong kind of end. */
+          lenth = -17;
+          break;
+        }
+        /* End ok.  Record end location. */
+        end_tmp = cp;
+        lenth = end_tmp+ 1- start_tmp;
+        /* Could break here, ignoring excessive end characters. */
+      }
+      else
+      {
+        /* Multiple end characters. */
+        lenth = -33;
+        break;
+      }
+    }
+  }
+
+  /* If both start and end were found,
+     then set result pointer where safe.
+  */
+  if (lenth > 0)
+  {
+    if (start != NULL)
+    {
+      *start = start_tmp;
+    }
+  }
+  return lenth;
+}
+
+
+/* 2005-02-08 SMS.
+   file_sys_type().
+
+   Determine the file system type for the (VMS) path name argument.
+*/
+local int file_sys_type( char *path)
+{
+  int acp_code;
+
+#ifdef DVI$C_ACP_F11V5
+
+/* Should know about ODS5 file system.  Do actual check.
+   (This should be non-VAX with __CRTL_VER >= 70200000.)
+*/
+
+  int sts;
+
+  struct dsc$descriptor_s dev_descr =
+   { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0 };
+
+  /* Load path argument into device descriptor. */
+  dev_descr.dsc$a_pointer = path;
+  dev_descr.dsc$w_length = strlen( dev_descr.dsc$a_pointer);
+
+  /* Get filesystem type code.
+     (Text results for this item code have been unreliable.)
+  */
+  sts = lib$getdvi( &((int) DVI$_ACPTYPE), 0, &dev_descr, &acp_code, 0, 0);
+
+  if ((sts & STS$M_SUCCESS) != STS$K_SUCCESS)
+  {
+    acp_code = -1;
+  }
+
+#else /* def DVI$C_ACP_F11V5 */
+
+/* Too old for ODS5 file system.  Must be ODS2. */
+
+  acp_code = DVI$C_ACP_F11V2;
+
+#endif /* def DVI$C_ACP_F11V5 */
+
+  return acp_code;
+}
+
+/*---------------------------------------------------------------------------
+
+    _vms_findfirst() and _vms_findnext(), based on public-domain DECUS C
+    fwild() and fnext() routines (originally written by Martin Minow, poss-
+    ibly modified by Jerry Leichter for bintnxvms.c), were written by Greg
+    Roelofs and are still in the public domain.  Routines approximate the
+    behavior of MS-DOS (MSC and Turbo C) findfirst and findnext functions.
+
+    2005-01-04 SMS.
+    Changed to use NAML instead of NAM, where available.
+
+  ---------------------------------------------------------------------------*/
+
+static char wild_version_part[10]="\0";
+
+local void vms_wild( char *p, zDIR *d)
+{
+  /*
+   * Do wildcard setup.
+   */
+  /* Set up the FAB and NAM[L] blocks. */
+  d->fab = cc$rms_fab;                  /* Initialize FAB. */
+  d->nam = CC_RMS_NAM;                  /* Initialize NAM[L]. */
+
+  d->fab.FAB_NAM = &d->nam;             /* FAB -> NAM[L] */
+
+#ifdef NAML$C_MAXRSS
+
+  d->fab.fab$l_dna =(char *) -1;        /* Using NAML for default name. */
+  d->fab.fab$l_fna = (char *) -1;       /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+  /* Argument file name and length. */
+  d->FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = p;
+  d->FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen(p);
+
+#define DEF_DEVDIR "SYS$DISK:[]"
+
+  /* Default file spec and length. */
+  d->FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNA = DEF_DEVDIR;
+  d->FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNS = sizeof( DEF_DEVDIR)- 1;
+
+  d->nam.NAM_ESA = d->d_qualwildname;   /* qualified wild name */
+  d->nam.NAM_ESS = NAM_MAXRSS;          /* max length */
+  d->nam.NAM_RSA = d->d_name;           /* matching file name */
+  d->nam.NAM_RSS = NAM_MAXRSS;          /* max length */
+
+  /* parse the file name */
+  if (sys$parse(&d->fab) != RMS$_NORMAL)
+    return;
+  /* Does this replace d->fab.fab$l_fna with a new string in its own space?
+     I sure hope so, since p is free'ed before this routine returns. */
+
+  /* have qualified wild name (i.e., disk:[dir.subdir]*.*); null-terminate
+   * and set wild-flag */
+  d->d_qualwildname[d->nam.NAM_ESL] = '\0';
+  d->d_wild = (d->nam.NAM_FNB & NAM$M_WILDCARD)? 1 : 0;   /* not used... */
+#ifdef DEBUG
+  fprintf(mesg, "  incoming wildname:  %s\n", p);
+  fprintf(mesg, "  qualified wildname:  %s\n", d->d_qualwildname);
+#endif /* DEBUG */
+}
+
+local zDIR *zopendir( ZCONST char *n)
+/* ZCONST char *n;         directory to open */
+/* Start searching for files in the VMS directory n */
+{
+  char *c;              /* scans VMS path */
+  zDIR *d;              /* malloc'd return value */
+  int m;                /* length of name */
+  char *p;              /* malloc'd temporary string */
+
+  if ((d = (zDIR *)malloc(sizeof(zDIR))) == NULL ||
+      (p = malloc((m = strlen(n)) + 4)) == NULL) {
+    if (d != NULL) free((zvoid *)d);
+    return NULL;
+  }
+  /* Directory may be in form "[DIR.SUB1.SUB2]" or "[DIR.SUB1]SUB2.DIR;1".
+     If latter, convert to former.
+     2005-01-31 SMS.  Changed to require ";1", as VMS does, which
+     simplified the code slightly, too.  Note that ODS5 allows ".DIR" in
+     any case (upper, lower, mixed).
+  */
+  if ((m > 0) && (*(c = strcpy(p,n)+m-1) != ']'))
+  {
+    if ((c- p < DIR_TYPE_VER_LEN) ||
+     strcasecmp((c+ 1- DIR_TYPE_VER_LEN), DIR_TYPE_VER))
+    {
+      free((zvoid *)d);  free((zvoid *)p);
+      return NULL;
+    }
+    c -= 4;             /* The "D". */
+    *c-- = '\0';        /* terminate at "DIR;1" */
+    *c = ']';           /* "." --> "]" */
+
+    /* Replace the formerly last "]" with ".".
+       For ODS5, ignore "^]".
+    */
+    while ((c > p) && ((*--c != ']') || (*(c- 1) == '^')))
+      ;
+    *c = '.';           /* "]" --> "." */
+  }
+  strcat(p, "*.*");
+  strcat(p, wild_version_part);
+  vms_wild(p, d);       /* set up wildcard */
+  free((zvoid *)p);
+  return d;
+}
+
+local char *readd( zDIR *d)
+/* zDIR *d;                directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+   no more entries or an error occurs. */
+{
+  int r;                /* return code */
+
+  do {
+    d->fab.fab$w_ifi = 0;       /* internal file index:  what does this do? */
+/*
+  2005-02-04 SMS.
+
+  From the docs:
+
+        Note that you must close the file before invoking the Search
+        service (FAB$W_IFI must be 0). 
+
+  The same is true for PARSE.  Most likely, it's cleared by setting
+  "fab = cc$rms_fab", and left that way, so clearing it here may very
+  well be pointless.  (I think it is, and I've never seen it explicitly
+  cleared elsewhere, but I haven't tested it everywhere either.)
+*/
+    /* get next match to possible wildcard */
+    if ((r = sys$search(&d->fab)) == RMS$_NORMAL)
+    {
+        d->d_name[d->nam.NAM_RSL] = '\0';   /* null terminate */
+        return (char *)d->d_name;   /* OK */
+    }
+  } while (r == RMS$_PRV);
+  return NULL;
+}
+
+
+int wild( char *p)
+/* char *p;                path/pattern to match */
+/* Expand the pattern based on the contents of the file system.
+   Return an error code in the ZE_ class.
+   Note that any command-line file argument may need wildcard expansion,
+   so all user-specified constituent file names pass through here.
+*/
+{
+  zDIR *d;              /* stream for reading directory */
+  char *e;              /* name found in directory */
+  int f;                /* true if there was a match */
+
+  int dir_len;          /* Length of the directory part of the name. */
+  char *dir_start;      /* First character of the directory part. */
+
+  /* special handling of stdin request */
+  if (strcmp(p, "-") == 0)   /* if compressing stdin */
+    return newname(p, 0, 0);
+
+  /* Determine whether this name has an absolute or relative directory
+     spec.  It's relative if there is no directory, or if the directory
+     has a leading dot ("[.").
+  */
+  dir_len = find_dir( p, &dir_start);
+  relative_dir_s = ((dir_len <= 0)? 1 : (dir_start[ 1] == '.'));
+
+  /* Search given pattern for matching names */
+  if ((d = (zDIR *)malloc(sizeof(zDIR))) == NULL)
+    return ZE_MEM;
+  vms_wild(p, d);       /* pattern may be more than just directory name */
+
+  /*
+   * Save version specified by user to use in recursive drops into
+   * subdirectories.
+   */
+  strncpy(wild_version_part, d->nam.NAM_L_VER, d->nam.NAM_B_VER);
+  wild_version_part[d->nam.NAM_B_VER] = '\0';
+
+  f = 0;
+  while ((e = readd(d)) != NULL)        /* "dosmatch" is already built in */
+    if (procname(e, 0) == ZE_OK)
+      f = 1;
+  free(d);
+
+  /* Done */
+  return f ? ZE_OK : ZE_MISS;
+}
+
+int procname( char *n, int caseflag)
+/* char *n;                name to process */
+/* int caseflag;           true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  zDIR *d;              /* directory stream from zopendir() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  struct stat s;        /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (LSSTAT(n, &s)
+#if defined(__TURBOC__) || defined(VMS) || defined(__WATCOMC__)
+           /* For these 3 compilers, stat() succeeds on wild card names! */
+           || isshexp(n)
+#endif
+          )
+  {
+    /* Not a file or directory--search for shell expression in zip file */
+    if (caseflag) {
+      p = malloc(strlen(n) + 1);
+      if (p != NULL)
+        strcpy(p, n);
+    } else
+      p = ex2in(n, 0, (int *)NULL);     /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->name);
+        m = 0;
+      }
+    }
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  if ((s.st_mode & S_IFDIR) == 0)
+  {
+    /* add or remove name of file */
+    if ((m = newname(n, 0, caseflag)) != ZE_OK)
+      return m;
+  } else {
+    if (dirnames && (m = newname(n, 1, caseflag)) != ZE_OK) {
+      return m;
+    }
+    /* recurse into directory */
+    if (recurse && (d = zopendir(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if ((m = procname(e, caseflag)) != ZE_OK)     /* recurse on name */
+        {
+          free(d);
+          return m;
+        }
+      }
+      free(d);
+    }
+  } /* (s.st_mode & S_IFDIR) == 0) */
+  return ZE_OK;
+}
+
+/* 2004-09-24 SMS.
+   Cuter strlower() and strupper() functions.
+*/
+
+local char *strlower( char *s)
+/* Convert all uppercase letters to lowercase in string s */
+{
+  for ( ; *s != '\0'; s++)
+    if (isupper( *s))
+      *s = tolower( *s);
+
+  return s;
+}
+
+local char *strupper( char *s)
+/* Convert all lowercase letters to uppercase in string s */
+{
+  for ( ; *s != '\0'; s++)
+    if (islower( *s))
+      *s = toupper( *s);
+
+  return s;
+}
+
+char *ex2in( char *x, int isdir, int *pdosflag)
+/* char *x;                external file name */
+/* int isdir;              input: x is a directory */
+/* int *pdosflag;          output: force MSDOS file attributes? */
+
+/* Convert the external file name to a zip file name, returning the
+   malloc'ed string or NULL if not enough memory.
+
+   2005-02-09 SMS.
+   Added some ODS5 support.
+
+   Note that if we were really clever, we'd save the truncated original
+   file name for later use as "iname", instead of running the de-escaped
+   product back through in2ex() to recover it later.
+
+   2005-11-13 SMS.
+   Changed to translate "[..." into enough "/" characters to cause
+   in2ex() to reconstruct it.  This should not be needed, however, as
+   pattern matching really should avoid ex2in() and in2ex().
+*/
+{
+  char *n;                      /* Internal file name (malloc'ed). */
+  char *nn;                     /* Temporary "n"-like pointer. */
+  char *ext_dir_and_name;       /* External dir]name (less "dev:["). */
+  char chr;                     /* Temporary character storage. */
+  int dosflag;
+  int down_case;                /* Resultant down-case flag. */
+  int dir_len;                  /* Directory spec length. */
+  int ods_level;                /* File system type. */
+
+  dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+  /* Locate the directory part of the external name. */
+  dir_len = find_dir( x, &ext_dir_and_name);
+  if (dir_len <= 0)
+  {
+    /* Directory not found.  Use whole external name. */
+    ext_dir_and_name = x;
+  }
+  else if (pathput)
+  {
+    /* Include directory. */
+    if (ext_dir_and_name[ 1] == '.')
+    {
+      /* Relative path.  If not a directory-depth wildcard, then drop
+         first "[." (or "<.").  If "[..." (or "<..."), then preserve all
+         characters, including the first "[" (or "<") for special
+         handling below.
+      */
+      if ((ext_dir_and_name[ 2] != '.') || (ext_dir_and_name[ 3] != '.'))
+      {
+        /* Normal relative path.  Drop first "[." (or "<."). */
+        dir_len -= 2;
+        ext_dir_and_name += 2;
+      }
+    }
+    else
+    {
+      /* Absolute path.  Skip first "[" (or "<"). */
+      dir_len -= 1;
+      ext_dir_and_name += 1;
+
+      /* 2007-04-26 SMS.
+         Skip past "000000." or "000000]" (or "000000>"), which should
+         not be stored in the archive.  This arises, for example, with
+         "zip -r archive [000000]foo.dir"
+      */
+#define MFD "000000"
+
+      if ((strncmp( ext_dir_and_name, MFD, strlen( MFD)) == 0) &&
+       ((ext_dir_and_name[ 6] == '.') ||
+       (ext_dir_and_name[ 6] == ']') ||
+       (ext_dir_and_name[ 6] == '>')))
+      {
+        dir_len -= 7;
+        ext_dir_and_name += 7;
+      } 
+    }
+  }
+  else
+  {
+    /* Junking paths.  Skip the whole directory spec. */
+    ext_dir_and_name += dir_len;
+    dir_len = 0;
+  }
+
+  /* Malloc space for internal name and copy it. */
+  if ((n = malloc(strlen( ext_dir_and_name)+ 1)) == NULL)
+    return NULL;
+  strcpy( n, ext_dir_and_name);
+
+  /* Convert VMS directory separators (".") to "/". */
+  if (dir_len > 0)
+  {
+    for (nn = n; nn < n+ dir_len; nn++)
+    {
+      chr = *nn;
+      if (chr == '^')
+      {
+        /* Skip ODS5 extended name escaped characters. */
+        nn++;
+        /* If escaped char is a hex digit, skip the second hex digit, too. */
+        if (char_prop[ (unsigned char) *nn]& 64)
+          nn++;
+      }
+      else if ((chr == '.') || ((nn == n) && ((chr == '[') || (chr == '<'))))
+      {
+        /* Convert VMS directory separator (".", or initial "[" or "<"
+           of "[..." or "<...") to "/".
+        */
+        *nn = '/';
+      }
+    }
+    /* Replace directory end character (typically "]") with "/". */
+    n[ dir_len- 1] = '/';
+  }
+
+  /* If relative path, then strip off the current directory. */
+  if (relative_dir_s)
+  {
+    char cwd[ NAM_MAXRSS+ 1];
+    char *cwd_dir_only;
+    char *q;
+    int cwd_dir_only_len;
+
+    q = getcwd( cwd, (sizeof( cwd)- 1));
+
+    /* 2004-09-24 SMS.
+       With SET PROCESSS /PARSE = EXTENDED, getcwd() can return a
+       mixed-case result, confounding the comparisons below with an
+       all-uppercase name in "n".  Always use a case-insensitive
+       comparison around here.
+    */
+
+    /* Locate the directory part of the external name. */
+    dir_len = find_dir( q, &cwd_dir_only);
+    if (dir_len > 0)
+    {
+      /* Skip first "[" (or "<"). */
+      cwd_dir_only++;
+      /* Convert VMS directory separators (".") to "/". */
+      for (q = cwd_dir_only; q < cwd_dir_only+ dir_len; q++)
+      {
+        chr = *q;
+        if (chr == '^')
+        {
+          /* Skip ODS5 extended name escaped characters. */
+          q++;
+          /* If escaped char is a hex digit, skip the second hex digit, too. */
+          if (char_prop[ (unsigned char) *q]& 64)
+            q++;
+        }
+        else if (chr == '.')
+        {
+          /* Convert VMS directory separator (".") to "/". */
+          *q = '/';
+        }
+      }
+      /* Replace directory end character (typically "]") with "/". */
+      cwd_dir_only[ dir_len- 2] = '/';
+    }
+
+    /* If the slash-converted cwd matches the front of the internal
+       name, then shuffle the remainder of the internal name to the
+       beginning of the internal name storage.
+
+       Because we already know that the path is relative, this test may
+       always succeed.
+    */
+    cwd_dir_only_len = strlen( cwd_dir_only);
+    if (strncasecmp( n, cwd_dir_only, cwd_dir_only_len) == 0)
+    {
+       nn = n+ cwd_dir_only_len;
+       q = n;
+       while (*q++ = *nn++);
+    }
+  } /* (relative_dir_s) */
+
+  /* 2007-05-22 SMS.
+   * If a device name is present, assume that it's a real (VMS) file
+   * specification, and do down-casing according to the ODS2 or ODS5
+   * down-casing policy.  If no device name is present, assume that it's
+   * a pattern ("-i", ...), and do no down-casing here.  (Case
+   * sensitivity in patterns is handled elsewhere.)
+   */
+  if (explicit_dev( x))
+  {
+    /* If ODS5 is possible, do complicated down-case check.
+
+       Note that the test for ODS2/ODS5 is misleading and over-broad. 
+       Here, "ODS2" includes anything from DVI$C_ACP_F11V1 (=1, ODS1) up
+       to (but not including) DVI$C_ACP_F11V5 (= 11, DVI$C_ACP_F11V5),
+       while "ODS5" includes anything from DVI$C_ACP_F11V5 on up.  See
+       DVIDEF.H.
+    */
+
+#if defined( DVI$C_ACP_F11V5) && defined( NAML$C_MAXRSS)
+
+    /* Check options and/or ODS level for down-case or preserve case. */
+    down_case = 0;      /* Assume preserve case. */
+    if ((vms_case_2 <= 0) && (vms_case_5 < 0))
+    {
+      /* Always down-case. */
+      down_case = 1;
+    }
+    else if ((vms_case_2 <= 0) || (vms_case_5 < 0))
+    {
+      /* Down-case depending on ODS level.  (Use (full) external name.) */
+      ods_level = file_sys_type( x);
+
+      if (ods_level > 0)
+      {
+        /* Valid ODS level.  (Name (full) contains device.)
+         * Down-case accordingly.
+         */
+        if (((ods_level < DVI$C_ACP_F11V5) && (vms_case_2 <= 0)) ||
+         ((ods_level >= DVI$C_ACP_F11V5) && (vms_case_5 < 0)))
+        {
+          /* Down-case for this ODS level. */
+          down_case = 1;
+        }
+      }
+    }
+
+#else /* defined( DVI$C_ACP_F11V5) && defined( NAML$C_MAXRSS) */
+
+/* No case-preserved names are possible (VAX).  Do simple down-case check. */
+
+    down_case = (vms_case_2 <= 0);
+
+#endif /* defined( DVI$C_ACP_F11V5) && defined( NAML$C_MAXRSS) [else] */
+
+    /* If down-casing, convert to lower case. */
+    if (down_case != 0)
+    {
+      strlower( n);
+    }
+  }
+
+  /* Remove simple ODS5 extended file name escape characters. */
+  eat_carets( n);
+
+  if (isdir)
+  {
+    if (strcasecmp( (nn = n+ strlen( n)- DIR_TYPE_VER_LEN), DIR_TYPE_VER))
+      error("directory not version 1");
+    else
+      if (pathput)
+        strcpy( nn, "/");
+      else
+        *n = '\0';              /* directories are discarded with zip -rj */
+  }
+  else if (vmsver == 0)
+  {
+    /* If not keeping version numbers, truncate the name at the ";".
+       (No escaped characters are expected in the version.)
+    */
+    if ((ext_dir_and_name = strrchr( n, ';')) != NULL)
+      *ext_dir_and_name = '\0';
+  }
+  else if (vmsver > 1)
+  {
+    /* Keeping version numbers, but as ".nnn", not ";nnn". */
+    if ((ext_dir_and_name = strrchr( n, ';')) != NULL)
+      *ext_dir_and_name = '.';
+  }
+
+  /* Remove a type-less dot. */
+  /* (Note that currently "name..ver" is not altered.) */
+  if ((ext_dir_and_name = strrchr( n, '.')) != NULL)
+  {
+    if (ext_dir_and_name[ 1] == '\0')           /* "name." -> "name" */
+      *ext_dir_and_name = '\0';
+    else if (ext_dir_and_name[ 1] == ';')       /* "name.;ver" -> "name;ver" */
+    {
+      char *f = ext_dir_and_name+ 1;
+      while (*ext_dir_and_name++ = *f++);
+    }
+  }
+
+  if (dosify)
+    msname(n);
+
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+
+  return n;
+}
+
+
+char *in2ex( char *n)
+/* char *n;                internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;              /* external file name */
+  char *t;              /* scans name */
+  int i;
+  char chr;
+  char *endp;
+  char *last_slash;
+  char *versionp;
+
+#ifdef NAML$C_MAXRSS
+
+  char buf[ NAML$C_MAXRSS+ 1];
+  unsigned char prop;
+  unsigned char uchr;
+  char *last_dot;
+
+#endif /* def NAML$C_MAXRSS */
+
+  /* Locate the last slash. */
+  last_slash = strrchr( n, '/');
+
+/* If ODS5 is possible, replace escape carets in name. */
+
+#ifdef NAML$C_MAXRSS
+
+  endp = n+ strlen( n);
+
+  /* Locate the version delimiter, if one is expected. */
+  if (vmsver == 0)
+  { /* No version expected. */
+    versionp = endp;
+  }
+  else
+  {
+    if (vmsver > 1)
+    { /* Expect a dot-version, ".nnn".  Locate the version ".".
+         Temporarily terminate at this dot to allow the last-dot search
+         below to find the last non-version dot.
+      */
+      versionp = strrchr( n, '.');
+      if (versionp != NULL)     /* Can't miss. */
+      {
+        *versionp = '\0';
+      }
+    }
+    else
+    { /* Expect a semi-colon-version, ";nnn".  Locate the ";".  */
+      versionp = strrchr( n, ';');
+    }
+    if ((versionp == NULL) || (versionp < last_slash))
+    { /* If confused, and the version delimiter was not in the name,
+         then ignore it.
+      */
+      versionp = endp;
+    }
+  }
+
+  /* No escape needed for the last dot, if it's part of the file name.
+     All dots in a directory must be escaped.
+  */
+  last_dot = strrchr( n, '.');
+
+  if ((last_dot != NULL) && (last_slash != NULL) && (last_dot < last_slash))
+  {
+    last_dot = last_slash;
+  }
+
+  /* Replace the version dot if necessary. */
+  if ((vmsver > 1) && (versionp != NULL) && (versionp < endp))
+  {
+    *versionp = '.';
+  }
+
+  /* Add ODS5 escape sequences.  Leave "/" and "?" for later.
+     The name here looks (roughly) like: dir1/dir2/a.b
+  */
+  t = n;
+  x = buf;
+  while (uchr = *t++)
+  {
+    /* Characters in the version do not need escaping. */
+    if (t <= versionp)
+    {
+      prop = char_prop[ uchr]& 31;
+      if (prop)
+      {
+        if (prop& 4)
+        { /* Dot. */
+          if (t < last_dot)
+          {
+            /* Dot which must be escaped. */
+            *x++ = '^';
+          }
+        }
+        else if (prop& 8)
+        {
+          /* Character needing hex-hex escape. */
+          *x++ = '^';
+          *x++ = hex_digit[ uchr>> 4];
+          uchr = hex_digit[ uchr& 15];
+        }
+        else
+        {
+          /* Non-dot character which must be escaped (and simple works).
+             "?" gains the caret but remains "?" until later.
+             ("/" remains (unescaped) "/".)
+          */
+          *x++ = '^';
+          if (prop& 2)
+          {
+            /* Escaped space (represented as "^_"). */
+            uchr = '_';
+          }
+        }
+      }
+    }
+    *x++ = uchr;
+  }
+  *x = '\0';
+
+  /* Point "n" to altered name buffer, and re-find the last slash. */
+  n = buf;
+  last_slash = strrchr( n, '/');
+
+#endif /* def NAML$C_MAXRSS */
+
+  if ((t = last_slash) == NULL)
+  {
+    if ((x = malloc(strlen(n) + 1 + DIR_PAD)) == NULL)
+      return NULL;
+    strcpy(x, n);
+  }
+  else
+  {
+    if ((x = malloc(strlen(n) + 3 + DIR_PAD)) == NULL)
+      return NULL;
+
+    /* Begin with "[". */
+    x[ 0] = '[';
+    i = 1;
+    if (*n != '/')
+    {
+      /* Relative path.  Add ".". */
+      x[ i++] = '.';
+    }
+    else
+    {
+      /* Absolute path.  Skip leading "/". */
+      n++;
+    }
+    strcpy( (x+ i), n);
+
+    /* Place the final ']'.  Remember where the name starts. */
+    *(t = x + i + (t - n)) = ']';
+    last_slash = t;
+
+    /* Replace "/" with ".", and "?" with (now escaped) "/", in the
+       directory part of the name.
+    */
+    while (--t > x)
+    {
+      chr = *t;
+      if (chr == '/')
+      {
+        *t = '.';
+      }
+      else if (chr == '?')
+      {
+        *t = '/';
+      }
+    }
+
+    /* Replace "?" with (now escaped) "/", in the non-directory part of
+       the name.
+    */
+    while ((chr = *(++last_slash)) != '\0')
+    {
+      if (chr == '?')
+      {
+        *last_slash = '/';
+      }
+    }
+  }
+
+/* If case preservation is impossible (VAX, say), and down-casing, then
+   up-case.  If case preservation is possible and wasn't done, then
+   there's no way to ensure proper restoration of original case, so
+   don't try.  This may differ from pre-3.0 behavior.
+*/
+#ifndef NAML$C_MAXRSS
+
+  if (vms_case_2 <= 0)
+  {
+    strupper( x);
+  }
+
+#endif /* ndef NAML$C_MAXRSS */
+
+  return x;
+}
+
+void stamp( char *f, ulg d)
+/* char *f;                name of file to change */
+/* ulg d;                  dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+  int tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year;
+  char timbuf[24];
+  static ZCONST char *month[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
+                                 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
+  struct VMStimbuf {
+      char *actime;           /* VMS revision date, ASCII format */
+      char *modtime;          /* VMS creation date, ASCII format */
+  } ascii_times;
+
+  ascii_times.actime = ascii_times.modtime = timbuf;
+
+  /* Convert DOS time to ASCII format for VMSmunch */
+  tm_sec = (int)(d << 1) & 0x3e;
+  tm_min = (int)(d >> 5) & 0x3f;
+  tm_hour = (int)(d >> 11) & 0x1f;
+  tm_mday = (int)(d >> 16) & 0x1f;
+  tm_mon = ((int)(d >> 21) & 0xf) - 1;
+  tm_year = ((int)(d >> 25) & 0x7f) + 1980;
+  sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", tm_mday, month[tm_mon],
+    tm_year, tm_hour, tm_min, tm_sec);
+
+  /* Set updated and accessed times of f */
+  if (VMSmunch(f, SET_TIMES, (char *)&ascii_times) != RMS$_NMF)
+    zipwarn("can't set zipfile time: ", f);
+}
+
+ulg filetime( char *f, ulg *a, zoff_t *n, iztimes *t)
+/* char *f;                name of file to get info on */
+/* ulg *a;                 return value: file attributes */
+/* zoff_t *n;              return value: file size */
+/* iztimes *t;             return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  struct stat s;        /* results of stat() */
+  /* convert to a malloc string dump FNMAX - 11/8/04 EG */
+  char *name;
+  int len = strlen(f);
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (name[len - 1] == '/')
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+
+  if (strcmp(f, "-") == 0) {
+    if (fstat(fileno(stdin), &s) != 0) {
+      free(name);
+      error("fstat(stdin)");
+    }
+  } else if (LSSTAT(name, &s) != 0) {
+             /* Accept about any file kind including directories
+              * (stored with trailing / with -r option)
+              */
+    free(name);
+    return 0;
+  }
+  free(name);
+
+  if (a != NULL) {
+    *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+    if ((s.st_mode & S_IFDIR) != 0) {
+      *a |= MSDOS_DIR_ATTR;
+    }
+  }
+  if (n != NULL)
+    *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1;
+  if (t != NULL) {
+    t->atime = s.st_mtime;
+#ifdef USE_MTIME
+    t->mtime = s.st_mtime;            /* Use modification time in VMS */
+#else
+    t->mtime = s.st_ctime;            /* Use creation time in VMS */
+#endif
+    t->ctime = s.st_ctime;
+  }
+
+#ifdef USE_MTIME
+  return unix2dostime((time_t *)&s.st_mtime); /* Use modification time in VMS */
+#else
+  return unix2dostime((time_t *)&s.st_ctime); /* Use creation time in VMS */
+#endif
+}
+
+int deletedir( char *d)
+/* char *d;                directory to delete */
+
+/* Delete the directory *d if it is empty, do nothing otherwise.
+   Return the result of rmdir(), delete(), or system().
+   For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
+ */
+{
+    /* code from Greg Roelofs, who horked it from Mark Edwards (unzip) */
+    int r, len;
+    char *s;              /* malloc'd string for system command */
+
+    len = strlen(d);
+    if ((s = malloc(len + 34)) == NULL)
+      return 127;
+
+    system(strcat(strcpy(s, "set prot=(o:rwed) "), d));
+    r = delete(d);
+    free(s);
+    return r;
+}
diff --git a/vms/zip.opt b/vms/zip.opt
new file mode 100644 (file)
index 0000000..7a4a872
--- /dev/null
@@ -0,0 +1 @@
+Ident = "Zip 3.0"
diff --git a/vms/zip_cli.cld b/vms/zip_cli.cld
new file mode 100644 (file)
index 0000000..38fc421
--- /dev/null
@@ -0,0 +1,168 @@
+       Module          ZIP_CLITABLE
+       Ident           "03-001"
+
+Define Verb            ZIP
+       Parameter       P1, Label=ZIPFILE, Prompt="Zip file"
+       Parameter       P2, Label=INFILE, VALUE(list), Prompt="Files to Zip"
+       Qualifier       DELETE, NonNegatable
+       Qualifier       FRESHEN, NonNegatable
+       Qualifier       MOVE, NonNegatable
+       Qualifier       UPDATE, NonNegatable
+       Qualifier       EXCLUDE, NonNegatable, VALUE(required,list)
+       Qualifier       INCLUDE, NonNegatable, VALUE(required,list)
+       Qualifier       EXLIST, NonNegatable, VALUE(type=$FILE,required)
+       Qualifier       INLIST, NonNegatable, VALUE(type=$FILE,required)
+       Qualifier       ADJUST_OFFSETS, NonNegatable
+       Qualifier       APPEND, NonNegatable
+       Qualifier       BATCH, NonNegatable, VALUE(type=$FILE)
+       Qualifier       BEFORE, NonNegatable, VALUE(type=$DATETIME)
+       Qualifier       COMMENTS, NonNegatable,
+                       VALUE(list,type=COMMENTS_KEYWORDS)
+       Qualifier       COMPRESSION, NonNegatable, VALUE(type=COMPRESS_OPTS)
+       Qualifier       COPY_ENTRIES, NonNegatable
+       Qualifier       DESCRIPTORS, NonNegatable
+       Qualifier       DIFFERENCE, NonNegatable
+       Qualifier       DIRNAMES, Negatable, Default
+       Qualifier       DISPLAY, NonNegatable,
+                        VALUE(type=DISPLAY_KEYWORDS, required, list)
+       Qualifier       DOT_VERSION, NonNegatable
+       Qualifier       ENCRYPT, Negatable, VALUE
+       Qualifier       EXTRA_FIELDS, Negatable, VALUE(type=EXTRA_OPTS)
+       Qualifier       FILESYNC, NonNegatable
+       Qualifier       FIX_ARCHIVE, NonNegatable, VALUE(type=FIX_OPTS)
+       Qualifier       FULL_PATH, Negatable, Default
+       Qualifier       GROW, NonNegatable
+       Qualifier       HELP, NonNegatable, VALUE(type=HELP_OPTS)
+       Qualifier       JUNK, NonNegatable
+       Qualifier       KEEP_VERSION, Negatable
+       Qualifier       LATEST, NonNegatable
+       Qualifier       LEVEL, VALUE(type=$NUMBER,required)
+       Qualifier       LICENSE, NonNegatable
+       Qualifier       LOG_FILE, NonNegatable,
+                       VALUE(list, required, type=LOG_OPTS)
+       Qualifier       MUST_MATCH, NonNegatable
+       Qualifier       OUTPUT, VALUE(required,type=$FILE)
+       Qualifier       PATTERN_CASE, NonNegatable, VALUE(type=PATT_CASE_OPTS)
+       Qualifier       PAUSE, Negatable
+       Qualifier       PKZIP, Negatable
+       Qualifier       PRESERVE_CASE, Negatable,
+                        VALUE(type=PRES_CASE_OPTS, list)
+       Qualifier       QUIET, NonNegatable
+       Qualifier       RECURSE, Negatable, VALUE(type=RECURSE_OPTS)
+       Qualifier       SHOW, NonNegatable,
+                        VALUE(type=SHOW_KEYWORDS, required, list)
+       Qualifier       SINCE, NonNegatable, VALUE(type=$DATETIME)
+       Qualifier       SPLIT, NonNegatable,
+                       VALUE(list, required, type=SPLIT_OPTS)
+       Qualifier       STORE_TYPES, NonNegatable, VALUE(required,list)
+       Qualifier       SYMLINKS, NonNegatable
+       Qualifier       TEMP_PATH, VALUE(required,type=$FILE)
+       Qualifier       TEST, NonNegatable, VALUE(type=TEST_OPTS)
+       Qualifier       TRANSLATE_EOL, NonNegatable,
+                       VALUE(type=EOL_KEYWORDS)
+       Qualifier       UNSFX, NonNegatable
+       Qualifier       VERBOSE, NonNegatable,
+                        VALUE(type=VERBOSE_OPTS, list)
+       Qualifier       VMS, NonNegatable, VALUE(type=VMS_OPTS)
+       Qualifier       WILDCARD, VALUE(type=WILDCARD_OPTS)
+       Qualifier       YYZ_ZIP, NonNegatable, Default
+       Qualifier       ZIP64, NonNegatable
+
+       Disallow        COPY_ENTRIES and (DELETE or FRESHEN or UPDATE)
+       Disallow        DELETE and (COPY_ENTRIES or FRESHEN or UPDATE)
+       Disallow        FRESHEN and (COPY_ENTRIES or DELETE or UPDATE)
+       Disallow        UPDATE and (COPY_ENTRIES or DELETE or FRESHEN)
+       Disallow        DIFFERENCE and (neg OUTPUT)
+       Disallow        DIFFERENCE and
+                        (FIX_ARCHIVE.NORMAL or FIX_ARCHIVE.FULL or
+                        COPY_ENTRIES or DELETE)
+       Disallow        APPEND and GROW
+       Disallow        FIX_ARCHIVE.NORMAL and FIX_ARCHIVE.FULL
+       Disallow        (FIX_ARCHIVE.NORMAL or FIX_ARCHIVE.FULL) and
+                        (neg OUTPUT)
+       Disallow        TRANSLATE_EOL.LF and TRANSLATE_EOL.CRLF
+       Disallow        FULL_PATH and JUNK
+       Disallow        RECURSE.PATH and RECURSE.FILENAMES
+       Disallow        (neg EXTRA_FIELDS) and
+                        (KEEP_EXISTING or EXTRA_FIELDS.NORMAL)
+
+Define Type            PATT_CASE_OPTS
+       Keyword         BLIND
+       Keyword         SENSITIVE, DEFAULT
+
+Define Type            COMMENTS_KEYWORDS
+       Keyword         ARCHIVE, DEFAULT
+       Keyword         FILES
+       Keyword         ZIP_FILE
+
+Define Type            COMPRESS_OPTS
+       Keyword         BZIP2
+       Keyword         DEFLATE, DEFAULT
+       Keyword         STORE
+
+Define Type            DISPLAY_KEYWORDS
+       Keyword         BYTES
+       Keyword         COUNTS
+       Keyword         DOTS, VALUE
+       Keyword         GLOBALDOTS
+       Keyword         USIZE
+       Keyword         VOLUME
+
+Define Type            EOL_KEYWORDS
+       Keyword         LF, DEFAULT
+       Keyword         CRLF
+
+Define Type            EXTRA_OPTS
+       Keyword         NORMAL, DEFAULT
+       Keyword         KEEP_EXISTING
+
+Define Type            FIX_OPTS
+       Keyword         NORMAL, DEFAULT
+       Keyword         FULL
+
+Define Type            HELP_OPTS
+       Keyword         NORMAL, DEFAULT
+       Keyword         EXTENDED
+
+Define Type            LOG_OPTS
+       Keyword         APPEND, Negatable
+       Keyword         INFORMATIONAL, Negatable
+       Keyword         FILE, NonNegatable, VALUE(required, type=$FILE)
+
+Define Type            PRES_CASE_OPTS
+       Keyword         NOODS2
+       Keyword         NOODS5
+       Keyword         ODS2
+       Keyword         ODS5
+
+Define Type            RECURSE_OPTS
+       Keyword         PATH, DEFAULT
+       Keyword         FILENAMES
+
+Define Type            SHOW_KEYWORDS
+       Keyword         COMMAND
+       Keyword         DEBUG
+       Keyword         FILES
+       Keyword         OPTIONS
+
+Define Type            SPLIT_OPTS
+       Keyword         BELL, Negatable
+       Keyword         PAUSE, Negatable
+       Keyword         SIZE, VALUE(required)
+       Keyword         VERBOSE, Negatable
+
+Define Type            TEST_OPTS
+       Keyword         UNZIP, VALUE(required)
+
+Define Type            VERBOSE_OPTS
+       Keyword         NORMAL, DEFAULT
+       Keyword         MORE
+       Keyword         DEBUG
+       Keyword         COMMAND
+
+Define Type            VMS_OPTS
+       Keyword         ALL
+
+Define Type            WILDCARD_OPTS
+       Keyword         NOSPAN
+
diff --git a/vms/zip_cli.help b/vms/zip_cli.help
new file mode 100644 (file)
index 0000000..1bb39c2
--- /dev/null
@@ -0,0 +1,1636 @@
+.!
+.!  File:       ZIP_CLI.HELP
+.!
+.!  Author:     Christian Spieler
+.!
+.!  Date:       05 Dec 95 (orig. ZIP.RNH, 22 Oct 91)
+.!
+.!  Description:
+.!
+.!      TPU-processable source file to produce VMS on-line help for
+.!      portable Zip.  Adapted from ZIP.RNH, originally based on
+.!      ZIP.MAN (now MANUAL).
+.!
+.!      To build:
+.!          $ EDIT /TPU/NOSECTION/NODISPLAY/COMMAND=CVTHELP.TPU ZIP_CLI.HELP
+.!          $ RUNOFF /OUT=ZIP_CLI.HLP ZIP_CLI.RNH
+.!          $ LIBR /HELP/INSERT libr ZIP_CLI
+.!
+.!  Modification history:
+.!
+.!      01-001          Christian Spieler       05-DEC-1995 02:02
+.!              Genesis.
+.!      01-002          Christian Spieler       20-JAN-1996 03:09
+.!              Modified /LICENSE and /VERBOSE descriptions.
+.!      01-003          Christian Spieler       11-FEB-1996 23:09
+.!              Added /[NO]EXTRA_FIELDS description.
+.!      01-004          Christian Spieler       11-MAR-1996 20:08
+.!              Removed /ENCRYPT=VERIFY option.
+.!      01-005          Christian Spieler       11-MAY-1996 23:08
+.!              Corrected/enhanced info about how to get help on UNIX options.
+.!      01-006          Christian Spieler       21-JUL-1997 22:26
+.!              Updated for new options of Zip 2.2.
+.!      01-006          Christian Spieler       14-OCT-1997 22:04
+.!              Cleanups for Zip 2.2 release (no version change).
+.!      01-007          Steven Schweda          15-MAY-2007
+.!              Zip 3.0.
+.!      01-007          Ed Gordon               15-MAY-2007
+.!              Minor updates to Zip 3.0 help.
+.!
+<INIT>
+<MAIN>
+ZIP
+
+Zip is a compression and file packaging utility for several operating
+systems, including UNIX, VMS,  MSDOS, OS/2, Windows 9x/NT/XP, Minix,
+Atari, Macintosh, Amiga, and Acorn RISC OS.  It is analogous to a
+combination of tar and compress and is compatible with PKZIP (Phil
+Katz's ZIP) for MSDOS systems.
+
+Zip is useful for packaging a set of files for distribution, for
+archiving files, and for saving disk space by temporarily compressing
+unused files or directories.  A companion program, UnZip, unpacks Zip
+archives.
+
+For brief help on Zip or UnZip, run the program without specifying any
+parameters on the command line.
+
+This description covers the Zip program which uses a VMS-style CLI
+command line.  The VMS CLI Zip program also accepts UNIX-style "-opt"
+options, but a separate Zip program is available which provides only a
+UNIX-style  command line, and it has its own documentation.  Refer to
+the Zip installation instructions for details.
+
+<FORMAT>
+ZIP [/options] archive inpath, inpath ...
+
+.!\f
+
+<TOPIC>
+Basic_Usage
+
+<FORMAT>
+ZIP [/options] archive inpath, inpath ...
+
+The default action of Zip is to add or replace entries in "archive" from
+the list of "inpath" file specifications, which can include directories
+and file names with VMS-style wildcards.  If /BATCH is specified, Zip
+will read file specifications from a list file or from SYS$INPUT
+(stdin).
+
+With SET PROCESS /PARSE_STYLE = EXTENDED (available on recent non-VAX
+systems), Zip preserves the case of the command line.  Otherwise, mixed-
+or upper-case arguments (file names) must be quoted.  Examples in this
+document generally do not show this quotation, so VAX and /PARSE_STYLE =
+TRADITIONAL users (that is, troglodytes) will need to add quotation
+where needed when working with these examples.
+
+General
+
+Zip reads one or more files, compresses the data (normally), and stores
+the compressed information into a single Zip archive file, along with
+information about each file (name, path, date and time of last
+modification, protection, and check information to verify file
+integrity).  On a VMS system, Zip can also save VMS/RMS file attributes,
+allowing UnZip to restore the files without loss of important file
+attributes.  Zip can pack an entire directory structure into a Zip
+archive with a single command.
+
+Compression
+
+Compression ratios of 2:1 to 3:1 are common for text files.  Zip has one
+standard compression method ("deflate") and can also store files without
+compression.  Zip (and UnZip) may be built with optional support for the
+bzip2 compression method.  Then, the user may select bzip2 compression
+instead of the default "deflate" method.  Zip automatically chooses
+simple storage over compression for a file, if the specified compression
+method does not actually compress the data in that file.
+
+Compatibility
+
+Zip and UnZip can work with archives produced by PKZIP (supporting most
+PKZIP features up to PKZIP version 4.6), and PKZIP and PKUNZIP can work
+with archives produced by Zip (with some exceptions, notably streamed
+archives, but recent changes in the .ZIP file standard may facilitate
+better compatibility).  Zip version 3.0 is compatible with PKZIP 2.04
+and also supports the Zip64 extensions of PKZIP 4.5 which allows
+archives as well as files to exceed the previous 2 GB limit (4 GB in
+some cases).  Zip also supports bzip2 compression if the bzip2 library
+is included when Zip is built.  Note that PKUNZIP 1.10 cannot extract
+files produced by PKZIP 2.04 or Zip 3.0.  You must use PKUNZIP 2.04g or
+UnZip 5.0p1 (or later versions) to extract them.
+
+Large Archives and Zip64
+
+Where the operating system and C run-time support allow, Zip 3.0 and
+UnZip 6.0 (and later versions) support large files (input and archive),
+using the Zip64 extensions to the original .ZIP file format.  On VMS,
+this genarally means non-VAX systems with VMS V7.2 or later (perhaps
+requiring a C RTL ECO before VMS V7.3-2).
+
+Zip automatically uses the Zip64 extensions when a file 4 GB or larger
+is added to an archive, an archive containing a Zip64 entry is updated
+(if the resulting archive still needs Zip64), the size of the archive
+will exceed 4 GB, or when the number of entries in the archive will
+exceed about 64K.  Zip64 is also used for archives streamed to a
+non-seekable output device.  You must use a 4.5 compatible UnZip to
+extract files using the Zip64 extensions such as UnZip 6.0 or later.
+
+In addition, streamed archives, entries encrypted with standard
+encryption, or split archives created with the pause option may not be
+compatible with PKZIP as data descriptors are used, and PKZIP at the
+time of this writing does not support data descriptors (but recent
+changes in the PKWare published .ZIP file standard now include some
+support for the data descriptor format Zip uses).
+
+<TOPIC>
+More_Usage
+
+Here is a very simple example of Zip use:
+
+<LITERAL>
+|  zip stuff.zip *.*
+<LARETIL>
+
+This will create the Zip archive "stuff.zip" (assuming it does not
+already exist) and put all the (non-directory) files (";0") from the
+current default directory into "stuff.zip" in a compressed form.  The
+archive is opened using a default file specification of
+"SYS$DISK:[].zip", so specifying "stuff" as the archive name would also
+create (or use an existing) "stuff.zip", but specifying "stuff.other"
+would give you that name.  In general, Zip doesn't care about the type
+in the file specification, but for split archives (archives split over
+multiple files), the user should normally specify a type-less name,
+because Zip will normally generate sequentially numbered types ".z01",
+".z02", and so on for the early splits, and then the required ".zip" for
+the last split.  These file types are required by the Zip standard for
+split archives.
+
+Standard VMS wildcard expansion ($SEARCH) is used to interpret the
+"inpath" file and directory specifications, like the "*.*" in this
+example.
+
+On VMS, the most natural way to archive an entire directory tree is to
+use a directory-depth wildcard ("[...]").  For example:
+
+<LITERAL>
+|  zip foo [...]*.*
+<LARETIL>
+
+This will create the file "foo.zip" containing all the files (";0") and
+directories in and below the current default directory.  A more
+UNIX-like way to do this would be to use the /RECURSE option:
+
+<LITERAL>
+|  zip /recurse foo *.*
+<LARETIL>
+
+Zip avoids including its own output files when selecting files to
+include in the archive, so it should be safe, as in this case, to create
+the archive in the same drectory as the input files.
+
+One or more specific files, directories, or subdirectories may also be
+specified:
+
+<LITERAL>
+|  zip foo.zip readme.txt, [www...]*.*, [.ftp...]*.*, -
+|   [.src]*.h, [.src]*.c
+<LARETIL>
+
+For security reasons, paths in Zip archives are always stored as
+relative paths, so some care is needed when creating an archive so that
+it will create the intended directory structure when UnZip is used to
+unpack it.
+
+To use /RECURSE with a specific directory, the name of the directory
+file itself must be specified:
+
+<LITERAL>
+|  zip /recurse foo.zip [000000]www.dir, ftp.dir
+<LARETIL>
+
+You may want to make an archive that contains the files in [.foo], but
+not record the directory name, "foo".  You can use the /JUNK (junk path)
+option to leave off the path:
+
+<LITERAL>
+|  zip /junk foo [.foo]*.*
+<LARETIL>
+
+If you are short on disk space, you might not have enough room to hold
+both the original directory and the corresponding compressed Zip
+archive.  In this case, you can create the archive in steps, and use the
+-m option.  For example, if [.foo] contains the subdirectories [.tom],
+[.dick], and [.harry], you could:
+
+<LITERAL>
+|  zip /move foo [.foo.tom...]*.*
+|  zip /move foo [.foo.dick...]*.*
+|  zip /move foo [.foo.harry...]*.*
+<LARETIL>
+
+The first command would create foo.zip, and the next two would add to
+it.  The /MOVE option will cause Zip to delete all files added to the
+archive after making or updating foo.zip.  No deletions will be done
+until the Zip operation has completed with no errors.  This option is
+obviously dangerous and should be used with care, but it does reduce the
+need for free disk space.  When /MOVE is used, the /TEST option is
+recommended and will test the resulting archive before deleting the
+input files.
+
+If a file specification list is too long to fit conveniently on the Zip
+command line, the /BATCH option can be used to cause Zip to read a list
+of file specifications from a file or from SYS$INPUT (stdin).  If a DCL
+command procedure is used, the names can be specified in the procedure:
+
+<LITERAL>
+|  $ zip foo /batch
+|  $ deck
+|  file_spec_1
+|  file_spec_2
+|  file_spec_3
+|  $ eod
+<LARETIL>
+
+The file specifications can also be put into a separate file, and fed
+into Zip by specifying that file as "/BATCH = list_file", or by
+explicitly defining SYS$INPUT, or by using PIPE.  For example, with the
+list in foo.zfl:
+<LITERAL>
+|  zip foo /batch = foo.zfl
+<LARETIL>
+or:
+<LITERAL>
+|  define /user_mode sys$input foo.zfl
+|  zip foo /batch
+<LARETIL>
+or:
+<LITERAL>
+|  pipe type foo.zfl | zip foo /batch
+<LARETIL>
+
+If Zip is not able to read a file, it issues a warning but continues.
+See the /MUST_MATCH option for more on how Zip handles patterns that are
+not matched and files that are not readable.  If some files were
+skipped, a warning is issued at the end of the Zip operation noting how
+many files were read and how many skipped.
+<TOPIC>
+Environment
+
+A user can specify default command-line options and arguments by
+defining an "environment variable" (that is, a logical name or DCL
+symbol), "ZIP_OPTS" or "ZIPOPT", to specify them.  If both "ZIP_OPTS"
+and "ZIPOPT" are specified, the definition of "ZIPOPT" prevails.
+
+UNIX-style command-line options are required in these variables, even
+for the VMS CLI Zip program.  For details, see the help topic
+UNIX_Options, or the separate Zip help for the UNIX-style command line.
+
+The C RTL function getenv() is used to sense these variables, so its
+behavior determines what happens if both a logical name and a symbol are
+defined.  As of VMS V7.3, a logical name supercedes a symbol.
+
+The "zip /VERBOSE" report should show the perceived settings of these
+variables.
+
+For example, the following will cause Zip to skip directories, include
+VMS portable attribute information, and perform all operations at
+quiet-level 1 by default:
+
+<LITERAL>
+|  $ define ZIP_OPTS "-qDV"
+<LARETIL>
+
+Note that the quotation marks here are required to preserve lowercase
+options (opposite of the command-line behavior).
+
+<TOPIC>
+Exit_Status
+
+On VMS, Zip's UNIX-style exit values are mapped into VMS-style status
+codes with facility code 1955 = %x7A3, and with the inhibit-message
+(%x10000000) and facility-specific (%x00008000) bits set:
+
+<LITERAL>
+|     %x17A38001                        normal exit
+|     %x17A38000+ 16* Zip_error_code    warnings
+|     %x17A38002+ 16* Zip_error_code    normal errors
+|     %x17A38004+ 16* Zip_error_code    fatal errors
+<LARETIL>
+
+Note that multiplying the UNIX-style Zip error code by 16 places it
+conveniently in the hexadecimal representation of the VMS exit code,
+"__" in %x17A38__s, where "s" is the severity code.  For example, a
+truncated archive might cause Zip error code 2, which would be
+transformed into the VMS exit status %x17A38024.
+
+The Zip VMS exit codes include severity values which approximate those
+defined by PKWARE, as shown in the following table:
+
+<LITERAL0>
+|  VMS      Zip err
+|severity    code     Error description
+|---------+---------+----------------------------------------------
+|Success       0      (OK) Normal; no errors or warnings detected.
+|Fatal         2      (EOF) Unexpected end of archive.
+|Error         3      (FORM) A generic error in the archive format
+|                     was detected.  Processing may have completed
+|                     successfully anyway;  some  broken  archives
+|                     created by other archivers have simple work-
+|                     arounds.
+|Fatal         4      (MEM) Zip was unable to allocate memory for
+|                     one or more buffers during program initializ-
+|                     ation.
+|Fatal         5      (LOGIC) A severe error in the archive format
+|                     was detected.  Processing  probably  failed
+|                     immediately.
+|Error         6      (BIG) Entry too large to  split,  read,  or
+|                     write.
+|Error         7      (NOTE) Invalid comment format.
+|Fatal         8      (TEST) Zip -T failed or out of memory.
+|Error         9      (ABORT) The user aborted  zip  prematurely
+|                     with  control-C (or equivalent).
+|Fatal        10      (TEMP) Zip  encountered an error while using
+|                     a tempfile.
+|Fatal        11      (READ) Read or seek error.
+|Warning      12      (NONE) Zip has nothing to do.
+|Error        13      (NAME) Missing or empty zip file.
+|Fatal        14      (WRITE) Error writing to a file.
+|Fatal        15      (CREAT) Zip was unable to create a file to
+|                     write to.
+|Error        16      (PARMS) Bad command line parameters.
+|Error        18      (OPEN) Zip could not open a specified file
+|                     to read.
+|Fatal        19      (COMPERR) Zip was built with options not
+|                     supported on this system.
+|Fatal        20      (ZIP64) Attempt to read unsupported Zip64
+|                     archive.
+<0LARETIL>
+
+<TOPIC>
+File_Names
+
+Zip deals with file names in the system file system and with file names
+in Zip archives.  File names in a Zip archive are stored in a UNIX-like
+path-name format.  For example, a VMS file specification like this:
+
+<LITERAL>
+[.zip30.vms]descrip.mms
+<LARETIL>
+
+could appear in a Zip archive as:
+
+<LITERAL>
+zip30/vms/descrip.mms
+<LARETIL>
+
+For security reasons, paths in Zip archives are always stored as
+relative paths, so an absolute VMS directory specification will be
+transformed to a relative path in the archive (that is, no leading "/").
+For example, the following absolute directory specification would give
+the same archive path as the previous (relative) example:
+
+<LITERAL>
+[zip30.vms]descrip.mms
+<LARETIL>
+
+Also, device names are dropped, so the following file specification
+would also give the same archive path:
+
+<LITERAL>
+sys$sysdevice:[zip30.vms]descrip.mms
+<LARETIL>
+
+If an archive is intended for use with PKUNZIP under MSDOS, then the
+/PKZIP option should be used to attempt to adjust the names and paths to
+conform to MSDOS character-set and length limitations, to store only the
+MSDOS file attributes (just the owner:write attribute from VMS), and to
+mark the entry as made under MSDOS (even though it wasn't).
+
+Note that file specifications in the file system must be specified using
+VMS notation, but file names in an archive must be specified using the
+UNIX-like notation used in the archive.  For example, where a BACKUP
+command might look like this:
+
+<LITERAL>
+$ back [.zip30...]*.* /excl = [...vms]*.c stuff.bck /save
+<LARETIL>
+
+a corresponding Zip command might look like this:
+
+<LITERAL>
+$ zip /exclude = "*/vms/*.c" stuff.zip [.zip30...]*.*
+<LARETIL>
+
+because the files to be added to the Zip archive are specified using VMS
+file specifications, but the /EXCLUDE option excludes names based
+on their archive path/file names.  Options dealing with archive names
+include /COPY_ENTRIES, /DELETE, /EXCLUDE, /INCLUDE, and
+/RECURSE=FILENAMES.
+
+Note that a UNIX-like path specification must be quoted, or else the
+slashes ("/") will confuse the command-line interpreter, causing errors
+like "%CLI-W-IVQUAL, unrecognized qualifier - check validity, spelling,
+and placement".
+
+Note: By default, on VMS, archive name pattern matching (/COPY_ENTRIES,
+/DELETE, /EXCLUDE, /INCLUDE, and /RECURSE=FILENAMES) is case sensitive,
+even when the file system is not case sensitive (or even case
+preserving).  This allows accurate matching of mixed-case names in an
+archive which may have been created on a system with a case sensitive
+file system, but it can involve extra effort on VMS, where it may be
+necessary to use unnatural case names (or the same names in multiple
+cases, like "*.obj *.OBJ") for this kind of pattern matching to give the
+desired behavior.  If completely case-blind pattern matching behavior is
+desired, specify the /PATTERN_CASE=BLIND option.
+<TOPIC>
+Modes_of_Operation
+
+Zip supports two distinct types of command modes, external and
+internal.  The external modes (update, grow, and freshen) read files
+from the file system (as well as from an existing archive) while the
+internal modes (delete and copy) operate exclusively on entries in an
+existing archive.
+
+<LITERAL>
+  /UPDATE
+<LARETIL>
+
+Update existing entries and add new files.  If the archive does not
+exist, create it.  This is the default mode, so /UPDATE is optional.
+
+<LITERAL>
+  /GROW
+<LARETIL>
+
+Grow (append to) the specified Zip archive, instead of creating a new
+one.  If this operation fails, Zip attempts to restore the archive to
+its original state.  If the restoration fails, the archive might become
+corrupted.  This option is ignored when there's no existing archive or
+when at least one archive member must be updated or deleted.
+
+<LITERAL>
+  /FRESHEN
+<LARETIL>
+
+Update existing entries in an existing archive.  Does not add new files
+to the archive.
+
+<LITERAL>
+  /DELETE
+<LARETIL>
+
+Delete entries from an existing archive.
+
+<LITERAL>
+  /COPY_ENTRIES
+<LARETIL>
+
+Select entries in an existing archive and copy them to a new archive.
+Copy mode is like update mode, but entries in the existing archive are
+selected by command line patterns rather than files from the file system
+and it uses the /OUTPUT option to write the resulting archive to a new
+file rather than updating the existing archive, leaving the original
+archive unchanged.
+
+<LITERAL>
+  /DIFFERENCE
+<LARETIL>
+
+Create an incremental backup-style archive, where the resulting archive
+will contain all new and changed files since the original archive was
+created.  For this to work, the input file list and current directory
+must be the same as during the original Zip operation.
+
+For example, if the existing archive was created using
+
+<LITERAL>
+zip foo_full.zip [.foo...]*.*
+<LARETIL>
+
+from just above the foo directory, then the command (also from just
+above the foo directory):
+
+<LITERAL>
+zip /difference /output = foo_incr.zip foo_full.zip [.foo...]*.*
+<LARETIL>
+
+creates the archive foo_incr.zip with just the files not in foo_full.zip
+and the files where the size or date-time of the files does not match
+that in foo_full.zip.  Note that in the "ZIP /DIFFERENCE" operation, the
+original full archive is specified as the input archive, and the /OUTPUT
+option is used to specify the new (incremental) output archive.
+
+<LITERAL>
+  /FILESYNC
+<LARETIL>
+
+Delete entries in the archive that do not match files on the OS.
+Normally files already in an archive that are not updated remain
+in the archive unchanged.  The /FILESYNC option deletes files in
+the archive that are not matched during the directory scan,
+resulting in the archive being updated having the same contents
+as a new archive would.  If much of the archive will remain
+unchanged, this can be faster than creating a new archive as
+copying entries is faster than compressing and adding new files.
+
+Normally, when updating an archive using relative file specifications
+("[]", "[.xxx]", and so on), it helps to have the same default directory
+as when the archive was created, but this is not a strict requirement.
+
+<TOPIC>
+Self_Extracting_Archives
+
+A self-extracting archive (SFX) comprises a normal Zip archive appended
+to a special UnZip program (such as UNZIPSFX_CLI.EXE) for the intended
+target system.
+
+The UnZip distribution includes a VMS command procedure,
+[,vms]makesfx.com, which can be used directly or adapted to create an
+SFX archive from a normal Zip archive.
+
+The .ZIP file format includes offsets to data structures in the archive,
+and these offsets are measured from the start of the archive file.
+Appending an archive to an UnZip SFX executable effectively moves the
+start of the archive file.  That makes the original offsets wrong, and
+that will cause the UnZip SFX program to emit warning messages when it
+tries to unpack the archive.  Zip /ADJUST_OFFSETS can be used to adjust
+these offsets in a self-extracting archive.  For example, to adjust the
+offsets in foo.sfx_exe:
+
+<LITERAL>
+|  zip /adjust_offsets foo.sfx_exe
+<LARETIL>
+
+Similarly, the UnZip SFX program can be removed from a self-extracting
+archive (and the offsets in the archive restored) using the /UNSFX
+option.  For example:
+
+<LITERAL>
+|  zip /unsfx foo.sfx_exe
+<LARETIL>
+
+Note that a self-extracting archive contains a normal Zip archive, and a
+normal UnZip program can be used to expand it in the normal way.  You
+may get a warning about extra bytes at the beginning of the archive (the
+UnZip SFX program), but UnZip should work properly after that.  This
+allows data in a self-extracting archive to be accessed on any system,
+not just the target system where its embedded UnZip SFX program runs.
+
+<TOPIC>
+Split_Archives
+
+Beginning with version 3.0, Zip supports split archives.  A split
+archive is one which is divided into multiple files, usually to allow it
+to be stored on multiple storage media (floppy diskettes, CD-ROMs, or
+the like) when a single medium would be too small to contain the whole
+archive.  (Note that split archives are not just unitary archives split
+into pieces, as the .ZIP file format includes offsets to data structures
+in the archive, and for a split archive these are based on the start of
+each split, not on the start of the whole archive.  Concatenating the
+pieces will invalidate these offsets, but UnZip can usually deal with
+it.  Zip will usually refuse to process such a spliced archive unless
+the /FIX = FULL option is used to fix the offsets.)
+
+For a split archive with, say, 20 split files, the files are typically
+named ARCHIVE.z01, ARCHIVE.z02, ..., ARCHIVE.z19, ARCHIVE.zip, where
+"ARCHIVE" is the archive name specified by the user on the Zip command
+line.  Note that the last split file is the ".zip" file.  In contrast,
+"spanned" archives are the original multi-disk archive generally
+requiring floppy disks and using volume labels to store disk numbers.
+Zip supports split archives but not spanned archives, though a procedure
+exists for converting split archives of the right size to spanned
+archives.  The reverse is also true, where each file of a spanned
+archive can be copied in order to files with the above names to create a
+split archive.
+
+<QUALIFIERS>
+<QUALIFIER>
+/ADJUST_OFFSETS
+
+/ADJUST_OFFSETS
+
+Adjust internal offsets of the Zip archive members after some data
+(e.g. a SFX executable stub) has been prepended to the archive file.
+<QUALIFIER>
+/APPEND
+
+/APPEND
+/GROW
+
+Grow (append to) the specified Zip archive, instead of creating a new
+one.  If this operation fails, Zip attempts to restore the archive to
+its original state.  If the restoration fails, the archive might become
+corrupted.  This option is ignored when there's no existing archive or
+when at least one archive member must be updated or deleted.
+
+See also /DELETE /DIFFERENCE, /FRESHEN, /UPDATE.
+<QUALIFIER>
+/BATCH
+
+/BATCH[=list_file]
+
+Read input file specifications (inpaths) from "list_file" (one per
+line).  The list_file defaults to SYS$INPUT.
+<QUALIFIER>
+/BEFORE
+
+/BEFORE=VMS_date_time
+
+Restricts the files by date-time when adding, updating, or freshening an
+archive.  Only files with modification date-times earlier than the
+specified date-time are accepted.
+
+See also /SINCE.
+<QUALIFIER>
+/COMMENTS
+
+/COMMENTS[=KEYWORD[,KEYWORD]]
+
+Add comments to the Zip archive.
+
+<LITERAL>
+|  ARCHIVE   Add/replace the multi-line archive comment. (default)
+|  FILES     Add file comment to each updated/added archive member.
+<LARETIL>
+
+The Zip program prompts for each comment to be added, which makes sense
+only if Zip is run interactively.
+
+The one-line file (archive member) comments are terminated by typing
+<Return>.  To skip a file comment, just type <Return> without entering
+any further characters.
+
+The Zip archive comment may be multi-line. The comment is ended by a
+line containing just a period, or by an end-of-file character (CTRL/Z).
+<QUALIFIER>
+/COMPRESSION
+
+/COMPRESSION = {BZIP2|DEFLATE|STORE}
+
+Specify the compression method to be used when adding or updating files
+in an archive.  STORE disables compression (like /LEVEL = 0).  Default:
+/COMPRESSION = DEFLATE.
+
+Zip can archive files with or without compression.  The standard
+compression method ("deflate") is compatible with all UnZip versions
+(except really old ones that only understand the "store" method).
+Current Zip and UnZip versions may be built with optional support for
+the bzip2 compression method.  (The bzip2 method can compress better,
+especially when compressing highly redundant files, but uses more CPU
+time, and requires an UnZip which includes the optional bzip2 support.
+See the installation instructions for details on adding bzip2
+compression support at build time.)
+<QUALIFIER>
+/COPY_ENTRIES
+
+/COPY_ENTRIES
+
+Select entries in an existing archive and copy them to a new archive.
+Copy mode is like update mode, but entries in the existing archive are
+selected by command line patterns rather than files from the file system
+and it uses the /OUTPUT option to write the resulting archive to a new
+file rather than updating the existing archive, leaving the original
+archive unchanged.
+<QUALIFIER>
+/DELETE
+
+/DELETE
+
+Delete entries from archive.
+
+See also /DIFFERENCE, /FRESHEN, /GROW, /UPDATE.
+<QUALIFIER>
+/DIFFERENCE
+
+/DIFFERENCE
+
+Create an incremental backup-style archive, where the resulting archive
+will contain all new and changed files since the original archive was
+created.  For this to work, the input file list and current directory
+must be the same as during the original Zip operation.
+
+See also /DELETE, /FRESHEN, /GROW, /UPDATE.
+<QUALIFIER>
+/DIRNAMES
+
+/DIRNAMES (default)
+/NODIRNAMES
+
+Store directory entries in the archive.
+<QUALIFIER>
+/DISPLAY
+
+/DISPLAY=(KEYWORD[,KEYWORD[...]])
+
+Enable display of progress messages.
+<LITERAL>
+|  BYTES        Running count of bytes processed and bytes to go.
+|  COUNTS       Running count of entries done and entries to go.
+|  DOTS = size  Dots every <size> MB while processing files.
+|               (0: no dots.)
+|  GLOBALDOTS   Progress dots reflect the whole archive instead of each
+|               file.
+|  USIZE        Uncompressed size of each entry.
+|  VOLUME       Display the volume (disk) number each entry is being
+|               written to.
+<LARETIL>
+
+The default is a dot every 10 MB of input file processed.  The /VERBOSE
+option also displays dots and used to at a higher rate than this (at the
+same rate as in previous versions of Zip) but this rate has been changed
+to the new 10 MB default, and is also controlled by /DISPLAY=DOTS=size.
+<QUALIFIER>
+/DOT_VERSION
+
+/DOT_VERSION
+
+Directs Zip to retain VMS file version numbers on names in an archive,
+but as ".nnn" instead of ";nnn".  By default, for compatibility
+with non-VMS systems, Zip strips VMS file version numbers from the names
+stored in an archive.  Thus, without /DOT_VERSION or /KEEP_VERSION, a
+version number wildcard (";*") can cause errors when multiple versions
+of a single file are treated as multiple files with the same name.
+
+See also /KEEP_VERSION.
+<QUALIFIER>
+/ENCRYPT
+
+/ENCRYPT[="password"]
+
+Encrypt new or updated archive entries using a password which is
+supplied by the user interactively on the terminal in response to a
+prompt.  (The password will not be echoed.)  If SYS$COMMAND is not a
+terminal, Zip will exit with an error.  The password is verified before
+being accepted.
+
+You may specify the password on the command line, although we do not
+recommend it because THIS IS INSECURE.  Remember to enclose the password
+string with quotation marks ("pass word"), to prevent automatic
+conversion to upper case or misinterpretation of punctuation characters
+by DCL.
+
+Because standard Zip encryption is weak, where security is truly
+important, use a strong encryption program, such as Pretty Good Privacy
+(PGP) or GNU Privacy Guard (GnuPG), on an archive instead of standard
+Zip encryption.  A stronger encryption method, such as AES, is planned
+for Zip 3.1.
+<QUALIFIER>
+/EXCLUDE
+
+/EXCLUDE=(file[,...])
+
+A comma-separated list of files to exclude when deleting, updating, or
+adding files in the archive.  If multiple files are specified, the list
+should be enclosed in parentheses.
+<QUALIFIER>
+/EXLIST
+
+/EXLIST=list_file
+
+The files matching the filename patterns listed in "list_file" are
+excluded when deleting, updating or adding files in the archive.
+The "list_file" is a normal text file with one filename pattern entry per
+line.  The name pattern entries are recognized exactly as found in
+"list_file", including leading, embedded, and trailing whitespace or most
+control characters (with exception of LineFeed and probably CarriageReturn).
+<QUALIFIER>
+/EXTRA_FIELDS
+
+/EXTRA_FIELDS (default)
+/NOEXTRA_FIELDS
+
+Allows (or suppresses) the saving of any optional extra fields in the
+archive.  (/NOEXTRA_FIELDS conflicts with /VMS[=ALL].)
+
+The .ZIP file format allows some extra data to be stored with a file in
+the archive.  For example, where local time zone information is
+available, Zip can store UTC date-time data for files.  (Look for
+USE_EF_UT_TIME in a "zip -v" report.)  On VMS, with /VMS[=ALL], Zip will
+also store VMS-specific file attributes.  These data are packaged as
+"extra fields" in the archive.  Some extra fields are specific to a
+particular operating system (like VMS file attributes).  Large files
+(bigger than 4GB) on any OS require an extra field to hold their 64-bit
+size data.  Depending on the capabilities of the UnZip program used to
+expand the archive, these extra fields may be used or ignored when files
+are extracted from the archive.
+
+Some extra fields, like UTC date-times or VMS file attributes, are
+optional.  Others, like the Zip64 extra field which holds 64-bit sizes
+for a large file, are required.
+<QUALIFIER>
+/FILESYNC
+
+/FILESYNC
+
+Delete entries in the archive that do not match files on the OS.
+Normally when an archive is updated, new files are added and changed
+files are updated but files that no longer exist on the OS are not
+deleted from the archive.  This option enables deleting of entries that
+are not matched on the OS.  Enabling this option should create archives
+that are the same as new archives, but since existing entries are copied
+instead of compressed, updating an existing archive with /FILESYNC can
+be much faster than creating a new archive.  If few files are being
+copied from the old archive, it may be faster to create a new archive
+instead.
+
+This option deletes files from the archive.  If you need to preserve the
+original archive, make a copy of the archive first, or use the /OUTPUT
+option to output the new archive to a new file.  Even though it's
+slower, creating a new archive with a new archive name is safer, avoids
+mismatches between archive and OS paths, and is preferred.
+<QUALIFIER>
+/FIX_ARCHIVE
+
+/FIX=_ARCHIVE={NORMAL|FULL}
+
+The /FIX_ARCHIVE=NORMAL option (NORMAL is the default) can be used if
+some portions of the archive are missing, but it requires a reasonably
+intact central directory.  The input archive is scanned as usual, but
+zip will ignore some problems. The resulting archive should  be valid,
+but any inconsistent entries will be left out.
+
+If the archive is too damaged or the end (where the central directory is
+situated) has been truncated, you must use /FIX_ARCHIVE=FULL.  This is
+a change from zip 2.32, where the /FIX=NORMAL option was able to read a
+truncated archive.  The /FIX=NORMAL option now more reliably fixes
+archives with minor damage, and the /FIX=FULL option is needed to fix
+some archives where /FIX=NORMAL was sufficient before.
+
+With /FIX=FULL, the archive is scanned from the beginning and Zip scans
+for special signatures to identify the limits between the archive
+members. The /FIX=NORMAL option is more reliable if the archive is not
+too much damaged, so try this option first.
+
+Neither option will recover archives that have been incorrectly
+transferred, such as by FTP in ASCII mode instead of binary.  After the
+repair, the /TEST (-t) option of UnZip may show that some files have a
+bad CRC. Such files cannot be recovered; you can remove them from the
+archive using the /DELETE option of Zip.
+
+Because of the uncertainty of the "fixing" process, it's required
+to specify an output archive, rather than risking further damage to the
+original damaged archive.  For example, to fix the damaged archive
+foo.zip:
+
+<LITERAL>
+zip /fix_archive /output=foo_fix foo
+<LARETIL>
+
+tries to read the entries normally, copying good entries to the new
+archive foo_fix.zip.  If this doesn't work, as when the archive is
+truncated, or if some entries are missed because of bad central
+directory entries, try /FIX_ARCHIVE=FULL:
+
+<LITERAL>
+zip /fix_archive=full /output=foo_fixfix foo
+<LARETIL>
+
+and compare the resulting archive to the archive created using
+/FIX=NORMAL.  The /FIX=FULL option may create an inconsistent archive. 
+Depending on what is damaged, you can then use the /FIX=NORMAL option to
+fix that archive.
+
+A split archive with missing split files can be fixed using /FIX=NORMAL
+if you have the last split of the archive (the ".zip" file).  If this
+file is missing, you must use /FIX=FULL to fix the archive, which will
+prompt you for the splits you have.
+
+Currently, the fix options can't recover an entry which has a bad
+checksum or is otherwise damaged.
+<QUALIFIER>
+/FRESHEN
+
+/FRESHEN
+
+Update existing entries in an existing archive.  Does not add new files
+to the archive.
+
+See also /DELETE, /DIFFERENCE, /GROW, /UPDATE.
+<QUALIFIER>
+/FULL_PATH
+
+/FULL_PATH  (default)
+/NOFULL_PATH
+
+Directs Zip to store the directory part of the file names (relative to
+the current working directory) in the Zip archive.  With /NOFULL_PATH,
+Zip stores only the file names, discarding any directory information.
+<QUALIFIER>
+/GROW
+
+/GROW
+/APPEND
+
+Grow (append to) the specified Zip archive, instead of creating a new
+one.  If this operation fails, Zip attempts to restore the archive to
+its original state.  If the restoration fails, the archive might become
+corrupted.  This option is ignored when there's no existing archive or
+when at least one archive member must be updated or deleted.
+
+See also /DELETE, /DIFFERENCE, /FRESHEN, /UPDATE.
+<QUALIFIER>
+/HELP
+
+/HELP[=EXTENDED]
+
+Display Zip's help screen, including the version message.  With
+/HELP=EXTENDED, more detailed (longer) help information is shown.
+<QUALIFIER>
+/INCLUDE
+
+/INCLUDE=(file[,...])
+
+A comma-separated list of files to include when deleting, updating, or
+adding files in the archive.  If multiple files are specified, the list
+should be enclosed in parentheses.
+<QUALIFIER>
+/INLIST
+
+/INLIST=list_file
+
+The files matching the filename patterns listed in "list_file" are
+included when deleting, updating, or adding files in the archive.
+The "list_file" is a normal text file with one filename pattern entry per
+line. The name pattern entries are recognized exactly as found in
+"list_file", including leading, embedded, and trailing whitespace or most
+control characters (with exception of LineFeed and probably CarriageReturn).
+<QUALIFIER>
+/JUNK
+
+/JUNK
+/NOJUNK (default)
+
+Junk (discard) the directory part of the file names for added entries
+(do not not save the directory structure). The /JUNK qualifier is an
+alias for /NOFULL_PATH.
+<QUALIFIER>
+/KEEP_VERSION
+
+/KEEP_VERSION
+/NOKEEP_VERSION (default)
+
+Directs Zip to retain VMS file version numbers on names in an archive.
+By default, for compatibility with non-VMS systems, Zip strips VMS
+file version numbers from the names stored in an archive.  Thus, without
+/DOT_VERSION or /KEEP_VERSION, a version number wildcard (";*") can
+cause errors when multiple versions of a single file are treated as
+multiple files with the same name.
+
+See also /DOT_VERSION.
+<QUALIFIER>
+/LATEST
+
+/LATEST
+
+The archive's creation and modification time is set to the latest
+modification time of all archive members.
+<QUALIFIER>
+/LEVEL
+
+/LEVEL=number
+
+Specifies the compression level:
+<LITERAL>
+|  0      Store
+|  1      Fastest compression (Defl:F)
+|  ...
+|  9      Best compression    (Defl:X)
+<LARETIL>
+
+The default level is 6.
+<QUALIFIER>
+/LICENSE
+
+/LICENSE
+
+Displays the Zip license.
+<QUALIFIER>
+/LOG_FILE
+
+/LOG_FILE=(FILE=log_file [, APPEND] [, INFORMATIONAL])
+
+Zip normally sends messages to the user's terminal, but these may be
+also directed to a log file.
+
+<LITERAL>
+  FILE=log_file
+<LARETIL>
+
+Open a logfile at the given path.  By default, a new version will be
+created.  
+
+<LITERAL>
+  APPEND
+<LARETIL>
+
+Append to an existing log file.  Default is to create a new version.
+
+<LITERAL>
+  INFORMATIONAL
+<LARETIL>
+
+Only warnings and errors are written to the log unless the INFORMATIONAL
+option is also specified, then all information messages are also written
+to the log.
+<QUALIFIER>
+/MOVE
+
+/MOVE
+
+Move the specified files into the Zip archive.  That is, Zip will delete
+any files which are successfully added to or updated in the archive.  No
+deletions will be done until the Zip operation has completed with no
+errors.  This option is obviously dangerous and should be used with
+care, but it does reduce the need for free disk space.  It's recommended
+that /TEST also be used to test the archive before the input files are
+deleted.
+<QUALIFIER>
+/MUST_MATCH
+
+/MUST_MATCH
+
+All input patterns must match at least one file and all input files
+found must be readable.  Normally when an input pattern does not match
+a file the "name not matched" warning is issued and when an input
+file has been found but later is missing or not readable a "missing or
+not readable" warning is issued.  In either case Zip continues
+creating the archive, with missing or unreadable new files being skipped
+and files already in the archive remaining unchanged.  After the
+archive is created, if any files were not readable zip returns the OPEN
+error code (18 on most systems) instead of the normal success return (0
+on most systems).  With /MUST_MATCH, Zip exits as soon as an input
+pattern is not matched (whenever the "name not matched" warning would be
+issued) or when an input file is not readable.  In either case Zip exits
+with an OPEN error and no archive is created.
+
+This option is useful when a known list of files is to be zipped so any
+missing or unreadable files should result in an error.  It may be less
+useful when used with wildcards, but Zip will still exit with an error
+if any input pattern doesn't match at least  one file or if any
+matched files are unreadable.  If you want to create the archive anyway
+and only need to know if files were skipped, then don't use /MUST_MATCH
+and just check the exit status.  Also, a log file (see /LOG_FILE) could
+be useful.
+<QUALIFIER>
+/PATTERN_CASE
+
+/PATTERN_CASE={BLIND|SENSITIVE}
+
+<LITERAL>
+|  BLIND      Use case-blind pattern matching for archive entry names.
+|  SENSITIVE  Use case-sensitive pattern matching for archive entry
+|             names.  (Default.)
+<LARETIL>
+
+By default, on VMS, archive name pattern matching (/COPY_ENTRIES,
+/DELETE, /EXCLUDE, /INCLUDE, and /RECURSE=FILENAMES) is case sensitive,
+even when the file system is not case sensitive (or even case
+preserving).  This allows accurate matching of mixed-case names in an
+archive which may have been created on a system with a case sensitive
+file system, but it can involve extra effort on VMS, where it may be
+necessary to use unnatural case names (or the same names in multiple
+cases, like "*.obj *.OBJ") for this kind of pattern matching to give the
+desired behavior.  If completely case-blind pattern matching behavior is
+desired, specify the /PATTERN_CASE=BLIND option.
+<QUALIFIER>
+/PKZIP
+
+/PKZIP
+/NOPKZIP (default)
+
+Create PKZIP-compatible archive entries.  File names and paths are
+adjusted to conform to MSDOS character-set and length
+limitations, to store only the MSDOS file attributes (just the
+owner:write attribute from VMS), and to mark the entry as made under
+MSDOS (even though it wasn't).
+<QUALIFIER>
+/PRESERVE_CASE
+
+/NOPRESERVE_CASE
+/PRESERVE_CASE[=(keyword[, ...])]
+
+Directs Zip to preserve the case of, or convert to lower-case, file names
+in the archive.  Optional keywords are:
+<LITERAL>
+|  NOODS2        Down-case ODS2 file names (default).
+|  NOODS5        Down-case ODS5 file names.
+|  ODS2          Preserve case of ODS2 file names.
+|  ODS5          Preserve case of ODS5 file names (default).
+<LARETIL>
+
+By default, file names from an ODS2 file system are converted to lower
+case for storage in an archive, while the case of file names from an
+ODS5 file system is preserved.
+
+/NOPRESERVE_CASE is equivalent to /PRESERVE_CASE = (NOODS2, NOODS5),
+which causes all file names to be converted to lower-case.  This is
+equivalent to the behavior of Zip before version 3.0.
+
+/PRESERVE_CASE is equivalent to /PRESERVE_CASE = (ODS2, ODS5), which
+preserves the case of all file names.
+<QUALIFIER>
+/QUIET
+
+/QUIET
+
+Quiet mode.  Eliminates informational messages and comment prompts.
+This mode may be useful in command procedures, or if the Zip operation
+is being performed as a background task ("$ spawn/nowait zip /quiet foo
+*.c").
+<QUALIFIER>
+/RECURSE
+
+/RECURSE[=KEYWORD]
+/NORECURSE (default)
+
+Directs Zip to recurse into subdirectories.
+The optional keywords recognized are:
+<LITERAL>
+|  PATH      take patterns as full path specifiers (-r) (default)
+|  FILENAMES start from current dir;
+|            only use filename part of file patterns (-R)
+<LARETIL>
+The optional FILENAMES keyword modifies the recursion algorithm to be
+(almost) compatible to PKZIP's behaviour on subdirectory recursion.
+
+On VMS, directory recursion can also be requested by using the
+directory depth wildcard ("[...]") in an input file specification.
+<QUALIFIER>
+/SHOW
+
+/SHOW=(KEYWORD[,KEYWORD[...]])
+
+Controls various diagnostic messages.
+
+The keywords recognized are:
+<LITERAL>
+|  COMMAND  Show command line arguments as processed (only, then exit).
+|  DEBUG    Show Debug information.
+|  FILES    Show files to process (only, then exit).
+|  OPTIONS  Show all available command-line options on this system.
+<LARETIL>
+<QUALIFIER>
+/SINCE
+
+/SINCE=VMS_date_time
+
+Restricts the files by date-time when adding, updating, or freshening an
+archive.  Only files with modification date-times at or later than the
+specified date-time are accepted.
+
+See also /BEFORE.
+<QUALIFIER>
+/SPLIT
+
+/SPLIT = (SIZE=size [, PAUSE [, BELL]] [, VERBOSE])
+
+Enables split archives, specifies the size of the splits, and controls
+other related behavior.
+
+SIZE=size  specifies the split size.  The size is given as a number
+followed optionally by a multiplier suffix of k (KB), m (MB, the default
+if no suffix is specified), g (GB), or t (TB).  (All are powers of 1024,
+not 1000).  64K is the minimum split size.  For example, the following
+command could be used to create a split archive called "foo" from the
+contents of the "bar" directory with splits of 670MB, which might be
+useful for burning on CDs:
+
+<LITERAL>
+|  zip /split = size = 670m foo [.bar...]*.*
+<LARETIL>
+
+Using /SPLIT without PAUSE as above creates all the splits in the
+directory
+specified by "foo", in this case the current default directory.  This
+split mode updates the splits as the archive is being created, requiring
+all splits to remain writable, but creates split archives that are
+readable by any UnZip that supports split archives.  See PAUSE below for
+enabling split pause mode which allows splits to be written directly to
+removable media.
+
+PAUSE  causes Zip to pause between splits to allow
+changing removable media, for example.  PAUSE uses stream mode to
+write splits so unzips that can't read stream mode entries may not
+be able to read some entries in the archive.  Unless standard encryption
+was used, copy mode using /COPY_ENTRIES can convert stream mode entries
+to normal entries.
+
+BELL  ring the terminal bell when Zip pauses for the next split
+destination.
+
+VERBOSE  enables verbose splitting and display details of how the
+splitting is being done.
+
+Though Zip does not update split archives, Zip provides the option
+/OUTPUT to allow split archives to be updated and saved in a new
+archive.  For example:
+
+<LITERAL>
+|  zip inarchive.zip foo.c bar.c /output = outarchive.zip
+<LARETIL>
+
+reads archive inarchive.zip, even if split, adds the files foo.c and
+bar.c, and writes the resulting archive to outarchive.zip.  If
+inarchive.zip is split, then outarchive.zip defaults to the same split
+size.  Be aware that outarchive.zip and any split files that are created
+with it are always overwritten without warning.  This may be changed in
+the future.
+<QUALIFIER>
+/STORE_TYPES
+
+/STORE_TYPES=(.ext1,.ext2,... )
+
+Normally, a file which is already compressed will not be compressed much
+further (if at all) by Zip, and trying to do it can waste considerable
+CPU time.  Zip can suppress compression on files with particular types,
+specified with /STORE_TYPES.  The default list of types where
+compression is suppressed is /STORE_TYPES=(.Z, .zip, .zoo, .arc, .lzh,
+ .arj), and the comparison is case-insensitive.
+
+/LEVEL=9 will override /STORE_TYPES, causing compression to be attempted
+for all files.
+<QUALIFIER>
+/SYMLINKS
+
+/SYMLINKS
+
+Store symbolic links as such in the Zip archive, instead of compressing
+and storing the file referred to by the link.  A symbolic link normally
+requires less storage than the actual file, both in the archive, and on
+the destination file system.
+
+On VMS, symbolic links are supported on ODS5 disks where the C RTL
+supports symbolic links.  Full support for symbolic links seems to
+require VMS V8.3, but a Zip program supporting symbolic links may be
+built on VMS V7.3-2.
+<QUALIFIER>
+/TEMP_PATH
+
+/TEMP_PATH=temp_dir
+
+When creating a new archive or normally when changing an existing
+archive, Zip will write a temporary file in the archive destination
+directory ("ZIxxxxxxxx", where "xxxxxxxx" is the hexadecimal process ID)
+with the new contents.  Then, if and when the Zip job has completed with
+no errors, it will rename the temporary file to the specified archive
+name (replacing the old archive, if any).
+
+/TEMP_PATH=temp_dir specifies an alternate device:[directory],
+"temp_dir", for the temporary file, but specifying a different device
+will force Zip to copy the temporary file to its final destination
+instead of simply renaming it, and that copying will take more time than
+renaming, especially for a large archive.  For example:
+
+<LITERAL>
+|  zip /temp_path = disk$scratch:[tmp] stuff *
+<LARETIL>
+
+will cause Zip to put its temporary files in the directory
+"disk$scratch:[tmp]", copying the temporary file back to the current
+directory as stuff.zip when it's complete.
+<QUALIFIER>
+/TEST
+
+/TEST[=UNZIP=unzip_cmd]
+
+Test the integrity of a Zip archive (the new one, if /OUTPUT is
+specified).  If the check fails, the old archive is unchanged  and
+(with the /MOVE option) no input files are removed.
+
+Implementation
+"zip /TEST" actually runs an "unzip -t" command to do the testing, so
+UnZip must be installed properly for this to work.
+
+With UNZIP=unzip_cmd, Zip uses the UnZip command specified by
+"unzip_cmd" (normally a DCL symbol), instead of the default command,
+"unzip -t".  This can be useful if multiple versions of UnZip are
+installed on a system, and the default DCL symbol "UNZIP" would run the
+wrong one (or the logical name DCL$PATH would lead to the wrong one).
+
+In "unzip_cmd", the string "{}" is replaced by the name of the
+(temporary) archive to be tested, otherwise the name of the archive is
+appended to the end of the command.  The exit status is checked for
+success severity.
+<QUALIFIER>
+/TRANSLATE_EOL
+
+/TRANSLATE_EOL[=KEYWORD]
+
+Selects conversion of the end-of-line markers in text files.  This
+option should be used on text files only.  The optional keywords
+recognized are:
+<LITERAL>
+|  LF        convert LF -> CRLF (UNIX to DOS) (default)
+|  CRLF      convert CRLF -> LF, strip trailing CTRL-Z's (DOS to UNIX)
+<LARETIL>
+
+The CRLF option may be useful when a DOS text file has been transfered
+to a VMS disk in stream (or stream_lf) format.
+<QUALIFIER>
+/UNSFX
+
+/UNSFX
+
+Strip any prepended data from the Zip archive.  ZIP /UNSFX is normally
+used to convert a self-extracting archive to a normal archive by
+removing the UnZip SFX executable from the beginning of the SFX archive.
+
+Note that a self-extracting archive contains a normal Zip archive, and a
+normal UnZip program can be used to expand it in the normal way.  You
+may get a warning about extra bytes at the beginning of the archive (the
+UnZip SFX program), but UnZip should work properly after that.  This
+allows data in a self-extracting archive to be accessed on any system,
+not just the target system where its embedded UnZip SFX program runs.
+<QUALIFIER>
+/UPDATE
+
+/UPDATE
+
+Update existing archive entries and add new files.  If the archive does
+not exist, create it.  This is the default mode, so /UPDATE is optional.
+
+See also /DELETE /DIFFERENCE, /GROW, /FRESHEN.
+<QUALIFIER>
+/VERBOSE
+
+/VERBOSE[=NORMAL|MORE|DEBUG] [, COMMAND]]
+
+Verbose mode or print diagnostic version info.
+
+Normally, when applied to real operations, this option enables the
+display of a progress indicator during compression (see /DISPLAY=DOTS
+for more on dots) and requests verbose diagnostic info about archive
+structure oddities.
+
+/VERBOSE with no value is equivalent to /VERBOSE=NORMAL.  MORE adds more
+messages, and DEBUG adds still more messages.
+
+When /VERBOSE is the only command line argument, a diagnostic report is
+displayed, showing:
+
+<LITERAL>
+|  o Copyright and other legal notices
+|  o Program name, version, and release date
+|  o Pointers to Info-ZIP FTP and Web sites
+|  o Program build information (compiler type and version, OS version,
+|    and the compilation date
+|  o Optional features enabled at compile-time
+|  o Environment variable definitions (ZIP_OPTS, ZIPOPT)
+<LARETIL>
+
+This information should be included in bug reports.
+
+/VERBOSE=COMMAND causes Zip to display the UNIX-style command-line
+argument vector which is generated from the VMS-style CLI command line
+before executing the command.  This is of primary interest to program
+developers debugging the CLI.
+<QUALIFIER>
+/VMS
+
+/VMS[=ALL]
+
+The /VMS and /VMS=ALL options cause Zip to store VMS file atributes
+(such as file organization, record format, carriage control, and so on)
+in VMS-specific "extra fields" in an archive along with the usual data.
+These extra fields are ignored on non-VMS systems, but on a VMS system,
+they allow UnZip to restore the files with their VMS attributes intact.
+
+With /VMS, Zip ignores any data in the file after the end-of-file (EOF)
+point (defined by FAT$L_EFBLK and FAT$W_FFBYTE), which works well for
+well-formed files (that is, those with no valid data beyond EOF).
+Portable-format files (Stream_LF, fixed-512) archived with /VMS should
+be extracted properly on a non-VMS system.  Files with more complex
+structures, such as indexed files and files with embedded byte counts or
+other such data may be of limited use on other systems.  (UnZip on
+non-VMS systems may be able to extract various VMS-format text files,
+however.)
+
+With /VMS=ALL, Zip processes all allocated blocks for the file
+(including those beyond EOF).  When extracted on a VMS system, the
+original file should be reproduced with as much fidelity as possible,
+but on a non-VMS system, most files will be seen as corrupt because of
+the data from beyond EOF.
+<QUALIFIER>
+/WILDCARD
+
+<LITERAL>
+/NOWILDCARD
+/WILDCARD=NOSPAN
+<LARETIL>
+
+Controls wildcard processing.
+
+/NOWILDCARD  Wildcard processing is disabled.
+
+/WILDCARD=NOSPAN  Wildcards don't span directory boundaries in paths.
+<QUALIFIER>
+/ZIP64
+
+/ZIP64
+
+Forces use of Zip64 archive format, even for small files.  This is
+mainly for testing and should never be used.  Zip will automatically
+use Zip64 as needed without this option.
+<TOPIC>
+UNIX_Options
+
+"zip -h" provides a concise list of common command-line options.  "zip
+-h2" provides more details.  "zip -so" provides a list of all available
+options.  "zip -v" shows the program version and available features.
+(The list below was derived from a "zip -so" listing.)
+
+Short-form options begin with a single hyphen ("-").  Long-form option
+begin with a double hyphen ("--"), and may be abbreviated to any
+unambiguous shorter string.  For example:
+
+<LITERAL>
+|  -v
+|  --verbose
+|  --verb
+<LARETIL>
+
+To avoid confusion, if a negatable option contains an embedded hyphen
+("-"), then avoid abbreviating it at the hyphen if you plan to negate
+it.  For example, if an option like --some-option were abbreviated to
+--some-, the parser would consider that trailing hyphen to be part of
+the option name, rather than as a negating trailing hyphen.  This
+behavior may change in the future, to interpret the trailing hyphen in
+--some- to be negating.  (So don't do it.)
+
+Some options may be negated (or modified) by appending a "-":
+
+<LITERAL>
+|  -la-
+|  --show-files-
+<LARETIL>
+
+Some options take a value, which may immediately follow the option, or
+be separated by a space or "=".  For example:
+<LITERAL>
+|  -ttmmddyyyy
+|  -tt mmddyyyy
+|  -tt=mmddyyyy
+<LARETIL>
+
+<LITERAL0>
+| Sh  Long                Description
+|----+-------------------+------------------------------------------------
+| 0   store               store (instead of compress)
+| 1   compress-1          compress faster (-2, -3, -4, ...)
+| 9   compress-9          compress better
+| ?                       show the Zip help screen
+| @   names-stdin         read input file patterns from SYS$INPUT (1/line)
+| A   adjust-sfx          adjust self-extracting executable
+| b   temp-path  path     use "path" directory for temporary files
+| C   preserve-case       preserve case of all file names added to archive
+| C-  preserve-case-      down-case all file names added to archive
+| C2  preserve-case-2     preserve case of ODS2 names added to archive
+| C2- preserve-case-2-    down-case ODS2 file added to archive (default)
+| C5  preserve-case-5     preserve case of ODS5 names added to arcv (dflt)
+| C5- preserve-case-5-    down-case ODS5 names added to archive
+| c   entry-comments      add a comment for each entry added to archive
+| D   no-dir-entries      do not add archive entries for directories
+| DF  difference-archive  difference archive: add only changed/new files
+| d   delete              delete entries in archive
+| db  display-bytes       display running byte counts
+| dc  display-counts      display running file counts
+| dd  display-dots        display progress dots for files (dflt sz = 10MB)
+| dg  display-globaldots  display progress dots for archive, not each file
+| ds  dot-size   size     set progress dot interval to "size" (MB)
+| du  display-usize       display original uncompressed size for entries
+| dv  display-volume      display volume (disk) number as in_disk>out_disk
+| e   encrypt             encrypt entries, ask for password
+| F   fix                 fix mostly intact archive (try F before FF)
+| FF  fixfix              salvage what can be salvaged (not as reliable)
+| FS  filesync            remove archive entries unmatched in file system
+| f   freshen             update existing entries (only changed files)
+| fd  force-descriptors   force data descriptors as if streaming
+| fz  force-zip64         force use of Zip64 format
+| g   grow                grow existing archive (unless update or delete)
+| H                       show the Zip help screen
+| h   help                show the Zip help screen
+| h2  more-help           show extended Zip help
+| i   include  pat1 [pat2 [...]]  include only names matching the patterns
+| J   junk-sfx            junk (remove) archive preamble (unzipsfx)
+| j   junk-paths          junk (don't store) dir names, only file names
+| k   DOS-names           simulate PKZIP-made archive (DOS 8.3 names)
+| L   license             show software license
+| l   to-crlf             translate end-of-lines (LF -> CRLF)
+| la  log-append          append to existing log file
+| lf  logfile-path  lfile  log to log file at lfile (default: new version)
+| li  log-info            include informational messages in log
+| ll  from-crlf           translate end-of-lines (CRLF -> LF)
+| MM  must-match          input file spec must exist (wildcrds must match)
+| m   move                delete files added to archive
+| n   suffixes  sfx1[:sfx2[...]]  don't compress files with these suffixes
+| nw  no-wild             no wildcards during add or update
+| O   output-file  ozf  use "ozf" as the output archive (dflt = inp archv)
+| o   latest-time         set archive date-time to match oldest entry
+| P   password  password  encrypt with supplied "password" string
+| q   quiet               quiet operation (no info messages)
+| R   recurse-patterns    recurse subdirs from cur dir, match names only
+| r   recurse-paths       recurse directories from specified path pats
+| s   split-size  size    split archive at "size" (K/MB)  (0: don't split)
+| sb  split-bell          ring termnl bell at pause for split medium chng
+| sc  show-command        show command line
+| sd  show-debug          show debug messages
+| sf  show-files          show files to process (only)
+| so  show-options        show list of all command-line options
+| sp  split-pause         pause to select split destination(s)
+| sv  split-verbose       be verbose about creating splits
+| T   test                test archive integrity (runs UnZip -T)
+| t   from-date  mmddyyyy  only do files since (at or after) "mmddyyyy"
+| tt  before-date  mmddyyyy  only do files before "mmddyyyy"
+| u   update              update changed files, add new files (default)
+| V   VMS-portable        save VMS file attributes
+| VV  VMS-specific        save VMS file attributes and all allocated blks
+| v   verbose             verbose messages (version info if only arg)
+| w   VMS-versions        save VMS version numbers in archive
+| ww  VMS-dot-versions    save VMS version numbers as ".nnn", not ";nnn"
+| X   strip-extra         strip all but critical extra fields
+| X-  strip-extra-        keep all extra fields
+| x   exclude  pat1 [pat2 [...]]  exclude all names matching the patterns
+| Z   compression-method mthd  use cmprs method "mthd" (bzip2 or deflate)
+| z   archive-comment     ask for archive comment
+<0LARETIL>
+
+With SET PROCESS /PARSE_STYLE = EXTENDED (available on recent non-VAX
+systems), Zip preserves the case of the command line.  Otherwise, mixed-
+or upper-case options and arguments must be quoted.  For example,
+"-V".  Examples in this document generally do not show this quotation.
+<TOPIC>
+Copyright_and_License
+
+Zip has an option to display its copyright and license.
+
+<LITERAL>
+|  /LICENSE
+<LARETIL>
+
+The license is reproduced below.
+
+This is version 2007-Mar-4 of the Info-ZIP license. The definitive
+version of this document should be available at
+ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely and a copy
+at http://www.info-zip.org/pub/infozip/license.html.
+
+--------------------------------------------------------
+<LITERAL0>
+|Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+|
+|For the purposes of this copyright and license, "Info-ZIP" is defined as
+|the following set of individuals:
+|
+|Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
+|Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth,
+|Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,
+|David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,
+|Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,
+|Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda, 
+|Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren,
+|Rich Wales, Mike White.
+| 
+|This software is provided "as is," without warranty of any kind, express
+|or implied.  In no event shall Info-ZIP or its contributors be held
+|liable for any direct, indirect, incidental, special or consequential
+|damages arising out of the use of or inability to use this software.
+| 
+|Permission is granted to anyone to use this software for any purpose,
+|including commercial applications, and to alter it and redistribute it
+|freely, subject to the above disclaimer and the following restrictions:
+| 
+|1. Redistributions of source code (in whole or in part) must retain
+|   the above copyright notice, definition, disclaimer, and this list
+|   of conditions.
+| 
+|2. Redistributions in binary form (compiled executables and libraries)
+|   must reproduce the above copyright notice, definition, disclaimer,
+|   and this list of conditions in documentation and/or other materials
+|   provided with the distribution.  The sole exception to this condition
+|   is redistribution of a standard UnZipSFX binary (including SFXWiz) as
+|   part of a self-extracting archive; that is permitted without inclusion
+|   of this license, as long as the normal SFX banner has not been removed
+|   from the binary or disabled.
+| 
+|3. Altered versions -- including, but not limited to, ports to new
+|   operating systems, existing ports with new graphical interfaces,
+|   versions with modified or added functionality, and dynamic, shared,
+|   or static library versions not from Info-ZIP -- must be plainly marked
+|   as such and must not be misrepresented as being the original source
+|   or, if binaries, compiled from the original source.  Such altered
+|   versions also must not be misrepresented as being Info-ZIP releases --
+|   including, but not limited to, labeling of the altered versions with
+|   the names "Info-ZIP" (or any variation thereof, including, but not
+|   limited to, different capitalizations), "Pocket UnZip," "WiZ" or
+|   "MacZip" without the explicit permission of Info-ZIP.  Such altered
+|   versions are further prohibited from misrepresentative use of the
+|   Zip-Bugs or Info-ZIP e-mail addresses or the Info-ZIP URL(s), such as
+|   to imply Info-ZIP will provide support for the altered versions.
+| 
+|4. Info-ZIP retains the right to use the names "Info-ZIP", "Zip",
+|   "UnZip", "UnZipSFX", "WiZ", "Pocket UnZip", "Pocket Zip", and
+|   "MacZip" for its own source and binary releases.
+<0LARETIL>
+
+===
diff --git a/vms/zip_msg.msg b/vms/zip_msg.msg
new file mode 100644 (file)
index 0000000..8654148
--- /dev/null
@@ -0,0 +1,57 @@
+!    VMS Error Message Source File for Zip
+!
+! Because the facility code was formally assigned by HP, the .FACILITY
+! directive below specifies /SYSTEM.  Because the messages are, in
+! general, specific to Zip, this file is not compiled with /SHARED.
+! For example:
+!
+!    MESSAGE /OBJECT = [.dest]ZIP_MSG.OBJ /NOSYMBOLS [.VMS]ZIP_MSG.MSG
+!
+!    LINK /SHAREABLE = [.dest]ZIP_MSG.EXE [.dest]ZIP_MSG.OBJ
+!
+!-----------------------------------------------------------------------
+
+.TITLE  Info-ZIP Zip Error Messages
+.FACILITY IZ_ZIP, 1955 /SYSTEM
+.IDENT 'V3.0-000'
+
+.BASE 0
+OK      /SUCCESS      <Normal successful completion>
+.BASE 4
+EOF     /FATAL        <Unexpected end of zip file>
+.BASE 6
+FORM    /ERROR        <Zip file structure invalid>
+.BASE 8
+MEM     /FATAL        <Out of memory>
+.BASE 10
+LOGIC   /FATAL        <Internal logic error>
+.BASE 12
+BIG     /ERROR        <Entry too big to split, read, or write>
+.BASE 14
+NOTE    /ERROR        <Invalid comment format>
+.BASE 16
+TEST    /FATAL        <Zip file invalid, could not spawn unzip, or wrong unzip>
+.BASE 18
+ABORT   /ERROR        <Interrupted>
+.BASE 20
+TEMP    /FATAL        <Temporary file failure>
+.BASE 22
+READ    /FATAL        <Input file read failure>
+.BASE 24
+NONE    /WARNING      <Nothing to do!>
+.BASE 26
+NAME    /ERROR        <Missing or empty zip file>
+.BASE 28
+WRITE   /FATAL        <Output file write failure>
+.BASE 30
+CREAT   /FATAL        <Could not create output file>
+.BASE 32
+PARMS   /ERROR        <Invalid command arguments>
+.BASE 36
+OPEN    /ERROR        <File not found or no read permission>
+.BASE 38
+COMPERR /FATAL        <Not supported>
+.BASE 40
+ZIP64   /FATAL        <Attempt to read unsupported Zip64 archive>
+
+.END
diff --git a/vms/zipup.h b/vms/zipup.h
new file mode 100644 (file)
index 0000000..8fe757f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2005-Feb-10 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+#ifndef __zipup_h
+#define __zipup_h 1
+
+#ifndef NO_ZIPUP_H
+
+#define fbad NULL
+typedef void *ftype;
+#define zopen(n,p)   (vms_native?vms_open(n)    :(ftype)fopen((n), p))
+#define zread(f,b,n) (vms_native?vms_read(f,b,n):fread((b),1,(n),(FILE*)(f)))
+#define zclose(f)    (vms_native?vms_close(f)   :fclose((FILE*)(f)))
+#define zerr(f)      (vms_native?vms_error(f)   :ferror((FILE*)(f)))
+#define zstdin stdin
+
+ftype vms_open OF((char *));
+unsigned int vms_read OF((ftype, char *, unsigned int));
+int vms_close OF((ftype));
+int vms_error OF((ftype));
+#ifdef VMS_PK_EXTRA
+int vms_get_attributes OF((ftype, struct zlist far *, iztimes *));
+#endif
+
+#endif /* !NO_ZIPUP_H */
+#endif /* !__zipup_h */
+
+
+#ifndef __zipup_cb_h
+#define __zipup_cb_h 1
+
+#ifdef __DECC
+
+/* File open callback ID values.  (See also OSDEP.H.) */
+
+#  define FHOW_ID 4
+
+/* File open callback ID storage. */
+
+extern int fhow_id;
+
+#define fhow "r", "acc", acc_cb, &fhow_id
+
+#else /* def __DECC */ /* (So, GNU C, VAX C, ...)*/
+
+#define fhow "r", "mbc=60"
+
+#endif /* def __DECC */
+
+#endif /* ndef __zipup_cb_h */
diff --git a/win32/README.NT b/win32/README.NT
new file mode 100644 (file)
index 0000000..d2b31f7
--- /dev/null
@@ -0,0 +1,17 @@
+From: Michael Tibbott <tibbott@classifieds2000.com>
+Subject: Zip on Windows NT problem - here's the answer
+Date: Wed, 10 Dec 1997 15:24:29 -0800
+
+If you're running NT Server (I am not sure about NT Workstation) then you
+should do the following to prevent zip/unzip from page swapping itself to
+death. And as an added bonus, the zip was about 6% faster.
+
+- open the network control panel
+
+- Click on the services tab
+
+- double-click on the server item to open its properties
+
+- Click the "maximize throughput for network applications" radio button
+
+- save and reboot
diff --git a/win32/README.TZ b/win32/README.TZ
new file mode 100644 (file)
index 0000000..ddce3f8
--- /dev/null
@@ -0,0 +1,7 @@
+From: paul.kienitz@shelter.sf.ca.us (Paul Kienitz)
+> It looks like I don't have to create a tzset() kluge for Watcom to check
+> the win32 API timezone information after all -- their new 10.6 release has
+> corrected this oversight.  The TZ variable overrides the API.  So the only
+> win32-related patch I want to make for Zip is just to use USE_EF_UT_TIME
+> unconditionally.  With this in place, timezone stuff is working flawlessly
+> with or without TZ being set.
diff --git a/win32/README.txt b/win32/README.txt
new file mode 100644 (file)
index 0000000..4d56445
--- /dev/null
@@ -0,0 +1,10 @@
+Win32/README.txt
+27 June 2008
+
+The resource files zip.rc and windll.rc must not get edited and saved from
+MS Visual Studio.  MS VS automatically re-adds its specific MFC-related resource
+infrastructure to the "xx.rc" files when saved after any modification.  The
+dependancies on MFC related headers break the compilation process, when you
+try to use the freely available MS Visual Studio Express Editions (2005 or 2008)
+for building Zip.  And, most third-party compilers also lack support for the
+propietary MFC environment.
diff --git a/win32/crc_i386.asm b/win32/crc_i386.asm
new file mode 100644 (file)
index 0000000..19998ff
--- /dev/null
@@ -0,0 +1,330 @@
+;===========================================================================
+; Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 2000-Apr-09 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+; crc_i386.asm, optimized CRC calculation function for Zip and UnZip,
+; created by Paul Kienitz and Christian Spieler.  Last revised 07 Jan 2007.
+;
+; Revised 06-Oct-96, Scott Field (sfield@microsoft.com)
+;   fixed to assemble with masm by not using .model directive which makes
+;   assumptions about segment alignment.  Also,
+;   avoid using loop, and j[e]cxz where possible.  Use mov + inc, rather
+;   than lodsb, and other misc. changes resulting in the following performance
+;   increases:
+;
+;      unrolled loops                NO_UNROLLED_LOOPS
+;      *8    >8      <8              *8      >8      <8
+;
+;      +54%  +42%    +35%            +82%    +52%    +25%
+;
+;   first item in each table is input buffer length, even multiple of 8
+;   second item in each table is input buffer length, > 8
+;   third item in each table is input buffer length, < 8
+;
+; Revised 02-Apr-97, Chr. Spieler, based on Rodney Brown (rdb@cmutual.com.au)
+;   Incorporated Rodney Brown's 32-bit-reads optimization as found in the
+;   UNIX AS source crc_i386.S. This new code can be disabled by defining
+;   the macro symbol NO_32_BIT_LOADS.
+;
+; Revised 12-Oct-97, Chr. Spieler, based on Rodney Brown (rdb@cmutual.com.au)
+;   Incorporated Rodney Brown's additional tweaks for 32-bit-optimized CPUs
+;   (like the Pentium Pro, Pentium II, and probably some Pentium clones).
+;   This optimization is controlled by the macro symbol __686 and is disabled
+;   by default. (This default is based on the assumption that most users
+;   do not yet work on a Pentium Pro or Pentium II machine ...)
+;
+; Revised 25-Mar-98, Cosmin Truta (cosmint@cs.ubbcluj.ro)
+;   Working without .model directive caused tasm32 version 5.0 to produce
+;   bad object code. The optimized alignments can be optionally disabled
+;   by defining NO_ALIGN, thus allowing to use .model flat. There is no need
+;   to define this macro if using other versions of tasm.
+;
+; Revised 16-Jan-2005, Cosmin Truta (cosmint@cs.ubbcluj.ro)
+;   Enabled the 686 build by default, because there are hardly any pre-686 CPUs
+;   in serious use nowadays. (See the 12-Oct-97 note above.)
+;
+; Revised 03-Jan-2006, Chr. Spieler
+;   Enlarged unrolling loops to "do 16 bytes per turn"; optimized access to
+;   data buffer in loop body (adjust pointer only once in loop body and use
+;   offsets to access each item); added additional support for the "unfolded
+;   tables" optimization variant (enabled by IZ_CRCOPTIM_UNFOLDTBL).
+;
+; Revised 07-Jan-2007, Chr. Spieler
+;   Recognize additional conditional flag CRC_TABLE_ONLY that prevents
+;   compilation of the crc32() function.
+;
+; FLAT memory model assumed.
+;
+; Loop unrolling can be disabled by defining the macro NO_UNROLLED_LOOPS.
+; This results in shorter code at the expense of reduced performance.
+;
+;==============================================================================
+;
+; Do NOT assemble this source if external crc32 routine from zlib gets used,
+; or only the precomputed CRC_32_Table is needed.
+;
+    IFNDEF USE_ZLIB
+    IFNDEF CRC_TABLE_ONLY
+;
+        .386p
+        name    crc_i386
+
+    IFDEF NO_ALIGN
+        .model flat
+    ENDIF
+
+    IFNDEF PRE_686
+    IFNDEF __686
+__686   EQU     1 ; optimize for Pentium Pro, Pentium II and compatible CPUs
+    ENDIF
+    ENDIF
+
+extrn   _get_crc_table:near    ; ZCONST ulg near *get_crc_table(void);
+
+;
+    IFNDEF NO_STD_STACKFRAME
+        ; Use a `standard' stack frame setup on routine entry and exit.
+        ; Actually, this option is set as default, because it results
+        ; in smaller code !!
+STD_ENTRY       MACRO
+                push    ebp
+                mov     ebp,esp
+        ENDM
+
+        Arg1    EQU     08H[ebp]
+        Arg2    EQU     0CH[ebp]
+        Arg3    EQU     10H[ebp]
+
+STD_LEAVE       MACRO
+                pop     ebp
+        ENDM
+
+    ELSE  ; NO_STD_STACKFRAME
+
+STD_ENTRY       MACRO
+        ENDM
+
+        Arg1    EQU     18H[esp]
+        Arg2    EQU     1CH[esp]
+        Arg3    EQU     20H[esp]
+
+STD_LEAVE       MACRO
+        ENDM
+
+    ENDIF ; ?NO_STD_STACKFRAME
+
+; These two (three) macros make up the loop body of the CRC32 cruncher.
+; registers modified:
+;   eax  : crc value "c"
+;   esi  : pointer to next data byte (or dword) "buf++"
+; registers read:
+;   edi  : pointer to base of crc_table array
+; scratch registers:
+;   ebx  : index into crc_table array
+;          (requires upper three bytes = 0 when __686 is undefined)
+    IFNDEF  __686 ; optimize for 386, 486, Pentium
+Do_CRC  MACRO
+                mov     bl,al                ; tmp = c & 0xFF
+                shr     eax,8                ; c = (c >> 8)
+                xor     eax,[edi+ebx*4]      ;  ^ table[tmp]
+        ENDM
+    ELSE ; __686 : optimize for Pentium Pro, Pentium II and compatible CPUs
+Do_CRC  MACRO
+                movzx   ebx,al                 ; tmp = c & 0xFF
+                shr     eax,8                  ; c = (c >> 8)
+                xor     eax,[edi+ebx*4]        ;  ^ table[tmp]
+        ENDM
+    ENDIF ; ?__686
+Do_CRC_byte     MACRO
+                xor     al, byte ptr [esi]     ; c ^= *buf
+                inc     esi                    ; buf++
+                Do_CRC                         ; c = (c >> 8) ^ table[c & 0xFF]
+        ENDM
+Do_CRC_byteof   MACRO   ofs
+                xor     al, byte ptr [esi+ofs] ; c ^= *(buf+ofs)
+                Do_CRC                         ; c = (c >> 8) ^ table[c & 0xFF]
+        ENDM
+    IFNDEF  NO_32_BIT_LOADS
+      IFDEF IZ_CRCOPTIM_UNFOLDTBL
+        ; the edx register is needed in crc calculation
+        SavLen  EQU     Arg3
+
+UpdCRC_dword    MACRO
+                movzx   ebx,al                 ; tmp = c & 0xFF
+                mov     edx,[edi+ebx*4+3072]   ;  table[256*3+tmp]
+                movzx   ebx,ah                 ; tmp = (c>>8) & 0xFF
+                shr     eax,16                 ;
+                xor     edx,[edi+ebx*4+2048]   ;  ^ table[256*2+tmp]
+                movzx   ebx,al                 ; tmp = (c>>16) & 0xFF
+                shr     eax,8                  ; tmp = (c>>24)
+                xor     edx,[edi+ebx*4+1024]   ;  ^ table[256*1+tmp]
+                mov     eax,[edi+eax*4]        ;  ^ table[256*0+tmp]
+                xor     eax,edx                ; ..
+        ENDM
+UpdCRC_dword_sh MACRO   dwPtrIncr
+                movzx   ebx,al                 ; tmp = c & 0xFF
+                mov     edx,[edi+ebx*4+3072]   ;  table[256*3+tmp]
+                movzx   ebx,ah                 ; tmp = (c>>8) & 0xFF
+                xor     edx,[edi+ebx*4+2048]   ;  ^ table[256*2+tmp]
+                shr     eax,16                 ;
+                movzx   ebx,al                 ; tmp = (c>>16) & 0xFF
+                add     esi, 4*dwPtrIncr       ; ((ulg *)buf) += dwPtrIncr
+                shr     eax,8                  ; tmp = (c>>24)
+                xor     edx,[edi+ebx*4+1024]   ;  ^ table[256*1+tmp]
+                mov     eax,[edi+eax*4]        ;  ^ table[256*0+tmp]
+                xor     eax,edx                ; ..
+        ENDM
+      ELSE ; IZ_CRCOPTIM_UNFOLDTBL
+        ; the edx register is not needed anywhere else
+        SavLen  EQU     edx
+
+UpdCRC_dword    MACRO
+                Do_CRC
+                Do_CRC
+                Do_CRC
+                Do_CRC
+        ENDM
+UpdCRC_dword_sh MACRO   dwPtrIncr
+                Do_CRC
+                Do_CRC
+                add     esi, 4*dwPtrIncr       ; ((ulg *)buf) += dwPtrIncr
+                Do_CRC
+                Do_CRC
+        ENDM
+      ENDIF ; ?IZ_CRCOPTIM_UNFOLDTBL
+Do_CRC_dword    MACRO
+                xor     eax, dword ptr [esi]   ; c ^= *(ulg *)buf
+                UpdCRC_dword_sh 1              ; ... ((ulg *)buf)++
+        ENDM
+Do_CRC_4dword   MACRO
+                xor     eax, dword ptr [esi]    ; c ^= *(ulg *)buf
+                UpdCRC_dword
+                xor     eax, dword ptr [esi+4]  ; c ^= *((ulg *)buf+1)
+                UpdCRC_dword
+                xor     eax, dword ptr [esi+8]  ; c ^= *((ulg *)buf+2)
+                UpdCRC_dword
+                xor     eax, dword ptr [esi+12] ; c ^= *((ulg *)buf]+3
+                UpdCRC_dword_sh        4               ; ... ((ulg *)buf)+=4
+        ENDM
+    ENDIF ; !NO_32_BIT_LOADS
+
+    IFNDEF NO_ALIGN
+_TEXT   segment use32 para public 'CODE'
+    ELSE
+_TEXT   segment use32
+    ENDIF
+        assume  CS: _TEXT
+
+        public  _crc32
+_crc32          proc    near  ; ulg crc32(ulg crc, ZCONST uch *buf, extent len)
+                STD_ENTRY
+                push    edi
+                push    esi
+                push    ebx
+                push    edx
+                push    ecx
+
+                mov     esi,Arg2            ; 2nd arg: uch *buf
+                sub     eax,eax             ;> if (!buf)
+                test    esi,esi             ;>   return 0;
+                jz      fine                ;> else {
+
+                call    _get_crc_table
+                mov     edi,eax
+                mov     eax,Arg1            ; 1st arg: ulg crc
+    IFNDEF __686
+                sub     ebx,ebx             ; ebx=0; make bl usable as a dword
+    ENDIF
+                mov     ecx,Arg3            ; 3rd arg: extent len
+                not     eax                 ;>   c = ~crc;
+
+                test    ecx,ecx
+    IFNDEF  NO_UNROLLED_LOOPS
+                jz      bail
+    IFNDEF  NO_32_BIT_LOADS
+align_loop:
+                test    esi,3               ; align buf pointer on next
+                jz      SHORT aligned_now   ;  dword boundary
+                Do_CRC_byte
+                dec     ecx
+                jnz     align_loop
+aligned_now:
+    ENDIF ; !NO_32_BIT_LOADS
+                mov     SavLen,ecx          ; save current len for later
+                shr     ecx,4               ; ecx = len / 16
+                jz      No_Sixteens
+    IFNDEF NO_ALIGN
+; align loop head at start of 486 internal cache line !!
+                align   16
+    ENDIF
+Next_Sixteen:
+    IFNDEF  NO_32_BIT_LOADS
+                Do_CRC_4dword
+    ELSE ; NO_32_BIT_LOADS
+                Do_CRC_byteof   0
+                Do_CRC_byteof   1
+                Do_CRC_byteof   2
+                Do_CRC_byteof   3
+                Do_CRC_byteof   4
+                Do_CRC_byteof   5
+                Do_CRC_byteof   6
+                Do_CRC_byteof   7
+                Do_CRC_byteof   8
+                Do_CRC_byteof   9
+                Do_CRC_byteof   10
+                Do_CRC_byteof   11
+                Do_CRC_byteof   12
+                Do_CRC_byteof   13
+                Do_CRC_byteof   14
+                Do_CRC_byteof   15
+                add     esi, 16                 ; buf += 16
+    ENDIF ; ?NO_32_BIT_LOADS
+                dec     ecx
+                jnz     Next_Sixteen
+No_Sixteens:
+                mov     ecx,SavLen
+                and     ecx,00000000FH      ; ecx = len % 16
+    IFNDEF  NO_32_BIT_LOADS
+                shr     ecx,2               ; ecx = len / 4
+                jz      SHORT No_Fours
+Next_Four:
+                Do_CRC_dword
+                dec     ecx
+                jnz     Next_Four
+No_Fours:
+                mov     ecx,SavLen
+                and     ecx,000000003H      ; ecx = len % 4
+    ENDIF ; !NO_32_BIT_LOADS
+    ENDIF ; !NO_UNROLLED_LOOPS
+                jz      SHORT bail          ;>   if (len)
+    IFNDEF NO_ALIGN
+; align loop head at start of 486 internal cache line !!
+                align   16
+    ENDIF
+loupe:                                      ;>     do {
+                Do_CRC_byte                 ;        c = CRC32(c,*buf++,crctab);
+                dec     ecx                 ;>     } while (--len);
+                jnz     loupe
+
+bail:                                       ;> }
+                not     eax                 ;> return ~c;
+fine:
+                pop     ecx
+                pop     edx
+                pop     ebx
+                pop     esi
+                pop     edi
+                STD_LEAVE
+                ret
+_crc32          endp
+
+_TEXT   ends
+;
+    ENDIF ; !CRC_TABLE_ONLY
+    ENDIF ; !USE_ZLIB
+;
+end
diff --git a/win32/crc_i386.c b/win32/crc_i386.c
new file mode 100644 (file)
index 0000000..971ee66
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* crc_i386.c -- Microsoft 32-bit C/C++ adaptation of crc_i386.asm
+ * Created by Rodney Brown from crc_i386.asm, modified by Chr. Spieler.
+ * Last revised: 07-Jan-2007
+ *
+ * Original coded (in crc_i386.asm) and put into the public domain
+ * by Paul Kienitz and Christian Spieler.
+ *
+ * Revised 06-Oct-96, Scott Field (sfield@microsoft.com)
+ *   fixed to assemble with masm by not using .model directive which makes
+ *   assumptions about segment alignment.  Also,
+ *   avoid using loop, and j[e]cxz where possible.  Use mov + inc, rather
+ *   than lodsb, and other misc. changes resulting in the following performance
+ *   increases:
+ *
+ *      unrolled loops                NO_UNROLLED_LOOPS
+ *      *8    >8      <8              *8      >8      <8
+ *
+ *      +54%  +42%    +35%            +82%    +52%    +25%
+ *
+ *   first item in each table is input buffer length, even multiple of 8
+ *   second item in each table is input buffer length, > 8
+ *   third item in each table is input buffer length, < 8
+ *
+ * Revised 02-Apr-97, Chr. Spieler, based on Rodney Brown (rdb@cmutual.com.au)
+ *   Incorporated Rodney Brown's 32-bit-reads optimization as found in the
+ *   UNIX AS source crc_i386.S. This new code can be disabled by defining
+ *   the macro symbol NO_32_BIT_LOADS.
+ *
+ * Revised 12-Oct-97, Chr. Spieler, based on Rodney Brown (rdb@cmutual.com.au)
+ *   Incorporated Rodney Brown's additional tweaks for 32-bit-optimized CPUs
+ *   (like the Pentium Pro, Pentium II, and probably some Pentium clones).
+ *   This optimization is controlled by the macro symbol __686 and is disabled
+ *   by default. (This default is based on the assumption that most users
+ *   do not yet work on a Pentium Pro or Pentium II machine ...)
+ *
+ * Revised 16-Nov-97, Chr. Spieler: Made code compatible with Borland C++
+ *   32-bit, removed unneeded kludge for potentially unknown movzx mnemonic,
+ *   confirmed correct working with MS VC++ (32-bit).
+ *
+ * Revised 22-May-98, Peter Kunath, Chr. Spieler: The 16-Nov-97 revision broke
+ *   MSVC 5.0. Inside preprocessor macros, each instruction is enclosed in its
+ *   own __asm {...} construct.  For MSVC, a "#pragma warning" was added to
+ *   shut up the "no return value" warning message.
+ *
+ * Revised 13-Dec-98, Chr. Spieler: Modified path to "zip.h" header file.
+ *
+ * Revised 16-Jan-2005, Cosmin Truta: Added the ASM_CRC guard, for easier
+ *   switching between ASM vs. non-ASM builds, when handling makefiles.
+ *   Also enabled the 686 build by default, because there are hardly any
+ *   pre-686 CPUs in serious use nowadays. (See the 12-Oct-97 note above.)
+ *
+ * Revised 03-Jan-2006, Chr. Spieler
+ *   Enlarged unrolling loops to "do 16 bytes per turn"; optimized access to
+ *   data buffer in loop body (adjust pointer only once in loop body and use
+ *   offsets to access each item); added additional support for the "unfolded
+ *   tables" optimization variant (enabled by IZ_CRCOPTIM_UNFOLDTBL).
+ *
+ * Revised 07-Jan-2007, Chr. Spieler
+ *   Recognize additional conditional flag CRC_TABLE_ONLY that prevents
+ *   compilation of the crc32() function.
+ *
+ * FLAT memory model assumed.
+ *
+ * Loop unrolling can be disabled by defining the macro NO_UNROLLED_LOOPS.
+ * This results in shorter code at the expense of reduced performance.
+ *
+ */
+
+#include "../zip.h"
+#include "../crc32.h"
+
+#if defined(ASM_CRC) && !defined(USE_ZLIB) && !defined(CRC_TABLE_ONLY)
+
+#if !defined(PRE_686) && !defined(__686)
+#  define __686
+#endif
+
+#ifndef ZCONST
+#  define ZCONST const
+#endif
+
+/* Select wether the following inline-assember code is supported. */
+#if (defined(_MSC_VER) && _MSC_VER >= 700)
+#if (defined(_M_IX86) && _M_IX86 >= 300)
+#  define MSC_INLINE_ASM_32BIT_SUPPORT
+   /* Disable warning for no return value, typical of asm functions */
+#  pragma warning( disable : 4035 )
+#endif
+#endif
+
+#if (defined(__BORLANDC__) && __BORLANDC__ >= 452)
+#  define MSC_INLINE_ASM_32BIT_SUPPORT
+#endif
+
+#ifdef MSC_INLINE_ASM_32BIT_SUPPORT
+/* This code is intended for Microsoft C/C++ (32-bit) compatible compilers. */
+
+/*
+ * These two (three) macros make up the loop body of the CRC32 cruncher.
+ * registers modified:
+ *   eax  : crc value "c"
+ *   esi  : pointer to next data byte (or dword) "buf++"
+ * registers read:
+ *   edi  : pointer to base of crc_table array
+ * scratch registers:
+ *   ebx  : index into crc_table array
+ *          (requires upper three bytes = 0 when __686 is undefined)
+ */
+#ifndef __686
+#define Do_CRC { \
+  __asm { mov   bl, al }; \
+  __asm { shr   eax, 8 }; \
+  __asm { xor   eax, [edi+ebx*4] }; }
+#else /* __686 */
+#define Do_CRC { \
+  __asm { movzx ebx, al }; \
+  __asm { shr   eax, 8  }; \
+  __asm { xor   eax, [edi+ebx*4] }; }
+#endif /* ?__686 */
+
+#define Do_CRC_byte { \
+  __asm { xor   al, byte ptr [esi] }; \
+  __asm { inc   esi }; \
+  Do_CRC; }
+
+#define Do_CRC_byteof(ofs) { \
+  __asm { xor   al, byte ptr [esi+(ofs)] }; \
+  Do_CRC; }
+
+#ifndef NO_32_BIT_LOADS
+#ifdef IZ_CRCOPTIM_UNFOLDTBL
+# define SavLen  len            /* the edx register is needed elsewhere */
+# define UpdCRC_dword { \
+   __asm { movzx   ebx,al }; \
+   __asm { mov     edx,[edi+ebx*4+3072] }; \
+   __asm { movzx   ebx,ah }; \
+   __asm { shr     eax,16 }; \
+   __asm { xor     edx,[edi+ebx*4+2048] }; \
+   __asm { movzx   ebx,al }; \
+   __asm { shr     eax,8 }; \
+   __asm { xor     edx,[edi+ebx*4+1024] }; \
+   __asm { mov     eax,[edi+eax*4] }; \
+   __asm { xor     eax,edx }; }
+# define UpdCRC_dword_sh(dwPtrIncr) { \
+   __asm { movzx   ebx,al }; \
+   __asm { mov     edx,[edi+ebx*4+3072] }; \
+   __asm { movzx   ebx,ah }; \
+   __asm { xor     edx,[edi+ebx*4+2048] }; \
+   __asm { shr     eax,16 }; \
+   __asm { movzx   ebx,al }; \
+   __asm { add     esi, 4*dwPtrIncr }; \
+   __asm { shr     eax,8 }; \
+   __asm { xor     edx,[edi+ebx*4+1024] }; \
+   __asm { mov     eax,[edi+eax*4] }; \
+   __asm { xor     eax,edx }; }
+#else /* !IZ_CRCOPTIM_UNFOLDTBL */
+# define SavLen  edx            /* the edx register is free for use here */
+# define UpdCRC_dword { \
+    Do_CRC; \
+    Do_CRC; \
+    Do_CRC; \
+    Do_CRC; }
+# define UpdCRC_dword_sh(dwPtrIncr) { \
+    Do_CRC; \
+    Do_CRC; \
+    __asm { add   esi, 4*(dwPtrIncr) }; \
+    Do_CRC; \
+    Do_CRC; }
+#endif /* ?IZ_CRCOPTIM_UNFOLDTBL */
+
+#define Do_CRC_dword { \
+  __asm { xor   eax, dword ptr [esi] }; \
+  UpdCRC_dword_sh(1); }
+
+#define Do_CRC_4dword { \
+  __asm { xor   eax, dword ptr [esi] }; \
+  UpdCRC_dword; \
+  __asm { xor   eax, dword ptr [esi+4] }; \
+  UpdCRC_dword; \
+  __asm { xor   eax, dword ptr [esi+8] }; \
+  UpdCRC_dword; \
+  __asm { xor   eax, dword ptr [esi+12] }; \
+  UpdCRC_dword_sh(4); }
+#endif /* !NO_32_BIT_LOADS */
+
+/* ========================================================================= */
+ulg crc32(crc, buf, len)
+    ulg crc;                    /* crc shift register */
+    ZCONST uch *buf;            /* pointer to bytes to pump through */
+    extent len;                 /* number of bytes in buf[] */
+/* Run a set of bytes through the crc shift register.  If buf is a NULL
+   pointer, then initialize the crc shift register contents instead.
+   Return the current crc in either case. */
+{
+    __asm {
+                push    edx
+                push    ecx
+
+                mov     esi,buf         ;/* 2nd arg: uch *buf              */
+                sub     eax,eax         ;/*> if (!buf)                     */
+                test    esi,esi         ;/*>   return 0;                   */
+                jz      fine            ;/*> else {                        */
+
+                call    get_crc_table
+                mov     edi,eax
+                mov     eax,crc         ;/* 1st arg: ulg crc               */
+#ifndef __686
+                sub     ebx,ebx         ;/* ebx=0; => bl usable as a dword */
+#endif
+                mov     ecx,len         ;/* 3rd arg: extent len            */
+                not     eax             ;/*>   c = ~crc;                   */
+
+                test    ecx,ecx
+#ifndef NO_UNROLLED_LOOPS
+                jz      bail
+#  ifndef NO_32_BIT_LOADS
+align_loop:
+                test    esi,3           ;/* align buf pointer on next      */
+                jz      aligned_now     ;/*  dword boundary                */
+    }
+                Do_CRC_byte             ;
+    __asm {
+                dec     ecx
+                jnz     align_loop
+aligned_now:
+#  endif /* !NO_32_BIT_LOADS */
+                mov     SavLen,ecx      ;/* save current len for later  */
+                shr     ecx,4           ;/* ecx = len / 16    */
+                jz      No_Sixteens
+; align loop head at start of 486 internal cache line !!
+                align   16
+Next_Sixteen:
+    }
+#  ifndef NO_32_BIT_LOADS
+                Do_CRC_4dword ;
+#  else /* NO_32_BIT_LOADS */
+                Do_CRC_byteof(0) ;
+                Do_CRC_byteof(1) ;
+                Do_CRC_byteof(2) ;
+                Do_CRC_byteof(3) ;
+                Do_CRC_byteof(4) ;
+                Do_CRC_byteof(5) ;
+                Do_CRC_byteof(6) ;
+                Do_CRC_byteof(7) ;
+                Do_CRC_byteof(8) ;
+                Do_CRC_byteof(9) ;
+                Do_CRC_byteof(10) ;
+                Do_CRC_byteof(11) ;
+                Do_CRC_byteof(12) ;
+                Do_CRC_byteof(13) ;
+                Do_CRC_byteof(14) ;
+                Do_CRC_byteof(15) ;
+    __asm {     add     esi,16 };
+#  endif /* ?NO_32_BIT_LOADS */
+    __asm {
+                dec     ecx
+                jnz     Next_Sixteen
+No_Sixteens:
+                mov     ecx,SavLen
+                and     ecx,00000000FH  ;/* ecx = len % 16    */
+#  ifndef NO_32_BIT_LOADS
+                shr     ecx,2
+                jz      No_Fours
+Next_Four:
+    }
+                Do_CRC_dword ;
+    __asm {
+                dec     ecx
+                jnz     Next_Four
+No_Fours:
+                mov     ecx,SavLen
+                and     ecx,000000003H  ;/* ecx = len % 4    */
+#  endif /* !NO_32_BIT_LOADS */
+#endif /* !NO_UNROLLED_LOOPS */
+                jz      bail            ;/*>  if (len)                       */
+; align loop head at start of 486 internal cache line !!
+                align   16
+loupe:                                  ;/*>    do {                         */
+    }
+                Do_CRC_byte             ;/*       c = CRC32(c,*buf++,crctab);*/
+    __asm {
+                dec     ecx             ;/*>    } while (--len);             */
+                jnz     loupe
+
+bail:                                   ;/*> }                               */
+                not     eax             ;/*> return ~c;                      */
+fine:
+                pop     ecx
+                pop     edx
+    }
+#ifdef NEED_RETURN
+    return _EAX;
+#endif
+}
+#endif /* MSC_INLINE_ASM_32BIT_SUPPORT */
+#if (defined(_MSC_VER) && _MSC_VER >= 700)
+#if (defined(_M_IX86) && _M_IX86 >= 300)
+   /* Reenable missing return value warning */
+#  pragma warning( default : 4035 )
+#endif
+#endif
+#endif /* ASM_CRC && !USE_ZLIB && !CRC_TABLE_ONLY */
diff --git a/win32/crc_lcc.asm b/win32/crc_lcc.asm
new file mode 100644 (file)
index 0000000..1538d32
--- /dev/null
@@ -0,0 +1,166 @@
+;===========================================================================
+; Copyright (c) 1990-2006 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 2000-Apr-09 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+; crc_lcc.asm, optimized CRC calculation function for Zip and UnZip,
+; created by Paul Kienitz and Christian Spieler.  Last revised 02 Jan 2006.
+;
+; The code in this file has been copied verbatim from crc_i386.{asm|S};
+; only the assembler syntax and metacommands have been adapted to
+; the habits of the free LCC-Win32 C compiler package.
+; This version of the code uses the "optimized for i686" variant of
+; crc_i386.{asm|S}.
+; IMPORTANT NOTE to the Info-ZIP editors:
+; The TAB characters in this source file are required by the parser of
+; the LCC-Win32 assembler program and MUST NOT be removed!!
+;
+; For more information (and a revision log), look into the original
+; source files.
+;
+       .text
+       .file "crc32.c"
+       .text
+       .type   _crc32,function
+_crc32:
+       pushl   %ebp
+       movl    %esp,%ebp
+       pushl   %ecx
+       pushl   %ebx
+       pushl   %esi
+       pushl   %edi
+       .line   34
+       .line   37
+       movl    12(%ebp),%esi
+       subl    %eax,%eax
+       testl   %esi,%esi
+       jz      _$3
+       .line   39
+       call    _get_crc_table
+       movl    %eax,%edi
+       .line   41
+       movl    8(%ebp),%eax
+       movl    16(%ebp),%ecx
+       notl    %eax
+       testl   %ecx,%ecx
+       jz      _$4
+_$5:
+       testl   $3,%esi
+       jz      _$6
+       xorb    (%esi),%al
+       incl    %esi
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       decl    %ecx
+       jnz     _$5
+_$6:
+       movl    %ecx,%edx
+       shrl    $4,%ecx
+       jz      _$8
+_$7:
+       xorl    (%esi),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       xorl    4(%esi),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       xorl    8(%esi),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       xorl    12(%esi),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       addl    $16,%esi
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       decl    %ecx
+       jnz     _$7
+_$8:
+       movl    %edx,%ecx
+       andl    $0x0f,%ecx
+        shrl   $2,%ecx
+       jz      _$10
+_$9:
+       xorl    (%esi),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       addl    $4,%esi
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       decl    %ecx
+       jnz     _$9
+_$10:
+       movl    %edx,%ecx
+       andl    $0x03,%ecx
+       jz      _$4
+_$11:
+       xorb    (%esi),%al
+       incl    %esi
+       movzbl  %al,%ebx
+       shrl    $8,%eax
+       xorl    (%edi,%ebx,4),%eax
+       decl    %ecx
+       jnz     _$11
+_$4:
+       xorl    $0xffffffff,%eax
+_$3:
+       .line   52
+       popl    %edi
+       popl    %esi
+       popl    %ebx
+       leave
+       ret
+_$34:
+       .size   _crc32,_$34-_crc32
+       .globl  _crc32
+       .extern _get_crc_table
diff --git a/win32/gvmat64.asm b/win32/gvmat64.asm
new file mode 100644 (file)
index 0000000..4b5aa4d
--- /dev/null
@@ -0,0 +1,513 @@
+;uInt longest_match_x64(
+;    deflate_state *s,
+;    IPos cur_match);                             /* current match */
+
+; gvmat64.asm -- Asm portion of the optimized longest_match for 32 bits x86
+; Copyright (C) 1995-2005 Jean-loup Gailly, Brian Raiter and Gilles Vollant.
+;
+; File written by Gilles Vollant, by converting to assembly the longest_match
+;  from Jean-loup Gailly in deflate.c of zLib and infoZip zip.
+;
+;  and by taking inspiration on asm686 with masm, optimised assembly code 
+;        from Brian Raiter, written 1998
+;
+;         http://www.zlib.net
+;         http://www.winimage.com/zLibDll
+;         http://www.muppetlabs.com/~breadbox/software/assembly.html
+;
+; to compile this file for infozip Zip, I use option:
+;   ml64.exe /Flgvmat64 /c /Zi /DINFOZIP gvmat64.asm
+;
+; to compile this file for zLib, I use option:
+;   ml64.exe /Flgvmat64 /c /Zi gvmat64.asm
+; Be carrefull to adapt zlib1222add below to your version of zLib
+;   (if you use a version of zLib before 1.0.4 or after 1.2.2.2, change
+;    value of zlib1222add later)
+;
+; This file compile with Microsoft Macro Assembler (x64) for AMD64
+;
+;   ml64.exe is given with Visual Studio 2005 and Windows 2003 server DDK
+;
+;   (you can get Windows 2003 server DDK with ml64 and cl for AMD64 from
+;      http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price)
+;
+
+
+;uInt longest_match(s, cur_match)
+;    deflate_state *s;
+;    IPos cur_match;                             /* current match */
+.code
+longest_match PROC
+
+
+;LocalVarsSize   equ 88
+ LocalVarsSize   equ 72
+
+; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12
+; free register :  r14,r15
+; register can be saved : rsp
+
+ chainlenwmask   equ  rsp + 8 - LocalVarsSize    ; high word: current chain len
+                                                 ; low word: s->wmask
+;window          equ  rsp + xx - LocalVarsSize   ; local copy of s->window ; stored in r10
+;windowbestlen   equ  rsp + xx - LocalVarsSize   ; s->window + bestlen , use r10+r11
+;scanstart       equ  rsp + xx - LocalVarsSize   ; first two bytes of string ; stored in r12w
+;scanend         equ  rsp + xx - LocalVarsSize   ; last two bytes of string use ebx
+;scanalign       equ  rsp + xx - LocalVarsSize   ; dword-misalignment of string r13
+;bestlen         equ  rsp + xx - LocalVarsSize   ; size of best match so far -> r11d
+;scan            equ  rsp + xx - LocalVarsSize   ; ptr to string wanting match -> r9
+IFDEF INFOZIP
+ELSE
+ nicematch       equ  (rsp + 16 - LocalVarsSize) ; a good enough match size
+ENDIF
+
+save_rdi        equ  rsp + 24 - LocalVarsSize
+save_rsi        equ  rsp + 32 - LocalVarsSize
+save_rbx        equ  rsp + 40 - LocalVarsSize
+save_rbp        equ  rsp + 48 - LocalVarsSize
+save_r12        equ  rsp + 56 - LocalVarsSize
+save_r13        equ  rsp + 64 - LocalVarsSize
+;save_r14        equ  rsp + 72 - LocalVarsSize
+;save_r15        equ  rsp + 80 - LocalVarsSize
+
+
+
+;  all the +4 offsets are due to the addition of pending_buf_size (in zlib
+;  in the deflate_state structure since the asm code was first written
+;  (if you compile with zlib 1.0.4 or older, remove the +4).
+;  Note : these value are good with a 8 bytes boundary pack structure
+
+
+    MAX_MATCH           equ     258
+    MIN_MATCH           equ     3
+    MIN_LOOKAHEAD       equ     (MAX_MATCH+MIN_MATCH+1)
+
+
+;;; Offsets for fields in the deflate_state structure. These numbers
+;;; are calculated from the definition of deflate_state, with the
+;;; assumption that the compiler will dword-align the fields. (Thus,
+;;; changing the definition of deflate_state could easily cause this
+;;; program to crash horribly, without so much as a warning at
+;;; compile time. Sigh.)
+
+;  all the +zlib1222add offsets are due to the addition of fields
+;  in zlib in the deflate_state structure since the asm code was first written
+;  (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").
+;  (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").
+;  if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").
+
+
+IFDEF INFOZIP
+
+_DATA   SEGMENT
+COMM    window_size:DWORD
+; WMask ; 7fff
+COMM    window:BYTE:010040H
+COMM    prev:WORD:08000H
+; MatchLen : unused
+; PrevMatch : unused
+COMM    strstart:DWORD
+COMM    match_start:DWORD
+; Lookahead : ignore
+COMM    prev_length:DWORD ; PrevLen
+COMM    max_chain_length:DWORD
+COMM    good_match:DWORD
+COMM    nice_match:DWORD
+prev_ad equ OFFSET prev
+window_ad equ OFFSET window
+nicematch equ nice_match
+_DATA ENDS
+WMask equ 07fffh
+
+ELSE
+
+  IFNDEF zlib1222add
+    zlib1222add equ 0
+  ENDIF
+dsWSize         equ 56+zlib1222add+(zlib1222add/2)
+dsWMask         equ 64+zlib1222add+(zlib1222add/2)
+dsWindow        equ 72+zlib1222add
+dsPrev          equ 88+zlib1222add
+dsMatchLen      equ 128+zlib1222add
+dsPrevMatch     equ 132+zlib1222add
+dsStrStart      equ 140+zlib1222add
+dsMatchStart    equ 144+zlib1222add
+dsLookahead     equ 148+zlib1222add
+dsPrevLen       equ 152+zlib1222add
+dsMaxChainLen   equ 156+zlib1222add
+dsGoodMatch     equ 172+zlib1222add
+dsNiceMatch     equ 176+zlib1222add
+
+window_size     equ [ rcx + dsWSize]
+WMask           equ [ rcx + dsWMask]
+window_ad       equ [ rcx + dsWindow]
+prev_ad         equ [ rcx + dsPrev]
+strstart        equ [ rcx + dsStrStart]
+match_start     equ [ rcx + dsMatchStart]
+Lookahead       equ [ rcx + dsLookahead] ; 0ffffffffh on infozip
+prev_length     equ [ rcx + dsPrevLen]
+max_chain_length equ [ rcx + dsMaxChainLen]
+good_match      equ [ rcx + dsGoodMatch]
+nice_match      equ [ rcx + dsNiceMatch]
+ENDIF
+
+; parameter 1 in r8(deflate state s), param 2 in rdx (cur match)
+
+; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and
+; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp
+;
+; All registers must be preserved across the call, except for
+;   rax, rcx, rdx, r8, r9, r10, and r11, which are scratch.
+
+
+
+;;; Save registers that the compiler may be using, and adjust esp to
+;;; make room for our stack frame.
+
+
+;;; Retrieve the function arguments. r8d will hold cur_match
+;;; throughout the entire function. edx will hold the pointer to the
+;;; deflate_state structure during the function's setup (before
+;;; entering the main loop.
+
+; parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match)
+
+; this clear high 32 bits of r8, which can be garbage in both r8 and rdx
+
+        mov [save_rdi],rdi
+        mov [save_rsi],rsi
+        mov [save_rbx],rbx
+        mov [save_rbp],rbp
+IFDEF INFOZIP
+        mov r8d,ecx
+ELSE
+        mov r8d,edx
+ENDIF
+        mov [save_r12],r12
+        mov [save_r13],r13
+;        mov [save_r14],r14
+;        mov [save_r15],r15
+
+
+;;; uInt wmask = s->w_mask;
+;;; unsigned chain_length = s->max_chain_length;
+;;; if (s->prev_length >= s->good_match) {
+;;;     chain_length >>= 2;
+;;; }
+
+        mov edi, prev_length
+        mov esi, good_match
+        mov eax, WMask
+        mov ebx, max_chain_length
+        cmp edi, esi
+        jl  LastMatchGood
+        shr ebx, 2
+LastMatchGood:
+
+;;; chainlen is decremented once beforehand so that the function can
+;;; use the sign flag instead of the zero flag for the exit test.
+;;; It is then shifted into the high word, to make room for the wmask
+;;; value, which it will always accompany.
+
+        dec ebx
+        shl ebx, 16
+        or  ebx, eax
+
+;;; on zlib only
+;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+IFDEF INFOZIP
+        mov [chainlenwmask], ebx
+; on infozip nice_match = [nice_match]
+ELSE
+        mov eax, nice_match
+        mov [chainlenwmask], ebx
+        mov r10d, Lookahead
+        cmp r10d, eax
+        cmovnl r10d, eax
+        mov [nicematch],r10d
+ENDIF
+
+;;; register Bytef *scan = s->window + s->strstart;
+        mov r10, window_ad
+        mov ebp, strstart
+        lea r13, [r10 + rbp]
+
+;;; Determine how many bytes the scan ptr is off from being
+;;; dword-aligned.
+
+         mov r9,r13
+         neg r13
+         and r13,3
+
+;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+;;;     s->strstart - (IPos)MAX_DIST(s) : NIL;
+IFDEF INFOZIP
+        mov eax,07efah ; MAX_DIST = (WSIZE-MIN_LOOKAHEAD) (0x8000-(3+8+1))
+ELSE
+        mov eax, window_size
+        sub eax, MIN_LOOKAHEAD
+ENDIF
+        xor edi,edi
+        sub ebp, eax
+
+        mov r11d, prev_length
+
+        cmovng ebp,edi
+
+;;; int best_len = s->prev_length;
+
+
+;;; Store the sum of s->window + best_len in esi locally, and in esi.
+
+       lea  rsi,[r10+r11]
+
+;;; register ush scan_start = *(ushf*)scan;
+;;; register ush scan_end   = *(ushf*)(scan+best_len-1);
+;;; Posf *prev = s->prev;
+
+        movzx r12d,word ptr [r9]
+        movzx ebx, word ptr [r9 + r11 - 1]
+
+        mov rdi, prev_ad
+
+;;; Jump into the main loop.
+
+        mov edx, [chainlenwmask]
+
+        cmp bx,word ptr [rsi + r8 - 1]
+        jz  LookupLoopIsZero
+
+LookupLoop1:
+        and r8d, edx
+
+        movzx   r8d, word ptr [rdi + r8*2]
+        cmp r8d, ebp
+        jbe LeaveNow
+        sub edx, 00010000h
+        js  LeaveNow
+
+LoopEntry1:
+        cmp bx,word ptr [rsi + r8 - 1]
+        jz  LookupLoopIsZero
+
+LookupLoop2:
+        and r8d, edx
+
+        movzx   r8d, word ptr [rdi + r8*2]
+        cmp r8d, ebp
+        jbe LeaveNow
+        sub edx, 00010000h
+        js  LeaveNow
+
+LoopEntry2:
+        cmp bx,word ptr [rsi + r8 - 1]
+        jz  LookupLoopIsZero
+
+LookupLoop4:
+        and r8d, edx
+
+        movzx   r8d, word ptr [rdi + r8*2]
+        cmp r8d, ebp
+        jbe LeaveNow
+        sub edx, 00010000h
+        js  LeaveNow
+
+LoopEntry4:
+
+        cmp bx,word ptr [rsi + r8 - 1]
+        jnz LookupLoop1
+        jmp LookupLoopIsZero
+
+
+;;; do {
+;;;     match = s->window + cur_match;
+;;;     if (*(ushf*)(match+best_len-1) != scan_end ||
+;;;         *(ushf*)match != scan_start) continue;
+;;;     [...]
+;;; } while ((cur_match = prev[cur_match & wmask]) > limit
+;;;          && --chain_length != 0);
+;;;
+;;; Here is the inner loop of the function. The function will spend the
+;;; majority of its time in this loop, and majority of that time will
+;;; be spent in the first ten instructions.
+;;;
+;;; Within this loop:
+;;; ebx = scanend
+;;; r8d = curmatch
+;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
+;;; esi = windowbestlen - i.e., (window + bestlen)
+;;; edi = prev
+;;; ebp = limit
+
+LookupLoop:
+        and r8d, edx
+
+        movzx   r8d, word ptr [rdi + r8*2]
+        cmp r8d, ebp
+        jbe LeaveNow
+        sub edx, 00010000h
+        js  LeaveNow
+
+LoopEntry:
+
+        cmp bx,word ptr [rsi + r8 - 1]
+        jnz LookupLoop1
+LookupLoopIsZero:
+        cmp     r12w, word ptr [r10 + r8]
+        jnz LookupLoop1
+
+
+;;; Store the current value of chainlen.
+        mov [chainlenwmask], edx
+
+;;; Point edi to the string under scrutiny, and esi to the string we
+;;; are hoping to match it up with. In actuality, esi and edi are
+;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is
+;;; initialized to -(MAX_MATCH_8 - scanalign).
+
+        lea rsi,[r8+r10]
+        mov rdx, 0fffffffffffffef8h; -(MAX_MATCH_8)
+        lea rsi, [rsi + r13 + 0108h] ;MAX_MATCH_8]
+        lea rdi, [r9 + r13 + 0108h] ;MAX_MATCH_8]
+
+        prefetcht1 [rsi+rdx]
+        prefetcht1 [rdi+rdx]
+        
+     
+;;; Test the strings for equality, 8 bytes at a time. At the end,
+;;; adjust rdx so that it is offset to the exact byte that mismatched.
+;;;
+;;; We already know at this point that the first three bytes of the
+;;; strings match each other, and they can be safely passed over before
+;;; starting the compare loop. So what this code does is skip over 0-3
+;;; bytes, as much as necessary in order to dword-align the edi
+;;; pointer. (rsi will still be misaligned three times out of four.)
+;;;
+;;; It should be confessed that this loop usually does not represent
+;;; much of the total running time. Replacing it with a more
+;;; straightforward "rep cmpsb" would not drastically degrade
+;;; performance.
+
+
+LoopCmps:
+        mov rax, [rsi + rdx]
+        xor rax, [rdi + rdx]
+        jnz LeaveLoopCmps
+
+        mov rax, [rsi + rdx + 8]
+        xor rax, [rdi + rdx + 8]
+        jnz LeaveLoopCmps8
+
+
+        mov rax, [rsi + rdx + 8+8]
+        xor rax, [rdi + rdx + 8+8]
+        jnz LeaveLoopCmps16
+
+        add rdx,8+8+8
+
+        jmp short LoopCmps
+LeaveLoopCmps16: add rdx,8
+LeaveLoopCmps8: add rdx,8
+LeaveLoopCmps:
+
+        test    eax, 0000FFFFh
+        jnz LenLower
+
+        test eax,0ffffffffh
+
+        jnz LenLower32
+
+        add rdx,4
+        shr rax,32
+        or ax,ax
+        jnz LenLower
+
+LenLower32:
+        shr eax,16
+        add rdx,2
+LenLower:   sub al, 1
+        adc rdx, 0
+;;; Calculate the length of the match. If it is longer than MAX_MATCH,
+;;; then automatically accept it as the best possible match and leave.
+
+        lea rax, [rdi + rdx]
+        sub rax, r9
+        cmp eax, MAX_MATCH
+        jge LenMaximum
+
+;;; If the length of the match is not longer than the best match we
+;;; have so far, then forget it and return to the lookup loop.
+;///////////////////////////////////
+
+        cmp eax, r11d
+        jg  LongerMatch
+
+        lea rsi,[r10+r11]
+
+        mov rdi, prev_ad
+        mov edx, [chainlenwmask]
+        jmp LookupLoop
+
+;;;         s->match_start = cur_match;
+;;;         best_len = len;
+;;;         if (len >= nice_match) break;
+;;;         scan_end = *(ushf*)(scan+best_len-1);
+
+LongerMatch:
+        mov r11d, eax
+        mov match_start, r8d
+        cmp eax, [nicematch]
+        jge LeaveNow
+
+        lea rsi,[r10+rax]
+
+        movzx   ebx, word ptr [r9 + rax - 1]
+        mov rdi, prev_ad
+        mov edx, [chainlenwmask]
+        jmp LookupLoop
+
+;;; Accept the current string, with the maximum possible length.
+
+LenMaximum:
+        mov r11d,MAX_MATCH
+        mov match_start, r8d
+
+;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+;;; return s->lookahead;
+
+LeaveNow:
+IFDEF INFOZIP
+        mov eax,r11d
+ELSE
+        mov eax, Lookahead
+        cmp r11d, eax
+        cmovng eax, r11d
+ENDIF
+
+;;; Restore the stack and return from whence we came.
+
+
+        mov rsi,[save_rsi]
+        mov rdi,[save_rdi]
+        mov rbx,[save_rbx]
+        mov rbp,[save_rbp]
+        mov r12,[save_r12]
+        mov r13,[save_r13]
+;        mov r14,[save_r14]
+;        mov r15,[save_r15]
+
+
+        ret 0
+; please don't remove this string !
+; Your can freely use gvmat64 in any free or commercial app
+; but it is far better don't remove the string in the binary!
+    db     0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0
+longest_match   ENDP
+
+match_init PROC
+  ret 0
+match_init ENDP
+
+
+END
diff --git a/win32/lm32_lcc.asm b/win32/lm32_lcc.asm
new file mode 100644 (file)
index 0000000..0450fe3
--- /dev/null
@@ -0,0 +1,174 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; match32.asm by Jean-loup Gailly.
+
+; match32.asm, optimized version of longest_match() in deflate.c
+; To be used only with 32 bit flat model. To simplify the code, the option
+; -DDYN_ALLOC is not supported.
+; This file is only optional. If you don't have an assembler, use the
+; C version (add -DNO_ASM to CFLAGS in makefile and remove match.o
+; from OBJI). If you have reduced WSIZE in zip.h, then make sure this is
+; assembled with an equivalent -DWSIZE=<whatever>.
+;
+; Win32 (Windows NT) version - 1994/04/13 by Steve Salisbury
+; * works with Microsoft MASM 6.1X and Microsoft Visual C++ / 32-bit edition
+;
+; The code in this file has been copied verbatim from match32.{asm|S};
+; only the assembler syntax and metacommands have been adapted to
+; the habits of the free LCC-Win32 C compiler package.
+; IMPORTANT NOTE to the Info-ZIP editors:
+; The TAB characters in this source file are required by the parser of
+; the LCC-Win32 assembler program and MUST NOT be removed!!
+;
+;==============================================================================
+;
+; Do NOT assemble this source if external crc32 routine from zlib gets used.
+;
+
+
+;/* This version is for 386 Unix or OS/2 in 32 bit mode.
+; * Warning: it uses the AT&T syntax: mov source,dest
+; * This file is only optional. If you want to force the C version,
+; * add -DNO_ASM to CFLAGS in Makefile and set OBJA to an empty string.
+; * If you have reduced WSIZE in (g)zip.h, then make sure this is
+; * assembled with an equivalent -DWSIZE=<whatever>.
+; * This version assumes static allocation of the arrays (-DDYN_ALLOC not used).
+; */
+
+        .text
+        .file  "match.S"
+
+
+        .text
+        .type  _match_init,function
+
+_match_init:
+        ret
+_$98:
+        .size  _match_init,_$98-_match_init
+        .globl _match_init
+
+;/*-----------------------------------------------------------------------
+; * Set match_start to the longest match starting at the given string and
+; * return its length. Matches shorter or equal to prev_length are discarded,
+; * in which case the result is equal to prev_length and match_start is
+; * garbage.
+; * IN assertions: cur_match is the head of the hash chain for the current
+; *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+; */
+
+        .align 4
+        .type  _longest_match,function
+
+_longest_match: ;/* int longest_match(cur_match) */
+
+;       cur_match     equ 20(%esp)
+;     /* return address */               /* esp+16 */
+        push    %ebp
+        push    %edi
+;/* esp+8  */
+        push    %esi
+;/* esp+4  */
+        push    %ebx
+;/* esp    */
+
+;/*
+; *      match        equ esi
+; *      scan         equ edi
+; *      chain_length equ ebp
+; *      best_len     equ ebx
+; *      limit        equ edx
+; */
+        mov     20(%esp),%esi
+        mov     _strstart,%edx
+        mov     _max_chain_length,%ebp
+        mov     %edx,%edi
+        sub     $(32768-262),%edx
+        cld
+        jae     limit_ok
+        sub     %edx,%edx
+limit_ok:
+        add     $2+_window,%edi
+        mov     _prev_length,%ebx
+        movw    -2(%edi),%cx
+        movw    -3(%ebx,%edi),%ax
+        cmp     _good_match,%ebx
+        jb      do_scan
+        shr     $2,%ebp
+        jmp     do_scan
+
+        .align 4
+long_loop:
+;/* at this point, edi == scan+2, esi == cur_match */
+        movw    -3(%ebx,%edi),%ax
+        movw     -2(%edi),%cx
+short_loop:
+;/*
+; * at this point, di == scan+2, si == cur_match,
+; * ax = scan[best_len-1..best_len] and cx = scan[0..1]
+; */
+        and     $(32768-1), %esi
+        dec     %ebp
+        movw    _prev(,%esi,2),%si
+        jz      the_end
+        cmp     %edx,%esi
+        jbe     the_end
+do_scan:
+        cmpw    _window-1(%ebx,%esi),%ax
+        jne     short_loop
+        cmpw    _window(%esi),%cx
+        jne     short_loop
+
+        add     $2+_window,%esi
+        mov     $((258>>1)-1),%ecx
+        mov     %edi,%eax
+        repe;   cmpsw
+;/* loop until mismatch */
+        je      maxmatch
+;/* match of length MAX_MATCH? */
+mismatch:
+        movb    -2(%edi),%cl
+        xchg    %edi,%eax
+        subb    -2(%esi),%cl
+        sub     %edi,%eax
+        sub     $2+_window,%esi
+        sub     %eax,%esi
+        subb    $1,%cl
+        adc     $0,%eax
+        cmp     %ebx,%eax
+        jle     long_loop
+        mov     %esi,_match_start
+        mov     %eax,%ebx
+        cmp     _nice_match,%eax
+; /* len >= nice_match ? */
+        jl      long_loop
+the_end:
+        mov     %ebx,%eax
+        pop     %ebx
+        pop     %esi
+        pop     %edi
+        pop     %ebp
+        ret
+        .align 4
+maxmatch:
+        cmpsb
+        jmp     mismatch
+_$99:
+
+        .size  _longest_match,_$99-_longest_match
+        .globl _longest_match
+
+        .extern        _nice_match
+        .extern        _good_match
+        .extern        _max_chain_length
+        .extern        _match_start
+        .extern        _strstart
+        .extern        _prev_length
+        .extern        _prev
+        .extern        _window
diff --git a/win32/makefile.a64 b/win32/makefile.a64
new file mode 100644 (file)
index 0000000..d2bc841
--- /dev/null
@@ -0,0 +1,134 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# 32-bit Microsoft Visual C++
+
+# To use, do "nmake -f makefile.w32"
+
+# Add -DNO_ASM to CFLAGS and comment out the ASMOBJS definition if
+# you do not have masm 6.1X.
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = $(LOCAL_ZIP)
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+ASMOBJS = gvmat64.obj
+
+# ------------- 32-bit Microsoft Visual C++ -------------
+CC=cl -nologo
+CFLAGS=-W3 -O2 -DNO_ASM_CRC -DASMV -DWIN32 $(LOC)
+UTILFLAGS=$(CFLAGS) -DUTIL -Fo$@
+
+# Remove "-coff" from ASFLAGS if you do not have MASM 6.11.
+
+AS=ml64 -nologo
+ASFLAGS= /c /Zi /DINFOZIP
+
+# If you build 16-bit executables with MS Visual C++ v1.0/1.5 and link them
+# with the /KNOWEAS switch, you can build dual-mode MS-DOS/Win32 executables
+# by passing the -stub switch to the 32-bit linker to specify the 16-bit part.
+
+LD=link -nologo
+LDFLAGS=advapi32.lib
+
+# variables
+OBJZ = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+    crc32.obj globals.obj
+
+OBJI = deflate.obj trees.obj $(ASMOBJS) win32.obj win32zip.obj nt.obj
+
+OBJU = zipfile_.obj fileio_.obj util_.obj globals.obj win32_.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj crc32_.obj crypt_.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h win32/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips:   $(ZIPS)
+
+zip.obj:        zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+    $(CC) -c $(CFLAGS) $*.c
+
+zipfile.obj:    zipfile.c $(ZIP_H) crc32.h
+    $(CC) -c $(CFLAGS) $*.c
+
+zipup.obj:      zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32/zipup.h
+    $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj:     fileio.c $(ZIP_H) crc32.h
+    $(CC) -c $(CFLAGS) $*.c
+
+util.obj:       util.c $(ZIP_H)
+    $(CC) -c $(CFLAGS) $*.c
+
+globals.obj:    globals.c $(ZIP_H)
+    $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj:    deflate.c $(ZIP_H)
+    $(CC) -c $(CFLAGS) $*.c
+
+trees.obj:      trees.c $(ZIP_H)
+    $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj:      crc32.c $(ZIP_H) crc32.h
+    $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj:      crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+    $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj:      ttyio.c $(ZIP_H) crypt.h ttyio.h
+    $(CC) -c $(CFLAGS) $*.c
+
+win32zip.obj:   win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+    $(CC) -c $(CFLAGS) -I. win32/win32zip.c
+
+win32.obj:      win32/win32.c $(ZIP_H) win32/win32zip.h
+    $(CC) -c $(CFLAGS) -I. win32/win32.c
+
+nt.obj:         win32/nt.c $(ZIP_H) win32/nt.h
+    $(CC) -c $(CFLAGS) -I. win32/nt.c
+
+zipcloak.obj:   zipcloak.c $(ZIP_H) revision.h crypt.h ttyio.h
+    $(CC) -c $(CFLAGS) $*.c
+
+zipnote.obj:    zipnote.c $(ZIP_H) revision.h
+    $(CC) -c $(CFLAGS) $*.c
+
+zipsplit.obj:   zipsplit.c $(ZIP_H) revision.h
+    $(CC) -c $(CFLAGS) $*.c
+
+zipfile_.obj:   zipfile.c $(ZIP_H) crc32.h
+    $(CC) -c $(UTILFLAGS) zipfile.c
+
+fileio_.obj:    fileio.c $(ZIP_H) crc32.h
+    $(CC) -c $(UTILFLAGS) fileio.c
+
+util_.obj:      util.c $(ZIP_H)
+    $(CC) -c $(UTILFLAGS) util.c
+
+crc32_.obj:     crc32.c $(ZIP_H) crc32.h
+    $(CC) -c $(UTILFLAGS) crc32.c
+
+crypt_.obj:     crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+    $(CC) -c $(UTILFLAGS) crypt.c
+
+win32_.obj:     win32/win32.c $(ZIP_H) win32/win32zip.h
+    $(CC) -c $(UTILFLAGS) -I. win32/win32.c
+
+gvmat64.obj:    win32/gvmat64.asm
+    $(AS) $(ASFLAGS) win32\gvmat64.asm
+
+zip.exe: $(OBJZ) $(OBJI)
+    $(LD) $(LDFLAGS) $(OBJZ) $(OBJI)
+
+zipcloak.exe: $(OBJC)
+    $(LD) $(LDFLAGS) $(OBJC)
+
+zipnote.exe: $(OBJN)
+    $(LD) $(LDFLAGS) $(OBJN)
+
+zipsplit.exe: $(OBJS)
+    $(LD) $(LDFLAGS) $(OBJS)
diff --git a/win32/makefile.bor b/win32/makefile.bor
new file mode 100644 (file)
index 0000000..10b4609
--- /dev/null
@@ -0,0 +1,189 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# Borland C++ for Win32.
+# By E-Yen Tan.
+# Updated on 18 Dec 2005 by Cosmin Truta.
+# Last updated on 22 Jun 2008 by Christian Spieler.
+
+# To use, do "make -fwin32\makefile.bor"
+
+# Add -DNO_ASM to LOC and comment out the ASMOBJS definition below
+# if you do not have tasm32.
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+!IF $(USEASM)
+LOC = $(LOCAL_ZIP)
+!ELSE
+LOC = -DNO_ASM $(LOCAL_ZIP)
+!ENDIF
+
+# CPU type: 3 (i386), 4 (i486), 5 (Pentium), etc.
+CPU_TYP = 6
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+!IF $(USEASM)
+ASMOBJS = match32.obj
+CRCA_O = crc_i386.obj
+!ENDIF
+
+ASCPUFLAG = __$(CPU_TYP)86
+
+VPATH=.;win32
+CC = bcc32
+CFLAGS=-w -w-aus -w-ccc -w-par -w-sig -O2 -I. -DWIN32 $(LOC)
+UTILFLAGS=-DUTIL $(CFLAGS) -o
+
+!ifdef USETASM16
+AS=tasm
+!else
+AS=tasm32
+!endif
+ASFLAGS=-ml -t -m2 -D$(ASCPUFLAG) $(LOC)
+
+LD=ilink32
+LDFLAGS=
+
+# variables
+OBJZ1 = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+       crc32.obj $(CRCA_O) globals.obj
+OBJZ2 = deflate.obj trees.obj $(ASMOBJS)
+OBJZS = win32zip.obj win32.obj win32i64.obj nt.obj
+OBJZ  = $(OBJZ1) $(OBJZ2) $(OBJZS)
+
+OBJU  = zipfile_.obj fileio_.obj util_.obj crc32_.obj $(CRCA_O) globals.obj \
+       win32_.obj win32i64.obj
+OBJN  = zipnote.obj $(OBJU)
+OBJC  = zipcloak.obj crypt_.obj ttyio.obj $(OBJU)
+OBJS  = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h win32/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips: $(ZIPS)
+
+zip.obj:        zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipfile.obj:    zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipup.obj:      zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32/zipup.h
+       $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj:     fileio.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+util.obj:       util.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+globals.obj:    globals.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj:    deflate.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+trees.obj:      trees.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj:      crc32.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj:      crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj:      ttyio.c $(ZIP_H) crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+win32zip.obj:   win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+       $(CC) -c $(CFLAGS) win32/$*.c
+
+win32.obj:      win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) -c $(CFLAGS) win32/$*.c
+
+win32i64.obj:   win32/win32i64.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) win32/$*.c
+
+nt.obj:         win32/nt.c $(ZIP_H) win32/nt.h
+       $(CC) -c $(CFLAGS) win32/$*.c
+
+zipcloak.obj:   zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipnote.obj:    zipnote.c $(ZIP_H) revision.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipsplit.obj:   zipsplit.c $(ZIP_H) revision.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipfile_.obj:   zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS)$* zipfile.c
+
+fileio_.obj:    fileio.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS)$* fileio.c
+
+util_.obj:      util.c $(ZIP_H)
+       $(CC) -c $(UTILFLAGS)$* util.c
+
+crc32_.obj:     crc32.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS)$* crc32.c
+
+crypt_.obj:     crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c $(UTILFLAGS)$* crypt.c
+
+win32_.obj:     win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) -c $(UTILFLAGS)$* win32/win32.c
+
+!ifdef USEMASM
+crc_i386.obj:   win32/crc_i386.asm
+       masm -ml win32/crc_i386.asm,$@;
+!else
+!ifndef ASMOVERBCC32
+crc_i386.obj:   win32/crc_i386.asm
+       $(AS) $(ASFLAGS) win32\crc_i386.asm, $@ ;
+!else
+crc_i386.obj:  win32/crc_i386.c crc32.h
+       $(CC) -c $(CFLAGS) -o$@ win32/crc_i386.c
+!endif
+!endif
+
+!ifdef USEMASM
+match32.obj:    win32/match32.asm
+       masm -ml win32/match32.asm,$@;
+!else
+match32.obj:    win32/match32.asm
+       $(AS) $(ASFLAGS) win32\match32.asm, $@ ;
+!endif
+
+zip.res:        win32/zip.rc revision.h
+       $(RC) /l 0x409 /fo$@ /i win32 /d WIN32 win32/zip.rc
+
+# Split the command line to fit in the MS-DOS 128 byte limit by using
+# Borland-Make specific response file syntax:
+zip.exe: $(OBJZ) zip.res
+       $(LD) -Gn -x -c -ap -Tpe @&&|
+c0x32.obj $(OBJZ),$@,,import32.lib cw32.lib,,zip.res
+|
+
+zipcloak.exe: $(OBJC)
+       $(CC) $(LDFLAGS) @&&|
+$(OBJC)
+|
+
+zipnote.exe: $(OBJN)
+       $(CC) $(LDFLAGS) @&&|
+$(OBJN)
+|
+
+zipsplit.exe: $(OBJS)
+       $(CC) $(LDFLAGS) @&&|
+$(OBJS)
+|
+
+clean:
+       -del *.obj
+       -del *.res
+       -del *.exe
+       -del *.tds
diff --git a/win32/makefile.dj b/win32/makefile.dj
new file mode 100644 (file)
index 0000000..902c9ed
--- /dev/null
@@ -0,0 +1,112 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit
+# for djgpp 2.01 and RSXNTDJ 1.3.1 under Windows 95 / Windows NT
+# Derived from makefile.os2 by E-Yen Tan. Last updated 07 Jan 2007.
+
+CC = gcc -O2 -m486 -Wall -Zwin32
+CFLAGS = -DWIN32 -DASM_CRC $(LOCAL_ZIP)
+AS = gcc
+ASFLAGS = -Di386
+LDFLAGS = -o ./
+LDFLAGS2 =
+OBJ=.o
+
+CRC32=crc_gcc
+OBJA    = matchgcc.o
+OBJZS   = win32.o win32zip.o nt.o
+OBJUS   = win32_.o
+OSDEP_H = win32/osdep.h
+
+ADVAPI32 = adv32
+ADVAPI32LIB = lib$(ADVAPI32).a
+L_ADVAPI32 = -l$(ADVAPI32)
+
+OBJZ1 = zip$(OBJ) zipfile$(OBJ) zipup$(OBJ) fileio$(OBJ) util$(OBJ) \
+       crc32$(OBJ) $(CRCA_O)
+OBJZ2 = globals$(OBJ) deflate$(OBJ) trees$(OBJ) crypt$(OBJ) \
+       ttyio$(OBJ)
+OBJZ  = $(OBJZ1) $(OBJZ2) $(OBJZS) $(OBJA)
+
+OBJU1 = zipfile_$(OBJ) fileio_$(OBJ) util_$(OBJ) crc32$(OBJ) globals$(OBJ)
+OBJU  = $(OBJU1) $(OBJUS)
+
+OBJN =  zipnote$(OBJ) $(OBJU)
+OBJS =  zipsplit$(OBJ) $(OBJU)
+OBJC =  zipcloak$(OBJ) crc32_$(OBJ) crypt_$(OBJ) ttyio$(OBJ) $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h $(OSDEP_H)
+
+# rules
+
+.SUFFIXES: .c $(OBJ)
+
+.c$(OBJ):
+       $(CC) -c -I. $(CFLAGS) $<
+
+.asm$(OBJ):
+       $(AS) $(ASFLAGS) $<
+
+all:    zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip$(OBJ):      zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipfile$(OBJ):  zipfile.c $(ZIP_H) crc32.h
+zipup$(OBJ):    zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32/zipup.h
+fileio$(OBJ):   fileio.c $(ZIP_H) crc32.h
+util$(OBJ):     util.c $(ZIP_H)
+globals$(OBJ):  globals.c $(ZIP_H)
+deflate$(OBJ):  deflate.c $(ZIP_H)
+trees$(OBJ):    trees.c $(ZIP_H)
+crc32$(OBJ):    crc32.c $(ZIP_H) crc32.h
+crypt$(OBJ):    crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio$(OBJ):    ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+win32zip$(OBJ): win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+       $(CC) -c -I. $(CFLAGS) win32/win32zip.c
+
+win32$(OBJ):    win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) -c -I. $(CFLAGS) win32/win32.c
+
+nt$(OBJ):       win32/nt.c $(ZIP_H) win32/nt.h
+       $(CC) -c -I. $(CFLAGS) win32/nt.c
+
+crc_gcc$(OBJ):  crc_i386.S                                      # 32bit, GNU AS
+       $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o$@ crc_i386.S
+
+matchgcc$(OBJ): match.S
+       $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o$@ match.S
+
+zipcloak$(OBJ): zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipnote$(OBJ):  zipnote.c $(ZIP_H) revision.h
+zipsplit$(OBJ): zipsplit.c $(ZIP_H) revision.h
+
+zipfile_$(OBJ): zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c -I. $(CFLAGS) -DUTIL -o$@ zipfile.c
+
+fileio_$(OBJ):  fileio.c $(ZIP_H) crc32.h
+       $(CC) -c -I. $(CFLAGS) -DUTIL -o$@ fileio.c
+
+util_$(OBJ):    util.c $(ZIP_H) os2/os2zip.h
+       $(CC) -c -I. $(CFLAGS) -DUTIL -o$@ util.c
+
+crc32_$(OBJ):   crc32.c $(ZIP_H) crc32.h
+       $(CC) -c -I. $(CFLAGS) -DUTIL -o$@ crc32.c
+
+crypt_$(OBJ):   crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c -I. $(CFLAGS) -DUTIL -o$@ crypt.c
+
+win32_$(OBJ):   win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) -c -I. $(CFLAGS) -DUTIL -o$@ win32/win32.c
+
+$(ADVAPI32LIB):
+       makelib "$(windir)/system/advapi32.dll" -o ./$@
+
+zip.exe: $(OBJZ) $(ADVAPI32LIB)
+       $(CC) $(LDFLAGS)$@ $(OBJZ) $(L_ADVAPI32) $(LDFLAGS2)
+
+zipcloak.exe: $(OBJC)
+       $(CC) $(LDFLAGS)$@ $(OBJC) $(LDFLAGS2)
+
+zipnote.exe: $(OBJN)
+       $(CC) $(LDFLAGS)$@ $(OBJN) $(LDFLAGS2)
+
+zipsplit.exe: $(OBJS)
+       $(CC) $(LDFLAGS)$@ $(OBJS) $(LDFLAGS2)
diff --git a/win32/makefile.emx b/win32/makefile.emx
new file mode 100644 (file)
index 0000000..5f050ab
--- /dev/null
@@ -0,0 +1,304 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit
+# using emx 0.9c+rsxnt for Windows 95/98 and Windows NT and emx 0.9c for DOS.
+# By Kai-Uwe Rommel, Chr. Spieler, E-Yen Tan (and others).
+# Last updated 18th February 2007.
+#
+# Supported Make utilities:
+# - Microsoft/IBM nmake (e.g. from MSC 6.0 or newer)
+# - dmake 3.8 or higher
+# - GNU make, at least version 3.68 (GNUish 16-bit port, RSXNT Make 3.75,
+#   DJGPP v1.12 Make 3.71, some versions of DJGPP v2.x 32-bit Make;
+#   current DJGPP v2.01 Make 3.76.1 does NOT work)
+# - NOT watcom make
+# The "smart" Make utilities mentioned below are Christian Spieler's
+# enhanced version of GNUish 16-bit Make (3.74) and his adaption of these
+# GNU Make sources to EMX (32-bit).
+
+# Supported 32-bit C Compilers (created programs run under WinNT/Win95 only):
+# - GNU gcc (emx/rsxnt kit 0.9c or newer)
+
+# Supported Cross-Compilers for MS-DOS:
+# - GNU gcc (emx kit 0.9c or newer, 32-bit)
+
+# Supported Assemblers:
+# - GNU as with GNU gcc
+
+
+# To use, enter "make/nmake/dmake -f win32/makefile.emx"
+# (this makefile depends on its name being "win32/makefile.emx").
+
+# Add -DDYN_ALLOC to ASFLAGS if you have defined it in tailor.h or CFLAGS
+
+# Note: assembly language modules are really only supported for
+# GNU gcc 32-bit compilation.
+
+
+default:
+       @echo "Enter $(MAKE) -f win32/makefile.emx target"
+       @echo "where target is one of:"
+       @echo "   gcc gccso gccdyn gccdebug gcczl gccdos gccdoszl"
+       @echo "   -----------------------------------------------"
+       @echo "Or, specify a specific target for a partial build,"
+       @echo "This uses >gcc< setup (win32 statically linked binary)"
+
+# emx 0.9c, gcc, PE format, statically linked C runtime and rsxnt.dll
+gcc:   all
+
+# emx 0.9c, gcc, PE format, statically linked C runtime, standalone
+gccso:
+       $(MAKE) -f win32/makefile.emx all \
+       CC="gcc -Zwin32 -Zsys -O2 -m486 -Wall" \
+       CFLAGS="-DWIN32 -DASM_CRC" \
+       AS="gcc -Zwin32" \
+       ASFLAGS="-Di386" \
+       LDFLAGS="-o ./" \
+       LDFLAGS2="-ladvapi32 -s" \
+       OUT="-o" \
+       OBJ=".o" \
+       CRCA_O="crc_gcc.o" \
+       CRCAUO="crcgcc_.o" \
+       OBJA="matchgcc.o" \
+       DEF="win32/zip.def"
+
+# emx 0.9c, gcc, PE format, dynamically linked C runtime and rsxnt.dll
+gccdyn:
+       $(MAKE) -f win32/makefile.emx all \
+       CC="gcc -Zwin32 -Zcrtdll=crtrsxnt -O2 -m486 -Wall" \
+       CFLAGS="-DWIN32 -DASM_CRC" \
+       AS="gcc -Zwin32" \
+       ASFLAGS="-Di386" \
+       LDFLAGS="-o ./" \
+       LDFLAGS2="-ladvapi32 -s" \
+       OUT="-o" \
+       OBJ=".o" \
+       CRCA_O="crc_gcc.o" \
+       CRCAUO="crcgcc_.o" \
+       OBJA="matchgcc.o" \
+       DEF="win32/zip.def"
+
+# emx 0.9c, gcc, PE format, with debug info for gdb
+gccdebug:
+       $(MAKE) -f win32/makefile.emx all \
+       CC="gcc -Zwin32 -O2 -g -Wall" \
+       CFLAGS="-DWIN32 -DASM_CRC" \
+       AS="gcc -Zwin32" \
+       ASFLAGS="-Di386" \
+       LDFLAGS="-o ./" \
+       LDFLAGS2="-ladvapi32 -Zsmall-conv" \
+       OUT="-o" \
+       OBJ=".o" \
+       CRCA_O="crc_gcc.o" \
+       CRCAUO="crcgcc_.o" \
+       OBJA="matchgcc.o" \
+       DEF="win32/zip.def"
+
+# emx 0.9c, gcc, PE format,, statically linked zlib, C runtime, and rsxnt.dll
+gcczl:
+       $(MAKE) -f win32/makefile.emx all \
+       CC="gcc -Zwin32 -O2 -m486 -Wall" \
+       CFLAGS="-DWIN32 -DUSE_ZLIB" \
+       AS="gcc -Zwin32" \
+       ASFLAGS="-Di386 -DUSE_ZLIB" \
+       LDFLAGS="-o ./" \
+       LDFLAGS2="-L. -lzlib -ladvapi32 -s" \
+       OUT="-o" \
+       OBJ=".o" \
+       CRCA_O="" \
+       CRCAUO="" \
+       OBJA="" \
+       DEF="win32/zip.def"
+
+# emx 0.9c, gcc, a.out format, for MS-DOS
+gccdos:
+       $(MAKE) -f win32/makefile.emx all \
+       CC="gcc -O2 -m486 -Wall" \
+       CFLAGS="-DDOS -DMSDOS -DASM_CRC" \
+       AS="gcc" \
+       ASFLAGS="-Di386" \
+       LDFLAGS="-o ./" \
+       LDFLAGS2="-s -Zsmall-conv" \
+       OUT="-o" \
+       OBJ=".o" \
+       CRCA_O="crc_gcc.o" \
+       CRCAUO="crcgcc_.o" \
+       OBJA="matchgcc.o" \
+       OBJZS="msdos.o" \
+       OBJUS="msdos_.o" \
+       OSDEP_H="msdos/osdep.h" \
+       ZIPUP_H="msdos/zipup.h"
+
+# emx 0.9c, gcc, a.out format, for MS-DOS, using zlib
+gccdoszl:
+       $(MAKE) -f win32/makefile.emx all \
+       CC="gcc -O2 -m486 -Wall" \
+       CFLAGS="-DDOS -DMSDOS -DUSE_ZLIB" \
+       AS="gcc" \
+       ASFLAGS="-Di386 -DUSE_ZLIB" \
+       LDFLAGS="-o ./" \
+       LDFLAGS2="-L. -lzlib -s -Zsmall-conv" \
+       OUT="-o" \
+       OBJ=".o" \
+       CRCA_O="" \
+       CRCAUO="" \
+       OBJA="" \
+       OBJZS="msdos.o" \
+       OBJUS="msdos_.o" \
+       OSDEP_H="msdos/osdep.h" \
+       ZIPUP_H="msdos/zipup.h"
+
+# VPATH = .;win32
+
+# variables
+
+#default settings for target dependent macros:
+
+# the "gcc" (statically linked Win32 executables) target:
+CC=gcc -Zwin32 -O2 -m486 -Wall
+CFLAGS=-DWIN32 -DASM_CRC
+AS=gcc -Zwin32
+ASFLAGS=-Di386
+LDFLAGS=-o ./
+LDFLAGS2=-ladvapi32 -s -Zsmall-conv
+OUT=-o
+OBJ=.o
+CRCA_O=crc_gcc$(OBJ)
+CRCAUO=crcgcc_$(OBJ)
+OBJA=matchgcc$(OBJ)
+OSDEP_H=win32/osdep.h
+ZIPUP_H=win32/zipup.h
+DEF=win32/zip.def
+
+DIRSEP = /
+AS_DIRSEP = /
+RM = del
+LOCAL_OPTS = $(LOCAL_ZIP)
+CCFLAGS = $(CFLAGS) $(LOCAL_OPTS)
+
+
+OBJZ1 = zip$(OBJ) zipfile$(OBJ) zipup$(OBJ) fileio$(OBJ) util$(OBJ) \
+       crc32$(OBJ) $(CRCA_O)
+OBJZ2 = globals$(OBJ) deflate$(OBJ) trees$(OBJ) crypt$(OBJ) \
+       ttyio$(OBJ)
+OBJZS =        win32zip$(OBJ) win32$(OBJ) nt$(OBJ)
+OBJZ  = $(OBJZ1) $(OBJZ2) $(OBJZS) $(OBJA)
+
+OBJU1 = zipfile_$(OBJ) fileio_$(OBJ) util_$(OBJ) crc32_$(OBJ) $(CRCAUO) \
+       globals$(OBJ)
+OBJUS = win32_$(OBJ)
+OBJU  = $(OBJU1) $(OBJUS)
+
+OBJN  = zipnote$(OBJ) $(OBJU)
+OBJS  = zipsplit$(OBJ) $(OBJU)
+OBJC1 = zipcloak$(OBJ) crypt_$(OBJ) ttyio$(OBJ)
+OBJC  = $(OBJC1) $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h $(OSDEP_H)
+
+# rules
+
+.SUFFIXES: .c $(OBJ)
+
+.c$(OBJ):
+       $(CC) -c -I. $(CCFLAGS) $(OUT)$@ $<
+
+# targets
+
+all:   zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip$(OBJ):     zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipfile$(OBJ): zipfile.c $(ZIP_H) crc32.h
+zipup$(OBJ):   zipup.c $(ZIP_H) revision.h crc32.h crypt.h $(ZIPUP_H)
+fileio$(OBJ):  fileio.c $(ZIP_H) crc32.h
+util$(OBJ):    util.c $(ZIP_H)
+globals$(OBJ): globals.c $(ZIP_H)
+deflate$(OBJ): deflate.c $(ZIP_H)
+trees$(OBJ):   trees.c $(ZIP_H)
+crc32$(OBJ):   crc32.c $(ZIP_H) crc32.h
+crypt$(OBJ):   crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio$(OBJ):   ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+msdos$(OBJ):   msdos/msdos.c $(ZIP_H)
+       $(CC) -c -I. $(CCFLAGS) msdos$(DIRSEP)msdos.c
+
+win32zip$(OBJ):        win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+       $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)win32zip.c
+
+win32$(OBJ):   win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)win32.c
+
+nt$(OBJ):      win32/nt.c $(ZIP_H) win32/nt.h
+       $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)nt.c
+
+crc_gcc$(OBJ): crc_i386.S                                      # 32bit, GNU AS
+       $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o $@ crc_i386.S
+
+matchgcc$(OBJ):        match.S
+       $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o $@ match.S
+
+zipcloak$(OBJ):        zipcloak.c $(ZIP_H) revision.h crypt.h ttyio.h
+zipnote$(OBJ): zipnote.c $(ZIP_H) revision.h
+zipsplit$(OBJ): zipsplit.c $(ZIP_H) revision.h
+
+zipfile_$(OBJ):        zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ zipfile.c
+
+fileio_$(OBJ): fileio.c $(ZIP_H) crc32.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ fileio.c
+
+util_$(OBJ):   util.c $(ZIP_H)
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ util.c
+
+crc32_$(OBJ):  crc32.c $(ZIP_H) crc32.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ crc32.c
+
+crypt_$(OBJ):  crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ crypt.c
+
+msdos_$(OBJ):  msdos/msdos.c $(ZIP_H)
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ msdos$(DIRSEP)msdos.c
+
+win32_$(OBJ):  win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ win32$(DIRSEP)win32.c
+
+crcgcc_$(OBJ): crc_i386.S                                      # 32bit, GNU AS
+       $(AS) $(ASFLAGS) -DUTIL -x assembler-with-cpp -c -o $@ crc_i386.S
+
+zip.exe: $(OBJZ)
+# for DUMB make utilities, uncomment the following commands:
+       -@$(RM) zip.rsp
+       @for %%f in ($(OBJZ1)) do echo %%f >> zip.rsp
+       @for %%f in ($(OBJZ2)) do echo %%f >> zip.rsp
+       @for %%f in ($(OBJZS) $(OBJA)) do echo %%f >> zip.rsp
+       $(CC) $(LDFLAGS)$@ @zip.rsp $(LDFLAGS2)
+       @$(RM) zip.rsp
+# smart make utilities (like well done ports of GNU Make) can use this:
+#      $(CC) $(LDFLAGS)$@ $(OBJZ) $(LDFLAGS2)
+
+zipcloak.exe: $(OBJC)
+# for DUMB make utilities, uncomment the following commands:
+       -@$(RM) zipcloak.rsp
+       @for %%f in ($(OBJC1)) do echo %%f >> zipcloak.rsp
+       @for %%f in ($(OBJU1)) do echo %%f >> zipcloak.rsp
+       @for %%f in ($(OBJUS)) do echo %%f >> zipcloak.rsp
+       $(CC) $(LDFLAGS)$@ @zipcloak.rsp $(LDFLAGS2)
+       @$(RM) zipcloak.rsp
+# smart make utilities (like well done ports of GNU Make) can use this:
+#      $(CC) $(LDFLAGS)$@ $(OBJC) $(LDFLAGS2)
+
+zipnote.exe: $(OBJN)
+# for DUMB make utilities, uncomment the following commands:
+       -@$(RM) zipnote.rsp
+       @for %%f in ($(OBJN)) do echo %%f >> zipnote.rsp
+       $(CC) $(LDFLAGS)$@ @zipnote.rsp $(LDFLAGS2)
+       @$(RM) zipnote.rsp
+# smart make utilities (like well done ports of GNU Make) can use this:
+#      $(CC) $(LDFLAGS)$@ $(OBJN) $(LDFLAGS2)
+
+zipsplit.exe: $(OBJS)
+# for DUMB make utilities, uncomment the following commands:
+       -@$(RM) zipsplit.rsp
+       @for %%f in ($(OBJN)) do echo %%f >> zipsplit.rsp
+       $(CC) $(LDFLAGS)$@ @zipsplit.rsp $(LDFLAGS2)
+       @$(RM) zipsplit.rsp
+# smart make utilities (like well done ports of GNU Make) can use this:
+#      $(CC) $(LDFLAGS)$@ $(OBJS) $(LDFLAGS2)
diff --git a/win32/makefile.gcc b/win32/makefile.gcc
new file mode 100644 (file)
index 0000000..d28c447
--- /dev/null
@@ -0,0 +1,159 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for port of gcc producing
+# native Win32-Intel binaries. Derived from makefile.w32.
+# Currently supported implementations: Cygwin and MinGW.
+# Authors: Cosmin Truta, Christian Spieler, and possibly others.
+# Last updated: 2008-Jun-22.
+#
+# To use, do "make -f win32/makefile.gcc".
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = $(LOCAL_ZIP)
+
+# ------------ GNU C ------------
+CC=gcc
+CFLAGS=-O2 -Wall -DWIN32 -DFORCE_WIN32_OVER_UNIX
+ifndef USEZLIB
+CCFLAGS=$(CFLAGS) $(LOC)
+else
+CCFLAGS=$(CFLAGS) -DUSE_ZLIB $(LOC)
+endif
+UTILFLAGS=$(CCFLAGS) -DUTIL -o$@
+
+#AS=as
+AS=$(CC)
+ifndef USEZLIB
+ASDEFS=
+else
+ASDEFS=-DUSE_ZLIB
+endif
+ASFLAGS=-c $(ASDEFS) $(LOC)
+
+RC=windres
+
+LD=$(CC)
+LDFLAGS=-o$@ -s
+ifndef USEZLIB
+LIBS=-luser32 -ladvapi32
+else
+LIBS=-L. -lz -luser32 -ladvapi32
+endif
+
+OSDEP_H = win32/osdep.h
+ZIPUP_H = win32/zipup.h
+
+# variables
+ifndef USEZLIB
+CRCA_O = crc_i386.o
+CRCAUO = crci386_.o
+OBJA  = match.o $(CRCA_O)
+else
+CRCA_O =
+CRCAUO =
+OBJA  =
+endif
+#use second definition for linking against libz
+
+OBJZ1 = zip.o crypt.o ttyio.o zipfile.o zipup.o fileio.o util.o \
+       crc32.o globals.o
+OBJZ2 = deflate.o trees.o $(OBJA)
+OBJZS = win32.o win32zip.o win32i64.o nt.o
+OBJZ  = $(OBJZ1) $(OBJZ2) $(OBJZS)
+
+OBJU1 = zipfile_.o fileio_.o util_.o crc32_.o $(CRCAUO) globals.o
+OBJUS = win32_.o win32i64.o
+OBJU  = $(OBJU1) $(OBJUS)
+
+OBJN  = zipnote.o $(OBJU)
+OBJS  = zipsplit.o $(OBJU)
+OBJC1 = zipcloak.o crypt_.o ttyio.o
+OBJC  = $(OBJC1) $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h $(OSDEP_H)
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+# rules
+
+.SUFFIXES: .c .o
+
+.c.o:
+       $(CC) -c $(CCFLAGS) -I. -o$@ $<
+
+# targets
+
+zips: $(ZIPS)
+
+zip.o: zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipfile.o: zipfile.c $(ZIP_H) crc32.h
+zipup.o: zipup.c $(ZIP_H) revision.h crc32.h crypt.h $(ZIPUP_H)
+fileio.o: fileio.c $(ZIP_H) crc32.h
+util.o: util.c $(ZIP_H)
+globals.o: globals.c $(ZIP_H)
+deflate.o: deflate.c $(ZIP_H)
+trees.o: trees.c $(ZIP_H)
+crc32.o: crc32.c $(ZIP_H) crc32.h
+crypt.o: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio.o: ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+win32zip.o: win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+       $(CC) -c $(CCFLAGS) -I. win32/win32zip.c
+
+win32.o: win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) -c $(CCFLAGS) -I. win32/win32.c
+
+win32i64.o: win32/win32i64.c $(ZIP_H)
+       $(CC) -c $(CCFLAGS) -I. win32/win32i64.c
+
+nt.o: win32/nt.c $(ZIP_H) win32/nt.h
+       $(CC) -c $(CCFLAGS) -I. win32/nt.c
+
+zipcloak.o: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipnote.o: zipnote.c $(ZIP_H) revision.h
+zipsplit.o: zipsplit.c $(ZIP_H) revision.h
+
+zipfile_.o: zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS) zipfile.c
+
+fileio_.o: fileio.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS) fileio.c
+
+util_.o: util.c $(ZIP_H)
+       $(CC) -c $(UTILFLAGS) util.c
+
+crc32_.o: crc32.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS) crc32.c
+
+crypt_.o: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c $(UTILFLAGS) crypt.c
+
+win32_.o: win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) -c $(UTILFLAGS) -I. win32/win32.c
+
+match.o: match.S
+       $(AS) $(ASFLAGS) match.S
+
+crc_i386.o: crc_i386.S
+       $(AS) $(ASFLAGS) crc_i386.S
+
+crci386_.o: crc_i386.S
+       $(AS) $(ASFLAGS) -DUTIL -o$@ crc_i386.S
+
+ziprc.o: win32/zip.rc revision.h
+       - $(RC) -o $@ win32/zip.rc
+
+zip.exe: $(OBJZ) ziprc.o
+       $(LD) $(LDFLAGS) $(OBJZ) ziprc.o $(LIBS)
+
+zipcloak.exe: $(OBJC)
+       $(LD) $(LDFLAGS) $(OBJC) $(LIBS)
+
+zipnote.exe: $(OBJN)
+       $(LD) $(LDFLAGS) $(OBJN)
+
+zipsplit.exe: $(OBJS)
+       $(LD) $(LDFLAGS) $(OBJS)
+
+clean:
+       rm -f *.o $(ZIPS)
diff --git a/win32/makefile.ibm b/win32/makefile.ibm
new file mode 100644 (file)
index 0000000..3cd2975
--- /dev/null
@@ -0,0 +1,123 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# 32-bit IBM Visual Age C++
+
+# To use, do "nmake -f win32\makefile.ibm"
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = $(LOCAL_ZIP)
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+# ASMOBJS = match32.obj
+
+# ------------- 32-bit IBM Visual Age C++ -------------
+CC=icc -q -O
+CFLAGS=-W0 -DWIN32 -Sm -DNO_ASM -DNO_MKTEMP $(LOC)
+UTILFLAGS=$(CFLAGS) -DUTIL -Fo$@
+LDFLAGS=
+LIBS=advapi32.lib
+AS=ml -nologo
+ASFLAGS=-c -Cx
+
+# variables
+OBJZ = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+       crc32.obj globals.obj
+
+OBJI = deflate.obj trees.obj $(ASMOBJS) win32.obj win32zip.obj nt.obj
+
+OBJU = zipfile_.obj fileio_.obj util_.obj globals.obj win32_.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj crc32_.obj crypt_.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h win32/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips:   $(ZIPS)
+
+zip.obj:        zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipfile.obj:    zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipup.obj:      zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32/zipup.h
+       $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj:     fileio.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+util.obj:       util.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+globals.obj:    globals.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj:    deflate.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+trees.obj:      trees.c $(ZIP_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj:      crc32.c $(ZIP_H) crc32.h
+       $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj:      crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj:      ttyio.c $(ZIP_H) crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+win32zip.obj:   win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+       $(CC) -c $(CFLAGS) -I. win32/win32zip.c
+
+win32.obj:      win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) -c $(CFLAGS) -I. win32/win32.c
+
+nt.obj:         win32/nt.c $(ZIP_H) win32/nt.h
+       $(CC) -c $(CFLAGS) -I. win32/nt.c
+
+zipcloak.obj:   zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipnote.obj:    zipnote.c $(ZIP_H) revision.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipsplit.obj:   zipsplit.c $(ZIP_H) revision.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zipfile_.obj:   zipfile.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS) zipfile.c
+
+fileio_.obj:    fileio.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS) fileio.c
+
+util_.obj:      util.c $(ZIP_H)
+       $(CC) -c $(UTILFLAGS) util.c
+
+crc32_.obj:     crc32.c $(ZIP_H) crc32.h
+       $(CC) -c $(UTILFLAGS) crc32.c
+
+crypt_.obj:     crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(CC) -c $(UTILFLAGS) crypt.c
+
+win32_.obj:     win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) -c $(UTILFLAGS) -I. win32/win32.c
+
+match32.obj:    win32/match32.asm
+       $(AS) $(ASFLAGS) win32\match32.asm
+
+zip.exe: $(OBJZ) $(OBJI)
+       $(CC) -Fe $@ $(LDFLAGS) $(OBJZ) $(OBJI) $(LIBS)
+
+zipcloak.exe: $(OBJC)
+       $(CC) -Fe $@ $(LDFLAGS) $(OBJC) $(LIBS)
+
+zipnote.exe: $(OBJN)
+       $(CC) -Fe $@ $(LDFLAGS) $(OBJN) $(LIBS)
+
+zipsplit.exe: $(OBJS)
+       $(CC) -Fe $@ $(LDFLAGS) $(OBJS) $(LIBS)
diff --git a/win32/makefile.lcc b/win32/makefile.lcc
new file mode 100644 (file)
index 0000000..6c7e8b5
--- /dev/null
@@ -0,0 +1,125 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit using LCC-Win32.
+# By E-Yen Tan (3 June 1998).
+# Last updated 9 February 2008 (Christian Spieler).
+
+# This compiler evaluates #include locations relative to current working dir,
+# not relative to the location of the file containing the #include directive.
+# As a consequence, a "-Iwin32" option is required to allow compilation of
+# the WIN32 specific sources.
+
+CC = lcc
+# -O caused a segmentation violation with previous versions of lcc, but
+# now the optimizer seems to be fixed.
+CCFLAGS = -Zp8 -O -DWIN32
+AS = lcc
+ASFLAGS =
+LD = lcclnk
+LDFLAGS = -s
+
+# Optional macros should be declared below.
+# LCC's Make will not read the LOCAL_ZIP environment variable.
+LOC = $(ASMFLG)
+
+# Options to select optimized assembler code for CRC32 calculation.
+#ifdef USEASM
+CRCA_O = crc_lcc.obj
+OBJA = lm32_lcc.obj
+ASMFLG = -DASM_CRC -DASMV
+#else
+#CRCA_O =
+#OBJA =
+#ASMFLG = -DNO_ASM
+#endif
+
+CFLAGS = $(CCFLAGS) $(LOC)
+
+OBJZS = win32.obj win32zip.obj nt.obj $(OBJA)
+OBJUS = win32_.obj
+
+OBJZ1 = zip.obj zipfile.obj zipup.obj fileio.obj util.obj
+OBJZ2 = crc32.obj $(CRCA_O) globals.obj
+OBJZ3 = deflate.obj trees.obj crypt.obj ttyio.obj
+OBJZ  = $(OBJZ1) $(OBJZ2) $(OBJZ3) $(OBJZS)
+
+OBJU1 = zipfile_.obj fileio_.obj util_.obj crc32_.obj globals.obj
+OBJU  = $(OBJU1) $(OBJUS)
+
+OBJN =  zipnote.obj $(OBJU)
+OBJS =  zipsplit.obj $(OBJU)
+OBJK =  zipcloak.obj crypt_.obj ttyio.obj
+OBJC =  $(OBJK) $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h win32/osdep.h
+
+# rules
+
+.SUFFIXES: .c .obj
+
+.c.obj:
+       $(CC) $(CFLAGS) $<
+
+.asm.obj:
+       $(AS) $(ASFLAGS) $<
+
+all:    zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip.obj:      zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipfile.obj:  zipfile.c $(ZIP_H) crc32.h
+zipup.obj:    zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32/zipup.h
+fileio.obj:   fileio.c $(ZIP_H) crc32.h
+util.obj:     util.c $(ZIP_H)
+globals.obj:  globals.c $(ZIP_H)
+deflate.obj:  deflate.c $(ZIP_H)
+trees.obj:    trees.c $(ZIP_H)
+crc32.obj:    crc32.c $(ZIP_H) crc32.h
+crypt.obj:    crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio.obj:    ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+win32.obj:    win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) $(CFLAGS) -Iwin32 -Fo$@ win32/win32.c
+
+win32zip.obj: win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+       $(CC) $(CFLAGS) -Iwin32 -Fo$@ win32/win32zip.c
+
+nt.obj:       win32/nt.c $(ZIP_H) win32/nt.h
+       $(CC) $(CFLAGS) -Iwin32 -Fo$@ win32/nt.c
+
+crc_lcc.obj:   win32/crc_lcc.asm
+       $(AS) $(ASFLAGS) -Fo$@ win32/crc_lcc.asm
+
+lm32_lcc.obj:  win32/lm32_lcc.asm
+       $(AS) $(ASFLAGS) -Fo$@ win32/lm32_lcc.asm
+
+zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipnote.obj:  zipnote.c $(ZIP_H) revision.h
+zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+
+zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+       $(CC) $(CFLAGS) -DUTIL -Fo$@ zipfile.c
+
+fileio_.obj:  fileio.c $(ZIP_H) crc32.h
+       $(CC) $(CFLAGS) -DUTIL -Fo$@ fileio.c
+
+util_.obj:    util.c $(ZIP_H)
+       $(CC) $(CFLAGS) -DUTIL -Fo$@ util.c
+
+crc32_.obj:   crc32.c $(ZIP_H) crc32.h
+       $(CC) $(CFLAGS) -DUTIL -Fo$@ crc32.c
+
+crypt_.obj:   crypt.c $(ZIP_H) crypt.h ttyio.h
+       $(CC) $(CFLAGS) -DUTIL -Fo$@ crypt.c
+
+win32_.obj:    win32/win32.c $(ZIP_H) win32/win32zip.h
+       $(CC) $(CFLAGS) -DUTIL -Iwin32 -Fo$@ win32/win32.c
+
+zip.exe: $(OBJZ)
+       $(LD) $(LDFLAGS) -o $@ $(OBJZ)
+
+zipcloak.exe: $(OBJC)
+       $(LD) $(LDFLAGS) -o $@ $(OBJC)
+
+zipnote.exe: $(OBJN)
+       $(LD) $(LDFLAGS) -o $@ $(OBJN)
+
+zipsplit.exe: $(OBJS)
+       $(LD) $(LDFLAGS) -o $@ $(OBJS)
diff --git a/win32/makefile.w10 b/win32/makefile.w10
new file mode 100644 (file)
index 0000000..0463f3b
--- /dev/null
@@ -0,0 +1,197 @@
+# WMAKE makefile for Windows 95 and Windows NT (Intel only)
+# using Watcom C/C++ v10.5+, by Paul Kienitz, last revised 22 Jun 2008.
+# Makes Zip.exe, ZipNote.exe, ZipCloak.exe, and ZipSplit.exe.
+#
+# Invoke from Zip source dir with "WMAKE -F WIN32\MAKEFILE.WAT [targets]"
+# To build with debug info use "WMAKE DEBUG=1 ..."
+# To build without any assembly modules use "WMAKE NOASM=1 ..."
+#
+# Other options to be fed to the compiler can be specified in an environment
+# variable called LOCAL_ZIP.  One possibility "-DDYN_ALLOC", but currently
+# this is not supported unless NOASM is also used.
+
+variation = $(%LOCAL_ZIP)
+
+# Stifle annoying "Delete this file?" questions when errors occur:
+.ERASE
+
+.EXTENSIONS:
+.EXTENSIONS: .exe .obj .c .h .asm
+
+# We maintain multiple sets of object files in different directories so that
+# we can compile msdos, dos/4gw, and win32 versions of Zip without their
+# object files interacting.  The following var must be a directory name
+# ending with a backslash.  All object file names must include this macro
+# at the beginning, for example "$(O)foo.obj".
+
+!ifdef DEBUG
+OBDIR = od32w
+!else
+OBDIR = ob32w
+!endif
+O = $(OBDIR)\   # comment here so backslash won't continue the line
+
+# The assembly hot-spot code in crc_i386.asm and match32.asm is optional.
+# This section controls its usage.
+
+!ifdef NOASM
+asmob =
+asmco =
+cvars = $+$(cvars)$- -DNO_ASM   # otherwise ASM_CRC might default on!
+# "$+$(foo)$-" means expand foo as it has been defined up to now; normally,
+# this make defers inner expansion until the outer macro is expanded.
+!else  # !NOASM
+asmco = $(O)crc_i386.obj
+asmob = $(asmco) $(O)match32.obj
+cvars = $+$(cvars)$- -DASMV -DASM_CRC
+!endif
+
+# Our object files.  OBJZ is for Zip, OBJC is for ZipCloak, OBJN is for
+# ZipNote, and OBJS is for ZipSplit:
+
+OBJZ3 = $(O)zip.obj $(O)crypt.obj $(O)ttyio.obj $(O)trees.obj $(O)zipup.obj
+OBJZ2 = $(OBJZ3) $(O)util.obj $(O)zipfile.obj $(O)fileio.obj $(O)deflate.obj
+OBJZ1 = $(OBJZ2) $(O)globals.obj $(O)crc32.obj $(asmob)
+OBJZ  = $(OBJZ1) $(O)win32zip.obj $(O)win32.obj $(O)win32i64.obj $(O)nt.obj
+
+OBJU1 = $(O)zipfile_.obj $(O)fileio_.obj $(O)util_.obj $(O)crc32_.obj $(asmco)
+OBJ_U = $(OBJU1) $(O)globals.obj $(O)win32_.obj $(O)win32i64_.obj
+
+OBJC  = $(O)zipcloak.obj $(O)crypt_.obj $(O)ttyio.obj $(OBJ_U)
+
+OBJN  = $(O)zipnote.obj $(OBJ_U)
+
+OBJS  = $(O)zipsplit.obj $(OBJ_U)
+
+# Common header files included by all C sources:
+
+ZIP_H = zip.h ziperr.h tailor.h win32\osdep.h
+
+# Now we have to pick out the proper compiler and options for it.
+
+cc     = wcc386
+link   = wlink
+asm    = wasm
+rc     = wrc
+# Use Pentium Pro timings, register args, static strings in code:
+cflags = -bt=NT -6r -zt -zq
+aflags = -bt=NT -mf -3 -zq
+rcflags= -bt=NT -DWIN32 -iwin32 -q
+lflags = sys NT
+cvars  = $+$(cvars)$- -DWIN32 $(variation)
+avars  = $+$(avars)$- $(variation)
+
+# Specify optimizations, or a nonoptimized debugging version:
+
+!ifdef DEBUG
+cdebug = -od -d2
+ldebug = d w all op symf
+!else
+cdebug = -s -oeilrt -zp4
+# note: -ol+ does not help.  -oa helps slightly but might be dangerous.
+ldebug = op el
+!endif
+
+# How to compile sources:
+.c.obj:
+       $(cc) $(cdebug) $(cflags) $(cvars) $< -fo=$@
+
+# Here we go!  By default, make all targets:
+all: Zip.exe ZipNote.exe ZipCloak.exe ZipSplit.exe
+
+# Convenient shorthand options for single targets:
+z:   Zip.exe       .SYMBOLIC
+n:   ZipNote.exe   .SYMBOLIC
+c:   ZipCloak.exe  .SYMBOLIC
+s:   ZipSplit.exe  .SYMBOLIC
+
+Zip.exe:       $(OBDIR) $(OBJZ) $(O)zip.res
+       $(link) $(lflags) $(ldebug) name $@ file {$(OBJZ)}
+       $(rc) $(O)zip.res $@
+
+ZipNote.exe:   $(OBDIR) $(OBJN)
+       $(link) $(lflags) $(ldebug) name $@ file {$(OBJN)}
+
+ZipCloak.exe:  $(OBDIR) $(OBJC)
+       $(link) $(lflags) $(ldebug) name $@ file {$(OBJC)}
+
+ZipSplit.exe:  $(OBDIR) $(OBJS)
+       $(link) $(lflags) $(ldebug) name $@ file {$(OBJS)}
+
+# Source dependencies:
+
+$(O)crc32.obj:    crc32.c $(ZIP_H) crc32.h      # only used if NOASM
+$(O)crypt.obj:    crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+$(O)deflate.obj:  deflate.c $(ZIP_H)
+$(O)fileio.obj:   fileio.c $(ZIP_H) crc32.h
+$(O)globals.obj:  globals.c $(ZIP_H)
+$(O)trees.obj:    trees.c $(ZIP_H)
+$(O)ttyio.obj:    ttyio.c $(ZIP_H) crypt.h ttyio.h
+$(O)util.obj:     util.c $(ZIP_H)
+$(O)zip.obj:      zip.c $(ZIP_H) crc32.h crypt.h revision.h ttyio.h
+$(O)zipfile.obj:  zipfile.c $(ZIP_H) crc32.h
+$(O)zipup.obj:    zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32\zipup.h
+$(O)zipnote.obj:  zipnote.c $(ZIP_H) revision.h
+$(O)zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+$(O)zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+
+# Special case object files:
+
+$(O)win32.obj:    win32\win32.c $(ZIP_H) win32\win32zip.h
+       $(cc) $(cdebug) $(cflags) $(cvars) win32\win32.c -fo=$@
+
+$(O)win32i64.obj: win32\win32i64.c $(ZIP_H)
+       $(cc) $(cdebug) $(cflags) $(cvars) win32\win32i64.c -fo=$@
+
+$(O)win32zip.obj: win32\win32zip.c $(ZIP_H) win32\win32zip.h win32\nt.h
+       $(cc) $(cdebug) $(cflags) $(cvars) win32\win32zip.c -fo=$@
+
+$(O)nt.obj:       win32\nt.c $(ZIP_H) win32\nt.h
+       $(cc) $(cdebug) $(cflags) $(cvars) win32\nt.c -fo=$@
+
+$(O)match32.obj:  win32\match32.asm
+       $(asm) $(aflags) $(avars) win32\match32.asm -fo=$@
+
+$(O)crc_i386.obj: win32\crc_i386.asm
+       $(asm) $(aflags) $(avars) win32\crc_i386.asm -fo=$@
+
+# Variant object files for ZipNote, ZipCloak, and ZipSplit:
+
+$(O)zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL zipfile.c -fo=$@
+
+$(O)fileio_.obj:  fileio.c $(ZIP_H) crc32.h
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL fileio.c -fo=$@
+
+$(O)util_.obj:    util.c $(ZIP_H)
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL util.c -fo=$@
+
+$(O)crc32_.obj:   crc32.c $(ZIP_H) crc32.h
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL crc32.c -fo=$@
+
+$(O)crypt_.obj:   crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL crypt.c -fo=$@
+
+$(O)win32_.obj:   win32\win32.c $(ZIP_H) win32\win32zip.h
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL win32\win32.c -fo=$@
+
+$(O)win32i64_.obj:   win32\win32i64.c $(ZIP_H)
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL win32\win32i64.c -fo=$@
+
+$(O)zip.res:     win32\zip.rc revision.h
+       $(rc) -r $(rcflags) -fo=$@ win32\zip.rc
+
+# Creation of subdirectory for intermediate files
+$(OBDIR):
+       -mkdir $@
+
+# Unwanted file removal:
+
+clean:     .SYMBOLIC
+       del $(O)*.obj
+
+cleaner:   clean  .SYMBOLIC
+       del Zip.exe
+       del ZipNote.exe
+       del ZipCloak.exe
+       del ZipSplit.exe
diff --git a/win32/makefile.w32 b/win32/makefile.w32
new file mode 100644 (file)
index 0000000..7afbf0e
--- /dev/null
@@ -0,0 +1,224 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# 32-bit Microsoft Visual C++
+
+# To use, do "nmake -f makefile.w32"
+
+# Add "NOASM=1" to the nmake command to disable usage of assembler sources
+# if you do not have masm 6.1X.
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = $(LOCAL_ZIP)
+
+!IFNDEF debug
+NODEBUG=1
+!ENDIF
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+!IFDEF NOASM
+ASMOBJS =
+CRCA_O =
+CFLG_ASM = -DNO_ASM
+!ELSE
+ASMOBJS = match32.obj
+CRCA_O = crci386c.obj
+CFLG_ASM = -DASM_CRC
+!ENDIF
+
+!IFDEF USEBZ2
+LOC=$(LOC) -DBZIP2_SUPPORT
+!IFNDEF debug
+EXTLIB=$(EXTLIB) libbz2.lib
+!ELSE
+EXTLIB=$(EXTLIB) libbz2.lib
+!ENDIF
+!ENDIF
+
+!IFDEF USEZLIB
+LOC=$(LOC) -DUSE_ZLIB
+ASMOBJS=
+!IFNDEF debug
+EXTLIB=$(EXTLIB) zlib.lib
+!ELSE
+EXTLIB=$(EXTLIB) zlib.lib
+!ENDIF
+!ENDIF
+
+!IFDEF USEZLIB
+USE_MSVCRT=1
+!ELSE
+!IFDEF USEBZIP2
+USE_MSVCRT=1
+!ELSE
+USE_MSVCRT=0
+!ENDIF
+!ENDIF # USEZLIB
+
+!IF $(USE_MSVCRT) == 1
+CRTLIB=-MD
+!ELSE
+!IF "$(VS80COMNTOOLS)" == ""
+CRTLIB=-ML
+!ELSE
+# no single-threaded CRT static lib, only multi-threaded in VC8
+CRTLIB=-MT
+!ENDIF
+!ENDIF
+
+!IFDEF NODEBUG
+cdebug = -O2
+cdbgsz = -O1
+!ELSE
+cdebug = -Od
+cdbgsz = $(cdebug)
+!ENDIF
+
+# ------------- 32-bit Microsoft Visual C++ -------------
+CC=cl -nologo
+CFLAGS=-W3 $(cdebug) -DWIN32 $(CFLG_ASM) $(CRTLIB) $(LOC)
+UTILFLAGS=$(CFLAGS) -DUTIL -Fo$@
+
+# Remove "-coff" from ASFLAGS if you do not have MASM 6.11.
+
+AS=ml -nologo
+ASFLAGS=-c -coff -Cx
+
+RC=rc
+
+# If you build 16-bit executables with MS Visual C++ v1.0/1.5 and link them
+# with the /KNOWEAS switch, you can build dual-mode MS-DOS/Win32 executables
+# by passing the -stub switch to the 32-bit linker to specify the 16-bit part.
+
+LD=link -nologo
+LDFLAGS=user32.lib advapi32.lib /OPT:NOWIN98 /INCREMENTAL:NO /PDB:$*.pdb $(EXTLIB)
+SYMS=/DEBUG:full /DEBUGTYPE:CV
+!IFDEF debug
+LDFLAGS=$(LDFLAGS) $(SYMS)
+CFLAGS=$(CFLAGS) /Zi
+!ELSE
+LDFLAGS=$(LDFLAGS) /RELEASE
+!IFDEF sym
+LDFLAGS=$(LDFLAGS) $(SYMS)
+CFLAGS=$(CFLAGS) /Zi
+!ENDIF
+!ENDIF
+
+# variables
+OBJZ = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+ crc32.obj $(CRCA_O) globals.obj
+
+OBJI = deflate.obj trees.obj $(ASMOBJS) win32.obj win32zip.obj nt.obj win32i64.obj
+
+OBJU = zipfile_.obj fileio_.obj util_.obj crc32_.obj $(CRCA_O) globals.obj \
+ win32_.obj win32i64.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj crypt_.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h win32/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips:   $(ZIPS)
+
+zip.obj:        zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile.obj:    zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipup.obj:      zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32/zipup.h
+ $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj:     fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+util.obj:       util.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+globals.obj:    globals.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj:    deflate.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj:      trees.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj:      crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj:      crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj:      ttyio.c $(ZIP_H) crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+win32i64.obj:   win32/win32i64.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) -I. win32/win32i64.c
+
+win32zip.obj:   win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+ $(CC) -c $(CFLAGS) -I. win32/win32zip.c
+
+win32.obj:      win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(CFLAGS) -I. win32/win32.c
+
+nt.obj:         win32/nt.c $(ZIP_H) win32/nt.h
+ $(CC) -c $(CFLAGS) -I. win32/nt.c
+
+zipcloak.obj:   zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipnote.obj:    zipnote.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipsplit.obj:   zipsplit.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile_.obj:   zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) zipfile.c
+
+fileio_.obj:    fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) fileio.c
+
+util_.obj:      util.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS) util.c
+
+crc32_.obj:     crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) crc32.c
+
+crypt_.obj:     crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(UTILFLAGS) crypt.c
+
+win32_.obj:     win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(UTILFLAGS) -I. win32/win32.c
+
+crci386c.obj:   win32/crc_i386.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) -I. -Fo$@ win32/crc_i386.c
+
+crc_i386.obj:   win32/crc_i386.asm
+ $(AS) $(ASFLAGS) win32\crc_i386.asm
+
+match32.obj:    win32/match32.asm
+ $(AS) $(ASFLAGS) win32\match32.asm
+
+zip.res:        win32/zip.rc revision.h
+       $(RC) /l 0x409 /fo$@ /i win32 /d WIN32 win32/zip.rc
+
+zip.exe: $(OBJZ) $(OBJI) zip.res
+ $(LD) $(LDFLAGS) $(OBJZ) $(OBJI) zip.res
+
+zipcloak.exe: $(OBJC)
+ $(LD) $(LDFLAGS) $(OBJC)
+
+zipnote.exe: $(OBJN)
+ $(LD) $(LDFLAGS) $(OBJN)
+
+zipsplit.exe: $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJS)
+
+clean:
+ -del *.obj
+ -del *.exe
diff --git a/win32/makefile.wat b/win32/makefile.wat
new file mode 100644 (file)
index 0000000..f13d580
--- /dev/null
@@ -0,0 +1,197 @@
+# WMAKE makefile for Windows 95 and Windows NT (Intel only)
+# using Watcom C/C++ v11.0+, by Paul Kienitz, last revised 22 Jun 2008.
+# Makes Zip.exe, ZipNote.exe, ZipCloak.exe, and ZipSplit.exe.
+#
+# Invoke from Zip source dir with "WMAKE -F WIN32\MAKEFILE.WAT [targets]"
+# To build with debug info use "WMAKE DEBUG=1 ..."
+# To build without any assembly modules use "WMAKE NOASM=1 ..."
+#
+# Other options to be fed to the compiler can be specified in an environment
+# variable called LOCAL_ZIP.  One possibility "-DDYN_ALLOC", but currently
+# this is not supported unless NOASM is also used.
+
+variation = $(%LOCAL_ZIP)
+
+# Stifle annoying "Delete this file?" questions when errors occur:
+.ERASE
+
+.EXTENSIONS:
+.EXTENSIONS: .exe .obj .c .h .asm
+
+# We maintain multiple sets of object files in different directories so that
+# we can compile msdos, dos/4gw, and win32 versions of Zip without their
+# object files interacting.  The following var must be a directory name
+# ending with a backslash.  All object file names must include this macro
+# at the beginning, for example "$(O)foo.obj".
+
+!ifdef DEBUG
+OBDIR = od32w
+!else
+OBDIR = ob32w
+!endif
+O = $(OBDIR)\   # comment here so backslash won't continue the line
+
+# The assembly hot-spot code in crc_i386.asm and match32.asm is optional.
+# This section controls its usage.
+
+!ifdef NOASM
+asmob =
+asmco =
+cvars = $+$(cvars)$- -DNO_ASM   # otherwise ASM_CRC might default on!
+# "$+$(foo)$-" means expand foo as it has been defined up to now; normally,
+# this make defers inner expansion until the outer macro is expanded.
+!else  # !NOASM
+asmco = $(O)crc_i386.obj
+asmob = $(asmco) $(O)match32.obj
+cvars = $+$(cvars)$- -DASMV -DASM_CRC
+!endif
+
+# Our object files.  OBJZ is for Zip, OBJC is for ZipCloak, OBJN is for
+# ZipNote, and OBJS is for ZipSplit:
+
+OBJZ3 = $(O)zip.obj $(O)crypt.obj $(O)ttyio.obj $(O)trees.obj $(O)zipup.obj
+OBJZ2 = $(OBJZ3) $(O)util.obj $(O)zipfile.obj $(O)fileio.obj $(O)deflate.obj
+OBJZ1 = $(OBJZ2) $(O)globals.obj $(O)crc32.obj $(asmob)
+OBJZ  = $(OBJZ1) $(O)win32zip.obj $(O)win32.obj $(O)win32i64.obj $(O)nt.obj
+
+OBJU1 = $(O)zipfile_.obj $(O)fileio_.obj $(O)util_.obj $(O)crc32_.obj $(asmco)
+OBJ_U = $(OBJU1) $(O)globals.obj $(O)win32_.obj $(O)win32i64_.obj
+
+OBJC  = $(O)zipcloak.obj $(O)crypt_.obj $(O)ttyio.obj $(OBJ_U)
+
+OBJN  = $(O)zipnote.obj $(OBJ_U)
+
+OBJS  = $(O)zipsplit.obj $(OBJ_U)
+
+# Common header files included by all C sources:
+
+ZIP_H = zip.h ziperr.h tailor.h win32\osdep.h
+
+# Now we have to pick out the proper compiler and options for it.
+
+cc     = wcc386
+link   = wlink
+asm    = wasm
+rc     = wrc
+# Use Pentium Pro timings, register args, static strings in code:
+cflags = -bt=NT -6r -zt -zq
+aflags = -bt=NT -mf -3 -zq
+rcflags= -bt=NT -DWIN32 -iwin32 -q
+lflags = sys NT
+cvars  = $+$(cvars)$- -DWIN32 $(variation)
+avars  = $+$(avars)$- -DWATCOM_DSEG $(variation)
+
+# Specify optimizations, or a nonoptimized debugging version:
+
+!ifdef DEBUG
+cdebug = -od -d2
+ldebug = d w all op symf
+!else
+cdebug = -s -obhikl+rt -oe=100 -zp8
+# -oa helps slightly but might be dangerous.
+ldebug = op el
+!endif
+
+# How to compile sources:
+.c.obj:
+       $(cc) $(cdebug) $(cflags) $(cvars) $[@ -fo=$@
+
+# Here we go!  By default, make all targets:
+all: Zip.exe ZipNote.exe ZipCloak.exe ZipSplit.exe
+
+# Convenient shorthand options for single targets:
+z:   Zip.exe       .SYMBOLIC
+n:   ZipNote.exe   .SYMBOLIC
+c:   ZipCloak.exe  .SYMBOLIC
+s:   ZipSplit.exe  .SYMBOLIC
+
+Zip.exe:       $(OBDIR) $(OBJZ) $(O)zip.res
+       $(link) $(lflags) $(ldebug) name $@ file {$(OBJZ)}
+       $(rc) $(O)zip.res $@
+
+ZipNote.exe:   $(OBDIR) $(OBJN)
+       $(link) $(lflags) $(ldebug) name $@ file {$(OBJN)}
+
+ZipCloak.exe:  $(OBDIR) $(OBJC)
+       $(link) $(lflags) $(ldebug) name $@ file {$(OBJC)}
+
+ZipSplit.exe:  $(OBDIR) $(OBJS)
+       $(link) $(lflags) $(ldebug) name $@ file {$(OBJS)}
+
+# Source dependencies:
+
+$(O)crc32.obj:    crc32.c $(ZIP_H) crc32.h      # only used if NOASM
+$(O)crypt.obj:    crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+$(O)deflate.obj:  deflate.c $(ZIP_H)
+$(O)fileio.obj:   fileio.c $(ZIP_H) crc32.h
+$(O)globals.obj:  globals.c $(ZIP_H)
+$(O)trees.obj:    trees.c $(ZIP_H)
+$(O)ttyio.obj:    ttyio.c $(ZIP_H) crypt.h ttyio.h
+$(O)util.obj:     util.c $(ZIP_H)
+$(O)zip.obj:      zip.c $(ZIP_H) crc32.h crypt.h revision.h ttyio.h
+$(O)zipfile.obj:  zipfile.c $(ZIP_H) crc32.h
+$(O)zipup.obj:    zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32\zipup.h
+$(O)zipnote.obj:  zipnote.c $(ZIP_H) revision.h
+$(O)zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+$(O)zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+
+# Special case object files:
+
+$(O)win32.obj:    win32\win32.c $(ZIP_H) win32\win32zip.h
+       $(cc) $(cdebug) $(cflags) $(cvars) win32\win32.c -fo=$@
+
+$(O)win32i64.obj: win32\win32i64.c $(ZIP_H)
+       $(cc) $(cdebug) $(cflags) $(cvars) win32\win32i64.c -fo=$@
+
+$(O)win32zip.obj: win32\win32zip.c $(ZIP_H) win32\win32zip.h win32\nt.h
+       $(cc) $(cdebug) $(cflags) $(cvars) win32\win32zip.c -fo=$@
+
+$(O)nt.obj:       win32\nt.c $(ZIP_H) win32\nt.h
+       $(cc) $(cdebug) $(cflags) $(cvars) win32\nt.c -fo=$@
+
+$(O)match32.obj:  win32\match32.asm
+       $(asm) $(aflags) $(avars) win32\match32.asm -fo=$@
+
+$(O)crc_i386.obj: win32\crc_i386.asm
+       $(asm) $(aflags) $(avars) win32\crc_i386.asm -fo=$@
+
+# Variant object files for ZipNote, ZipCloak, and ZipSplit:
+
+$(O)zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL zipfile.c -fo=$@
+
+$(O)fileio_.obj:  fileio.c $(ZIP_H) crc32.h
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL fileio.c -fo=$@
+
+$(O)util_.obj:    util.c $(ZIP_H)
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL util.c -fo=$@
+
+$(O)crc32_.obj:   crc32.c $(ZIP_H) crc32.h
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL crc32.c -fo=$@
+
+$(O)crypt_.obj:   crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL crypt.c -fo=$@
+
+$(O)win32_.obj:   win32\win32.c $(ZIP_H) win32\win32zip.h
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL win32\win32.c -fo=$@
+
+$(O)win32i64_.obj:   win32\win32i64.c $(ZIP_H)
+       $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL win32\win32i64.c -fo=$@
+
+$(O)zip.res:     win32\zip.rc revision.h
+       $(rc) -r $(rcflags) -fo=$@ win32\zip.rc
+
+# Creation of subdirectory for intermediate files
+$(OBDIR):
+       -mkdir $@
+
+# Unwanted file removal:
+
+clean:     .SYMBOLIC
+       del $(O)*.obj
+
+cleaner:   clean  .SYMBOLIC
+       del Zip.exe
+       del ZipNote.exe
+       del ZipCloak.exe
+       del ZipSplit.exe
diff --git a/win32/makenoas.w32 b/win32/makenoas.w32
new file mode 100644 (file)
index 0000000..403b087
--- /dev/null
@@ -0,0 +1,219 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# 32-bit Microsoft Visual C++
+
+# To use, do "nmake -f makefile.w32"
+
+# This version disables assembly.
+# Add -DNO_ASM to CFLAGS and comment out the ASMOBJS definition if
+# you do not have masm 6.1X.
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = $(LOCAL_ZIP)
+
+!IFNDEF debug
+NODEBUG=1
+!ENDIF
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+#ASMOBJS = match32.obj
+CRCA_O = crci386c.obj
+CFLG_ASM = -DASM_CRC
+
+!IFDEF USEBZ2
+LOC=$(LOC) -DBZIP2_SUPPORT
+!IFNDEF debug
+EXTLIB=$(EXTLIB) libbz2.lib
+!ELSE
+EXTLIB=$(EXTLIB) libbz2.lib
+!ENDIF
+!ENDIF
+
+!IFDEF USEZLIB
+LOC=$(LOC) -DUSE_ZLIB
+ASMOBJS=
+!IFNDEF debug
+EXTLIB=$(EXTLIB) zlib.lib
+!ELSE
+EXTLIB=$(EXTLIB) zlib.lib
+!ENDIF
+!ENDIF
+
+!IFDEF USEZLIB
+USE_MSVCRT=1
+!ELSE
+!IFDEF USEBZIP2
+USE_MSVCRT=1
+!ELSE
+USE_MSVCRT=0
+!ENDIF
+!ENDIF # USEZLIB
+
+!IF $(USE_MSVCRT) == 1
+CRTLIB=-MD
+!ELSE
+!IF "$(VS80COMNTOOLS)" == ""
+CRTLIB=-ML
+!ELSE
+# no single-threaded CRT static lib, only multi-threaded in VC8
+CRTLIB=-MT
+!ENDIF
+!ENDIF
+
+!IFDEF NODEBUG
+cdebug = -O2
+cdbgsz = -O1
+!ELSE
+cdebug = -Od
+cdbgsz = $(cdebug)
+!ENDIF
+
+# ------------- 32-bit Microsoft Visual C++ -------------
+CC=cl -nologo
+CFLAGS=-W3 $(cdebug) -DWIN32 $(CFLG_ASM) $(CRTLIB) $(LOC) -DNO_ASM
+UTILFLAGS=$(CFLAGS) -DUTIL -Fo$@
+
+# Remove "-coff" from ASFLAGS if you do not have MASM 6.11.
+
+AS=ml -nologo
+ASFLAGS=-c -coff -Cx
+
+RC=rc
+
+# If you build 16-bit executables with MS Visual C++ v1.0/1.5 and link them
+# with the /KNOWEAS switch, you can build dual-mode MS-DOS/Win32 executables
+# by passing the -stub switch to the 32-bit linker to specify the 16-bit part.
+
+LD=link -nologo
+LDFLAGS=user32.lib advapi32.lib /OPT:NOWIN98 /INCREMENTAL:NO /PDB:$*.pdb $(EXTLIB)
+SYMS=/DEBUG:full /DEBUGTYPE:CV
+!IFDEF debug
+LDFLAGS=$(LDFLAGS) $(SYMS)
+CFLAGS=$(CFLAGS) /Zi
+!ELSE
+LDFLAGS=$(LDFLAGS) /RELEASE
+!IFDEF sym
+LDFLAGS=$(LDFLAGS) $(SYMS)
+CFLAGS=$(CFLAGS) /Zi
+!ENDIF
+!ENDIF
+
+# variables
+OBJZ = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+ crc32.obj $(CRCA_O) globals.obj
+
+OBJI = deflate.obj trees.obj $(ASMOBJS) win32.obj win32zip.obj nt.obj win32i64.obj
+
+OBJU = zipfile_.obj fileio_.obj util_.obj crc32_.obj $(CRCA_O) globals.obj \
+ win32_.obj win32i64.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj crypt_.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h win32/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips:   $(ZIPS)
+
+zip.obj:        zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile.obj:    zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipup.obj:      zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32/zipup.h
+ $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj:     fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+util.obj:       util.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+globals.obj:    globals.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj:    deflate.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj:      trees.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj:      crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj:      crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj:      ttyio.c $(ZIP_H) crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+win32i64.obj:   win32/win32i64.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) -I. win32/win32i64.c
+
+win32zip.obj:   win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+ $(CC) -c $(CFLAGS) -I. win32/win32zip.c
+
+win32.obj:      win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(CFLAGS) -I. win32/win32.c
+
+nt.obj:         win32/nt.c $(ZIP_H) win32/nt.h
+ $(CC) -c $(CFLAGS) -I. win32/nt.c
+
+zipcloak.obj:   zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipnote.obj:    zipnote.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipsplit.obj:   zipsplit.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile_.obj:   zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) zipfile.c
+
+fileio_.obj:    fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) fileio.c
+
+util_.obj:      util.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS) util.c
+
+crc32_.obj:     crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) crc32.c
+
+crypt_.obj:     crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(UTILFLAGS) crypt.c
+
+win32_.obj:     win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(UTILFLAGS) -I. win32/win32.c
+
+crci386c.obj:   win32/crc_i386.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) -I. -Fo$@ win32/crc_i386.c
+
+crc_i386.obj:   win32/crc_i386.asm
+ $(AS) $(ASFLAGS) win32\crc_i386.asm
+
+match32.obj:    win32/match32.asm
+ $(AS) $(ASFLAGS) win32\match32.asm
+
+zip.res:        win32/zip.rc revision.h
+       $(RC) /l 0x409 /fo$@ /i win32 /d WIN32 win32/zip.rc
+
+zip.exe: $(OBJZ) $(OBJI) zip.res
+ $(LD) $(LDFLAGS) $(OBJZ) $(OBJI) zip.res
+
+zipcloak.exe: $(OBJC)
+ $(LD) $(LDFLAGS) $(OBJC)
+
+zipnote.exe: $(OBJN)
+ $(LD) $(LDFLAGS) $(OBJN)
+
+zipsplit.exe: $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJS)
+
+clean:
+ -del *.obj
+ -del *.exe
diff --git a/win32/match32.asm b/win32/match32.asm
new file mode 100644 (file)
index 0000000..81db41f
--- /dev/null
@@ -0,0 +1,192 @@
+;===========================================================================
+; Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+;
+; See the accompanying file LICENSE, version 2005-Feb-10 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+;
+; match32.asm by Jean-loup Gailly.
+
+; match32.asm, optimized version of longest_match() in deflate.c
+; To be used only with 32 bit flat model. To simplify the code, the option
+; -DDYN_ALLOC is not supported.
+; This file is only optional. If you don't have an assembler, use the
+; C version (add -DNO_ASM to CFLAGS in makefile and remove match.o
+; from OBJI). If you have reduced WSIZE in zip.h, then make sure this is
+; assembled with an equivalent -DWSIZE=<whatever>.
+;
+; Win32 (Windows NT) version - 1994/04/13 by Steve Salisbury
+; * works with Microsoft MASM 6.1X and Microsoft Visual C++ / 32-bit edition
+;
+; Adapted to work with Borland Turbo Assembler 5.0 by Cosmin Truta, 1997
+;
+; Adapted to work with OpenWatcom WASM by Chr. Spieler, 2005
+; (Define the symbol WATCOM_DSEG to activate the specific Watcom C
+; data segment naming convention.)
+;
+;==============================================================================
+;
+; Do NOT assemble this source if external crc32 routine from zlib gets used.
+;
+    IFNDEF USE_ZLIB
+;
+        .386p
+    ifdef ASM_NEW
+        .MODEL  FLAT
+    endif
+
+        name    match
+
+    ifdef ASM_NEW
+_BSS    segment public use32
+    else
+_BSS    segment public use32 'DATA'
+    endif
+        extrn   _match_start  : dword
+        extrn   _prev_length  : dword
+        extrn   _good_match   : dword
+    ifndef FULL_SEARCH
+        extrn   _nice_match   : dword
+    endif
+        extrn   _strstart     : dword
+        extrn   _max_chain_length : dword
+        extrn   _prev         : word
+        extrn   _window       : byte
+_BSS    ends
+
+   ifdef WATCOM_DSEG
+DGROUP  group   _BSS
+   endif
+
+   ifdef ASM_NEW
+_TEXT   segment public use32
+   else
+_TEXT   segment para public use32 'CODE'
+   endif
+        assume CS: _TEXT
+        assume DS: _BSS, ES: _BSS, FS: _BSS
+        public  _match_init
+        public  _longest_match
+
+    ifndef      WSIZE
+        WSIZE         equ 32768         ; keep in sync with zip.h !
+    endif
+        MIN_MATCH     equ 3
+        MAX_MATCH     equ 258
+        MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
+        MAX_DIST      equ (WSIZE-MIN_LOOKAHEAD)
+
+; initialize or check the variables used in match.asm.
+
+_match_init proc near
+        ret
+_match_init endp
+
+; -----------------------------------------------------------------------
+; Set match_start to the longest match starting at the given string and
+; return its length. Matches shorter or equal to prev_length are discarded,
+; in which case the result is equal to prev_length and match_start is
+; garbage.
+; IN assertions: cur_match is the head of the hash chain for the current
+;   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+
+; int longest_match(cur_match)
+
+_longest_match proc near
+
+        cur_match    equ dword ptr [esp+20]
+        ; return address                ; esp+16
+        push    ebp                     ; esp+12
+        push    edi                     ; esp+8
+        push    esi                     ; esp+4
+        push    ebx                     ; esp
+
+;       match        equ esi
+;       scan         equ edi
+;       chain_length equ ebp
+;       best_len     equ ebx
+;       limit        equ edx
+
+        mov     esi,cur_match
+        mov     edx,_strstart
+        mov     ebp,_max_chain_length   ; chain_length = max_chain_length
+        mov     edi,edx
+        sub     edx,MAX_DIST            ; limit = strstart-MAX_DIST
+        cld                             ; string ops increment esi and edi
+        jae     short limit_ok
+        sub     edx,edx                 ; limit = NIL
+limit_ok:
+        add     edi,2+offset _window    ; edi = offset(window + strstart + 2)
+        mov     ebx,_prev_length        ; best_len = prev_length
+        mov     cx,[edi-2]              ; cx = scan[0..1]
+        mov     ax,[ebx+edi-3]          ; ax = scan[best_len-1..best_len]
+        cmp     ebx,_good_match         ; do we have a good match already?
+        jb      short do_scan
+        shr     ebp,2                   ; chain_length >>= 2
+        jmp     short do_scan
+
+        align   4                       ; align destination of branch
+long_loop:
+; at this point, edi == scan+2, esi == cur_match
+        mov     ax,[ebx+edi-3]          ; ax = scan[best_len-1..best_len]
+        mov     cx,[edi-2]              ; cx = scan[0..1]
+short_loop:
+; at this point, edi == scan+2, esi == cur_match,
+; ax = scan[best_len-1..best_len] and cx = scan[0..1]
+        and     esi,WSIZE-1
+        dec     ebp                     ; --chain_length
+        mov     si,_prev[esi+esi]       ; cur_match = prev[cur_match]
+                                        ; top word of esi is still 0
+        jz      short the_end
+        cmp     esi,edx                 ; cur_match <= limit ?
+        jbe     short the_end
+do_scan:
+        cmp     ax,word ptr _window[ebx+esi-1]   ; check match at best_len-1
+        jne     short_loop
+        cmp     cx,word ptr _window[esi]         ; check min_match_length match
+        jne     short_loop
+
+        lea     esi,_window[esi+2]      ; esi = match
+        mov     ecx,(MAX_MATCH-2)/2     ; scan for at most MAX_MATCH bytes
+        mov     eax,edi                 ; eax = scan+2
+        repe    cmpsw                   ; loop until mismatch
+        je      short maxmatch          ; match of length MAX_MATCH?
+mismatch:
+        mov     cl,[edi-2]              ; mismatch on first or second byte?
+        xchg    eax,edi                 ; edi = scan+2, eax = end of scan
+        sub     cl,[esi-2]              ; cl = 0 if first bytes equal
+        sub     eax,edi                 ; eax = len
+        sub     esi,2+offset _window    ; esi = match - (2 + offset(window))
+        sub     esi,eax                 ; esi = cur_match (= match - len)
+        sub     cl,1                    ; set carry if cl == 0 (can't use DEC)
+        adc     eax,0                   ; eax = carry ? len+1 : len
+        cmp     eax,ebx                 ; len > best_len ?
+        jle     long_loop
+        mov     _match_start,esi        ; match_start = cur_match
+        mov     ebx,eax                 ; ebx = best_len = len
+    ifdef FULL_SEARCH
+        cmp     eax,MAX_MATCH           ; len >= MAX_MATCH ?
+    else
+        cmp     eax,_nice_match         ; len >= nice_match ?
+    endif
+        jl      long_loop
+the_end:
+        mov     eax,ebx                 ; result = eax = best_len
+        pop     ebx
+        pop     esi
+        pop     edi
+        pop     ebp
+        ret
+maxmatch:                               ; come here if maximum match
+        cmpsb                           ; increment esi and edi
+        jmp     mismatch                ; force match_length = MAX_LENGTH
+
+_longest_match endp
+
+_TEXT   ends
+;
+    ENDIF ; !USE_ZLIB
+;
+end
diff --git a/win32/nt.c b/win32/nt.c
new file mode 100644 (file)
index 0000000..aa0529f
--- /dev/null
@@ -0,0 +1,492 @@
+/*
+  win32/nt.c - Zip 3
+
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*++
+
+Copyright (c) 1996  Scott Field
+
+Module Name:
+
+    nt.c (formerly nt_zip.c)
+
+Abstract:
+
+    This module implements WinNT security descriptor operations for the
+    Win32 Info-ZIP project.  Operation such as querying file security,
+    using/querying local and remote privileges.  The contents of this module
+    are only relevant when the code is running on Windows NT, and the target
+    volume supports persistent Acl storage.
+
+    User privileges that allow accessing certain privileged aspects of the
+    security descriptor (such as the Sacl) are only used if the user specified
+    to do so.
+
+    In the future, this module may be expanded to support storage of
+    OS/2 EA data, Macintosh resource forks, and hard links, which are all
+    supported by NTFS.
+
+Author:
+
+    Scott Field (sfield@microsoft.com)  27-Sep-96
+
+--*/
+
+#include "../zip.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#ifdef __RSXNT__
+#  include "../win32/rsxntwin.h"
+#endif
+#include "../win32/nt.h"
+
+#ifdef NTSD_EAS         /* This file is only needed for NTSD handling */
+
+/* Borland C++ does not define FILE_SHARE_DELETE. Others also? */
+#ifndef FILE_SHARE_DELETE
+#  define FILE_SHARE_DELETE 0x00000004
+#endif
+
+/* This macro definition is missing in old versions of MS' winbase.h. */
+#ifndef InterlockedExchangePointer
+#  define InterlockedExchangePointer(Target, Value) \
+      (PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value))
+#endif
+
+/* private prototypes */
+
+static BOOL Initialize(VOID);
+#if 0   /* currently unused */
+static BOOL Shutdown(VOID);
+#endif
+static VOID GetRemotePrivilegesGet(CHAR *FileName, PDWORD dwRemotePrivileges);
+static VOID InitLocalPrivileges(VOID);
+
+
+BOOL bZipInitialized = FALSE;  /* module level stuff initialized? */
+HANDLE hZipInitMutex = NULL;   /* prevent multiple initialization */
+
+BOOL g_bBackupPrivilege = FALSE;    /* for local get file security override */
+BOOL g_bZipSaclPrivilege = FALSE;      /* for local get sacl operations, only when
+                                       backup privilege not present */
+
+/* our single cached volume capabilities structure that describes the last
+   volume root we encountered.  A single entry like this works well in the
+   zip/unzip scenario for a number of reasons:
+   1. typically one extraction path during unzip.
+   2. typically process one volume at a time during zip, and then move
+      on to the next.
+   3. no cleanup code required and no memory leaks.
+   4. simple code.
+
+   This approach should be reworked to a linked list approach if we expect to
+   be called by many threads which are processing a variety of input/output
+   volumes, since lock contention and stale data may become a bottleneck. */
+
+VOLUMECAPS g_VolumeCaps;
+CRITICAL_SECTION VolumeCapsLock;
+
+
+static BOOL Initialize(VOID)
+{
+    HANDLE hMutex;
+    HANDLE hOldMutex;
+
+    if(bZipInitialized) return TRUE;
+
+    hMutex = CreateMutex(NULL, TRUE, NULL);
+    if(hMutex == NULL) return FALSE;
+
+    hOldMutex = (HANDLE)InterlockedExchangePointer((void *)&hZipInitMutex,
+                                                   hMutex);
+
+    if(hOldMutex != NULL) {
+        /* somebody setup the mutex already */
+        InterlockedExchangePointer((void *)&hZipInitMutex,
+                                   hOldMutex);
+
+        CloseHandle(hMutex); /* close new, un-needed mutex */
+
+        /* wait for initialization to complete and return status */
+        WaitForSingleObject(hOldMutex, INFINITE);
+        ReleaseMutex(hOldMutex);
+
+        return bZipInitialized;
+    }
+
+    /* initialize module level resources */
+
+    InitializeCriticalSection( &VolumeCapsLock );
+    memset(&g_VolumeCaps, 0, sizeof(VOLUMECAPS));
+
+    InitLocalPrivileges();
+
+    bZipInitialized = TRUE;
+
+    ReleaseMutex(hMutex); /* release correct mutex */
+
+    return TRUE;
+}
+
+#if 0   /* currently not used ! */
+static BOOL Shutdown(VOID)
+{
+    /* really need to free critical sections, disable enabled privilges, etc,
+       but doing so brings up possibility of race conditions if those resources
+       are about to be used.  The easiest way to handle this is let these
+       resources be freed when the process terminates... */
+
+    return TRUE;
+}
+#endif /* never */
+
+
+static VOID GetRemotePrivilegesGet(char *FileName, PDWORD dwRemotePrivileges)
+{
+    HANDLE hFile;
+
+    *dwRemotePrivileges = 0;
+
+    /* see if we have the SeBackupPrivilege */
+
+    hFile = CreateFileA(
+        FileName,
+        ACCESS_SYSTEM_SECURITY | GENERIC_READ | READ_CONTROL,
+        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+        NULL,
+        OPEN_EXISTING,
+        FILE_FLAG_BACKUP_SEMANTICS,
+        NULL
+        );
+
+    if(hFile != INVALID_HANDLE_VALUE) {
+        /* no remote way to determine SeBackupPrivilege -- just try a read
+           to simulate it */
+        SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
+        PSECURITY_DESCRIPTOR sd;
+        DWORD cbBuf = 0;
+
+        GetKernelObjectSecurity(hFile, si, NULL, cbBuf, &cbBuf);
+
+        if(ERROR_INSUFFICIENT_BUFFER == GetLastError()) {
+            if((sd = HeapAlloc(GetProcessHeap(), 0, cbBuf)) != NULL) {
+                if(GetKernelObjectSecurity(hFile, si, sd, cbBuf, &cbBuf)) {
+                    *dwRemotePrivileges |= OVERRIDE_BACKUP;
+                }
+                HeapFree(GetProcessHeap(), 0, sd);
+            }
+        }
+
+        CloseHandle(hFile);
+    } else {
+
+        /* see if we have the SeSecurityPrivilege */
+        /* note we don't need this if we have SeBackupPrivilege */
+
+        hFile = CreateFileA(
+            FileName,
+            ACCESS_SYSTEM_SECURITY,
+            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, /* maximum sharing */
+            NULL,
+            OPEN_EXISTING,
+            0,
+            NULL
+            );
+
+        if(hFile != INVALID_HANDLE_VALUE) {
+            CloseHandle(hFile);
+            *dwRemotePrivileges |= OVERRIDE_SACL;
+        }
+    }
+}
+
+
+BOOL ZipGetVolumeCaps(
+    char *rootpath,         /* filepath, or NULL */
+    char *name,             /* filename associated with rootpath */
+    PVOLUMECAPS VolumeCaps  /* result structure describing capabilities */
+    )
+{
+    char TempRootPath[MAX_PATH + 1];
+    DWORD cchTempRootPath = 0;
+    BOOL bSuccess = TRUE;   /* assume success until told otherwise */
+
+    if(!bZipInitialized) if(!Initialize()) return FALSE;
+
+    /* process the input path to produce a consistent path suitable for
+       compare operations and also suitable for certain picky Win32 API
+       that don't like forward slashes */
+
+    if(rootpath != NULL && rootpath[0] != '\0') {
+        DWORD i;
+
+        cchTempRootPath = lstrlen(rootpath);
+        if(cchTempRootPath > MAX_PATH) return FALSE;
+
+        /* copy input, converting forward slashes to back slashes as we go */
+
+        for(i = 0 ; i <= cchTempRootPath ; i++) {
+            if(rootpath[i] == '/') TempRootPath[i] = '\\';
+            else TempRootPath[i] = rootpath[i];
+        }
+
+        /* check for UNC and Null terminate or append trailing \ as appropriate */
+
+        /* possible valid UNCs we are passed follow:
+           \\machine\foo\bar (path is \\machine\foo\)
+           \\machine\foo     (path is \\machine\foo\)
+           \\machine\foo\
+           \\.\c$\           (FIXFIX: Win32API doesn't like this - GetComputerName())
+           LATERLATER: handling mounted DFS drives in the future will require
+                       slightly different logic which isn't available today.
+                       This is required because directories can point at
+                       different servers which have differing capabilities.
+         */
+
+        if(TempRootPath[0] == '\\' && TempRootPath[1] == '\\') {
+            DWORD slash = 0;
+
+            for(i = 2 ; i < cchTempRootPath ; i++) {
+                if(TempRootPath[i] == '\\') {
+                    slash++;
+
+                    if(slash == 2) {
+                        i++;
+                        TempRootPath[i] = '\0';
+                        cchTempRootPath = i;
+                        break;
+                    }
+                }
+            }
+
+            /* if there was only one slash found, just tack another onto the end */
+
+            if(slash == 1 && TempRootPath[cchTempRootPath] != '\\') {
+                TempRootPath[cchTempRootPath] = TempRootPath[0]; /* '\' */
+                TempRootPath[cchTempRootPath+1] = '\0';
+                cchTempRootPath++;
+            }
+
+        } else {
+
+            if(TempRootPath[1] == ':') {
+
+                /* drive letter specified, truncate to root */
+                TempRootPath[2] = '\\';
+                TempRootPath[3] = '\0';
+                cchTempRootPath = 3;
+            } else {
+
+                /* must be file on current drive */
+                TempRootPath[0] = '\0';
+                cchTempRootPath = 0;
+            }
+
+        }
+
+    } /* if path != NULL */
+
+    /* grab lock protecting cached entry */
+    EnterCriticalSection( &VolumeCapsLock );
+
+    if(!g_VolumeCaps.bValid || lstrcmpi(g_VolumeCaps.RootPath, TempRootPath) != 0) {
+
+        /* no match found, build up new entry */
+
+        DWORD dwFileSystemFlags;
+        DWORD dwRemotePrivileges = 0;
+        BOOL bRemote = FALSE;
+
+        /* release lock during expensive operations */
+        LeaveCriticalSection( &VolumeCapsLock );
+
+        bSuccess = GetVolumeInformation(
+            (TempRootPath[0] == '\0') ? NULL : TempRootPath,
+            NULL, 0,
+            NULL, NULL,
+            &dwFileSystemFlags,
+            NULL, 0);
+
+        /* only if target volume supports Acls, and we were told to use
+           privileges do we need to go out and test for the remote case */
+
+        if(bSuccess && (dwFileSystemFlags & FS_PERSISTENT_ACLS) && VolumeCaps->bUsePrivileges) {
+            if(GetDriveType( (TempRootPath[0] == '\0') ? NULL : TempRootPath ) == DRIVE_REMOTE) {
+                bRemote = TRUE;
+
+                /* make a determination about our remote capabilities */
+
+                GetRemotePrivilegesGet(name, &dwRemotePrivileges);
+            }
+        }
+
+        /* always take the lock again, since we release it below */
+        EnterCriticalSection( &VolumeCapsLock );
+
+        /* replace the existing data if successful */
+        if(bSuccess) {
+
+            lstrcpynA(g_VolumeCaps.RootPath, TempRootPath, cchTempRootPath+1);
+            g_VolumeCaps.bProcessDefer = FALSE;
+            g_VolumeCaps.dwFileSystemFlags = dwFileSystemFlags;
+            g_VolumeCaps.bRemote = bRemote;
+            g_VolumeCaps.dwRemotePrivileges = dwRemotePrivileges;
+            g_VolumeCaps.bValid = TRUE;
+        }
+    }
+
+    if(bSuccess) {
+        /* copy input elements */
+        g_VolumeCaps.bUsePrivileges = VolumeCaps->bUsePrivileges;
+        g_VolumeCaps.dwFileAttributes = VolumeCaps->dwFileAttributes;
+
+        /* give caller results */
+        memcpy(VolumeCaps, &g_VolumeCaps, sizeof(VOLUMECAPS));
+    } else {
+        g_VolumeCaps.bValid = FALSE;
+    }
+
+    LeaveCriticalSection( &VolumeCapsLock ); /* release lock */
+
+    return bSuccess;
+}
+
+BOOL SecurityGet(
+    char *resource,
+    PVOLUMECAPS VolumeCaps,
+    unsigned char *buffer,
+    DWORD *cbBuffer
+    )
+{
+    HANDLE hFile;
+    DWORD dwDesiredAccess;
+    DWORD dwFlags;
+    PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR)buffer;
+    SECURITY_INFORMATION RequestedInfo;
+    BOOL bBackupPrivilege = FALSE;
+    BOOL bSaclPrivilege = FALSE;
+    BOOL bSuccess = FALSE;
+
+    DWORD cchResourceLen;
+
+    if(!bZipInitialized) if(!Initialize()) return FALSE;
+
+    /* see if we are dealing with a directory */
+    /* rely on the fact resource has a trailing [back]slash, rather
+       than calling expensive GetFileAttributes() */
+
+    cchResourceLen = lstrlenA(resource);
+
+    if(resource[cchResourceLen-1] == '/' || resource[cchResourceLen-1] == '\\')
+        VolumeCaps->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+
+    /* setup privilege usage based on if told we can use privileges, and if so,
+       what privileges we have */
+
+    if(VolumeCaps->bUsePrivileges) {
+        if(VolumeCaps->bRemote) {
+            /* use remotely determined privileges */
+            if(VolumeCaps->dwRemotePrivileges & OVERRIDE_BACKUP)
+                bBackupPrivilege = TRUE;
+
+            if(VolumeCaps->dwRemotePrivileges & OVERRIDE_SACL)
+                bSaclPrivilege = TRUE;
+        } else {
+            /* use local privileges */
+            bBackupPrivilege = g_bBackupPrivilege;
+            bSaclPrivilege = g_bZipSaclPrivilege;
+        }
+    }
+
+    /* always try to read the basic security information:  Dacl, Owner, Group */
+
+    dwDesiredAccess = READ_CONTROL;
+
+    RequestedInfo = OWNER_SECURITY_INFORMATION |
+                    GROUP_SECURITY_INFORMATION |
+                    DACL_SECURITY_INFORMATION;
+
+    /* if we have the SeBackupPrivilege or SeSystemSecurityPrivilege, read
+       the Sacl, too */
+
+    if(bBackupPrivilege || bSaclPrivilege) {
+        dwDesiredAccess |= ACCESS_SYSTEM_SECURITY;
+        RequestedInfo |= SACL_SECURITY_INFORMATION;
+    }
+
+    dwFlags = 0;
+
+    /* if we have the backup privilege, specify that */
+    /* opening a directory requires FILE_FLAG_BACKUP_SEMANTICS */
+
+    if(bBackupPrivilege || (VolumeCaps->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+        dwFlags |= FILE_FLAG_BACKUP_SEMANTICS;
+
+    hFile = CreateFileA(
+        resource,
+        dwDesiredAccess,
+        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, /* maximum sharing */
+        NULL,
+        OPEN_EXISTING,
+        dwFlags,
+        NULL
+        );
+
+    if(hFile == INVALID_HANDLE_VALUE) return FALSE;
+
+    if(GetKernelObjectSecurity(hFile, RequestedInfo, sd, *cbBuffer, cbBuffer)) {
+        *cbBuffer = GetSecurityDescriptorLength( sd );
+        bSuccess = TRUE;
+    }
+
+    CloseHandle(hFile);
+
+    return bSuccess;
+}
+
+static VOID InitLocalPrivileges(VOID)
+{
+    HANDLE hToken;
+    TOKEN_PRIVILEGES tp;
+
+    /* try to enable some interesting privileges that give us the ability
+       to get some security information that we normally cannot.
+
+       note that enabling privileges is only relevant on the local machine;
+       when accessing files that are on a remote machine, any privileges
+       that are present on the remote machine get enabled by default. */
+
+    if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
+        return;
+
+    tp.PrivilegeCount = 1;
+    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+    /* try to enable SeBackupPrivilege.
+       if this succeeds, we can read all aspects of the security descriptor */
+
+    if(LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &tp.Privileges[0].Luid)) {
+        if(AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL) &&
+           GetLastError() == ERROR_SUCCESS) g_bBackupPrivilege = TRUE;
+    }
+
+    /* try to enable SeSystemSecurityPrivilege if SeBackupPrivilege not present.
+       if this succeeds, we can read the Sacl */
+
+    if(!g_bBackupPrivilege &&
+        LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &tp.Privileges[0].Luid)) {
+
+        if(AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL) &&
+           GetLastError() == ERROR_SUCCESS) g_bZipSaclPrivilege = TRUE;
+    }
+
+    CloseHandle(hToken);
+}
+#endif /* NTSD_EAS */
diff --git a/win32/nt.h b/win32/nt.h
new file mode 100644 (file)
index 0000000..f722530
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+  win32/nt.h - Zip 3
+
+  Copyright (c) 1990-2003 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2003-May-08 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef _NT_ZIP_H
+#define _NT_ZIP_H
+
+/* central header for EF_NTSD "SD" extra field */
+
+#define EF_NTSD_MAX_VER_SUPPORT (0)
+                        /* describes maximum ver# we know how to handle */
+
+typedef struct
+{
+  USHORT nID;
+  USHORT nSize;
+  ULONG lSize;
+}
+EF_NTSD_C_HEADER, *PEF_NTSD_C_HEADER;
+
+#define EF_NTSD_C_LEN (sizeof(EF_NTSD_C_HEADER))
+
+/* local header for EF_NTSD "SD" extra field */
+
+#pragma pack(1) /* bytes following structure immediately follow BYTE Version */
+
+typedef struct
+{
+  USHORT nID;   /* tag for this extra block type */
+  USHORT nSize; /* total data size for this block */
+  ULONG lSize;  /* uncompressed security descriptor data size */
+  BYTE Version; /* Version of uncompressed security descriptor data format */
+}
+IZ_PACKED EF_NTSD_L_HEADER, *PEF_NTSD_L_HEADER;
+
+#pragma pack()
+
+/*  ...followed by... */
+/*  SHORT CType;  compression type */
+/*  ULONG EACRC;  CRC value for uncompressed security descriptor data */
+/*  <var.> Variable length data */
+
+
+#define EF_NTSD_L_LEN (EF_NTSD_C_LEN + sizeof(BYTE))
+                                /* avoid alignment size computation */
+
+#define NTSD_BUFFERSIZE (1024)  /* threshold to cause malloc() */
+
+#define OVERRIDE_BACKUP     1   /* we have SeBackupPrivilege on remote */
+#define OVERRIDE_RESTORE    2   /* we have SeRestorePrivilege on remote */
+#define OVERRIDE_SACL       4   /* we have SeSystemSecurityPrivilege on remote */
+
+typedef struct {
+    BOOL bValid;                /* are our contents valid? */
+    BOOL bProcessDefer;         /* process deferred entry yet? */
+    BOOL bUsePrivileges;        /* use privilege overrides? */
+    DWORD dwFileSystemFlags;    /* describes target file system */
+    BOOL bRemote;               /* is volume remote? */
+    DWORD dwRemotePrivileges;   /* relevant only on remote volumes */
+    DWORD dwFileAttributes;
+    char RootPath[MAX_PATH+1];  /* path to network / filesystem */
+} VOLUMECAPS, *PVOLUMECAPS, *LPVOLUMECAPS;
+
+BOOL SecurityGet(char *resource, PVOLUMECAPS VolumeCaps, unsigned char *buffer,
+                 DWORD *cbBuffer);
+BOOL ZipGetVolumeCaps(char *rootpath, char *name, PVOLUMECAPS VolumeCaps);
+
+#endif /* _NT_ZIP_H */
+
diff --git a/win32/osdep.h b/win32/osdep.h
new file mode 100644 (file)
index 0000000..eaf6507
--- /dev/null
@@ -0,0 +1,617 @@
+/*
+  win32/osdep.h
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/* Automatic setting of the common Microsoft C idenfifier MSC.
+ * NOTE: Watcom also defines M_I*86 !
+ */
+#if defined(_MSC_VER) || (defined(M_I86) && !defined(__WATCOMC__))
+#  ifndef MSC
+#    define MSC                 /* This should work for older MSC, too!  */
+#  endif
+#endif
+
+/* Tell Microsoft Visual C++ 2005 to leave us alone and
+ * let us use standard C functions the way we're supposed to.
+ */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#  ifndef _CRT_SECURE_NO_DEPRECATE
+#    define _CRT_SECURE_NO_DEPRECATE
+#  endif
+#  ifndef _CRT_NONSTDC_NO_DEPRECATE
+#    define _CRT_NONSTDC_NO_DEPRECATE
+#  endif
+#endif
+
+#if defined(__WATCOMC__) && defined(__386__)
+#  define WATCOMC_386
+#endif
+
+#if (defined(__CYGWIN32__) && !defined(__CYGWIN__))
+#  define __CYGWIN__            /* compatibility for CygWin B19 and older */
+#endif
+
+/* enable multibyte character set support by default */
+#ifndef _MBCS
+#  define _MBCS
+#endif
+#if defined(__CYGWIN__)
+#  undef _MBCS
+#endif
+
+/* Get types and stat */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <io.h>
+
+#ifndef MSDOS
+/*
+ * Windows 95 (and Windows NT) file systems are (to some extend)
+ * extensions of MSDOS. Common features include for example:
+ *      FAT or (FAT like) file systems,
+ *      '\\' as directory separator in paths,
+ *      "\r\n" as record (line) terminator in text files, ...
+ */
+#  define MSDOS
+/* inherit MS-DOS file system etc. stuff */
+#endif
+
+#define USE_CASE_MAP
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+                     procname(n, filter_match_case))
+#define BROKEN_FSEEK
+#ifndef __RSXNT__
+#  define HAVE_FSEEKABLE
+#endif
+
+
+/* popen
+ *
+ * On Win32 must map to _popen() and _pclose()
+ */
+#define popen _popen
+#define pclose _pclose
+
+/* WIN32_OEM
+ *
+ * This enables storing paths in archives on WIN32 in OEM format
+ * which is more work but seems the standard now.  It also enables
+ * converting paths in read DOS archives from assumed OEM to ANSI.
+ */
+#ifndef NO_WIN32_OEM
+#  define WIN32_OEM
+#endif
+
+/* Large File Support
+ *
+ *  If this is set it is assumed that the port
+ *  supports 64-bit file calls.  The types are
+ *  defined here.  Any local implementations are
+ *  in Win32.c and the prototypes for the calls are
+ *  in tailor.h.  Note that a port must support
+ *  these calls fully or should not set
+ *  LARGE_FILE_SUPPORT.
+ */
+
+/* Note also that ZOFF_T_FORMAT_SIZE_PREFIX has to be defined here
+   or tailor.h will define defaults */
+
+/* If port has LARGE_FILE_SUPPORT then define here
+   to make large file support automatic unless overridden */
+
+
+#ifndef LARGE_FILE_SUPPORT
+# ifndef NO_LARGE_FILE_SUPPORT
+    /* MS C and VC */
+#   if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)
+#     define LARGE_FILE_SUPPORT
+#   endif
+#   if defined(__WATCOMC__)
+#     define LARGE_FILE_SUPPORT
+#   endif
+# endif
+#endif
+
+#ifdef LARGE_FILE_SUPPORT
+  /* 64-bit Large File Support */
+
+  /* Only types and the printf format stuff go here.  Functions
+     go in tailor.h since ANSI prototypes are required and the OF define
+     is not defined here. */
+
+# if (defined(_MSC_VER) && (_MSC_VER >= 1100)) || defined(__MINGW32__)
+    /* MS C and VC, MinGW32 */
+    /* these compiler systems use the Microsoft C RTL */
+
+    /* base types for file offsets and file sizes */
+    typedef __int64             zoff_t;
+    typedef unsigned __int64    uzoff_t;
+
+    /* 64-bit stat struct */
+    typedef struct _stati64 z_stat;
+
+    /* printf format size prefix for zoff_t values */
+#   define ZOFF_T_FORMAT_SIZE_PREFIX "I64"
+
+# elif (defined(__GNUC__) || defined(ULONG_LONG_MAX))
+    /* GNU C */
+
+    /* base types for file offsets and file sizes */
+    typedef long long           zoff_t;
+    typedef unsigned long long  uzoff_t;
+
+#  ifdef __CYGWIN__
+    /* Use Cygwin's own stat struct */
+     typedef struct stat z_stat;
+#  else
+    /* 64-bit stat struct */
+    typedef struct _stati64 z_stat;
+#  endif
+
+    /* printf format size prefix for zoff_t values */
+#   define ZOFF_T_FORMAT_SIZE_PREFIX "ll"
+
+# elif (defined(__WATCOMC__) && (__WATCOMC__ >= 1100))
+    /* WATCOM C */
+
+    /* base types for file offsets and file sizes */
+    typedef __int64             zoff_t;
+    typedef unsigned __int64    uzoff_t;
+
+    /* 64-bit stat struct */
+    typedef struct _stati64 z_stat;
+
+    /* printf format size prefix for zoff_t values */
+#   define ZOFF_T_FORMAT_SIZE_PREFIX "ll"
+
+# elif (defined(__IBMC__) && (__IBMC__ >= 350))
+    /* IBM C */
+
+    /* base types for file offsets and file sizes */
+    typedef __int64             zoff_t;
+    typedef unsigned __int64    uzoff_t;
+
+    /* 64-bit stat struct */
+
+    /* printf format size prefix for zoff_t values */
+#   define ZOFF_T_FORMAT_SIZE_PREFIX "I64"
+
+# else
+#   undef LARGE_FILE_SUPPORT
+# endif
+
+#endif
+
+#if 0
+# ifndef ZOFF_T_FORMAT_SIZE_PREFIX
+    /* unsupported WIN32 */
+
+    /* base types for file offsets and file sizes */
+    typedef long long           zoff_t;
+    typedef unsigned long long  uzoff_t;
+
+    /* 64-bit stat struct */
+    typedef struct stat z_stat;
+
+    /* printf format size prefix for zoff_t values */
+#   define ZOFF_T_FORMAT_SIZE_PREFIX "ll"
+# endif
+#endif
+
+
+/* Automatically set ZIP64_SUPPORT if supported */
+
+/* MS C and VC */
+#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__WATCOMC__)
+# ifdef LARGE_FILE_SUPPORT
+#   ifndef NO_ZIP64_SUPPORT
+#     ifndef ZIP64_SUPPORT
+#       define ZIP64_SUPPORT
+#     endif
+#   endif
+# endif
+#endif
+
+
+#ifndef LARGE_FILE_SUPPORT
+  /* No Large File Support */
+
+  /* base type for file offsets and file sizes */
+  typedef long zoff_t;
+  typedef unsigned long uzoff_t;
+
+  /* stat struct */
+  typedef struct stat z_stat;
+
+  /* printf format size prefix for zoff_t values */
+# define ZOFF_T_FORMAT_SIZE_PREFIX "l"
+#endif
+
+
+  /* UNICODE */
+#ifdef WIN32
+  /* assume wide character conversion functions */
+# ifndef UNICODE_SUPPORT
+#   ifndef NO_UNICODE_SUPPORT
+#     define UNICODE_SUPPORT
+#   endif
+# endif
+#endif
+
+#if 0
+  /* this is now generic */
+# ifdef UNICODE_SUPPORT
+  /* Set up Unicode support - 9/27/05 EG */
+
+  /* type of wide string characters */
+#  define zchar wchar_t
+
+  /* default char string used if a wide char can't be converted */
+#  define zchar_default "_"
+
+# else
+#  define zchar char
+# endif
+#endif
+
+
+/* File operations--use "b" for binary if allowed or fixed length 512 on VMS
+ *                  use "S" for sequential access on NT to prevent the NT
+ *                  file cache eating up memory with large .zip files
+ */
+#define FOPR "rb"
+#define FOPM "r+b"
+#define FOPW "wbS"
+
+#if (defined(__CYGWIN__) && !defined(NO_MKTIME))
+#  define NO_MKTIME             /* Cygnus' mktime() implementation is buggy */
+#endif
+#if (!defined(NT_TZBUG_WORKAROUND) && !defined(NO_NT_TZBUG_WORKAROUND))
+#  define NT_TZBUG_WORKAROUND
+#endif
+#if (defined(UTIL) && defined(NT_TZBUG_WORKAROUND))
+#  undef NT_TZBUG_WORKAROUND    /* the Zip utilities do not use time-stamps */
+#endif
+#if !defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME)
+#  define USE_EF_UT_TIME
+#endif
+#if (!defined(NO_NTSD_EAS) && !defined(NTSD_EAS))
+#  define NTSD_EAS
+#endif
+
+#if (defined(NTSD_EAS) && !defined(ZP_NEED_MEMCOMPR))
+#  define ZP_NEED_MEMCOMPR
+#endif
+
+#ifdef WINDLL
+# ifndef NO_ASM
+#   define NO_ASM
+# endif
+# ifndef MSWIN
+#   define MSWIN
+# endif
+# ifndef REENTRANT
+#   define REENTRANT
+# endif
+#endif /* WINDLL */
+
+/* Enable use of optimized x86 assembler version of longest_match() for
+   MSDOS, WIN32 and OS2 per default.  */
+#if !defined(NO_ASM) && !defined(ASMV)
+#  define ASMV
+#endif
+
+/* Enable use of optimized x86 assembler version of crc32() for
+   MSDOS, WIN32 and OS2 per default.  */
+#if !defined(NO_ASM) && !defined(ASM_CRC)  && !defined(NO_ASM_CRC)
+#  define ASM_CRC
+#endif
+
+#if !defined(__GO32__) && !defined(__EMX__) && !defined(__CYGWIN__)
+#  define NO_UNISTD_H
+#endif
+
+/* Microsoft C requires additional attributes attached to all RTL function
+ * declarations when linking against the CRTL dll.
+ */
+#ifdef MSC
+#  ifdef IZ_IMP
+#    undef IZ_IMP
+#  endif
+#  define IZ_IMP _CRTIMP
+#else
+# ifndef IZ_IMP
+#   define IZ_IMP
+# endif
+#endif
+
+/* WIN32 runs solely on little-endian processors; enable support
+ * for the 32-bit optimized CRC-32 C code by default.
+ */
+#ifdef IZ_CRC_BE_OPTIMIZ
+#  undef IZ_CRC_BE_OPTIMIZ
+#endif
+#if !defined(IZ_CRC_LE_OPTIMIZ) && !defined(NO_CRC_OPTIMIZ)
+#  define IZ_CRC_LE_OPTIMIZ
+#endif
+
+/* the following definitions are considered as "obsolete" by Microsoft and
+ * might be missing in some versions of <windows.h>
+ */
+#ifndef AnsiToOem
+#  define AnsiToOem CharToOemA
+#endif
+#ifndef OemToAnsi
+#  define OemToAnsi OemToCharA
+#endif
+
+/* handlers for OEM <--> ANSI string conversions */
+#if defined(__RSXNT__) || defined(WIN32_CRT_OEM)
+   /* RSXNT uses OEM coded strings in functions supplied by C RTL */
+#  ifdef CRTL_CP_IS_ISO
+#    undef CRTL_CP_IS_ISO
+#  endif
+#  ifndef CRTL_CP_IS_OEM
+#    define CRTL_CP_IS_OEM
+#  endif
+#else
+   /* "real" native WIN32 compilers use ANSI coded strings in C RTL calls */
+#  ifndef CRTL_CP_IS_ISO
+#    define CRTL_CP_IS_ISO
+#  endif
+#  ifdef CRTL_CP_IS_OEM
+#    undef CRTL_CP_IS_OEM
+#  endif
+#endif
+
+#ifdef CRTL_CP_IS_ISO
+   /* C RTL's file system support assumes ANSI coded strings */
+#  define ISO_TO_INTERN(src, dst)  {if ((src) != (dst)) strcpy((dst), (src));}
+#  define OEM_TO_INTERN(src, dst)  OemToAnsi(src, dst)
+#  define INTERN_TO_ISO(src, dst)  {if ((src) != (dst)) strcpy((dst), (src));}
+#  define INTERN_TO_OEM(src, dst)  AnsiToOem(src, dst)
+#  define _OEM_INTERN(str1) OEM_TO_INTERN(str1, str1)
+#  define _ISO_INTERN(str1) {;}
+#  define _INTERN_OEM(str1) INTERN_TO_OEM(str1, str1)
+#  define _INTERN_ISO(str1) {;}
+#endif /* CRTL_CP_IS_ISO */
+#ifdef CRTL_CP_IS_OEM
+   /* C RTL's file system support assumes OEM coded strings */
+#  define ISO_TO_INTERN(src, dst)  AnsiToOem(src, dst)
+#  define OEM_TO_INTERN(src, dst)  {if ((src) != (dst)) strcpy((dst), (src));}
+#  define INTERN_TO_ISO(src, dst)  OemToAnsi(src, dst)
+#  define INTERN_TO_OEM(src, dst)  {if ((src) != (dst)) strcpy((dst), (src));}
+#  define _OEM_INTERN(str1) {;}
+#  define _ISO_INTERN(str1) ISO_TO_INTERN(str1, str1)
+#  define _INTERN_OEM(str1) {;}
+#  define _INTERN_ISO(str1) INTERN_TO_ISO(str1, str1)
+#endif /* CRTL_CP_IS_OEM */
+
+/* The following "OEM vs. ISO Zip entry names" code has been copied from UnZip.
+ * It should be applicable to the generic Zip code. However, currently only
+ * the Win32 port of Zip supplies the required charset conversion functions.
+ * (The Win32 port uses conversion functions supplied by the OS.)
+ */
+/* Convert filename (and file comment string) into "internal" charset.
+ * This macro assumes that Zip entry filenames are coded in OEM (IBM DOS)
+ * codepage when made on
+ *  -> DOS (this includes 16-bit Windows 3.1)  (FS_FAT_)
+ *  -> OS/2                                    (FS_HPFS_)
+ *  -> Win95/WinNT with Nico Mak's WinZip      (FS_NTFS_ && hostver == "5.0")
+ * EXCEPTIONS:
+ *  PKZIP for Windows 2.5, 2.6, and 4.0 flag their entries as "FS_FAT_", but
+ *  the filename stored in the local header is coded in Windows ANSI (CP 1252
+ *  resp. ISO 8859-1 on US and western Europe locale settings).
+ *  Likewise, PKZIP for UNIX 2.51 flags its entries as "FS_FAT_", but the
+ *  filenames stored in BOTH the local and the central header are coded
+ *  in the local system's codepage (usually ANSI codings like ISO 8859-1,
+ *  but could also be UTF-8 on "modern" setups...).
+ *
+ * All other ports are assumed to code zip entry filenames in ISO (8859-1
+ * on "Western" localisations).
+ */
+#define FS_FAT_           0    /* filesystem used by MS-DOS, OS/2, Win32 */
+#define FS_HPFS_          6    /* filesystem used by OS/2 (and NT 3.x) */
+#define FS_NTFS_          11   /* filesystem used by Windows NT */
+#ifndef Ext_ASCII_TO_Native
+#  define Ext_ASCII_TO_Native(string, hostnum, hostver, isuxatt, islochdr) \
+    if (((hostnum) == FS_FAT_ && \
+         !(((islochdr) || (isuxatt)) && \
+           ((hostver) == 25 || (hostver) == 26 || (hostver) == 40))) || \
+        (hostnum) == FS_HPFS_ || \
+        ((hostnum) == FS_NTFS_ && (hostver) == 50)) { \
+        _OEM_INTERN((string)); \
+    } else { \
+        _ISO_INTERN((string)); \
+    }
+#endif
+
+#if (defined(__RSXNT__) && defined(__CRTRSXNT__))
+#  include <crtrsxnt.h>
+#endif
+
+#ifdef _MBCS
+#  if (!defined(__EMX__) && !defined(__MINGW32__) && !defined(__CYGWIN__))
+#    include <stdlib.h>
+#    include <mbstring.h>
+#  endif
+#  if (defined(__MINGW32__) && !defined(MB_CUR_MAX))
+#    ifdef __MSVCRT__
+       IZ_IMP extern int *__p___mb_cur_max(void);
+#      define MB_CUR_MAX (*__p___mb_cur_max())
+#    else
+       IZ_IMP extern int *_imp____mb_cur_max_dll;
+#      define MB_CUR_MAX (*_imp____mb_cur_max_dll)
+#    endif
+#  endif
+#  if (defined(__LCC__) && !defined(MB_CUR_MAX))
+     IZ_IMP extern int *_imp____mb_cur_max;
+#    define MB_CUR_MAX (*_imp____mb_cur_max)
+#  endif
+#endif
+
+#ifdef __LCC__
+#  include <time.h>
+#  ifndef tzset
+#    define tzset _tzset
+#  endif
+#  ifndef utime
+#    define utime _utime
+#  endif
+#endif
+#ifdef __MINGW32__
+   IZ_IMP extern void _tzset(void);     /* this is missing in <time.h> */
+#  ifndef tzset
+#    define tzset _tzset
+#  endif
+#endif
+#if (defined(__RSXNT__) || defined(__EMX__)) && !defined(tzset)
+#  define tzset _tzset
+#endif
+#ifdef W32_USE_IZ_TIMEZONE
+#  ifdef __BORLANDC__
+#    define tzname tzname
+#    define IZTZ_DEFINESTDGLOBALS
+#  endif
+#  ifndef tzset
+#    define tzset _tzset
+#  endif
+#  ifndef timezone
+#    define timezone _timezone
+#  endif
+#  ifndef daylight
+#    define daylight _daylight
+#  endif
+#  ifndef tzname
+#    define tzname _tzname
+#  endif
+#  if (!defined(NEED__ISINDST) && !defined(__BORLANDC__))
+#    define NEED__ISINDST
+#  endif
+#  ifdef IZTZ_GETLOCALETZINFO
+#    undef IZTZ_GETLOCALETZINFO
+#  endif
+#  define IZTZ_GETLOCALETZINFO GetPlatformLocalTimezone
+#endif /* W32_USE_IZ_TIMEZONE */
+
+#ifdef MATCH
+#  undef MATCH
+#endif
+#define MATCH dosmatch          /* use DOS style wildcard matching */
+#ifdef UNICODE_SUPPORT
+# ifdef WIN32
+#   define MATCHW dosmatchw
+# endif
+#endif
+
+#ifdef ZCRYPT_INTERNAL
+#  ifdef WINDLL
+#    define ZCR_SEED2     (unsigned)3141592654L /* use PI as seed pattern */
+#  else
+#    include <process.h>        /* getpid() declaration for srand seed */
+#  endif
+#endif
+
+/* Up to now, all versions of Microsoft C runtime libraries lack the support
+ * for customized (non-US) switching rules between daylight saving time and
+ * standard time in the TZ environment variable string.
+ * But non-US timezone rules are correctly supported when timezone information
+ * is read from the OS system settings in the Win32 registry.
+ * The following work-around deletes any TZ environment setting from
+ * the process environment.  This results in a fallback of the RTL time
+ * handling code to the (correctly interpretable) OS system settings, read
+ * from the registry.
+ */
+#ifdef USE_EF_UT_TIME
+# if (defined(__WATCOMC__) || defined(__CYGWIN__) || \
+      defined(W32_USE_IZ_TIMEZONE))
+#   define iz_w32_prepareTZenv()
+# else
+#   define iz_w32_prepareTZenv()        putenv("TZ=")
+# endif
+#endif
+
+/* This patch of stat() is useful for at least three compilers.  It is   */
+/* difficult to take a stat() of a root directory under Windows95, so  */
+/* zstat_zipwin32() detects that case and fills in suitable values.    */
+#ifndef __RSXNT__
+#  ifndef W32_STATROOT_FIX
+#    define W32_STATROOT_FIX
+#  endif
+#endif /* !__RSXNT__ */
+
+#if (defined(NT_TZBUG_WORKAROUND) || defined(W32_STATROOT_FIX))
+#  define W32_STAT_BANDAID
+#  ifdef LARGE_FILE_SUPPORT         /* E. Gordon 9/12/03 */
+   int zstat_zipwin32(const char *path, z_stat *buf);
+#  else
+   int zstat_zipwin32(const char *path, struct stat *buf);
+#  endif
+#  ifdef UNICODE_SUPPORT
+#   ifdef LARGE_FILE_SUPPORT
+     int zstat_zipwin32w(const wchar_t *pathw, struct _stati64 *buf);
+#   else
+     int zstat_zipwin32w(const wchar_t *pathw, struct _stat *buf);
+#   endif
+#  endif
+#  ifdef SSTAT
+#    undef SSTAT
+#  endif
+#  define SSTAT zstat_zipwin32
+#  ifdef UNICODE_SUPPORT
+#    define SSTATW zstat_zipwin32w
+#  endif
+#endif /* NT_TZBUG_WORKAROUND || W32_STATROOT_FIX */
+
+int getch_win32(void);
+
+#ifdef __GNUC__
+# define IZ_PACKED      __attribute__((packed))
+#else
+# define IZ_PACKED
+#endif
+
+/* for some (all ?) versions of IBM C Set/2 and IBM C Set++ */
+#ifndef S_IFMT
+#  define S_IFMT 0xF000
+#endif /* !S_IFMT */
+
+#ifdef __WATCOMC__
+#  include <stdio.h>    /* PATH_MAX is defined here */
+#  define NO_MKTEMP
+
+/* Get asm routines to link properly without using "__cdecl": */
+#  ifdef __386__
+#    ifdef ASMV
+#      pragma aux match_init    "_*" parm caller [] modify []
+#      pragma aux longest_match "_*" parm caller [] value [eax] \
+                                      modify [eax ecx edx]
+#    endif
+#    if defined(ASM_CRC) && !defined(USE_ZLIB)
+#      pragma aux crc32         "_*" parm caller [] value [eax] modify [eax]
+#      pragma aux get_crc_table "_*" parm caller [] value [eax] \
+                                      modify [eax ecx edx]
+#    endif /* ASM_CRC && !USE_ZLIB */
+#  endif /* __386__ */
+   /* Watcom C (like the other Win32 C compiler systems) does not support
+    * symlinks on Win32, but defines the S_IFLNK symbol nevertheless.
+    * However, the existence of this symbol is used as "symlinks supported"
+    * indicator in the generic Zip code (see tailor.h). So, for a simple
+    * work-around, this symbol is undefined here. */
+#  ifdef S_IFLNK
+#    undef S_IFLNK
+#  endif
+#  ifdef UNICODE_SUPPORT
+     /* Watcom C does not supply wide-char definitions in the "standard"
+      * headers like MSC; so we have to pull in a wchar-specific header.
+      */
+#    include <wchar.h>
+#  endif
+#endif /* __WATCOMC__ */
diff --git a/win32/readme.a64 b/win32/readme.a64
new file mode 100644 (file)
index 0000000..54b2750
--- /dev/null
@@ -0,0 +1,42 @@
+readme.x64
+==========
+
+[Note - the gvmat64.asm longest_match routine in Windows 64-bit assembler
+and makefile.a64 used to compile it were provided at the last minute and
+are currently untested by Info-ZIP.  They are provided to allow testing of
+this optimization which is planned for inclusion in Zip 3.0.
+USE AT YOUR OWN RISK.  That said, thanks Gilles for providing this
+optimization and we plan to better support it in Zip 3.0.  2/28/2005 EG]
+
+makefile.asm64 is a makefile for 64 bits optimized version of zip for 
+Microsoft Windows running on AMD64 (Athlon64/Opteron) and Intel EM64T
+(the Pentium 4 and Xeon with 64 bits extension)
+
+makefile.asm64 contain a makefile for 64 Microsoft C++ for Windows 64 bits,
+extended edition (for both AMD64 and Intel EM64T), included in Visual
+Studio 2005
+
+to compile it, start the C++ AMD64 build environnement prompt,
+go to the zip source directory and start
+
+   nmake -a -f makefile.a64
+
+This makefile uses gvmat64.asm, which is the optimized longest_match written
+in assembly code for AMD64/Intel EM64T
+
+gvmat64.asm was tested by Gilles Vollant on AMD64 with infozip, and also tested
+with a lot of file with zLib 1.2.2 on both AMD64 and Intel EM64T processor.
+
+It was written by Gilles Vollant, by modifiying the longest_match
+from Jean-loup Gailly in deflate.c of zLib and infoZip zip.
+and modifying asm686 (1998), optimised assembly code from Brian Raiter,
+(see http://www.muppetlabs.com/~breadbox/software/assembly.html)
+
+
+Gilles Vollant
+info@winimage.com
+
+http://www.winimage.com
+http://www.winimage.com/zLibdll
+
+
diff --git a/win32/rsxntwin.h b/win32/rsxntwin.h
new file mode 100644 (file)
index 0000000..a710a35
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+  win32/rsxntwin.h - Zip 3
+
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* rsxntwin.h
+ *
+ * fills some gaps in the rsxnt 1.3 win32 header files (<windows.h>) that are
+ * required for compiling Info-ZIP sources for Win NT / Win 95
+ */
+
+#ifdef __RSXNT__
+#if !defined (_RSXNTWIN_H)
+#define _RSXNTWIN_H
+
+#ifdef TFUNCT   /* TFUNCT is undefined when MSSDK headers are used */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PASCAL __stdcall
+
+#define ANYSIZE_ARRAY 1
+
+#ifndef TIME_ZONE_ID_UNKNOWN
+#  define TIME_ZONE_ID_UNKNOWN  0
+#endif
+#ifndef TIME_ZONE_ID_INVALID
+#  define TIME_ZONE_ID_INVALID  (DWORD)0xFFFFFFFFL
+#endif
+
+#define FILE_ATTRIBUTE_HIDDEN   0x00000002
+#define FILE_ATTRIBUTE_SYSTEM   0x00000004
+
+#define FILE_SHARE_DELETE       0x00000004
+
+#define FILE_PERSISTENT_ACLS    0x00000008
+
+#define HFILE_ERROR        ((HFILE)-1)
+
+#define FS_PERSISTENT_ACLS      FILE_PERSISTENT_ACLS
+
+
+BOOL WINAPI DosDateTimeToFileTime(WORD, WORD, LPFILETIME);
+
+
+#ifndef SetVolumeLabel
+#define SetVolumeLabel TFUNCT(SetVolumeLabel)
+#endif
+BOOL WINAPI SetVolumeLabel(LPCTSTR, LPCTSTR);
+
+
+#ifndef GetDriveType
+#define GetDriveType TFUNCT(GetDriveType)
+#endif
+DWORD GetDriveType(LPCTSTR);
+
+#define DRIVE_UNKNOWN     0
+#define DRIVE_REMOVABLE   2
+#define DRIVE_FIXED       3
+#define DRIVE_REMOTE      4
+#define DRIVE_CDROM       5
+#define DRIVE_RAMDISK     6
+
+#ifndef SearchPath
+#define SearchPath TFUNCT(SearchPath)
+#endif
+BOOL WINAPI SearchPath(LPCTSTR, LPCTSTR, LPCTSTR, UINT, LPTSTR, LPTSTR *);
+
+#define ERROR_SUCCESS                   0
+#define ERROR_INSUFFICIENT_BUFFER       122
+
+LONG WINAPI InterlockedExchange(LPLONG, LONG);
+
+#define ACCESS_SYSTEM_SECURITY          0x01000000L
+
+typedef PVOID PSECURITY_DESCRIPTOR;
+typedef PVOID PSID;
+typedef struct _ACL {
+    BYTE  AclRevision;
+    BYTE  Sbz1;
+    WORD   AclSize;
+    WORD   AceCount;
+    WORD   Sbz2;
+} ACL;
+typedef ACL *PACL;
+
+typedef struct _LUID {
+    DWORD LowPart;
+    LONG HighPart;
+} LUID, *PLUID;
+
+typedef struct _LUID_AND_ATTRIBUTES {
+    LUID Luid;
+    DWORD Attributes;
+    } LUID_AND_ATTRIBUTES, * PLUID_AND_ATTRIBUTES;
+
+typedef struct _TOKEN_PRIVILEGES {
+    DWORD PrivilegeCount;
+    LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];
+} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
+
+#define TOKEN_QUERY             0x0008
+#define TOKEN_ADJUST_PRIVILEGES 0x0020
+
+BOOL WINAPI OpenProcessToken(HANDLE, DWORD, PHANDLE);
+BOOL WINAPI AdjustTokenPrivileges(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD,
+                PTOKEN_PRIVILEGES, PDWORD);
+
+#ifndef LookupPrivilegeValue
+#define LookupPrivilegeValue TFUNCT(LookupPrivilegeValue)
+#endif
+BOOL WINAPI LookupPrivilegeValue(LPCTSTR, LPCTSTR, PLUID);
+
+typedef DWORD SECURITY_INFORMATION, *PSECURITY_INFORMATION;
+#define OWNER_SECURITY_INFORMATION      0x00000001L
+#define GROUP_SECURITY_INFORMATION      0x00000002L
+#define DACL_SECURITY_INFORMATION       0x00000004L
+#define SACL_SECURITY_INFORMATION       0x00000008L
+
+typedef WORD SECURITY_DESCRIPTOR_CONTROL, *PSECURITY_DESCRIPTOR_CONTROL;
+#define SE_DACL_PRESENT         0x0004
+#define SE_SACL_PRESENT         0x0010
+
+#define SE_PRIVILEGE_ENABLED    0x00000002L
+
+#define SE_SECURITY_NAME                  TEXT("SeSecurityPrivilege")
+#define SE_BACKUP_NAME                    TEXT("SeBackupPrivilege")
+#define SE_RESTORE_NAME                   TEXT("SeRestorePrivilege")
+
+BOOL WINAPI GetKernelObjectSecurity(HANDLE, SECURITY_INFORMATION,
+                PSECURITY_DESCRIPTOR, DWORD, LPDWORD);
+BOOL WINAPI SetKernelObjectSecurity(HANDLE, SECURITY_INFORMATION,
+                PSECURITY_DESCRIPTOR);
+BOOL WINAPI IsValidSid(PSID);
+BOOL WINAPI IsValidAcl(PACL);
+BOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR);
+BOOL WINAPI IsValidSecurityDescriptor(PSECURITY_DESCRIPTOR);
+DWORD WINAPI GetSecurityDescriptorLength(PSECURITY_DESCRIPTOR);
+BOOL WINAPI GetSecurityDescriptorControl(PSECURITY_DESCRIPTOR,
+                PSECURITY_DESCRIPTOR_CONTROL, LPDWORD);
+BOOL WINAPI SetSecurityDescriptorControl(PSECURITY_DESCRIPTOR,
+                SECURITY_DESCRIPTOR_CONTROL, SECURITY_DESCRIPTOR_CONTROL);
+BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR,
+                                      LPBOOL, PACL *, LPBOOL);
+BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR, BOOL, PACL, BOOL);
+BOOL WINAPI GetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR,
+                                      LPBOOL, PACL *, LPBOOL);
+BOOL WINAPI SetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR, BOOL, PACL, BOOL);
+BOOL WINAPI GetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR, PSID *, LPBOOL);
+BOOL WINAPI SetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR, PSID, BOOL);
+BOOL WINAPI GetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR, PSID *, LPBOOL);
+BOOL WINAPI SetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR, PSID, BOOL);
+VOID WINAPI InitializeCriticalSection();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TFUNCT */
+
+#ifndef CP_UTF8
+#  define CP_UTF8               65001           /* UTF-8 translation */
+#endif
+
+#endif /* !defined (_RSXNTWIN_H) */
+#endif /* __RSXNT__ */
diff --git a/win32/vc6/ReadmeVC.txt b/win32/vc6/ReadmeVC.txt
new file mode 100644 (file)
index 0000000..f0295cb
--- /dev/null
@@ -0,0 +1,10 @@
+VC6 Readme
+
+This directory has a VC6 project list that can be used to compile Zip
+and the utilities.  It does not include bzip2 support.
+
+The vc6bz2 directory provides a variant of this directory that includes
+the settings needed for including bzip2 support in Zip.
+
+Ed Gordon
+26 March 2007
diff --git a/win32/vc6/zip.dsp b/win32/vc6/zip.dsp
new file mode 100644 (file)
index 0000000..10acbe1
--- /dev/null
@@ -0,0 +1,337 @@
+# Microsoft Developer Studio Project File - Name="zip" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=zip - Win32 ASM Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "zip.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "zip.mak" CFG="zip - Win32 ASM Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "zip - Win32 ASM Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zip - Win32 ASM Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zip - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zip - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "zip - Win32 ASM Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "zip___Win32_ASM_Release"\r
+# PROP BASE Intermediate_Dir "zip___Win32_ASM_Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "zip___Win32_ASM_Release"\r
+# PROP Intermediate_Dir "zip___Win32_ASM_Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "ASM_CRC" /D "ASMV" /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 ASM Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "zip___Win32_ASM_Debug"\r
+# PROP BASE Intermediate_Dir "zip___Win32_ASM_Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "zip___Win32_ASM_Debug"\r
+# PROP Intermediate_Dir "zip___Win32_ASM_Debug"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "ASM_CRC" /D "ASMV" /FR /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "zip___Win32_Release"\r
+# PROP BASE Intermediate_Dir "zip___Win32_Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "zip___Win32_Release"\r
+# PROP Intermediate_Dir "zip___Win32_Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /D "NO_ASM" /D "WIN32" /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "zip___Win32_Debug"\r
+# PROP BASE Intermediate_Dir "zip___Win32_Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "zip___Win32_Debug"\r
+# PROP Intermediate_Dir "zip___Win32_Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "NO_ASM" /FR /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "zip - Win32 ASM Release"\r
+# Name "zip - Win32 ASM Debug"\r
+# Name "zip - Win32 Release"\r
+# Name "zip - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crc32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crypt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\deflate.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\fileio.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\globals.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\nt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\trees.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ttyio.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\util.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32i64.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32zip.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zip.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\zip.rc\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zipfile.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zipup.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crc32.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crypt.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ebcdic.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\nt.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\osdep.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\revision.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\tailor.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ttyio.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32zip.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zip.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ziperr.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\zipup.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Assembler Files"\r
+\r
+# PROP Default_Filter "asm;obj"\r
+# Begin Source File\r
+\r
+SOURCE=..\crc_i386.asm\r
+\r
+!IF  "$(CFG)" == "zip - Win32 ASM Release"\r
+\r
+# Begin Custom Build - Assembling...\r
+IntDir=.\zip___Win32_ASM_Release\r
+InputPath=..\crc_i386.asm\r
+InputName=crc_i386\r
+\r
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 ASM Debug"\r
+\r
+# Begin Custom Build - Assembling...\r
+IntDir=.\zip___Win32_ASM_Debug\r
+InputPath=..\crc_i386.asm\r
+InputName=crc_i386\r
+\r
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 Release"\r
+\r
+# PROP Exclude_From_Build 1\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 Debug"\r
+\r
+# PROP Exclude_From_Build 1\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\match32.asm\r
+\r
+!IF  "$(CFG)" == "zip - Win32 ASM Release"\r
+\r
+# Begin Custom Build - Assembling...\r
+IntDir=.\zip___Win32_ASM_Release\r
+InputPath=..\match32.asm\r
+InputName=match32\r
+\r
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 ASM Debug"\r
+\r
+# Begin Custom Build - Assembling...\r
+IntDir=.\zip___Win32_ASM_Debug\r
+InputPath=..\match32.asm\r
+InputName=match32\r
+\r
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 Release"\r
+\r
+# PROP Exclude_From_Build 1\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 Debug"\r
+\r
+# PROP Exclude_From_Build 1\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win32/vc6/zip.dsw b/win32/vc6/zip.dsw
new file mode 100644 (file)
index 0000000..681d183
--- /dev/null
@@ -0,0 +1,65 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
+\r
+###############################################################################\r
+\r
+Project: "zip"=".\zip.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "zipcloak"=".\zipcloak.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "zipnote"=".\zipnote.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "zipsplit"=".\zipsplit.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
diff --git a/win32/vc6/zipcloak.dsp b/win32/vc6/zipcloak.dsp
new file mode 100644 (file)
index 0000000..e09ccd7
--- /dev/null
@@ -0,0 +1,264 @@
+# Microsoft Developer Studio Project File - Name="zipcloak" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=zipcloak - Win32 ASM Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "zipcloak.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "zipcloak.mak" CFG="zipcloak - Win32 ASM Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "zipcloak - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zipcloak - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zipcloak - Win32 ASM Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zipcloak - Win32 ASM Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "zipcloak - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "zipcloak___Win32_Release"\r
+# PROP BASE Intermediate_Dir "zipcloak___Win32_Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "zipcloak___Win32_Release"\r
+# PROP Intermediate_Dir "zipcloak___Win32_Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /D "UTIL" /D "WIN32" /D "NO_ASM" /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "zipcloak - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "zipcloak___Win32_Debug"\r
+# PROP BASE Intermediate_Dir "zipcloak___Win32_Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "zipcloak___Win32_Debug"\r
+# PROP Intermediate_Dir "zipcloak___Win32_Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /D "NO_ASM" /FR /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ELSEIF  "$(CFG)" == "zipcloak - Win32 ASM Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "zipcloak___Win32_ASM_Debug"\r
+# PROP BASE Intermediate_Dir "zipcloak___Win32_ASM_Debug"\r
+# PROP BASE Ignore_Export_Lib 0\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "zipcloak___Win32_ASM_Debug"\r
+# PROP Intermediate_Dir "zipcloak___Win32_ASM_Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /FR /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /FR /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ELSEIF  "$(CFG)" == "zipcloak - Win32 ASM Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "zipcloak___Win32_ASM_Release"\r
+# PROP BASE Intermediate_Dir "zipcloak___Win32_ASM_Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "zipcloak___Win32_ASM_Release"\r
+# PROP Intermediate_Dir "zipcloak___Win32_ASM_Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "UTIL" /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "UTIL" /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "zipcloak - Win32 Release"\r
+# Name "zipcloak - Win32 Debug"\r
+# Name "zipcloak - Win32 ASM Debug"\r
+# Name "zipcloak - Win32 ASM Release"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crc32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crypt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\fileio.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\globals.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ttyio.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\util.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32i64.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zipcloak.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zipfile.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crc32.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crypt.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ebcdic.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\osdep.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\revision.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\tailor.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ttyio.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32zip.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zip.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ziperr.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Assembler Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\crc_i386.asm\r
+\r
+!IF  "$(CFG)" == "zipcloak - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "zipcloak - Win32 Debug"\r
+\r
+!ELSEIF  "$(CFG)" == "zipcloak - Win32 ASM Debug"\r
+\r
+# Begin Custom Build - Assembling...\r
+IntDir=.\zipcloak___Win32_ASM_Debug\r
+InputPath=..\crc_i386.asm\r
+InputName=crc_i386\r
+\r
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "zipcloak - Win32 ASM Release"\r
+\r
+# Begin Custom Build - Assembling...\r
+IntDir=.\zipcloak___Win32_ASM_Release\r
+InputPath=..\crc_i386.asm\r
+InputName=crc_i386\r
+\r
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"\r
+\r
+# End Custom Build\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win32/vc6/zipnote.dsp b/win32/vc6/zipnote.dsp
new file mode 100644 (file)
index 0000000..a7f9f57
--- /dev/null
@@ -0,0 +1,248 @@
+# Microsoft Developer Studio Project File - Name="zipnote" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=zipnote - Win32 ASM Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "zipnote.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "zipnote.mak" CFG="zipnote - Win32 ASM Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "zipnote - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zipnote - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zipnote - Win32 ASM Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zipnote - Win32 ASM Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "zipnote - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "zipnote___Win32_Release"\r
+# PROP BASE Intermediate_Dir "zipnote___Win32_Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "zipnote___Win32_Release"\r
+# PROP Intermediate_Dir "zipnote___Win32_Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /D "UTIL" /D "WIN32" /D "NO_ASM" /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "zipnote - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "zipnote___Win32_Debug"\r
+# PROP BASE Intermediate_Dir "zipnote___Win32_Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "zipnote___Win32_Debug"\r
+# PROP Intermediate_Dir "zipnote___Win32_Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "NO_ASM" /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /D "NO_ASM" /FR /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ELSEIF  "$(CFG)" == "zipnote - Win32 ASM Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "zipnote___Win32_ASM_Debug"\r
+# PROP BASE Intermediate_Dir "zipnote___Win32_ASM_Debug"\r
+# PROP BASE Ignore_Export_Lib 0\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "zipnote___Win32_ASM_Debug"\r
+# PROP Intermediate_Dir "zipnote___Win32_ASM_Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /FR /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /FR /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ELSEIF  "$(CFG)" == "zipnote - Win32 ASM Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "zipnote___Win32_ASM_Release"\r
+# PROP BASE Intermediate_Dir "zipnote___Win32_ASM_Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "zipnote___Win32_ASM_Release"\r
+# PROP Intermediate_Dir "zipnote___Win32_ASM_Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "UTIL" /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "UTIL" /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "zipnote - Win32 Release"\r
+# Name "zipnote - Win32 Debug"\r
+# Name "zipnote - Win32 ASM Debug"\r
+# Name "zipnote - Win32 ASM Release"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crc32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\fileio.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\globals.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\util.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32i64.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zipfile.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zipnote.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crc32.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ebcdic.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\osdep.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\revision.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\tailor.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32zip.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zip.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ziperr.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Assembler Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\crc_i386.asm\r
+\r
+!IF  "$(CFG)" == "zipnote - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "zipnote - Win32 Debug"\r
+\r
+!ELSEIF  "$(CFG)" == "zipnote - Win32 ASM Debug"\r
+\r
+# Begin Custom Build - Assembling...\r
+IntDir=.\zipnote___Win32_ASM_Debug\r
+InputPath=..\crc_i386.asm\r
+InputName=crc_i386\r
+\r
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "zipnote - Win32 ASM Release"\r
+\r
+# Begin Custom Build - Assembling...\r
+IntDir=.\zipnote___Win32_ASM_Release\r
+InputPath=..\crc_i386.asm\r
+InputName=crc_i386\r
+\r
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"\r
+\r
+# End Custom Build\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win32/vc6/zipsplit.dsp b/win32/vc6/zipsplit.dsp
new file mode 100644 (file)
index 0000000..ae5565d
--- /dev/null
@@ -0,0 +1,248 @@
+# Microsoft Developer Studio Project File - Name="zipsplit" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=zipsplit - Win32 ASM Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "zipsplit.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "zipsplit.mak" CFG="zipsplit - Win32 ASM Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "zipsplit - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zipsplit - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zipsplit - Win32 ASM Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zipsplit - Win32 ASM Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "zipsplit - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "zipsplit___Win32_Release"\r
+# PROP BASE Intermediate_Dir "zipsplit___Win32_Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "zipsplit___Win32_Release"\r
+# PROP Intermediate_Dir "zipsplit___Win32_Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /D "UTIL" /D "WIN32" /D "NO_ASM" /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "zipsplit - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "zipsplit___Win32_Debug"\r
+# PROP BASE Intermediate_Dir "zipsplit___Win32_Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "zipsplit___Win32_Debug"\r
+# PROP Intermediate_Dir "zipsplit___Win32_Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /D "NO_ASM" /FR /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ELSEIF  "$(CFG)" == "zipsplit - Win32 ASM Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "zipsplit___Win32_ASM_Debug"\r
+# PROP BASE Intermediate_Dir "zipsplit___Win32_ASM_Debug"\r
+# PROP BASE Ignore_Export_Lib 0\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "zipsplit___Win32_ASM_Debug"\r
+# PROP Intermediate_Dir "zipsplit___Win32_ASM_Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /FR /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /FR /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ELSEIF  "$(CFG)" == "zipsplit - Win32 ASM Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "zipsplit___Win32_ASM_Release"\r
+# PROP BASE Intermediate_Dir "zipsplit___Win32_ASM_Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "zipsplit___Win32_ASM_Release"\r
+# PROP Intermediate_Dir "zipsplit___Win32_ASM_Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "UTIL" /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "UTIL" /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "zipsplit - Win32 Release"\r
+# Name "zipsplit - Win32 Debug"\r
+# Name "zipsplit - Win32 ASM Debug"\r
+# Name "zipsplit - Win32 ASM Release"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crc32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\fileio.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\globals.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\util.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32i64.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zipfile.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zipsplit.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crc32.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ebcdic.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\osdep.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\revision.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\tailor.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32zip.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zip.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ziperr.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Assembler Files"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\crc_i386.asm\r
+\r
+!IF  "$(CFG)" == "zipsplit - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "zipsplit - Win32 Debug"\r
+\r
+!ELSEIF  "$(CFG)" == "zipsplit - Win32 ASM Debug"\r
+\r
+# Begin Custom Build - Assembling...\r
+IntDir=.\zipsplit___Win32_ASM_Debug\r
+InputPath=..\crc_i386.asm\r
+InputName=crc_i386\r
+\r
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "zipsplit - Win32 ASM Release"\r
+\r
+# Begin Custom Build - Assembling...\r
+IntDir=.\zipsplit___Win32_ASM_Release\r
+InputPath=..\crc_i386.asm\r
+InputName=crc_i386\r
+\r
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"\r
+\r
+# End Custom Build\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win32/vc6bz2/ReadVCBZ.txt b/win32/vc6bz2/ReadVCBZ.txt
new file mode 100644 (file)
index 0000000..3aafd6f
--- /dev/null
@@ -0,0 +1,19 @@
+VC6bz2 Readme
+
+This directory has a VC6 project list that can be used to compile Zip
+and the utilities.  The Zip project includes support for the bzip2
+compression method.
+
+To include bzip2 support, get a copy of the bzip2 source (bzip2-1.0.4
+or later from http://www.bzip.org/ for instance), expand the bzip2
+source into a directory, then copy the contents of the bzip2-1.0.4
+directory, for instance, into the zip bzip2 directory.  Use this
+project to compile zip and bzip2 support should be included.  See
+bzip2/install.txt for additional information.
+
+The vc6 directory is similar to this directory but does not include
+bzip2 support.  Use that if you do not have a copy of bzip2 or do not
+need bzip2 support.
+
+Ed Gordon
+26 March 2007
diff --git a/win32/vc6bz2/zip.dsp b/win32/vc6bz2/zip.dsp
new file mode 100644 (file)
index 0000000..fee0af4
--- /dev/null
@@ -0,0 +1,381 @@
+# Microsoft Developer Studio Project File - Name="zip" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=zip - Win32 Debug bzip2\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "zip.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "zip.mak" CFG="zip - Win32 Debug bzip2"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "zip - Win32 ASM Release bzip2" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zip - Win32 ASM Debug bzip2" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zip - Win32 Release bzip2" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "zip - Win32 Debug bzip2" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "zip - Win32 ASM Release bzip2"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "zip___Win32_ASM_Release_bzip2"\r
+# PROP BASE Intermediate_Dir "zip___Win32_ASM_Release_bzip2"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "zip___Win32_ASM_Release_bzip2"\r
+# PROP Intermediate_Dir "zip___Win32_ASM_Release_bzip2"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "ASM_CRC" /D "ASMV" /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "../../bzip2" /D "ASM_CRC" /D "ASMV" /D "WIN32" /D "BZIP2_SUPPORT" /D "BZ_NO_STDIO" /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 ASM Debug bzip2"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "zip___Win32_ASM_Debug_bzip2"\r
+# PROP BASE Intermediate_Dir "zip___Win32_ASM_Debug_bzip2"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "zip___Win32_ASM_Debug_bzip2"\r
+# PROP Intermediate_Dir "zip___Win32_ASM_Debug_bzip2"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "ASM_CRC" /D "ASMV" /FR /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../bzip2" /D "ASM_CRC" /D "ASMV" /D "WIN32" /D "BZIP2_SUPPORT" /D "BZ_NO_STDIO" /FR /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 Release bzip2"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "zip___Win32_Release_bzip2"\r
+# PROP BASE Intermediate_Dir "zip___Win32_Release_bzip2"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "zip___Win32_Release_bzip2"\r
+# PROP Intermediate_Dir "zip___Win32_Release_bzip2"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NO_ASM" /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "../../bzip2" /D "NO_ASM" /D "WIN32" /D "BZIP2_SUPPORT" /D "BZ_NO_STDIO" /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 Debug bzip2"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "zip___Win32_Debug_bzip2"\r
+# PROP BASE Intermediate_Dir "zip___Win32_Debug_bzip2"\r
+# PROP BASE Ignore_Export_Lib 0\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "zip___Win32_Debug_bzip2"\r
+# PROP Intermediate_Dir "zip___Win32_Debug_bzip2"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "NO_ASM" /D "WIN32" /FR /FD /GZ /c\r
+# SUBTRACT BASE CPP /WX\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../bzip2" /D "NO_ASM" /D "WIN32" /D "BZIP2_SUPPORT" /D "BZ_NO_STDIO" /FR /FD /GZ /c\r
+# SUBTRACT CPP /WX\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "zip - Win32 ASM Release bzip2"\r
+# Name "zip - Win32 ASM Debug bzip2"\r
+# Name "zip - Win32 Release bzip2"\r
+# Name "zip - Win32 Debug bzip2"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\..\bzip2\blocksort.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\bzip2\bzlib.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\bzip2\compress.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crc32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\bzip2\crctable.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crypt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\bzip2\decompress.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\deflate.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\fileio.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\globals.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\bzip2\huffman.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\nt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\bzip2\randtable.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\trees.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ttyio.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\util.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32i64.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32zip.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zbz2err.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zip.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\zip.rc\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zipfile.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zipup.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\..\bzip2\bzlib.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crc32.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\crypt.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ebcdic.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\nt.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\osdep.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\revision.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\tailor.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ttyio.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\win32zip.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\zip.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\ziperr.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\zipup.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Assembler Files"\r
+\r
+# PROP Default_Filter "asm;obj"\r
+# Begin Source File\r
+\r
+SOURCE=..\crc_i386.asm\r
+\r
+!IF  "$(CFG)" == "zip - Win32 ASM Release bzip2"\r
+\r
+# Begin Custom Build - Assembling...\r
+IntDir=.\zip___Win32_ASM_Release_bzip2\r
+InputPath=..\crc_i386.asm\r
+InputName=crc_i386\r
+\r
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 ASM Debug bzip2"\r
+\r
+# Begin Custom Build - Assembling...\r
+IntDir=.\zip___Win32_ASM_Debug_bzip2\r
+InputPath=..\crc_i386.asm\r
+InputName=crc_i386\r
+\r
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 Release bzip2"\r
+\r
+# PROP BASE Exclude_From_Build 1\r
+# PROP Exclude_From_Build 1\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 Debug bzip2"\r
+\r
+# PROP BASE Exclude_From_Build 1\r
+# PROP Exclude_From_Build 1\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\match32.asm\r
+\r
+!IF  "$(CFG)" == "zip - Win32 ASM Release bzip2"\r
+\r
+# Begin Custom Build - Assembling...\r
+IntDir=.\zip___Win32_ASM_Release_bzip2\r
+InputPath=..\match32.asm\r
+InputName=match32\r
+\r
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 ASM Debug bzip2"\r
+\r
+# Begin Custom Build - Assembling...\r
+IntDir=.\zip___Win32_ASM_Debug_bzip2\r
+InputPath=..\match32.asm\r
+InputName=match32\r
+\r
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+       ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 Release bzip2"\r
+\r
+# PROP BASE Exclude_From_Build 1\r
+# PROP Exclude_From_Build 1\r
+\r
+!ELSEIF  "$(CFG)" == "zip - Win32 Debug bzip2"\r
+\r
+# PROP BASE Exclude_From_Build 1\r
+# PROP Exclude_From_Build 1\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/win32/vc6bz2/zip.dsw b/win32/vc6bz2/zip.dsw
new file mode 100644 (file)
index 0000000..bab0fdd
--- /dev/null
@@ -0,0 +1,65 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
+\r
+###############################################################################\r
+\r
+Project: "zip"=.\zip.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "zipcloak"=..\vc6\zipcloak.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "zipnote"=..\vc6\zipnote.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "zipsplit"=..\vc6\zipsplit.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
diff --git a/win32/win32.c b/win32/win32.c
new file mode 100644 (file)
index 0000000..5798053
--- /dev/null
@@ -0,0 +1,1488 @@
+/*
+  win32/win32.c - Zip 3
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/*
+ * WIN32 specific functions for ZIP.
+ *
+ * The WIN32 version of ZIP heavily relies on the MSDOS and OS2 versions,
+ * since we have to do similar things to switch between NTFS, HPFS and FAT.
+ */
+
+
+#include "../zip.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <time.h>
+#include <ctype.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+/* for LARGE_FILE_SUPPORT but may not be needed */
+#include <io.h>
+
+#ifdef __RSXNT__
+#  include <alloca.h>
+#  include "../win32/rsxntwin.h"
+#endif
+#include "../win32/win32zip.h"
+
+#define A_RONLY    0x01
+#define A_HIDDEN   0x02
+#define A_SYSTEM   0x04
+#define A_LABEL    0x08
+#define A_DIR      0x10
+#define A_ARCHIVE  0x20
+
+
+#define EAID     0x0009
+
+#if (defined(__MINGW32__) && !defined(USE_MINGW_GLOBBING))
+   int _CRT_glob = 0;   /* suppress command line globbing by C RTL */
+#endif
+
+#ifndef UTIL
+
+extern int noisy;
+
+#ifdef NT_TZBUG_WORKAROUND
+local int FSusesLocalTime(const char *path);
+#ifdef UNICODE_SUPPORt
+local int FSusesLocalTimeW(const wchar_t *path);
+#endif
+#endif
+#if (defined(USE_EF_UT_TIME) || defined(NT_TZBUG_WORKAROUND))
+local int FileTime2utime(FILETIME *pft, time_t *ut);
+#endif
+#if (defined(NT_TZBUG_WORKAROUND) && defined(W32_STAT_BANDAID))
+local int VFatFileTime2utime(const FILETIME *pft, time_t *ut);
+#endif
+
+
+/* FAT / HPFS detection */
+
+int IsFileSystemOldFAT(char *dir)
+{
+  static char lastDrive = '\0';    /* cached drive of last GetVolumeInformation call */
+  static int lastDriveOldFAT = 0;  /* cached OldFAT value of last GetVolumeInformation call */
+  char root[4];
+  DWORD vfnsize;
+  DWORD vfsflags;
+
+    /*
+     * We separate FAT and HPFS+other file systems here.
+     * I consider other systems to be similar to HPFS/NTFS, i.e.
+     * support for long file names and being case sensitive to some extent.
+     */
+
+    strncpy(root, dir, 3);
+    if ( isalpha((uch)root[0]) && (root[1] == ':') ) {
+      root[0] = to_up(dir[0]);
+      root[2] = '\\';
+      root[3] = 0;
+    }
+    else {
+      root[0] = '\\';
+      root[1] = 0;
+    }
+    if (lastDrive == root[0]) {
+      return lastDriveOldFAT;
+    }
+
+    if ( !GetVolumeInformation(root, NULL, 0,
+                               NULL, &vfnsize, &vfsflags,
+                               NULL, 0)) {
+        fprintf(mesg, "zip diagnostic: GetVolumeInformation failed\n");
+        return(FALSE);
+    }
+
+    lastDrive = root[0];
+    lastDriveOldFAT = vfnsize <= 12;
+
+    return lastDriveOldFAT;
+}
+
+#ifdef UNICODE_SUPPORT
+int IsFileSystemOldFATW(wchar_t *dir)
+{
+  static wchar_t lastDrive = (wchar_t)'\0';    /* cached drive of last GetVolumeInformation call */
+  static int lastDriveOldFAT = 0;  /* cached OldFAT value of last GetVolumeInformation call */
+  wchar_t root[4];
+  DWORD vfnsize;
+  DWORD vfsflags;
+
+    /*
+     * We separate FAT and HPFS+other file systems here.
+     * I consider other systems to be similar to HPFS/NTFS, i.e.
+     * support for long file names and being case sensitive to some extent.
+     */
+
+    wcsncpy(root, dir, 3);
+    if ( iswalpha(root[0]) && (root[1] == (wchar_t)':') ) {
+      root[0] = towupper(dir[0]);
+      root[2] = (wchar_t)'\\';
+      root[3] = 0;
+    }
+    else {
+      root[0] = (wchar_t)'\\';
+      root[1] = 0;
+    }
+    if (lastDrive == root[0]) {
+      return lastDriveOldFAT;
+    }
+
+    if ( !GetVolumeInformationW(root, NULL, 0,
+                                NULL, &vfnsize, &vfsflags,
+                                NULL, 0)) {
+        fprintf(mesg, "zip diagnostic: GetVolumeInformation failed\n");
+        return(FALSE);
+    }
+
+    lastDrive = root[0];
+    lastDriveOldFAT = vfnsize <= 12;
+
+    return lastDriveOldFAT;
+}
+#endif
+
+
+/* access mode bits and time stamp */
+
+int GetFileMode(char *name)
+{
+DWORD dwAttr;
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+  char *ansi_name = (char *)alloca(strlen(name) + 1);
+
+  OemToAnsi(name, ansi_name);
+  name = ansi_name;
+#endif
+
+  dwAttr = GetFileAttributes(name);
+  if ( dwAttr == 0xFFFFFFFF ) {
+    zipwarn("reading file attributes failed: ", name);
+    /*
+    fprintf(mesg, "zip diagnostic: GetFileAttributes failed");
+    fflush();
+    */
+    return(0x20); /* the most likely, though why the error? security? */
+  }
+  return(
+          (dwAttr&FILE_ATTRIBUTE_READONLY  ? A_RONLY   :0)
+        | (dwAttr&FILE_ATTRIBUTE_HIDDEN    ? A_HIDDEN  :0)
+        | (dwAttr&FILE_ATTRIBUTE_SYSTEM    ? A_SYSTEM  :0)
+        | (dwAttr&FILE_ATTRIBUTE_DIRECTORY ? A_DIR     :0)
+        | (dwAttr&FILE_ATTRIBUTE_ARCHIVE   ? A_ARCHIVE :0));
+}
+
+#ifdef UNICODE_SUPPORT
+int GetFileModeW(wchar_t *namew)
+{
+DWORD dwAttr;
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+  wchar_t *ansi_namew = (wchar_t *)alloca((wcslen(namew) + 1) * sizeof(wchar_t));
+
+  CharToAnsiW(namew, ansi_namew);
+  namew = ansi_namew;
+#endif
+
+  dwAttr = GetFileAttributesW(namew);
+  if ( dwAttr == 0xFFFFFFFF ) {
+    char *name = wchar_to_local_string(namew);
+    zipwarn("reading file attributes failed: ", name);
+    free(name);
+    return(0x20); /* the most likely, though why the error? security? */
+  }
+  return(
+          (dwAttr&FILE_ATTRIBUTE_READONLY  ? A_RONLY   :0)
+        | (dwAttr&FILE_ATTRIBUTE_HIDDEN    ? A_HIDDEN  :0)
+        | (dwAttr&FILE_ATTRIBUTE_SYSTEM    ? A_SYSTEM  :0)
+        | (dwAttr&FILE_ATTRIBUTE_DIRECTORY ? A_DIR     :0)
+        | (dwAttr&FILE_ATTRIBUTE_ARCHIVE   ? A_ARCHIVE :0));
+}
+#endif
+
+
+int ClearArchiveBitW(wchar_t *namew)
+{
+DWORD dwAttr;
+  dwAttr = GetFileAttributesW(namew);
+  if ( dwAttr == 0xFFFFFFFF ) {
+    fprintf(mesg, "zip diagnostic: GetFileAttributes failed\n");
+    return(0);
+  }
+
+  if (!SetFileAttributesW(namew, (DWORD)(dwAttr & ~FILE_ATTRIBUTE_ARCHIVE))) {
+    fprintf(mesg, "zip diagnostic: SetFileAttributes failed\n");
+    perror("SetFileAttributes");
+    return(0);
+  }
+  return(1);
+}
+
+int ClearArchiveBit(char *name)
+{
+DWORD dwAttr;
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+  char *ansi_name = (char *)alloca(strlen(name) + 1);
+
+  OemToAnsi(name, ansi_name);
+  name = ansi_name;
+#endif
+
+  dwAttr = GetFileAttributes(name);
+  if ( dwAttr == 0xFFFFFFFF ) {
+    fprintf(mesg, "zip diagnostic: GetFileAttributes failed\n");
+    return(0);
+  }
+
+  if (!SetFileAttributes(name, (DWORD)(dwAttr & ~FILE_ATTRIBUTE_ARCHIVE))) {
+    fprintf(mesg, "zip diagnostic: SetFileAttributes failed\n");
+    perror("SetFileAttributes");
+    return(0);
+  }
+  return(1);
+}
+
+
+#ifdef NT_TZBUG_WORKAROUND
+local int FSusesLocalTime(const char *path)
+{
+    char  *tmp0;
+    char   rootPathName[4];
+    char   tmp1[MAX_PATH], tmp2[MAX_PATH];
+    DWORD  volSerNo, maxCompLen, fileSysFlags;
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+    char *ansi_path = (char *)alloca(strlen(path) + 1);
+
+    OemToAnsi(path, ansi_path);
+    path = ansi_path;
+#endif
+
+    if (isalpha((uch)path[0]) && (path[1] == ':'))
+        tmp0 = (char *)path;
+    else
+    {
+        GetFullPathName(path, MAX_PATH, tmp1, &tmp0);
+        tmp0 = &tmp1[0];
+    }
+    strncpy(rootPathName, tmp0, 3);   /* Build the root path name, */
+    rootPathName[3] = '\0';           /* e.g. "A:/"                */
+
+    GetVolumeInformation((LPCTSTR)rootPathName, (LPTSTR)tmp1, (DWORD)MAX_PATH,
+                         &volSerNo, &maxCompLen, &fileSysFlags,
+                         (LPTSTR)tmp2, (DWORD)MAX_PATH);
+
+    /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in
+     * local time!
+     */
+    return !strncmp(strupr(tmp2), "FAT", 3) ||
+           !strncmp(tmp2, "VFAT", 4) ||
+           !strncmp(tmp2, "HPFS", 4);
+
+} /* end function FSusesLocalTime() */
+
+# ifdef UNICODE_SUPPORT
+local int FSusesLocalTimeW(const wchar_t *path)
+{
+    wchar_t  *tmp0;
+    wchar_t   rootPathName[4];
+    wchar_t   tmp1[MAX_PATH], tmp2[MAX_PATH];
+    DWORD  volSerNo, maxCompLen, fileSysFlags;
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+    wchar_t *ansi_path = (wchar_t *)alloca((wcslen(path) + 1) * sizeof(wchar_t));
+
+    CharToAnsiW(path, ansi_path);
+    path = ansi_path;
+#endif
+
+    if (iswalpha(path[0]) && (path[1] == (wchar_t)':'))
+        tmp0 = (wchar_t *)path;
+    else
+    {
+        GetFullPathNameW(path, MAX_PATH, tmp1, &tmp0);
+        tmp0 = &tmp1[0];
+    }
+    wcsncpy(rootPathName, tmp0, 3);   /* Build the root path name, */
+    rootPathName[3] = (wchar_t)'\0';           /* e.g. "A:/"                */
+
+    GetVolumeInformationW(rootPathName, tmp1, (DWORD)MAX_PATH,
+                         &volSerNo, &maxCompLen, &fileSysFlags,
+                         tmp2, (DWORD)MAX_PATH);
+
+    /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in
+     * local time!
+     */
+    return !wcsncmp(_wcsupr(tmp2), L"FAT", 3) ||
+           !wcsncmp(tmp2, L"VFAT", 4) ||
+           !wcsncmp(tmp2, L"HPFS", 4);
+
+} /* end function FSusesLocalTimeW() */
+# endif
+
+#endif /* NT_TZBUG_WORKAROUND */
+
+
+#if (defined(USE_EF_UT_TIME) || defined(NT_TZBUG_WORKAROUND))
+
+#if (defined(__GNUC__) || defined(ULONG_LONG_MAX))
+   typedef long long            LLONG64;
+   typedef unsigned long long   ULLNG64;
+#elif (defined(__WATCOMC__) && (__WATCOMC__ >= 1100))
+   typedef __int64              LLONG64;
+   typedef unsigned __int64     ULLNG64;
+#elif (defined(_MSC_VER) && (_MSC_VER >= 1100))
+   typedef __int64              LLONG64;
+   typedef unsigned __int64     ULLNG64;
+#elif (defined(__IBMC__) && (__IBMC__ >= 350))
+   typedef __int64              LLONG64;
+   typedef unsigned __int64     ULLNG64;
+#else
+#  define NO_INT64
+#endif
+
+#  define UNIX_TIME_ZERO_HI  0x019DB1DEUL
+#  define UNIX_TIME_ZERO_LO  0xD53E8000UL
+#  define NT_QUANTA_PER_UNIX 10000000L
+#  define FTQUANTA_PER_UT_L  (NT_QUANTA_PER_UNIX & 0xFFFF)
+#  define FTQUANTA_PER_UT_H  (NT_QUANTA_PER_UNIX >> 16)
+#  define UNIX_TIME_UMAX_HI  0x0236485EUL
+#  define UNIX_TIME_UMAX_LO  0xD4A5E980UL
+#  define UNIX_TIME_SMIN_HI  0x0151669EUL
+#  define UNIX_TIME_SMIN_LO  0xD53E8000UL
+#  define UNIX_TIME_SMAX_HI  0x01E9FD1EUL
+#  define UNIX_TIME_SMAX_LO  0xD4A5E980UL
+
+local int FileTime2utime(FILETIME *pft, time_t *ut)
+{
+#ifndef NO_INT64
+    ULLNG64 NTtime;
+
+    NTtime = ((ULLNG64)pft->dwLowDateTime +
+              ((ULLNG64)pft->dwHighDateTime << 32));
+
+    /* underflow and overflow handling */
+#ifdef CHECK_UTIME_SIGNED_UNSIGNED
+    if ((time_t)0x80000000L < (time_t)0L)
+    {
+        if (NTtime < ((ULLNG64)UNIX_TIME_SMIN_LO +
+                      ((ULLNG64)UNIX_TIME_SMIN_HI << 32))) {
+            *ut = (time_t)LONG_MIN;
+            return FALSE;
+        }
+        if (NTtime > ((ULLNG64)UNIX_TIME_SMAX_LO +
+                      ((ULLNG64)UNIX_TIME_SMAX_HI << 32))) {
+            *ut = (time_t)LONG_MAX;
+            return FALSE;
+        }
+    }
+    else
+#endif /* CHECK_UTIME_SIGNED_UNSIGNED */
+    {
+        if (NTtime < ((ULLNG64)UNIX_TIME_ZERO_LO +
+                      ((ULLNG64)UNIX_TIME_ZERO_HI << 32))) {
+            *ut = (time_t)0;
+            return FALSE;
+        }
+        if (NTtime > ((ULLNG64)UNIX_TIME_UMAX_LO +
+                      ((ULLNG64)UNIX_TIME_UMAX_HI << 32))) {
+            *ut = (time_t)ULONG_MAX;
+            return FALSE;
+        }
+    }
+
+    NTtime -= ((ULLNG64)UNIX_TIME_ZERO_LO +
+               ((ULLNG64)UNIX_TIME_ZERO_HI << 32));
+    *ut = (time_t)(NTtime / (unsigned long)NT_QUANTA_PER_UNIX);
+    return TRUE;
+#else /* NO_INT64 (64-bit integer arithmetics may not be supported) */
+    /* nonzero if `y' is a leap year, else zero */
+#   define leap(y) (((y)%4 == 0 && (y)%100 != 0) || (y)%400 == 0)
+    /* number of leap years from 1970 to `y' (not including `y' itself) */
+#   define nleap(y) (((y)-1969)/4 - ((y)-1901)/100 + ((y)-1601)/400)
+    /* daycount at the end of month[m-1] */
+    static ZCONST ush ydays[] =
+      { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
+
+    time_t days;
+    SYSTEMTIME w32tm;
+
+    /* underflow and overflow handling */
+#ifdef CHECK_UTIME_SIGNED_UNSIGNED
+    if ((time_t)0x80000000L < (time_t)0L)
+    {
+        if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) ||
+            ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) &&
+             (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) {
+            *ut = (time_t)LONG_MIN;
+            return FALSE;
+        if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) ||
+            ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) &&
+             (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) {
+            *ut = (time_t)LONG_MAX;
+            return FALSE;
+        }
+    }
+    else
+#endif /* CHECK_UTIME_SIGNED_UNSIGNED */
+    {
+        if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) ||
+            ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) &&
+             (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) {
+            *ut = (time_t)0;
+            return FALSE;
+        }
+        if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) ||
+            ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) &&
+             (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) {
+            *ut = (time_t)ULONG_MAX;
+            return FALSE;
+        }
+    }
+
+    FileTimeToSystemTime(pft, &w32tm);
+
+    /* set `days' to the number of days into the year */
+    days = w32tm.wDay - 1 + ydays[w32tm.wMonth-1] +
+           (w32tm.wMonth > 2 && leap (w32tm.wYear));
+
+    /* now set `days' to the number of days since 1 Jan 1970 */
+    days += 365 * (time_t)(w32tm.wYear - 1970) +
+            (time_t)(nleap(w32tm.wYear));
+
+    *ut = (time_t)(86400L * days + 3600L * (time_t)w32tm.wHour +
+                   (time_t)(60 * w32tm.wMinute + w32tm.wSecond));
+    return TRUE;
+#endif /* ?NO_INT64 */
+} /* end function FileTime2utime() */
+#endif /* USE_EF_UT_TIME || NT_TZBUG_WORKAROUND */
+
+
+#if (defined(NT_TZBUG_WORKAROUND) && defined(W32_STAT_BANDAID))
+
+local int VFatFileTime2utime(const FILETIME *pft, time_t *ut)
+{
+    FILETIME lft;
+    SYSTEMTIME w32tm;
+    struct tm ltm;
+
+    FileTimeToLocalFileTime(pft, &lft);
+    FileTimeToSystemTime(&lft, &w32tm);
+    /* underflow and overflow handling */
+    /* TODO: The range checks are not accurate, the actual limits may
+     *       be off by one daylight-saving-time shift (typically 1 hour),
+     *       depending on the current state of "is_dst".
+     */
+#ifdef CHECK_UTIME_SIGNED_UNSIGNED
+    if ((time_t)0x80000000L < (time_t)0L)
+    {
+        if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) ||
+            ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) &&
+             (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) {
+            *ut = (time_t)LONG_MIN;
+            return FALSE;
+        if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) ||
+            ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) &&
+             (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) {
+            *ut = (time_t)LONG_MAX;
+            return FALSE;
+        }
+    }
+    else
+#endif /* CHECK_UTIME_SIGNED_UNSIGNED */
+    {
+        if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) ||
+            ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) &&
+             (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) {
+            *ut = (time_t)0;
+            return FALSE;
+        }
+        if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) ||
+            ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) &&
+             (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) {
+            *ut = (time_t)ULONG_MAX;
+            return FALSE;
+        }
+    }
+    ltm.tm_year = w32tm.wYear - 1900;
+    ltm.tm_mon = w32tm.wMonth - 1;
+    ltm.tm_mday = w32tm.wDay;
+    ltm.tm_hour = w32tm.wHour;
+    ltm.tm_min = w32tm.wMinute;
+    ltm.tm_sec = w32tm.wSecond;
+    ltm.tm_isdst = -1;  /* let mktime determine if DST is in effect */
+    *ut = mktime(&ltm);
+
+    /* a cheap error check: mktime returns "(time_t)-1L" on conversion errors.
+     * Normally, we would have to apply a consistency check because "-1"
+     * could also be a valid time. But, it is quite unlikely to read back odd
+     * time numbers from file systems that store time stamps in DOS format.
+     * (The only known exception is creation time on VFAT partitions.)
+     */
+    return (*ut != (time_t)-1L);
+
+} /* end function VFatFileTime2utime() */
+#endif /* NT_TZBUG_WORKAROUND && W32_STAT_BANDAID */
+
+
+#if 0           /* Currently, this is not used at all */
+
+long GetTheFileTime(char *name, iztimes *z_ut)
+{
+HANDLE h;
+FILETIME Modft, Accft, Creft, lft;
+WORD dh, dl;
+#ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
+  char *ansi_name = (char *)alloca(strlen(name) + 1);
+
+  OemToAnsi(name, ansi_name);
+  name = ansi_name;
+#endif
+
+  h = CreateFile(name, FILE_READ_ATTRIBUTES, FILE_SHARE_READ,
+                 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  if ( h != INVALID_HANDLE_VALUE ) {
+    BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
+    CloseHandle(h);
+#ifdef USE_EF_UT_TIME
+    if (ftOK && (z_ut != NULL)) {
+      FileTime2utime(&Modft, &(z_ut->mtime));
+      if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+          FileTime2utime(&Accft, &(z_ut->atime));
+      else
+          z_ut->atime = z_ut->mtime;
+      if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+          FileTime2utime(&Creft, &(z_ut->ctime));
+      else
+          z_ut->ctime = z_ut->mtime;
+    }
+#endif
+    FileTimeToLocalFileTime(&ft, &lft);
+    FileTimeToDosDateTime(&lft, &dh, &dl);
+    return(dh<<16) | dl;
+  }
+  else
+    return 0L;
+}
+
+#endif /* never */
+
+
+void ChangeNameForFAT(char *name)
+{
+  char *src, *dst, *next, *ptr, *dot, *start;
+  static char invalid[] = ":;,=+\"[]<>| \t";
+
+  if ( isalpha((uch)name[0]) && (name[1] == ':') )
+    start = name + 2;
+  else
+    start = name;
+
+  src = dst = start;
+  if ( (*src == '/') || (*src == '\\') )
+    src++, dst++;
+
+  while ( *src )
+  {
+    for ( next = src; *next && (*next != '/') && (*next != '\\'); next++ );
+
+    for ( ptr = src, dot = NULL; ptr < next; ptr++ )
+      if ( *ptr == '.' )
+      {
+        dot = ptr; /* remember last dot */
+        *ptr = '_';
+      }
+
+    if ( dot == NULL )
+      for ( ptr = src; ptr < next; ptr++ )
+        if ( *ptr == '_' )
+          dot = ptr; /* remember last _ as if it were a dot */
+
+    if ( dot && (dot > src) &&
+         ((next - dot <= 4) ||
+          ((next - src > 8) && (dot - src > 3))) )
+    {
+      if ( dot )
+        *dot = '.';
+
+      for ( ptr = src; (ptr < dot) && ((ptr - src) < 8); ptr++ )
+        *dst++ = *ptr;
+
+      for ( ptr = dot; (ptr < next) && ((ptr - dot) < 4); ptr++ )
+        *dst++ = *ptr;
+    }
+    else
+    {
+      if ( dot && (next - src == 1) )
+        *dot = '.';           /* special case: "." as a path component */
+
+      for ( ptr = src; (ptr < next) && ((ptr - src) < 8); ptr++ )
+        *dst++ = *ptr;
+    }
+
+    *dst++ = *next; /* either '/' or 0 */
+
+    if ( *next )
+    {
+      src = next + 1;
+
+      if ( *src == 0 ) /* handle trailing '/' on dirs ! */
+        *dst = 0;
+    }
+    else
+      break;
+  }
+
+  for ( src = start; *src != 0; ++src )
+    if ( (strchr(invalid, *src) != NULL) || (*src == ' ') )
+      *src = '_';
+}
+
+char *GetLongPathEA(char *name)
+{
+    return(NULL); /* volunteers ? */
+}
+
+#ifdef UNICODE_SUPPORT
+wchar_t *GetLongPathEAW(wchar_t *name)
+{
+    return(NULL); /* volunteers ? */
+}
+#endif
+
+
+int IsFileNameValid(x)
+char *x;
+{
+    WIN32_FIND_DATA fd;
+    HANDLE h;
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+    char *ansi_name = (char *)alloca(strlen(x) + 1);
+
+    OemToAnsi(x, ansi_name);
+    x = ansi_name;
+#endif
+
+    if ((h = FindFirstFile(x, &fd)) == INVALID_HANDLE_VALUE)
+        return FALSE;
+    FindClose(h);
+    return TRUE;
+}
+
+char *getVolumeLabel(drive, vtime, vmode, vutim)
+  int drive;    /* drive name: 'A' .. 'Z' or '\0' for current drive */
+  ulg *vtime;   /* volume label creation time (DOS format) */
+  ulg *vmode;   /* volume label file mode */
+  time_t *vutim;/* volume label creationtime (UNIX format) */
+
+/* If a volume label exists for the given drive, return its name and
+   pretend to set its time and mode. The returned name is static data. */
+{
+  char rootpath[4];
+  static char vol[14];
+  DWORD fnlen, flags;
+
+  *vmode = A_ARCHIVE | A_LABEL;           /* this is what msdos returns */
+  *vtime = dostime(1980, 1, 1, 0, 0, 0);  /* no true date info available */
+  *vutim = dos2unixtime(*vtime);
+  strcpy(rootpath, "x:\\");
+  rootpath[0] = (char)drive;
+  if (GetVolumeInformation(drive ? rootpath : NULL, vol, 13, NULL,
+                           &fnlen, &flags, NULL, 0))
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+    return (AnsiToOem(vol, vol), vol);
+#else
+    return vol;
+#endif
+  else
+    return NULL;
+}
+
+#endif /* !UTIL */
+
+
+
+int ZipIsWinNT(void)    /* returns TRUE if real NT, FALSE if Win95 or Win32s */
+{
+    static DWORD g_PlatformId = 0xFFFFFFFF; /* saved platform indicator */
+
+    if (g_PlatformId == 0xFFFFFFFF) {
+        /* note: GetVersionEx() doesn't exist on WinNT 3.1 */
+        if (GetVersion() < 0x80000000)
+            g_PlatformId = TRUE;
+        else
+            g_PlatformId = FALSE;
+    }
+    return (int)g_PlatformId;
+}
+
+
+#ifndef UTIL
+#ifdef __WATCOMC__
+#  include <io.h>
+#  define _get_osfhandle _os_handle
+/* gaah -- Watcom's docs claim that _get_osfhandle exists, but it doesn't.  */
+#endif
+
+#ifdef HAVE_FSEEKABLE
+/*
+ * return TRUE if file is seekable
+ */
+int fseekable(fp)
+FILE *fp;
+{
+    return GetFileType((HANDLE)_get_osfhandle(fileno(fp))) == FILE_TYPE_DISK;
+}
+#endif /* HAVE_FSEEKABLE */
+#endif /* !UTIL */
+
+
+#if 0 /* seems to be never used; try it out... */
+char *StringLower(char *szArg)
+{
+  char *szPtr;
+/*  unsigned char *szPtr; */
+  for ( szPtr = szArg; *szPtr; szPtr++ )
+    *szPtr = lower[*szPtr];
+  return szArg;
+}
+#endif /* never */
+
+
+
+#ifdef W32_STAT_BANDAID
+
+/* All currently known variants of WIN32 operating systems (Windows 95/98,
+ * WinNT 3.x, 4.0, 5.0) have a nasty bug in the OS kernel concerning
+ * conversions between UTC and local time: In the time conversion functions
+ * of the Win32 API, the timezone offset (including seasonal daylight saving
+ * shift) between UTC and local time evaluation is erratically based on the
+ * current system time. The correct evaluation must determine the offset
+ * value as it {was/is/will be} for the actual time to be converted.
+ *
+ * The C runtime lib's stat() returns utc time-stamps so that
+ * localtime(timestamp) corresponds to the (potentially false) local
+ * time shown by the OS' system programs (Explorer, command shell dir, etc.)
+ *
+ * For the NTFS file system (and other filesystems that store time-stamps
+ * as UTC values), this results in st_mtime (, st_{c|a}time) fields which
+ * are not stable but vary according to the seasonal change of "daylight
+ * saving time in effect / not in effect".
+ *
+ * To achieve timestamp consistency of UTC (UT extra field) values in
+ * Zip archives, the Info-ZIP programs require work-around code for
+ * proper time handling in stat() (and other time handling routines).
+ */
+/* stat() functions under Windows95 tend to fail for root directories.   *
+ * Watcom and Borland, at least, are affected by this bug.  Watcom made  *
+ * a partial fix for 11.0 but still missed some cases.  This substitute  *
+ * detects the case and fills in reasonable values.  Otherwise we get    *
+ * effects like failure to extract to a root dir because it's not found. */
+
+#ifdef LARGE_FILE_SUPPORT         /* E. Gordon 9/12/03 */
+ int zstat_zipwin32(const char *path, z_stat *buf)
+#else
+ int zstat_zipwin32(const char *path, struct stat *buf)
+#endif
+{
+# ifdef LARGE_FILE_SUPPORT         /* E. Gordon 9/12/03 */
+    if (!zstat(path, buf))
+# else
+    if (!stat(path, buf))
+# endif
+    {
+#ifdef NT_TZBUG_WORKAROUND
+        /* stat was successful, now redo the time-stamp fetches */
+        int fs_uses_loctime = FSusesLocalTime(path);
+        HANDLE h;
+        FILETIME Modft, Accft, Creft;
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+        char *ansi_path = (char *)alloca(strlen(path) + 1);
+
+        OemToAnsi(path, ansi_path);
+#       define Ansi_Path  ansi_path
+#else
+#       define Ansi_Path  path
+#endif
+
+        Trace((stdout, "stat(%s) finds modtime %08lx\n", path, buf->st_mtime));
+        h = CreateFile(Ansi_Path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ,
+                       NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+        if (h != INVALID_HANDLE_VALUE) {
+            BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
+            CloseHandle(h);
+
+            if (ftOK) {
+                if (!fs_uses_loctime) {
+                    /*  On a filesystem that stores UTC timestamps, we refill
+                     *  the time fields of the struct stat buffer by directly
+                     *  using the UTC values as returned by the Win32
+                     *  GetFileTime() API call.
+                     */
+                    FileTime2utime(&Modft, &(buf->st_mtime));
+                    if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+                        FileTime2utime(&Accft, &(buf->st_atime));
+                    else
+                        buf->st_atime = buf->st_mtime;
+                    if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+                        FileTime2utime(&Creft, &(buf->st_ctime));
+                    else
+                        buf->st_ctime = buf->st_mtime;
+                    Tracev((stdout,"NTFS, recalculated modtime %08lx\n",
+                            buf->st_mtime));
+                } else {
+                    /*  On VFAT and FAT-like filesystems, the FILETIME values
+                     *  are converted back to the stable local time before
+                     *  converting them to UTC unix time-stamps.
+                     */
+                    VFatFileTime2utime(&Modft, &(buf->st_mtime));
+                    if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+                        VFatFileTime2utime(&Accft, &(buf->st_atime));
+                    else
+                        buf->st_atime = buf->st_mtime;
+                    if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+                        VFatFileTime2utime(&Creft, &(buf->st_ctime));
+                    else
+                        buf->st_ctime = buf->st_mtime;
+                    Tracev((stdout, "VFAT, recalculated modtime %08lx\n",
+                            buf->st_mtime));
+                }
+            }
+        }
+#       undef Ansi_Path
+#endif /* NT_TZBUG_WORKAROUND */
+        return 0;
+    }
+#ifdef W32_STATROOT_FIX
+    else
+    {
+        DWORD flags;
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+        char *ansi_path = (char *)alloca(strlen(path) + 1);
+
+        OemToAnsi(path, ansi_path);
+#       define Ansi_Path  ansi_path
+#else
+#       define Ansi_Path  path
+#endif
+
+        flags = GetFileAttributes(Ansi_Path);
+        if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) {
+            Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n",
+                   path));
+#ifdef LARGE_FILE_SUPPORT         /* E. Gordon 9/12/03 */
+            memset(buf, 0, sizeof(z_stat));
+#else
+            memset(buf, 0, sizeof(struct stat));
+#endif
+            buf->st_atime = buf->st_ctime = buf->st_mtime =
+              dos2unixtime(DOSTIME_MINIMUM);
+            /* !!!   you MUST NOT add a cast to the type of "st_mode" here;
+             * !!!   different compilers do not agree on the "st_mode" size!
+             * !!!   (And, some compiler may not declare the "mode_t" type
+             * !!!   identifier, so you cannot use it, either.)
+             */
+            buf->st_mode = S_IFDIR | S_IREAD |
+                           ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE);
+            return 0;
+        } /* assumes: stat() won't fail on non-dirs without good reason */
+#       undef Ansi_Path
+    }
+#endif /* W32_STATROOT_FIX */
+    return -1;
+}
+
+
+# ifdef UNICODE_SUPPORT
+
+int zstat_zipwin32w(const wchar_t *pathw, zw_stat *buf)
+{
+    if (!zwstat(pathw, buf))
+    {
+#ifdef NT_TZBUG_WORKAROUND
+        /* stat was successful, now redo the time-stamp fetches */
+        int fs_uses_loctime = FSusesLocalTimeW(pathw);
+        HANDLE h;
+        FILETIME Modft, Accft, Creft;
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+        char *ansi_path = (char *)alloca(strlen(pathw) + 1);
+
+        OemToAnsi(path, ansi_path);
+#       define Ansi_Path  ansi_path
+#else
+#       define Ansi_Path  pathw
+#endif
+
+        Trace((stdout, "stat(%s) finds modtime %08lx\n", pathw, buf->st_mtime));
+        h = CreateFileW(Ansi_Path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ,
+                       NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+        if (h != INVALID_HANDLE_VALUE) {
+            BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
+            CloseHandle(h);
+
+            if (ftOK) {
+                if (!fs_uses_loctime) {
+                    /*  On a filesystem that stores UTC timestamps, we refill
+                     *  the time fields of the struct stat buffer by directly
+                     *  using the UTC values as returned by the Win32
+                     *  GetFileTime() API call.
+                     */
+                    FileTime2utime(&Modft, &(buf->st_mtime));
+                    if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+                        FileTime2utime(&Accft, &(buf->st_atime));
+                    else
+                        buf->st_atime = buf->st_mtime;
+                    if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+                        FileTime2utime(&Creft, &(buf->st_ctime));
+                    else
+                        buf->st_ctime = buf->st_mtime;
+                    Tracev((stdout,"NTFS, recalculated modtime %08lx\n",
+                            buf->st_mtime));
+                } else {
+                    /*  On VFAT and FAT-like filesystems, the FILETIME values
+                     *  are converted back to the stable local time before
+                     *  converting them to UTC unix time-stamps.
+                     */
+                    VFatFileTime2utime(&Modft, &(buf->st_mtime));
+                    if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+                        VFatFileTime2utime(&Accft, &(buf->st_atime));
+                    else
+                        buf->st_atime = buf->st_mtime;
+                    if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+                        VFatFileTime2utime(&Creft, &(buf->st_ctime));
+                    else
+                        buf->st_ctime = buf->st_mtime;
+                    Tracev((stdout, "VFAT, recalculated modtime %08lx\n",
+                            buf->st_mtime));
+                }
+            }
+        }
+#       undef Ansi_Path
+#endif /* NT_TZBUG_WORKAROUND */
+        return 0;
+    }
+#ifdef W32_STATROOT_FIX
+    else
+    {
+        DWORD flags;
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+        char *ansi_path = (char *)alloca(strlen(pathw) + 1);
+
+        OemToAnsi(path, ansi_path);
+#       define Ansi_Path  ansi_path
+#else
+#       define Ansi_Path  pathw
+#endif
+
+        flags = GetFileAttributesW(Ansi_Path);
+        if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) {
+            Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n",
+                   pathw));
+#ifdef LARGE_FILE_SUPPORT         /* E. Gordon 9/12/03 */
+            memset(buf, 0, sizeof(z_stat));
+#else
+            memset(buf, 0, sizeof(struct stat));
+#endif
+            buf->st_atime = buf->st_ctime = buf->st_mtime =
+              dos2unixtime(DOSTIME_MINIMUM);
+            /* !!!   you MUST NOT add a cast to the type of "st_mode" here;
+             * !!!   different compilers do not agree on the "st_mode" size!
+             * !!!   (And, some compiler may not declare the "mode_t" type
+             * !!!   identifier, so you cannot use it, either.)
+             */
+            buf->st_mode = S_IFDIR | S_IREAD |
+                           ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE);
+            return 0;
+        } /* assumes: stat() won't fail on non-dirs without good reason */
+#       undef Ansi_Path
+    }
+#endif /* W32_STATROOT_FIX */
+    return -1;
+}
+
+# endif
+
+
+#endif /* W32_STAT_BANDAID */
+
+
+
+#ifdef W32_USE_IZ_TIMEZONE
+#include "timezone.h"
+#define SECSPERMIN      60
+#define MINSPERHOUR     60
+#define SECSPERHOUR     (SECSPERMIN * MINSPERHOUR)
+static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule);
+
+static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule)
+{
+    if (lpw32tm->wYear != 0) {
+        ptrule->r_type = JULIAN_DAY;
+        ptrule->r_day = ydays[lpw32tm->wMonth - 1] + lpw32tm->wDay;
+    } else {
+        ptrule->r_type = MONTH_NTH_DAY_OF_WEEK;
+        ptrule->r_mon = lpw32tm->wMonth;
+        ptrule->r_day = lpw32tm->wDayOfWeek;
+        ptrule->r_week = lpw32tm->wDay;
+    }
+    ptrule->r_time = (long)lpw32tm->wHour * SECSPERHOUR +
+                     (long)(lpw32tm->wMinute * SECSPERMIN) +
+                     (long)lpw32tm->wSecond;
+}
+
+int GetPlatformLocalTimezone(register struct state * ZCONST sp,
+        void (*fill_tzstate_from_rules)(struct state * ZCONST sp_res,
+                                        ZCONST struct rule * ZCONST start,
+                                        ZCONST struct rule * ZCONST end))
+{
+    TIME_ZONE_INFORMATION tzinfo;
+    DWORD res;
+
+    /* read current timezone settings from registry if TZ envvar missing */
+    res = GetTimeZoneInformation(&tzinfo);
+    if (res != TIME_ZONE_ID_INVALID)
+    {
+        struct rule startrule, stoprule;
+
+        conv_to_rule(&(tzinfo.StandardDate), &stoprule);
+        conv_to_rule(&(tzinfo.DaylightDate), &startrule);
+        sp->timecnt = 0;
+        sp->ttis[0].tt_abbrind = 0;
+        if ((sp->charcnt =
+             WideCharToMultiByte(CP_ACP, 0, tzinfo.StandardName, -1,
+                                 sp->chars, sizeof(sp->chars), NULL, NULL))
+            == 0)
+            sp->chars[sp->charcnt++] = '\0';
+        sp->ttis[1].tt_abbrind = sp->charcnt;
+        sp->charcnt +=
+            WideCharToMultiByte(CP_ACP, 0, tzinfo.DaylightName, -1,
+                                sp->chars + sp->charcnt,
+                                sizeof(sp->chars) - sp->charcnt, NULL, NULL);
+        if ((sp->charcnt - sp->ttis[1].tt_abbrind) == 0)
+            sp->chars[sp->charcnt++] = '\0';
+        sp->ttis[0].tt_gmtoff = - (tzinfo.Bias + tzinfo.StandardBias)
+                                * MINSPERHOUR;
+        sp->ttis[1].tt_gmtoff = - (tzinfo.Bias + tzinfo.DaylightBias)
+                                * MINSPERHOUR;
+        sp->ttis[0].tt_isdst = 0;
+        sp->ttis[1].tt_isdst = 1;
+        sp->typecnt = (startrule.r_mon == 0 && stoprule.r_mon == 0) ? 1 : 2;
+
+        if (sp->typecnt > 1)
+            (*fill_tzstate_from_rules)(sp, &startrule, &stoprule);
+        return TRUE;
+    }
+    return FALSE;
+}
+#endif /* W32_USE_IZ_TIMEZONE */
+
+
+
+#ifndef WINDLL
+/* This replacement getch() function was originally created for Watcom C
+ * and then additionally used with CYGWIN. Since UnZip 5.4, all other Win32
+ * ports apply this replacement rather that their supplied getch() (or
+ * alike) function.  There are problems with unabsorbed LF characters left
+ * over in the keyboard buffer under Win95 (and 98) when ENTER was pressed.
+ * (Under Win95, ENTER returns two(!!) characters: CR-LF.)  This problem
+ * does not appear when run on a WinNT console prompt!
+ */
+
+/* Watcom 10.6's getch() does not handle Alt+<digit><digit><digit>. */
+/* Note that if PASSWD_FROM_STDIN is defined, the file containing   */
+/* the password must have a carriage return after the word, not a   */
+/* Unix-style newline (linefeed only).  This discards linefeeds.    */
+
+int getch_win32(void)
+{
+  HANDLE stin;
+  DWORD rc;
+  unsigned char buf[2];
+  int ret = -1;
+  DWORD odemode = ~(DWORD)0;
+
+#  ifdef PASSWD_FROM_STDIN
+  stin = GetStdHandle(STD_INPUT_HANDLE);
+#  else
+  stin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
+                    FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+  if (stin == INVALID_HANDLE_VALUE)
+    return -1;
+#  endif
+  if (GetConsoleMode(stin, &odemode))
+    SetConsoleMode(stin, ENABLE_PROCESSED_INPUT);  /* raw except ^C noticed */
+  if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1)
+    ret = buf[0];
+  /* when the user hits return we get CR LF.  We discard the LF, not the CR,
+   * because when we call this for the first time after a previous input
+   * such as the one for "replace foo? [y]es, ..." the LF may still be in
+   * the input stream before whatever the user types at our prompt. */
+  if (ret == '\n')
+    if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1)
+      ret = buf[0];
+  if (odemode != ~(DWORD)0)
+    SetConsoleMode(stin, odemode);
+#  ifndef PASSWD_FROM_STDIN
+  CloseHandle(stin);
+#  endif
+  return ret;
+}
+
+
+
+/******************************/
+/*  Function version_local()  */
+/******************************/
+
+void version_local()
+{
+    static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s.\n\n";
+#if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DJGPP__))
+    char buf[80];
+#if (defined(_MSC_VER) && (_MSC_VER > 900))
+    char buf2[80];
+#endif
+#endif
+
+/* Define the compiler name and version strings */
+#if defined(_MSC_VER)  /* MSC == MSVC++, including the SDK compiler */
+    sprintf(buf, "Microsoft C %d.%02d ", _MSC_VER/100, _MSC_VER%100);
+#  define COMPILER_NAME1        buf
+#  if (_MSC_VER == 800)
+#    define COMPILER_NAME2      "(Visual C++ v1.1)"
+#  elif (_MSC_VER == 850)
+#    define COMPILER_NAME2      "(Windows NT v3.5 SDK)"
+#  elif (_MSC_VER == 900)
+#    define COMPILER_NAME2      "(Visual C++ v2.x)"
+#  elif (_MSC_VER > 900)
+    sprintf(buf2, "(Visual C++ v%d.%d)", _MSC_VER/100 - 6, _MSC_VER%100/10);
+#    define COMPILER_NAME2      buf2
+#  else
+#    define COMPILER_NAME2      "(bad version)"
+#  endif
+#elif defined(__WATCOMC__)
+#  if (__WATCOMC__ % 10 > 0)
+/* We do this silly test because __WATCOMC__ gives two digits for the  */
+/* minor version, but Watcom packaging prefers to show only one digit. */
+    sprintf(buf, "Watcom C/C++ %d.%02d", __WATCOMC__ / 100,
+            __WATCOMC__ % 100);
+#  else
+    sprintf(buf, "Watcom C/C++ %d.%d", __WATCOMC__ / 100,
+            (__WATCOMC__ % 100) / 10);
+#  endif /* __WATCOMC__ % 10 > 0 */
+#  define COMPILER_NAME1        buf
+#  define COMPILER_NAME2        ""
+#elif defined(__TURBOC__)
+#  ifdef __BORLANDC__
+#    define COMPILER_NAME1      "Borland C++"
+#    if (__BORLANDC__ == 0x0452)   /* __BCPLUSPLUS__ = 0x0320 */
+#      define COMPILER_NAME2    " 4.0 or 4.02"
+#    elif (__BORLANDC__ == 0x0460)   /* __BCPLUSPLUS__ = 0x0340 */
+#      define COMPILER_NAME2    " 4.5"
+#    elif (__BORLANDC__ == 0x0500)   /* __TURBOC__ = 0x0500 */
+#      define COMPILER_NAME2    " 5.0"
+#    elif (__BORLANDC__ == 0x0520)   /* __TURBOC__ = 0x0520 */
+#      define COMPILER_NAME2    " 5.2 (C++ Builder 1.0)"
+#    elif (__BORLANDC__ == 0x0530)   /* __BCPLUSPLUS__ = 0x0530 */
+#      define COMPILER_NAME2    " 5.3 (C++ Builder 3.0)"
+#    elif (__BORLANDC__ == 0x0540)   /* __BCPLUSPLUS__ = 0x0540 */
+#      define COMPILER_NAME2    " 5.4 (C++ Builder 4.0)"
+#    elif (__BORLANDC__ == 0x0550)   /* __BCPLUSPLUS__ = 0x0550 */
+#      define COMPILER_NAME2    " 5.5 (C++ Builder 5.0)"
+#    elif (__BORLANDC__ == 0x0551)   /* __BCPLUSPLUS__ = 0x0551 */
+#      define COMPILER_NAME2    " 5.5.1 (C++ Builder 5.0.1)"
+#    elif (__BORLANDC__ == 0x0560)   /* __BCPLUSPLUS__ = 0x0560 */
+#      define COMPILER_NAME2    " 5.6 (C++ Builder 6)"
+#    else
+#      define COMPILER_NAME2    " later than 5.6"
+#    endif
+#  else /* !__BORLANDC__ */
+#    define COMPILER_NAME1      "Turbo C"
+#    if (__TURBOC__ >= 0x0400)     /* Kevin:  3.0 -> 0x0401 */
+#      define COMPILER_NAME2    "++ 3.0 or later"
+#    elif (__TURBOC__ == 0x0295)     /* [661] vfy'd by Kevin */
+#      define COMPILER_NAME2    "++ 1.0"
+#    endif
+#  endif /* __BORLANDC__ */
+#elif defined(__GNUC__)
+#  ifdef __RSXNT__
+#    if (defined(__DJGPP__) && !defined(__EMX__))
+    sprintf(buf, "rsxnt(djgpp v%d.%02d) / gcc ",
+            __DJGPP__, __DJGPP_MINOR__);
+#      define COMPILER_NAME1    buf
+#    elif defined(__DJGPP__)
+   sprintf(buf, "rsxnt(emx+djgpp v%d.%02d) / gcc ",
+            __DJGPP__, __DJGPP_MINOR__);
+#      define COMPILER_NAME1    buf
+#    elif (defined(__GO32__) && !defined(__EMX__))
+#      define COMPILER_NAME1    "rsxnt(djgpp v1.x) / gcc "
+#    elif defined(__GO32__)
+#      define COMPILER_NAME1    "rsxnt(emx + djgpp v1.x) / gcc "
+#    elif defined(__EMX__)
+#      define COMPILER_NAME1    "rsxnt(emx)+gcc "
+#    else
+#      define COMPILER_NAME1    "rsxnt(unknown) / gcc "
+#    endif
+#  elif defined(__CYGWIN__)
+#      define COMPILER_NAME1    "Cygnus win32 / gcc "
+#  elif defined(__MINGW32__)
+#      define COMPILER_NAME1    "mingw32 / gcc "
+#  else
+#      define COMPILER_NAME1    "gcc "
+#  endif
+#  define COMPILER_NAME2        __VERSION__
+#elif defined(__LCC__)
+#  define COMPILER_NAME1        "LCC-Win32"
+#  define COMPILER_NAME2        ""
+#else
+#  define COMPILER_NAME1        "unknown compiler (SDK?)"
+#  define COMPILER_NAME2        ""
+#endif
+
+/* Define the compile date string */
+#ifdef __DATE__
+#  define COMPILE_DATE " on " __DATE__
+#else
+#  define COMPILE_DATE ""
+#endif
+
+    printf(CompiledWith, COMPILER_NAME1, COMPILER_NAME2,
+           "\nWindows 9x / Windows NT", " (32-bit)", COMPILE_DATE);
+
+    return;
+
+} /* end function version_local() */
+#endif /* !WINDLL */
+
+
+/* --------------------------------------------------- */
+/* Large File Support
+ *
+ * Moved to Win32i64.c to avoid conflicts in same name functions
+ * in WiZ using UnZip and Zip libraries.
+ * 9/25/2003
+ */
+
+
+/* --------------------------------------------------- */
+/* Unicode Support for Win32
+ *
+ */
+
+#ifdef UNICODE_SUPPORT
+# if 0
+
+  /* get the wide command line and convert to argvw */
+  /* windows ignores argv and gets argvw separately */
+  zchar **get_wide_argv(argv)
+    char **argv;
+  {
+    int i;
+    int argc;
+    int size;
+    zchar **argvw = NULL;
+    zchar *commandline = NULL;
+    zchar **a = NULL;
+
+    commandline = GetCommandLineW();
+    a = CommandLineToArgvW(commandline, &argc);
+
+    if (a == NULL) {
+      /* failed */
+      ZIPERR(ZE_COMPERR, "get_wide_argv");
+    }
+
+    /* copy args so can use free_args() */
+    if ((argvw = (zchar **)malloc((argc + 1) * sizeof(zchar *))) == NULL) {
+      ZIPERR(ZE_MEM, "get_wide_argv");
+    }
+    for (i = 0; i < argc; i++) {
+      size = zstrlen(a[i]) + 1;
+      if ((argvw[i] = (zchar *)malloc(size * sizeof(zchar))) == NULL) {
+        ZIPERR(ZE_MEM, "get_wide_argv");
+      }
+      if ((argvw[i] = copy_zstring(a[i])) == NULL) {
+        ZIPERR(ZE_MEM, "get_wide_argv");
+      }
+    }
+    argvw[argc] = L'\0';
+
+    /* free original argvw */
+    LocalFree(a);
+
+    return argvw;
+  }
+# endif
+
+
+/* convert wide character string to multi-byte character string */
+/* win32 version */
+char *wide_to_local_string(wide_string)
+  zwchar *wide_string;
+{
+  int i;
+  wchar_t wc;
+  int bytes_char;
+  int default_used;
+  int wsize = 0;
+  int max_bytes = 9;
+  char buf[9];
+  char *buffer = NULL;
+  char *local_string = NULL;
+
+  if (wide_string == NULL)
+    return NULL;
+
+  for (wsize = 0; wide_string[wsize]; wsize++) ;
+
+  if (max_bytes < MB_CUR_MAX)
+    max_bytes = MB_CUR_MAX;
+
+  if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "wide_to_local_string");
+  }
+
+  /* convert it */
+  buffer[0] = '\0';
+  for (i = 0; i < wsize; i++) {
+    if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) {
+      /* wchar_t probably 2 bytes */
+      /* could do surrogates if state_dependent and wctomb can do */
+      wc = zwchar_to_wchar_t_default_char;
+    } else {
+      wc = (wchar_t)wide_string[i];
+    }
+    /* Unter some vendor's C-RTL, the Wide-to-MultiByte conversion functions
+     * (like wctomb() et. al.) do not use the same codepage as the other
+     * string arguments I/O functions (fopen, mkdir, rmdir etc.).
+     * Therefore, we have to fall back to the underlying Win32-API call to
+     * achieve a consistent behaviour for all supported compiler environments.
+     * Failing RTLs are for example:
+     *   Borland (locale uses OEM-CP as default, but I/O functions expect ANSI
+     *            names)
+     *   Watcom  (only "C" locale, wctomb() always uses OEM CP)
+     * (in other words: all supported environments except the Microsoft RTLs)
+     */
+    bytes_char = WideCharToMultiByte(
+                          CP_ACP, WC_COMPOSITECHECK,
+                          &wc, 1,
+                          (LPSTR)buf, sizeof(buf),
+                          NULL, &default_used);
+    if (default_used)
+      bytes_char = -1;
+    if (unicode_escape_all) {
+      if (bytes_char == 1 && (uch)buf[0] <= 0x7f) {
+        /* ASCII */
+        strncat(buffer, buf, 1);
+      } else {
+        /* use escape for wide character */
+        char *e = wide_char_to_escape_string(wide_string[i]);
+        strcat(buffer, e);
+        free(e);
+      }
+    } else if (bytes_char > 0) {
+      /* multi-byte char */
+      strncat(buffer, buf, bytes_char);
+    } else {
+      /* no MB for this wide */
+      if (use_wide_to_mb_default) {
+        /* default character */
+        strcat(buffer, wide_to_mb_default_string);
+      } else {
+        /* use escape for wide character */
+        char *e = wide_char_to_escape_string(wide_string[i]);
+        strcat(buffer, e);
+        free(e);
+      }
+    }
+  }
+  if ((local_string = (char *)realloc(buffer, strlen(buffer) + 1)) == NULL) {
+    free(buffer);
+    ZIPERR(ZE_MEM, "wide_to_local_string");
+  }
+
+  return local_string;
+}
+
+/* convert multi-byte character string to wide character string */
+/* win32 version */
+zwchar *local_to_wide_string(local_string)
+  char *local_string;
+{
+  int wsize;
+  wchar_t *wc_string;
+  zwchar *wide_string;
+
+  /* for now try to convert as string - fails if a bad char in string */
+  wsize = MultiByteToWideChar(CP_ACP, 0,
+                        local_string, -1, NULL, 0);
+  if (wsize == (size_t)-1) {
+    /* could not convert */
+    return NULL;
+  }
+
+  /* convert it */
+  if ((wc_string = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t))) == NULL) {
+    ZIPERR(ZE_MEM, "local_to_wide_string");
+  }
+  wsize = MultiByteToWideChar(CP_ACP, 0,
+           local_string, -1,
+           wc_string, wsize + 1);
+  wc_string[wsize] = (wchar_t) 0;
+
+  /* in case wchar_t is not zwchar */
+  if ((wide_string = (zwchar *)malloc((wsize + 1) * sizeof(zwchar))) == NULL) {
+    free(wc_string);
+    ZIPERR(ZE_MEM, "local_to_wide_string");
+  }
+  for (wsize = 0; (wide_string[wsize] = (zwchar)wc_string[wsize]); wsize++) ;
+  wide_string[wsize] = (zwchar)0;
+  free(wc_string);
+
+  return wide_string;
+}
+#endif /* UNICODE_SUPPORT */
+
+
+/*
+# if defined(UNICODE_SUPPORT) || defined(WIN32_OEM)
+*/
+/* convert oem to ansi character string */
+char *oem_to_local_string(local_string, oem_string)
+  char *local_string;
+  char *oem_string;
+{
+  /* convert OEM to ANSI character set */
+  OemToChar(oem_string, local_string);
+
+  return local_string;
+}
+/*
+# endif
+*/
+
+
+/*
+#if defined(UNICODE_SUPPORT) || defined(WIN32_OEM)
+*/
+/* convert local to oem character string */
+char *local_to_oem_string(oem_string, local_string)
+  char *oem_string;
+  char *local_string;
+{
+  /* convert to OEM display character set */
+  CharToOem(local_string, oem_string);
+  return oem_string;
+}
+/*
+#endif
+*/
+
diff --git a/win32/win32i64.c b/win32/win32i64.c
new file mode 100644 (file)
index 0000000..a07eb1a
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+  win32/win32i64.c - Zip 3
+
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2005-Feb-10 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+#include "../zip.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <time.h>
+#include <ctype.h>
+#include <windows.h>
+/* for LARGE_FILE_SUPPORT but may not be needed */
+#include <io.h>
+
+
+/* --------------------------------------------------- */
+/* Large File Support
+ *
+ * Initial functions by E. Gordon and R. Nausedat
+ * 9/10/2003
+ *
+ * These implement 64-bit file support for Windows.  The
+ * defines and headers are in win32/osdep.h.
+ *
+ * These moved from win32.c by Mike White to avoid conflicts
+ * in WiZ of same name functions in UnZip and Zip libraries.
+ * 9/25/04 EG
+ */
+
+#if defined(LARGE_FILE_SUPPORT) && !defined(__CYGWIN__)
+
+/* 64-bit buffered ftello
+ *
+ * Win32 does not provide a 64-bit buffered
+ * ftell (in the published api anyway) so below provides
+ * hopefully close version.
+ * We have not gotten _telli64 to work with buffered
+ * streams.  Below cheats by using fgetpos improperly and
+ * may not work on other ports.
+ */
+
+zoff_t zftello(stream)
+  FILE *stream;
+{
+  fpos_t fpos = 0;
+  
+  if (fgetpos(stream, &fpos) != 0) {
+    return -1L;
+  } else {
+    return fpos;
+  }
+}
+
+
+/* 64-bit buffered fseeko
+ *
+ * Win32 does not provide a 64-bit buffered
+ * fseeko so use _lseeki64 and fflush.  Note
+ * that SEEK_CUR can lose track of location
+ * if fflush is done between the last buffered
+ * io and this call.
+ */
+
+int zfseeko(stream, offset, origin)
+  FILE *stream;
+  zoff_t offset;
+  int origin;
+{
+  zoff_t location;
+
+  location = zftello(stream);
+  fflush(stream);
+  if (origin == SEEK_CUR) {
+    /* instead of synching up lseek easier just to figure and
+       use an absolute offset */
+    offset = location + offset;
+    location = _lseeki64(fileno(stream), offset, SEEK_SET);
+  } else {
+    location = _lseeki64(fileno(stream), offset, origin);
+  }
+  if (location == -1L) {
+    return -1L;
+  } else {
+    return 0;
+  }
+}
+#endif  /* Win32 LARGE_FILE_SUPPORT */
+
+#if 0
+FILE* zfopen(filename,mode)
+char *filename;
+char *mode;
+{
+FILE* fTemp;
+  
+  fTemp = fopen(filename,mode);
+  if( fTemp == NULL )
+    return NULL;
+  
+  /* sorry, could not make VC60 and its rtl work properly without setting the file buffer to NULL. the  */
+  /* problem seems to be _telli64 which seems to return the max stream position, comments are welcome   */
+  setbuf(fTemp,NULL);
+
+  return fTemp;
+}
+#endif
+/* --------------------------------------------------- */
diff --git a/win32/win32zip.c b/win32/win32zip.c
new file mode 100644 (file)
index 0000000..07c8886
--- /dev/null
@@ -0,0 +1,1980 @@
+/*
+  win32/win32zip.c - Zip 3
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef UTIL    /* this file contains nothing used by UTIL */
+
+#include "../zip.h"
+
+#include <ctype.h>
+#if !defined(__EMX__) && !defined(__CYGWIN__)
+#include <direct.h>     /* for rmdir() */
+#endif
+#include <time.h>
+
+#ifndef __BORLANDC__
+#include <sys/utime.h>
+#else
+#include <utime.h>
+#endif
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h> /* for findfirst/findnext stuff */
+#ifdef __RSXNT__
+#  include "../win32/rsxntwin.h"
+#endif
+
+#include <io.h>
+
+#define PAD           0
+#define PATH_END      '/'
+#define HIDD_SYS_BITS (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)
+
+
+#ifdef UNICODE_SUPPORT
+typedef struct zdirscanw {
+  HANDLE d_hFindFile;
+  int    d_first;
+  WIN32_FIND_DATAW d_fdw;
+} zDIRSCANW;
+#endif
+
+typedef struct zdirscan {
+  HANDLE d_hFindFile;
+  int    d_first;
+  WIN32_FIND_DATA d_fd;
+} zDIRSCAN;
+
+#define INVALID_WIN32_FILE_ATTRIBS ~0
+#ifdef UNICODE_SUPPORT
+#define GetDirAttribsW(d)   ((d)->d_fdw.dwFileAttributes)
+#endif
+#define GetDirAttribs(d)   ((d)->d_fd.dwFileAttributes)
+
+#include "../win32/win32zip.h"
+#include "../win32/nt.h"
+
+/* Local functions */
+local zDIRSCAN        * OpenDirScan      OF((ZCONST char *n));
+local struct zdirscan * GetNextDirEntry  OF((zDIRSCAN *d));
+local void              CloseDirScan     OF((zDIRSCAN *d));
+
+#ifdef UNICODE_SUPPORT
+local zDIRSCANW        * OpenDirScanW     OF((ZCONST wchar_t *wn));
+local struct zdirscanw * GetNextDirEntryW OF((zDIRSCANW *dw));
+local void               CloseDirScanW    OF((zDIRSCANW *dw));
+#endif
+
+local char           *readd        OF((zDIRSCAN *));
+#ifdef UNICODE_SUPPORT
+local wchar_t        *readdw       OF((zDIRSCANW *));
+#endif
+
+local int             wild_recurse OF((char *, char *));
+#ifdef UNICODE_SUPPORT
+local int             wild_recursew OF((wchar_t *, wchar_t *));
+#endif
+
+#ifdef NTSD_EAS
+   local void GetSD OF((char *path, char **bufptr, ush *size,
+                        char **cbufptr, ush *csize));
+#endif
+#ifdef USE_EF_UT_TIME
+   local int GetExtraTime OF((struct zlist far *z, iztimes *z_utim));
+#endif
+local int procname_win32 OF((char *n, int caseflag, DWORD attribs));
+#ifdef UNICODE_SUPPORT
+local int procname_win32w OF((wchar_t *n, int caseflag, DWORD attribs));
+#endif
+
+/* Module level variables */
+extern char *label /* = NULL */ ;       /* defined in fileio.c */
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Module level constants */
+local ZCONST char wild_match_all[] = "*.*";
+
+
+#ifdef UNICODE_SUPPORT
+
+local zDIRSCANW *OpenDirScanW(nw)
+ZCONST wchar_t *nw;          /* directory to open */
+/* Start searching for files in the MSDOS directory n */
+{
+  zDIRSCANW *dw;         /* malloc'd return value */
+  wchar_t *pw;              /* malloc'd temporary string */
+  wchar_t *qw;
+  size_t i;
+
+  if ((dw = (zDIRSCANW *)malloc(sizeof(zDIRSCANW))) == NULL) {
+    return NULL;
+  }
+
+  if ((pw = (wchar_t *)malloc(wcslen(nw) * sizeof(wchar_t) +
+      (2 + sizeof(wild_match_all)) * sizeof(wchar_t))) == NULL) {
+    if (dw != NULL) free((zvoid *)dw);
+    return NULL;
+  }
+  wcscpy(pw, nw);
+
+  qw = pw + wcslen(pw);
+  if ((qw - pw) > 0 && wcschr(pw, (wchar_t)':') == (qw - 1))
+      *qw++ = (wchar_t)'.';
+  if ((qw - pw) > 0 && wcschr(pw, (wchar_t)'/') != (qw - 1))
+    *qw++ = (wchar_t)'/';
+
+  for (i = 0; i < strlen(wild_match_all); i++) {
+    qw[i] = (wchar_t)wild_match_all[i];
+  }
+  qw[i] = (wchar_t)'\0';
+
+  dw->d_hFindFile = FindFirstFileW(pw, &dw->d_fdw);
+  free((zvoid *)pw);
+
+  if (dw->d_hFindFile == INVALID_HANDLE_VALUE)
+  {
+    free((zvoid *)dw);
+    return NULL;
+  }
+
+  dw->d_first = 1;
+  return dw;
+}
+
+#endif
+
+local zDIRSCAN *OpenDirScan(n)
+ZCONST char *n;          /* directory to open */
+/* Start searching for files in the MSDOS directory n */
+{
+  zDIRSCAN *d;          /* malloc'd return value */
+  char *p;              /* malloc'd temporary string */
+  char *q;
+
+  if ((d = (zDIRSCAN *)malloc(sizeof(zDIRSCAN))) == NULL ||
+      (p = malloc(strlen(n) + (2 + sizeof(wild_match_all)))) == NULL) {
+    if (d != NULL) free((zvoid *)d);
+    return NULL;
+  }
+  strcpy(p, n);
+  q = p + strlen(p);
+  if ((q - p) > 0 && MBSRCHR(p, ':') == (q - 1))
+      *q++ = '.';
+  if ((q - p) > 0 && MBSRCHR(p, '/') != (q - 1))
+    *q++ = '/';
+  strcpy(q, wild_match_all);
+
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+  OemToAnsi(p, p);
+#endif
+  d->d_hFindFile = FindFirstFile(p, &d->d_fd);
+  free((zvoid *)p);
+
+  if (d->d_hFindFile == INVALID_HANDLE_VALUE)
+  {
+    free((zvoid *)d);
+    return NULL;
+  }
+
+  d->d_first = 1;
+  return d;
+}
+
+
+#ifdef UNICODE_SUPPORT
+
+local struct zdirscanw *GetNextDirEntryW(dw)
+zDIRSCANW *dw;            /* directory stream to read from */
+/* Return pointer to first or next directory entry, or NULL if end. */
+{
+  if (dw->d_first)
+    dw->d_first = 0;
+  else
+  {
+    if (!FindNextFileW(dw->d_hFindFile, &dw->d_fdw))
+        return NULL;
+  }
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+  CharToOemW(dw->d_fdw.cFileName, dw->d_fdw.cFileName);
+#endif
+  return (struct zdirscanw *)dw;
+}
+
+#endif
+
+local struct zdirscan *GetNextDirEntry(d)
+zDIRSCAN *d;            /* directory stream to read from */
+/* Return pointer to first or next directory entry, or NULL if end. */
+{
+  if (d->d_first)
+    d->d_first = 0;
+  else
+  {
+    if (!FindNextFile(d->d_hFindFile, &d->d_fd))
+        return NULL;
+  }
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+  AnsiToOem(d->d_fd.cFileName, d->d_fd.cFileName);
+#endif
+  return (struct zdirscan *)d;
+}
+
+local void CloseDirScan(d)
+zDIRSCAN *d;            /* directory stream to close */
+{
+  FindClose(d->d_hFindFile);
+  free((zvoid *)d);
+}
+
+#ifdef UNICODE_SUPPORT
+
+local void CloseDirScanW(dw)
+zDIRSCANW *dw;         /* directory stream to close */
+{
+  FindClose(dw->d_hFindFile);
+  free((zvoid *)dw);
+}
+
+#endif
+
+
+#ifdef UNICODE_SUPPORT
+
+local wchar_t *readdw(dw)
+  zDIRSCANW *dw;         /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream dw, or NULL if
+   no more entries or an error occurs. */
+{
+  struct zdirscanw *ew;
+
+  do
+    ew = GetNextDirEntryW(dw);
+  while (ew &&
+         ((!hidden_files && ew->d_fdw.dwFileAttributes & HIDD_SYS_BITS) ||
+          (only_archive_set &&
+           !(ew->d_fdw.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) &&
+           !(ew->d_fdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))));
+  if (ew == NULL)
+    return (wchar_t *) NULL;
+  return ew->d_fdw.cFileName;
+}
+
+#endif
+
+local char *readd(d)
+zDIRSCAN *d;            /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+   no more entries or an error occurs. */
+{
+  struct zdirscan *e;
+
+  do
+    e = GetNextDirEntry(d);
+  while (e &&
+         ((!hidden_files && e->d_fd.dwFileAttributes & HIDD_SYS_BITS) ||
+          (only_archive_set &&
+           !(e->d_fd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) &&
+           !(e->d_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))));
+  /* When a wide character that is not supported by the current character
+     set is found, FindFirstFile and FindNextFile return a "?" in that spot.
+     A question mark is illegal in file names, so this flags that something
+     needs to be done.  It seems the fix is to use the 8.3 name in
+     this case, as that allows directory scans to continue.
+   */
+  if (e == NULL)
+    return (char *) NULL;
+  if (strchr(e->d_fd.cFileName, '?') && e->d_fd.cAlternateFileName) {
+    /* Have '?' in name, assume wide character we can't handle is in
+       the name and use short name if there is one.
+    */
+    return e->d_fd.cAlternateFileName;
+  }
+  return e->d_fd.cFileName;
+}
+
+
+#if 0
+/* scan for the file in p and return Windows long name */
+char *get_win32_longpath(p, n)
+  char *p;               /* path to get short name path for */
+  char **n;              /* pointer to name in returned path */
+{
+  char  *q;              /* return string */
+  char  *c;
+  int    is_dir = 0;
+  char  *f;
+  char  *fp;
+  int    nr;
+  int    fplen;
+  int    fplen2;
+  HANDLE d_hFindFile;
+  WIN32_FIND_DATA d_fd;
+  int slashes = 0;
+  int returnslashes = 0;
+
+  if (p == NULL)
+    return NULL;
+
+  /* count path components */
+  for (f = p; *f; f++) {
+    if (*f == '/' || *f == '\\') {
+      slashes++;
+    }
+  }
+  /* Ignore trailing slash */
+  if (*p && (*(f - 1) == '/' || *(f - 1) == '\\'))
+    slashes--;
+
+  /* get the length of the full path */
+  fplen = GetFullPathName(p, 0, NULL, NULL);
+
+  if ((fp = malloc(fplen + 1)) == NULL) {
+    return NULL;
+  }
+  /* get full path */
+  fplen2 = GetFullPathName(p, fplen, fp, &f);
+  if (fplen2 > fplen) {
+    /* something changed */
+    free(fp);
+    return NULL;
+  }
+  c = fp + strlen(fp) - 1;
+  if (*c == '\\' || *c == '/') {
+    is_dir = 1;
+    *c = '\0';
+  }
+
+  d_hFindFile = FindFirstFile(fp, &d_fd);
+  free(fp);
+
+  if (d_hFindFile == INVALID_HANDLE_VALUE)
+  {
+    return NULL;
+  }
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+  AnsiToOem(d->d_fd.cFileName, d->d_fd.cFileName);
+#endif
+
+  FindClose(d_hFindFile);
+
+  if (d_fd.cFileName == NULL) {
+    return NULL;
+  }
+
+  /* get the length of the full path */
+  fplen = GetFullPathName(d_fd.cFileName, 0, NULL, NULL);
+
+  if ((fp = malloc(fplen + 1)) == NULL) {
+    return NULL;
+  }
+  /* get full path */
+  fplen2 = GetFullPathName(d_fd.cFileName, fplen, fp, &f);
+  if (fplen2 > fplen) {
+    /* something changed */
+    free(fp);
+    return NULL;
+  }
+
+  /* characters from end to start of last component */
+  nr = 0;
+
+  /* find start of relative path we came in with */
+  for (f = fp + strlen(fp); f != fp; f--) {
+    if (*f == ':')
+      break;
+    if (*f == '/' || *f == '\\') {
+      returnslashes++;
+      /* convert \ to / */
+      *f = '/';
+      if (nr == 0)
+        /* first slash from end */
+        nr = strlen(fp) - (f - fp);
+      if (returnslashes > slashes)
+        break;
+    }
+    if (*f == '\\' && *(f + 1) == '\\')
+      break;
+  }
+  if (f != fp)
+    /* on slash in middle */
+    f++;
+
+  if ((q = malloc(strlen(f) + 2)) == NULL) {
+    return NULL;
+  }
+  strcpy(q, f);
+  *n = q + (strlen(q) - nr + 1);
+  if (is_dir) {
+    strcat(q, "/");
+  }
+  free(fp);
+
+  return q;
+}
+#endif
+
+
+#if 0
+/* scan for the file in p and return Windows UTF-8 name */
+char *get_win32_utf8path(p)
+  char *p;               /* path to get utf-8 name for */
+{
+  char     *q;           /* return string */
+  char     *r = NULL;
+  int       is_dir = 0;
+  char     *f;
+  char     *fcp;
+  char     *fp;
+  wchar_t  *qw;
+  char     *lastc = '\0';
+  int       fplen;
+  int       fplen2;
+  int       ulen;
+  int       ulenw;
+  HANDLE    d_hFindFile;
+  WIN32_FIND_DATAW d_fd;
+  int pathslashes = 0;
+  int componentslashes = 0;
+  int slashes = 0;
+
+  if (p == NULL)
+    return NULL;
+
+  /* count path components */
+  for (f = p; *f; PREINCSTR(f)) {
+    if (*f == '/' || *f == '\\') {
+      slashes++;
+    }
+    lastc = f;
+  }
+  /* do not count trailing / */
+  if (*lastc == '/' || *lastc == '\\') {
+    is_dir = 1;
+    slashes--;
+  }
+
+  /* Get the short path (as a bad long path could cause FindFirstFile to fail) */
+
+  /* get the length of the short path */
+  fplen = GetShortPathName(p, NULL, 0);
+
+  if ((fp = malloc(fplen + 1)) == NULL) {
+    return NULL;
+  }
+  /* get short path */
+  fplen2 = GetShortPathName(p, fp, fplen);
+  if (fplen2 > fplen) {
+    /* something changed */
+    free(fp);
+    return NULL;
+  }
+
+  for (pathslashes = 0; pathslashes <= slashes; pathslashes++)
+  {
+
+    /* get component path */
+    if ((fcp = malloc(fplen + 1)) == NULL) {
+      return NULL;
+    }
+    strcpy(fcp, fp);
+    componentslashes = 0;
+    for (f = fcp; *f; PREINCSTR(f)) {
+      if (*f == '/' || *f == '\\') {
+        componentslashes++;
+        if (componentslashes > pathslashes)
+          break;
+      }
+      lastc = f;
+    }
+    *f = '\0';
+
+
+    /* Get information for the file, including wide path */
+
+    /* get length */
+    ulenw = MultiByteToWideChar(
+                CP_ACP,            /* ANSI code page */
+                0,                 /* flags for character-type options */
+                fcp,               /* string to convert */
+                -1,                /* string length (-1 = NULL terminated) */
+                NULL,              /* buffer */
+                0 );               /* buffer length (0 = return length) */
+    if (ulenw == 0) {
+      /* failed */
+      free(fcp);
+      free(fp);
+      return NULL;
+    }
+    ulenw++;
+    /* get length in bytes */
+    ulen = sizeof(wchar_t) * (ulenw + 1);
+    if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
+      free(fcp);
+      free(fp);
+      return NULL;
+    }
+    /* convert multibyte to wide */
+    ulen = MultiByteToWideChar(
+               CP_ACP,            /* ANSI code page */
+               0,                 /* flags for character-type options */
+               fcp,               /* string to convert */
+               -1,                /* string length (-1 = NULL terminated) */
+               qw,                /* buffer */
+               ulenw);            /* buffer length (0 = return length) */
+    if (ulen == 0) {
+      /* failed */
+      free(qw);
+      free(fcp);
+      free(fp);
+      return 0;
+    }
+
+    d_hFindFile = FindFirstFileW(qw, &d_fd);
+    /* If this Win32 platform does not support Unicode wide paths
+       this returns INVALID_HANDLE_VALUE and the OS error is
+       "No such file or directory".  We return NULL and go with
+       the UTF-8 version of z->iname in f->uname.
+     */
+    free(qw);
+    free(fcp);
+    FindClose(d_hFindFile);
+
+    if (d_hFindFile == INVALID_HANDLE_VALUE)
+    {
+      return NULL;
+    }
+
+    /* Get buffer length */
+    ulen = WideCharToMultiByte(
+                    CP_UTF8,        /* UTF-8 code page */
+                    0,              /* flags */
+                    d_fd.cFileName, /* string to convert */
+                    -1,             /* input chars (-1 = NULL terminated) */
+                    NULL,           /* buffer */
+                    0,              /* size of buffer (0 = return needed size) */
+                    NULL,           /* default char */
+                    NULL);          /* used default char */
+    if (ulen == 0) {
+      /* failed */
+      return NULL;
+    }
+    ulen += 2;
+    if ((q = malloc(ulen + 1)) == NULL) {
+      return NULL;
+    }
+
+    /* Convert the Unicode string to UTF-8 */
+    if ((ulen = WideCharToMultiByte(
+                    CP_UTF8,        /* UTF-8 code page */
+                    0,              /* flags */
+                    d_fd.cFileName, /* string to convert */
+                    -1,             /* input chars (-1 = NULL terminated) */
+                    q,              /* buffer */
+                    ulen,           /* size of buffer (0 = return needed size) */
+                    NULL,           /* default char */
+                    NULL)) == 0)    /* used default char */
+    {
+      free(fp);
+      free(q);
+      return NULL;
+    }
+
+    if (r == NULL) {
+      /* first one */
+      r = q;
+    } else {
+      if ((r = realloc(r, strlen(r) + strlen(q) + 3)) == NULL) {
+        free(fp);
+        free(q);
+        return NULL;
+      }
+      strcat(r, "/");
+      strcat(r, q);
+      free(q);
+    }
+  }
+
+  free(fp);
+
+  if (is_dir) {
+    strcat(r, "/");
+  }
+
+  return r;
+}
+#endif
+
+
+#define ONENAMELEN 255
+
+/* whole is a pathname with wildcards, wildtail points somewhere in the  */
+/* middle of it.  All wildcards to be expanded must come AFTER wildtail. */
+
+
+#ifdef UNICODE_SUPPORT
+
+wchar_t *local_to_wchar_string(local_string)
+  char *local_string;       /* path to get utf-8 name for */
+{
+  wchar_t  *qw;
+  int       ulen;
+  int       ulenw;
+
+  if (local_string == NULL)
+    return NULL;
+
+    /* get length */
+    ulenw = MultiByteToWideChar(
+                CP_ACP,            /* ANSI code page */
+                0,                 /* flags for character-type options */
+                local_string,      /* string to convert */
+                -1,                /* string length (-1 = NULL terminated) */
+                NULL,              /* buffer */
+                0 );               /* buffer length (0 = return length) */
+    if (ulenw == 0) {
+      /* failed */
+      return NULL;
+    }
+    ulenw++;
+    /* get length in bytes */
+    ulen = sizeof(wchar_t) * (ulenw + 1);
+    if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
+      return NULL;
+    }
+    /* convert multibyte to wide */
+    ulen = MultiByteToWideChar(
+               CP_ACP,            /* ANSI code page */
+               0,                 /* flags for character-type options */
+               local_string,      /* string to convert */
+               -1,                /* string length (-1 = NULL terminated) */
+               qw,                /* buffer */
+               ulenw);            /* buffer length (0 = return length) */
+    if (ulen == 0) {
+      /* failed */
+      free(qw);
+      return NULL;
+    }
+
+  return qw;
+}
+
+
+wchar_t *utf8_to_wchar_string(utf8_string)
+  char *utf8_string;       /* path to get utf-8 name for */
+{
+  wchar_t  *qw;
+  int       ulen;
+  int       ulenw;
+
+  if (utf8_string == NULL)
+    return NULL;
+
+    /* get length */
+    ulenw = MultiByteToWideChar(
+                CP_UTF8,           /* UTF-8 code page */
+                0,                 /* flags for character-type options */
+                utf8_string,       /* string to convert */
+                -1,                /* string length (-1 = NULL terminated) */
+                NULL,              /* buffer */
+                0 );               /* buffer length (0 = return length) */
+    if (ulenw == 0) {
+      /* failed */
+      return NULL;
+    }
+    ulenw++;
+    /* get length in bytes */
+    ulen = sizeof(wchar_t) * (ulenw + 1);
+    if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
+      return NULL;
+    }
+    /* convert multibyte to wide */
+    ulen = MultiByteToWideChar(
+               CP_UTF8,           /* UTF-8 code page */
+               0,                 /* flags for character-type options */
+               utf8_string,       /* string to convert */
+               -1,                /* string length (-1 = NULL terminated) */
+               qw,                /* buffer */
+               ulenw);            /* buffer length (0 = return length) */
+    if (ulen == 0) {
+      /* failed */
+      free(qw);
+      return NULL;
+    }
+
+  return qw;
+}
+
+
+
+/* Convert wchar_t string to utf8 using Windows calls
+   so any characters needing more than one wchar_t are
+   are handled by Windows */
+char *wchar_to_utf8_string(wstring)
+  wchar_t *wstring;
+{
+  char     *q;           /* return string */
+  int       ulen;
+
+  if (wstring == NULL)
+    return NULL;
+
+  /* Get buffer length */
+  ulen = WideCharToMultiByte(
+                  CP_UTF8,        /* UTF-8 code page */
+                  0,              /* flags */
+                  wstring,        /* string to convert */
+                  -1,             /* input chars (-1 = NULL terminated) */
+                  NULL,           /* buffer */
+                  0,              /* size of buffer (0 = return needed size) */
+                  NULL,           /* default char */
+                  NULL);          /* used default char */
+  if (ulen == 0) {
+    /* failed */
+    return NULL;
+  }
+  ulen += 2;
+  if ((q = malloc(ulen + 1)) == NULL) {
+    return NULL;
+  }
+
+  /* Convert the Unicode string to UTF-8 */
+  if ((ulen = WideCharToMultiByte(
+                  CP_UTF8,        /* UTF-8 code page */
+                  0,              /* flags */
+                  wstring,        /* string to convert */
+                  -1,             /* input chars (-1 = NULL terminated) */
+                  q,              /* buffer */
+                  ulen,           /* size of buffer (0 = return needed size) */
+                  NULL,           /* default char */
+                  NULL)) == 0)    /* used default char */
+  {
+    free(q);
+    return NULL;
+  }
+
+  return q;
+}
+
+
+local int wild_recursew(whole, wildtail)
+  wchar_t *whole;
+  wchar_t *wildtail;
+{
+    zDIRSCANW *dirw;
+    wchar_t *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
+    extent newlen;
+    int amatch = 0, e = ZE_MISS;
+
+    if (!isshexpw(wildtail)) {
+        if (GetFileAttributesW(whole) != 0xFFFFFFFF) {    /* file exists? */
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+            CharToOemW(whole, whole);
+#endif
+            return procnamew(whole, 0);
+        }
+        else
+            return ZE_MISS;                     /* woops, no wildcards! */
+    }
+
+    /* back up thru path components till existing dir found */
+    do {
+        name = wildtail + wcslen(wildtail) - 1;
+        for (;;)
+            if (name-- <= wildtail || *name == PATH_END) {
+                subwild = name + 1;
+                plug2 = *subwild;
+                *subwild = 0;
+                break;
+            }
+        if (glue)
+            *glue = plug;
+        glue = subwild;
+        plug = plug2;
+        dirw = OpenDirScanW(whole);
+    } while (!dirw && subwild > wildtail);
+    wildtail = subwild;                 /* skip past non-wild components */
+
+    if ((subwild = wcschr(wildtail + 1, PATH_END)) != NULL) {
+        /* this "+ 1" dodges the   ^^^ hole left by *glue == 0 */
+        *(subwild++) = 0;               /* wildtail = one component pattern */
+        newlen = wcslen(whole) + wcslen(subwild) + (ONENAMELEN + 2);
+    } else
+        newlen = wcslen(whole) + (ONENAMELEN + 1);
+    if (!dirw || ((newwhole = malloc(newlen * sizeof(wchar_t))) == NULL)) {
+        if (glue)
+            *glue = plug;
+        e = dirw ? ZE_MEM : ZE_MISS;
+        goto ohforgetit;
+    }
+    wcscpy(newwhole, whole);
+    newlen = wcslen(newwhole);
+    if (glue)
+        *glue = plug;                           /* repair damage to whole */
+    if (!isshexpw(wildtail)) {
+        e = ZE_MISS;                            /* non-wild name not found */
+        goto ohforgetit;
+    }
+
+    while ((name = readdw(dirw)) != NULL) {
+        if (wcscmp(name, L".") && wcscmp(name, L"..") &&
+            MATCHW(wildtail, name, 0)) {
+            wcscpy(newwhole + newlen, name);
+            if (subwild) {
+                name = newwhole + wcslen(newwhole);
+                *(name++) = (wchar_t)PATH_END;
+                wcscpy(name, subwild);
+                e = wild_recursew(newwhole, name);
+            } else
+                e = procname_win32w(newwhole, 0, GetDirAttribsW(dirw));
+            newwhole[newlen] = 0;
+            if (e == ZE_OK)
+                amatch = 1;
+            else if (e != ZE_MISS)
+                break;
+        }
+    }
+
+  ohforgetit:
+    if (dirw) CloseDirScanW(dirw);
+    if (subwild) *--subwild = PATH_END;
+    if (newwhole) free(newwhole);
+    if (e == ZE_MISS && amatch)
+        e = ZE_OK;
+    return e;
+}
+
+#endif
+
+
+local int wild_recurse(whole, wildtail)
+  char *whole;
+  char *wildtail;
+{
+    zDIRSCAN *dir;
+    char *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
+    extent newlen;
+    int amatch = 0, e = ZE_MISS;
+
+    if (!isshexp(wildtail)) {
+        if (GetFileAttributes(whole) != 0xFFFFFFFF) {    /* file exists? */
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+            AnsiToOem(whole, whole);
+#endif
+            return procname(whole, 0);
+        }
+        else
+            return ZE_MISS;                     /* woops, no wildcards! */
+    }
+
+    /* back up thru path components till existing dir found */
+    do {
+        name = wildtail + strlen(wildtail) - 1;
+        for (;;)
+            if (name-- <= wildtail || *name == PATH_END) {
+                subwild = name + 1;
+                plug2 = *subwild;
+                *subwild = 0;
+                break;
+            }
+        if (glue)
+            *glue = plug;
+        glue = subwild;
+        plug = plug2;
+        dir = OpenDirScan(whole);
+    } while (!dir && subwild > wildtail);
+    wildtail = subwild;                 /* skip past non-wild components */
+
+    if ((subwild = MBSCHR(wildtail + 1, PATH_END)) != NULL) {
+        /* this "+ 1" dodges the   ^^^ hole left by *glue == 0 */
+        *(subwild++) = 0;               /* wildtail = one component pattern */
+        newlen = strlen(whole) + strlen(subwild) + (ONENAMELEN + 2);
+    } else
+        newlen = strlen(whole) + (ONENAMELEN + 1);
+    if (!dir || ((newwhole = malloc(newlen)) == NULL)) {
+        if (glue)
+            *glue = plug;
+        e = dir ? ZE_MEM : ZE_MISS;
+        goto ohforgetit;
+    }
+    strcpy(newwhole, whole);
+    newlen = strlen(newwhole);
+    if (glue)
+        *glue = plug;                           /* repair damage to whole */
+    if (!isshexp(wildtail)) {
+        e = ZE_MISS;                            /* non-wild name not found */
+        goto ohforgetit;
+    }
+
+    while ((name = readd(dir)) != NULL) {
+        if (strcmp(name, ".") && strcmp(name, "..") &&
+            MATCH(wildtail, name, 0)) {
+            strcpy(newwhole + newlen, name);
+            if (subwild) {
+                name = newwhole + strlen(newwhole);
+                *(name++) = PATH_END;
+                strcpy(name, subwild);
+                e = wild_recurse(newwhole, name);
+            } else
+                e = procname_win32(newwhole, 0, GetDirAttribs(dir));
+            newwhole[newlen] = 0;
+            if (e == ZE_OK)
+                amatch = 1;
+            else if (e != ZE_MISS)
+                break;
+        }
+    }
+
+  ohforgetit:
+    if (dir) CloseDirScan(dir);
+    if (subwild) *--subwild = PATH_END;
+    if (newwhole) free(newwhole);
+    if (e == ZE_MISS && amatch)
+        e = ZE_OK;
+    return e;
+}
+
+
+#ifdef UNICODE_SUPPORT
+int has_win32_wide() {
+  DWORD r;
+
+  /* test if we have wide function support */
+
+  /* check if already set */
+  if (no_win32_wide != -1)
+    return !no_win32_wide;
+
+  /* assume we don't */
+  no_win32_wide = 1;
+
+  /* get attributes for this directory */
+  r = GetFileAttributes(".");
+
+  /* r should be 16 = FILE_ATTRIBUTE_DIRECTORY */
+  if (r == FILE_ATTRIBUTE_DIRECTORY) {
+    /* now see if it works for the wide version */
+    r = GetFileAttributesW(L".");
+    /* if this fails then we probably don't have wide functions */
+    if (r == 0xFFFFFFFF) {
+      /* error is probably "This function is only valid in Win32 mode." */
+    } else if (r == FILE_ATTRIBUTE_DIRECTORY) {
+      /* worked, so assume we have wide support */
+      no_win32_wide = 0;
+    }
+  }
+
+  return !no_win32_wide;
+}
+#endif
+
+
+int wild(w)
+  char *w;               /* path/pattern to match */
+/* If not in exclude mode, expand the pattern based on the contents of the
+   file system.  Return an error code in the ZE_ class. */
+{
+    char *p;             /* path */
+    char *q;             /* diskless path */
+    int e;               /* result */
+#ifdef UNICODE_SUPPORT
+    wchar_t *pw;         /* wide path */
+    wchar_t *qw;         /* wide diskless path */
+#endif
+
+    if (volume_label == 1) {
+      volume_label = 2;
+      label = getVolumeLabel((w != NULL && isascii((uch)w[0]) && w[1] == ':')
+                             ? to_up(w[0]) : '\0',
+                             &label_time, &label_mode, &label_utim);
+      if (label != NULL)
+        (void)newname(label, 0, 0);
+      if (w == NULL || (isascii((uch)w[0]) && w[1] == ':' && w[2] == '\0'))
+        return ZE_OK;
+      /* "zip -$ foo a:" can be used to force drive name */
+    }
+    /* special handling of stdin request */
+    if (strcmp(w, "-") == 0)   /* if compressing stdin */
+        return newname(w, 0, 0);
+
+    /* Allocate and copy pattern, leaving room to add "." if needed */
+    if ((p = malloc(strlen(w) + 2)) == NULL)
+        return ZE_MEM;
+    strcpy(p, w);
+
+    /* Normalize path delimiter as '/' */
+    for (q = p; *q; INCSTR(q))            /* use / consistently */
+        if (*q == '\\')
+            *q = '/';
+
+#ifdef UNICODE_SUPPORT
+    if (!no_win32_wide) {
+      /* wide char version */
+      pw = local_to_wchar_string(p);
+
+      /* Separate the disk part of the path */
+      if ((qw = wcschr(pw, ':')) != NULL) {
+          if (wcschr(++qw, ':'))     /* sanity check for safety of wild_recurse */
+              return ZE_MISS;
+      } else
+          qw = pw;
+
+      /* Normalize bare disk names */
+      if (qw > pw && !*qw)
+          wcscpy(qw, L".");
+    } else {
+      /* multibyte version */
+      /* Separate the disk part of the path */
+      if ((q = MBSCHR(p, ':')) != NULL) {
+          if (MBSCHR(++q, ':'))     /* sanity check for safety of wild_recurse */
+              return ZE_MISS;
+      } else
+          q = p;
+
+      /* Normalize bare disk names */
+      if (q > p && !*q)
+          strcpy(q, ".");
+    }
+#else
+    /* multibyte version */
+    /* Separate the disk part of the path */
+    if ((q = MBSCHR(p, ':')) != NULL) {
+        if (MBSCHR(++q, ':'))     /* sanity check for safety of wild_recurse */
+            return ZE_MISS;
+    } else
+        q = p;
+
+    /* Normalize bare disk names */
+    if (q > p && !*q)
+        strcpy(q, ".");
+#endif
+
+    /* Here we go */
+#ifdef UNICODE_SUPPORT
+    if (!no_win32_wide) {
+      /* use wide Unicode directory scan */
+      e = wild_recursew(pw, qw);
+
+      free(pw);
+    } else {
+      /* use multibyte directory scan */
+      e = wild_recurse(p, q);
+    }
+#else
+    e = wild_recurse(p, q);
+#endif
+    free((zvoid *)p);
+    return e;
+}
+
+
+local int procname_win32(n, caseflag, attribs)
+  char *n;                /* name to process */
+  int caseflag;           /* true to force case-sensitive match */
+  DWORD attribs;
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  char *a;              /* path and name for recursion */
+  zDIRSCAN *d;          /* directory stream from OpenDirScan() */
+  char *e;              /* pointer to name from readd() */
+  int m;                /* matched flag */
+  char *p;              /* path for recursion */
+  z_stat s;             /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (strcmp(n, "-") == 0)   /* if compressing stdin */
+    return newname(n, 0, caseflag);
+  else if (attribs != INVALID_WIN32_FILE_ATTRIBS)
+  {
+    /* Avoid calling stat() for performance reasons when it is already known
+       (from a previous directory scan) that the passed name corresponds to
+       a "real existing" file.  The only information needed further down in
+       this function is the distinction between directory entries and other
+       (typically normal file) entries.  This distinction can be derived from
+       the file's attributes that the directory lookup has already provided
+       "for free".
+     */
+    s.st_mode = ((attribs & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR : S_IFREG);
+  }
+  else if (LSSTAT(n, &s)
+#ifdef __TURBOC__
+           /* For this compiler, stat() succeeds on wild card names! */
+           /* Unfortunately, this causes failure on names containing */
+           /* square bracket characters, which are legal in win32.   */
+           || isshexp(n)
+#endif
+          )
+  {
+#ifdef UNICODE_SUPPORT
+    char *uname = NULL;
+#endif
+    /* Not a file or directory--search for shell expression in zip file */
+    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCH(p, z->iname, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->oname);
+        m = 0;
+      }
+    }
+#ifdef UNICODE_SUPPORT
+    /* also check escaped Unicode names */
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (z->zuname) {
+#ifdef WIN32
+        /* It seems something is lost in going from a listed
+           name from zip -su in a console window to using that
+           name in a command line.  This kluge may fix it
+           and just takes zuname, converts to oem (i.e.ouname),
+           then converts it back which ends up not the same as
+           started with.
+         */
+        uname = z->wuname;
+#else
+        uname = z->zuname;
+#endif
+        if (MATCH(p, uname, caseflag))
+        {
+          z->mark = pcount ? filter(uname, caseflag) : 1;
+          if (verbose) {
+              fprintf(mesg, "zip diagnostic: %scluding %s\n",
+                 z->mark ? "in" : "ex", z->oname);
+              fprintf(mesg, "     Escaped Unicode:  %s\n",
+                 z->ouname);
+          }
+          m = 0;
+        }
+      }
+    }
+#endif
+    free((zvoid *)p);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  for (p = n; *p; INCSTR(p))    /* use / consistently */
+    if (*p == '\\')
+      *p = '/';
+  if ((s.st_mode & S_IFDIR) == 0)
+  {
+    /* add exclusions in directory recurse but ignored for single file */
+    DWORD dwAttr;
+
+    dwAttr = GetFileMode(n);
+
+    if ((hidden_files ||
+         !(dwAttr & FILE_ATTRIBUTE_HIDDEN || dwAttr & FILE_ATTRIBUTE_SYSTEM)) &&
+        (!only_archive_set || (dwAttr & FILE_ATTRIBUTE_ARCHIVE)))
+    {
+      /* add or remove name of file */
+      if ((m = newname(n, 0, caseflag)) != ZE_OK)
+        return m;
+    }
+  } else {
+    /* Add trailing / to the directory name */
+    if ((p = (char *) malloc(strlen(n)+2)) == NULL)
+      return ZE_MEM;
+    if (strcmp(n, ".") == 0 || strcmp(n, "/.") == 0) {
+      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      strcpy(p, n);
+      a = p + strlen(p);
+      if (lastchar(p) != '/')
+        strcpy(a, "/");
+      if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+        free((zvoid *)p);
+        return m;
+      }
+    }
+    /* recurse into directory */
+    if (recurse && (d = OpenDirScan(n)) != NULL)
+    {
+      while ((e = readd(d)) != NULL) {
+        if (strcmp(e, ".") && strcmp(e, ".."))
+        {
+          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+          {
+            CloseDirScan(d);
+            free((zvoid *)p);
+            return ZE_MEM;
+          }
+          strcat(strcpy(a, p), e);
+          if ((m = procname_win32(a, caseflag, GetDirAttribs(d)))
+              != ZE_OK)         /* recurse on name */
+          {
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", a);
+            else
+              ziperr(m, a);
+          }
+          free((zvoid *)a);
+        }
+      }
+      CloseDirScan(d);
+    }
+    free((zvoid *)p);
+  } /* (s.st_mode & S_IFDIR) == 0) */
+  return ZE_OK;
+}
+
+
+#ifdef UNICODE_SUPPORT
+local int procname_win32w(nw, caseflag, attribs)
+  wchar_t *nw;             /* name to process */
+  int caseflag;           /* true to force case-sensitive match */
+  DWORD attribs;
+/* Process a name or sh expression to operate on (or exclude).  Return
+   an error code in the ZE_ class. */
+{
+  wchar_t *aw;          /* path and name for recursion */
+  zDIRSCANW *dw;        /* directory stream from OpenDirScan() */
+  wchar_t *ew;          /* pointer to name from readd() */
+  int m;                /* matched flag */
+  wchar_t *pw;          /* path for recursion */
+  zw_stat s;            /* result of stat() */
+  struct zlist far *z;  /* steps through zfiles list */
+
+  if (wcscmp(nw, L"-") == 0)   /* if compressing stdin */
+    return newnamew(nw, 0, caseflag);
+  else if (attribs != INVALID_WIN32_FILE_ATTRIBS)
+  {
+    /* Avoid calling stat() for performance reasons when it is already known
+       (from a previous directory scan) that the passed name corresponds to
+       a "real existing" file.  The only information needed further down in
+       this function is the distinction between directory entries and other
+       (typically normal file) entries.  This distinction can be derived from
+       the file's attributes that the directory lookup has already provided
+       "for free".
+     */
+    s.st_mode = ((attribs & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR : S_IFREG);
+  }
+  else if (LSSTATW(nw, &s)
+#ifdef __TURBOC__
+           /* For this compiler, stat() succeeds on wild card names! */
+           /* Unfortunately, this causes failure on names containing */
+           /* square bracket characters, which are legal in win32.   */
+           || isshexpw(nw)
+#endif
+          )
+  {
+    wchar_t *unamew = NULL;
+    /* Not a file or directory--search for shell expression in zip file */
+    pw = ex2inw(nw, 0, (int *)NULL);     /* shouldn't affect matching chars */
+    m = 1;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (MATCHW(pw, z->znamew, caseflag))
+      {
+        z->mark = pcount ? filter(z->zname, caseflag) : 1;
+        if (verbose)
+            fprintf(mesg, "zip diagnostic: %scluding %s\n",
+               z->mark ? "in" : "ex", z->oname);
+        m = 0;
+      }
+    }
+    /* also check escaped Unicode names */
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (z->zuname) {
+        unamew = z->znamew;
+        if (MATCHW(pw, unamew, caseflag))
+        {
+          z->mark = pcount ? filter(z->iname, caseflag) : 1;
+          if (verbose) {
+              fprintf(mesg, "zip diagnostic: %scluding %s\n",
+                 z->mark ? "in" : "ex", z->oname);
+              fprintf(mesg, "     Escaped Unicode:  %s\n",
+                 z->ouname);
+          }
+          m = 0;
+        }
+      }
+    }
+    free((zvoid *)pw);
+    return m ? ZE_MISS : ZE_OK;
+  }
+
+  /* Live name--use if file, recurse if directory */
+  for (pw = nw; *pw; pw++)    /* use / consistently */
+    if (*pw == (wchar_t)'\\')
+      *pw = (wchar_t)'/';
+  if ((s.st_mode & S_IFDIR) == 0)
+  {
+    /* add exclusions in directory recurse but ignored for single file */
+    DWORD dwAttr;
+
+    dwAttr = GetFileModeW(nw);
+
+    if ((hidden_files ||
+         !(dwAttr & FILE_ATTRIBUTE_HIDDEN || dwAttr & FILE_ATTRIBUTE_SYSTEM)) &&
+        (!only_archive_set || (dwAttr & FILE_ATTRIBUTE_ARCHIVE)))
+    {
+      /* add or remove name of file */
+      if ((m = newnamew(nw, 0, caseflag)) != ZE_OK)
+        return m;
+    }
+  } else {
+    /* Add trailing / to the directory name */
+    pw = (wchar_t *)malloc( (wcslen(nw)+2) * sizeof(wchar_t) );
+    if (pw == NULL)
+      return ZE_MEM;
+    if (wcscmp(nw, L".") == 0 || wcscmp(nw, L"/.") == 0) {
+      *pw = (wchar_t)'\0';  /* avoid "./" prefix and do not create zip entry */
+    } else {
+      wcscpy(pw, nw);
+      aw = pw + wcslen(pw);
+      if (pw[wcslen(pw) - 1] != (wchar_t)'/')
+        wcscpy(aw, L"/");
+      if (dirnames && (m = newnamew(pw, 1, caseflag)) != ZE_OK) {
+        free((zvoid *)pw);
+        return m;
+      }
+    }
+    /* recurse into directory */
+    if (recurse && (dw = OpenDirScanW(nw)) != NULL)
+    {
+      while ((ew = readdw(dw)) != NULL) {
+        if (wcscmp(ew, L".") && wcscmp(ew, L".."))
+        {
+          if ((aw = malloc((wcslen(pw) + wcslen(ew) + 1) * sizeof(wchar_t))) == NULL)
+          {
+            CloseDirScanW(dw);
+            free((zvoid *)pw);
+            return ZE_MEM;
+          }
+          wcscat(wcscpy(aw, pw), ew);
+          if ((m = procname_win32w(aw, caseflag, GetDirAttribsW(dw)))
+              != ZE_OK)         /* recurse on name */
+          {
+            char *a;
+            char *ad;
+
+            a = wchar_to_local_string(aw);
+            ad = local_to_display_string(a);
+
+            if (m == ZE_MISS)
+              zipwarn("name not matched: ", ad);
+            else
+              ziperr(m, a);
+            free(ad);
+            free(a);
+          }
+          free((zvoid *)aw);
+        }
+      }
+      CloseDirScanW(dw);
+    }
+    free((zvoid *)pw);
+  } /* (s.st_mode & S_IFDIR) == 0) */
+  return ZE_OK;
+}
+#endif
+
+
+#ifdef UNICODE_SUPPORT
+int procnamew(nw, caseflag)
+  wchar_t *nw;          /* name to process */
+  int caseflag;         /* true to force case-sensitive match */
+{
+    return procname_win32w(nw, caseflag, INVALID_WIN32_FILE_ATTRIBS);
+}
+#endif
+
+int procname(n, caseflag)
+  char *n;             /* name to process */
+  int caseflag;         /* true to force case-sensitive match */
+{
+    return procname_win32(n, caseflag, INVALID_WIN32_FILE_ATTRIBS);
+}
+
+char *ex2in(x, isdir, pdosflag)
+  char *x;             /* external file name */
+  int isdir;            /* input: x is a directory */
+  int *pdosflag;        /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *n;              /* internal file name (malloc'ed) */
+  char *t;              /* shortened name */
+  int dosflag;
+
+
+  dosflag = dosify || IsFileSystemOldFAT(x);
+  if (!dosify && use_longname_ea && (t = GetLongPathEA(x)) != NULL)
+  {
+    x = t;
+    dosflag = 0;
+  }
+
+  /* Find starting point in name before doing malloc */
+  /* Strip drive specification */
+  t = *x && isascii((uch)*x) && *(x + 1) == ':' ? x + 2 : x;
+  /* Strip "//host/share/" part of a UNC name */
+  if ((!strncmp(x,"//",2) || !strncmp(x,"\\\\",2)) &&
+      (x[2] != '\0' && x[2] != '/' && x[2] != '\\')) {
+    n = x + 2;
+    while (*n != '\0' && *n != '/' && *n != '\\')
+      INCSTR(n);        /* strip host name */
+    if (*n != '\0') {
+      INCSTR(n);
+      while (*n != '\0' && *n != '/' && *n != '\\')
+        INCSTR(n);      /* strip `share' name */
+    }
+    if (*n != '\0')
+      t = n + MB_CLEN(n);
+  }
+  /* Strip leading "/" to convert an absolute path into a relative path */
+  while (*t == '/' || *t == '\\')
+    t++;
+  /* Strip leading "./" as well as drive letter */
+  while (*t == '.' && (t[1] == '/' || t[1] == '\\'))
+    t += 2;
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+  for (n = t; *n; INCSTR(n))
+    if (*n == '\\')
+      *n = '/';
+
+  if (!pathput)
+    t = last(t, PATH_END);
+
+  /* Malloc space for internal name and copy it */
+  if ((n = malloc(strlen(t) + 1)) == NULL)
+    return NULL;
+  strcpy(n, t);
+
+  if (dosify)
+    msname(n);
+
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+  OemToAnsi(n, n);
+#endif
+  return n;
+}
+
+#ifdef UNICODE_SUPPORT
+wchar_t *ex2inw(xw, isdir, pdosflag)
+  wchar_t *xw;          /* external file name */
+  int isdir;            /* input: x is a directory */
+  int *pdosflag;        /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  wchar_t *nw;          /* internal file name (malloc'ed) */
+  wchar_t *tw;          /* shortened name */
+  int dosflag;
+
+
+  dosflag = dosify || IsFileSystemOldFATW(xw);
+  if (!dosify && use_longname_ea && (tw = GetLongPathEAW(xw)) != NULL)
+  {
+    xw = tw;
+    dosflag = 0;
+  }
+
+  /* Find starting point in name before doing malloc */
+  /* Strip drive specification */
+  tw = *xw && iswascii(*xw) && *(xw + 1) == (wchar_t)':' ? xw + 2 : xw;
+  /* Strip "//host/share/" part of a UNC name */
+  if ((!wcsncmp(xw,L"//",2) || !wcsncmp(xw,L"\\\\",2)) &&
+      (xw[2] != (wchar_t)'\0' && xw[2] != (wchar_t)'/' && xw[2] != (wchar_t)'\\')) {
+    nw = xw + 2;
+    while (*nw != (wchar_t)'\0' && *nw != (wchar_t)'/' && *nw != (wchar_t)'\\')
+      nw++;        /* strip host name */
+    if (*nw != (wchar_t)'\0') {
+      nw++;
+      while (*nw != (wchar_t)'\0' && *nw != (wchar_t)'/' && *nw != (wchar_t)'\\')
+        nw++;      /* strip `share' name */
+    }
+    if (*nw != (wchar_t)'\0')
+      tw = nw++;
+  }
+  /* Strip leading "/" to convert an absolute path into a relative path */
+  while (*tw == (wchar_t)'/' || *tw == (wchar_t)'\\')
+    tw++;
+  /* Strip leading "./" as well as drive letter */
+  while (*tw == (wchar_t)'.' && (tw[1] == (wchar_t)'/' || tw[1] == (wchar_t)'\\'))
+    tw += 2;
+
+  /* Make changes, if any, to the copied name (leave original intact) */
+  for (nw = tw; *nw; nw++)
+    if (*nw == '\\')
+      *nw = '/';
+
+  if (!pathput)
+    tw = lastw(tw, PATH_END);
+
+  /* Malloc space for internal name and copy it */
+  if ((nw = malloc((wcslen(tw) + 1) * sizeof(wchar_t))) == NULL)
+    return NULL;
+  wcscpy(nw, tw);
+
+  if (dosify)
+    msnamew(nw);
+
+  /* Returned malloc'ed name */
+  if (pdosflag)
+    *pdosflag = dosflag;
+#if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+  CharToAnsiW(nw, nw);
+#endif
+  return nw;
+}
+#endif
+
+
+char *in2ex(n)
+  char *n;             /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  char *x;             /* external file name */
+
+  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+    return NULL;
+  strcpy(x, n);
+# if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+  AnsiToOem(x, x);
+# endif
+  return x;
+}
+
+#ifdef UNICODE_SUPPORT
+wchar_t *in2exw(nw)
+  wchar_t *nw;            /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+   string or NULL if not enough memory. */
+{
+  wchar_t *xw;            /* external file name */
+
+  if ((xw = malloc((wcslen(nw) + 1 + PAD) * sizeof(wchar_t))) == NULL)
+    return NULL;
+  wcscpy(xw, nw);
+# if defined(__RSXNT__)  /* RSXNT/EMX C rtl uses OEM charset */
+  CharToOemW(xw, xw);
+# endif
+  return xw;
+}
+#endif
+
+
+void stamp(f, d)
+  char *f;                /* name of file to change */
+  ulg d;                  /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+#if defined(__TURBOC__) && !defined(__BORLANDC__)
+  int h;                /* file handle */
+
+  if ((h = open(f, 0)) != -1)
+  {
+    setftime(h, (struct ftime *)&d);
+    close(h);
+  }
+#else /* !__TURBOC__ */
+
+  struct utimbuf u;     /* argument for utime() */
+
+  /* Convert DOS time to time_t format in u.actime and u.modtime */
+  u.actime = u.modtime = dos2unixtime(d);
+
+  /* Set updated and accessed times of f */
+  utime(f, &u);
+#endif /* ?__TURBOC__ */
+}
+
+ulg filetime(f, a, n, t)
+  char *f;              /* name of file to get info on */
+  ulg *a;               /* return value: file attributes */
+  zoff_t *n;            /* return value: file size */
+  iztimes *t;           /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  z_stat s;             /* results of zstat() */
+
+  /* converted to malloc instead of using FNMAX - 11/8/04 EG */
+  char *name;
+  unsigned int len = strlen(f);
+  int isstdin = !strcmp(f, "-");
+
+  if (f == label) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((name = malloc(len + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  strcpy(name, f);
+  if (MBSRCHR(name, '/') == (name + len - 1))
+    name[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+
+  /* zip64 support 08/31/2003 R.Nausedat */
+  if (isstdin) {
+    if (zfstat(fileno(stdin), &s) != 0) {
+      free(name);
+      error("fstat(stdin)");
+    }
+    time((time_t *)&s.st_mtime);       /* some fstat()s return time zero */
+  } else if (LSSTAT(name, &s) != 0) {
+             /* Accept about any file kind including directories
+              * (stored with trailing / with -r option)
+              */
+    free(name);
+    return 0;
+  }
+
+  if (a != NULL) {
+#ifdef WIN32_OEM
+    /* When creating DOS-like archives with OEM-charset names, only the
+       standard FAT attributes should be used.
+       (Note: On a Win32 system, the UNIX style attributes from stat()
+              do not contain any additional information...)
+     */
+    *a = (isstdin ? 0L : (ulg)GetFileMode(name));
+#else
+    *a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)GetFileMode(name));
+#endif
+  }
+  if (n != NULL)
+    /* device return -1 */
+    *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+  if (t != NULL) {
+    t->atime = s.st_atime;
+    t->mtime = s.st_mtime;
+    t->ctime = s.st_ctime;
+  }
+  free(name);
+
+  return unix2dostime((time_t *)&s.st_mtime);
+}
+
+#ifdef UNICODE_SUPPORT
+ulg filetimew(fw, a, n, t)
+  wchar_t *fw;          /* name of file to get info on */
+  ulg *a;               /* return value: file attributes */
+  zoff_t *n;            /* return value: file size */
+  iztimes *t;           /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0.  Else, return the file's last
+   modified date and time as an MSDOS date and time.  The date and
+   time is returned in a long with the date most significant to allow
+   unsigned integer comparison of absolute times.  Also, if a is not
+   a NULL pointer, store the file attributes there, with the high two
+   bytes being the Unix attributes, and the low byte being a mapping
+   of that to DOS attributes.  If n is not NULL, store the file size
+   there.  If t is not NULL, the file's access, modification and creation
+   times are stored there as UNIX time_t values.
+   If f is "-", use standard input as the file. If f is a device, return
+   a file size of -1 */
+{
+  zw_stat sw;           /* results of zstat() */
+
+  /* converted to malloc instead of using FNMAX - 11/8/04 EG */
+  wchar_t *namew;
+  unsigned int len = wcslen(fw);
+  int isstdin = !wcscmp(fw, L"-");
+  wchar_t *labelw = local_to_wchar_string(label);
+
+  if (labelw && wcscmp(fw, labelw) == 0) {
+    if (a != NULL)
+      *a = label_mode;
+    if (n != NULL)
+      *n = -2L; /* convention for a label name */
+    if (t != NULL)
+      t->atime = t->mtime = t->ctime = label_utim;
+    return label_time;
+  }
+  if ((namew = malloc((len + 1) * sizeof(wchar_t))) == NULL) {
+    ZIPERR(ZE_MEM, "filetime");
+  }
+  wcscpy(namew, fw);
+  if (wcsrchr(namew, (wchar_t)'/') == (namew + len - 1))
+    namew[len - 1] = '\0';
+  /* not all systems allow stat'ing a file with / appended */
+
+  /* zip64 support 08/31/2003 R.Nausedat */
+  if (isstdin) {
+    if (zwfstat(fileno(stdin), &sw) != 0) {
+      free(namew);
+      error("fstat(stdin)");
+    }
+    time((time_t *)&sw.st_mtime);       /* some fstat()s return time zero */
+  } else if (LSSTATW(namew, &sw) != 0) {
+             /* Accept about any file kind including directories
+              * (stored with trailing / with -r option)
+              */
+    free(namew);
+    return 0;
+  }
+
+  if (a != NULL) {
+#ifdef WIN32_OEM
+    /* When creating DOS-like archives with OEM-charset names, only the
+       standard FAT attributes should be used.
+       (Note: On a Win32 system, the UNIX style attributes from stat()
+              do not contain any additional information...)
+     */
+    *a = (isstdin ? 0L : (ulg)GetFileModeW(namew));
+#else
+    *a = ((ulg)sw.st_mode << 16) | (isstdin ? 0L : (ulg)GetFileModeW(namew));
+#endif
+  }
+  if (n != NULL)
+    /* device return -1 */
+    *n = (sw.st_mode & S_IFMT) == S_IFREG ? sw.st_size : -1L;
+  if (t != NULL) {
+    t->atime = sw.st_atime;
+    t->mtime = sw.st_mtime;
+    t->ctime = sw.st_ctime;
+  }
+  free(namew);
+
+  return unix2dostime((time_t *)&sw.st_mtime);
+}
+#endif
+
+
+
+#ifdef NTSD_EAS
+
+/* changed size, csize from size_t to ush 3/10/2005 EG */
+local void GetSD(char *path, char **bufptr, ush *size,
+                        char **cbufptr, ush *csize)
+{
+  unsigned char stackbuffer[NTSD_BUFFERSIZE];
+  unsigned long bytes = NTSD_BUFFERSIZE;
+  unsigned char *buffer = stackbuffer;
+  unsigned char *DynBuffer = NULL;
+  ulg cbytes;
+  PEF_NTSD_L_HEADER pLocalHeader;
+  PEF_NTSD_C_HEADER pCentralHeader;
+  VOLUMECAPS VolumeCaps;
+
+  /* check target volume capabilities */
+  if (!ZipGetVolumeCaps(path, path, &VolumeCaps) ||
+     !(VolumeCaps.dwFileSystemFlags & FS_PERSISTENT_ACLS)) {
+    return;
+  }
+
+  VolumeCaps.bUsePrivileges = use_privileges;
+  VolumeCaps.dwFileAttributes = 0;
+  /* should set to file attributes, if possible */
+
+  if (!SecurityGet(path, &VolumeCaps, buffer, (LPDWORD)&bytes)) {
+
+    /* try to malloc the buffer if appropriate */
+    if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+        DynBuffer = malloc(bytes);
+        if(DynBuffer == NULL) return;
+
+        buffer = DynBuffer; /* switch to the new buffer and try again */
+
+        if(!SecurityGet(path, &VolumeCaps, buffer, (LPDWORD)&bytes)) {
+            free(DynBuffer);
+            return;
+        }
+
+    } else {
+        return; /* bail */
+    }
+  }
+
+  /* # bytes to compress: compress type, CRC, data bytes */
+  cbytes = (2 + 4 + EB_DEFLAT_EXTRA) + bytes;
+
+
+  /* our two possible failure points.  don't allow trashing of any data
+     if either fails - notice that *size and *csize don't get updated.
+     *bufptr leaks if malloc() was used and *cbufptr alloc fails - this
+     isn't relevant because it's probably indicative of a bigger problem. */
+
+  if(*size)
+    *bufptr = realloc(*bufptr, *size + EF_NTSD_L_LEN + cbytes);
+  else
+    *bufptr = malloc(EF_NTSD_L_LEN + cbytes);
+
+  if(*csize)
+    *cbufptr = realloc(*cbufptr, *csize + EF_NTSD_C_LEN);
+  else
+    *cbufptr = malloc(EF_NTSD_C_LEN);
+
+  if(*bufptr == NULL || *cbufptr == NULL) {
+    if(DynBuffer) free(DynBuffer);
+    return;
+  }
+
+  /* local header */
+
+  pLocalHeader = (PEF_NTSD_L_HEADER) (*bufptr + *size);
+
+  cbytes = memcompress(((char *)pLocalHeader + EF_NTSD_L_LEN), cbytes,
+                       (char *)buffer, bytes);
+
+  if (cbytes > 0x7FFF) {
+    sprintf(errbuf, "security info too large to store (%ld bytes), %d max", bytes, 0x7FFF);
+    zipwarn(errbuf, "");
+    zipwarn("security info not stored: ", path);
+    if(DynBuffer) free(DynBuffer);
+    return;
+  }
+
+  *size += EF_NTSD_L_LEN + (ush)cbytes;
+
+  pLocalHeader->nID = EF_NTSD;
+  pLocalHeader->nSize = (USHORT)(EF_NTSD_L_LEN - EB_HEADSIZE
+                                 + cbytes);
+  pLocalHeader->lSize = bytes; /* uncompressed size */
+  pLocalHeader->Version = 0;
+
+  /* central header */
+
+  pCentralHeader = (PEF_NTSD_C_HEADER) (*cbufptr + *csize);
+  *csize += EF_NTSD_C_LEN;
+
+  pCentralHeader->nID = EF_NTSD;
+  pCentralHeader->nSize = EF_NTSD_C_LEN - EB_HEADSIZE;  /* sbz */
+  pCentralHeader->lSize = bytes;
+
+  if (noisy) {
+    sprintf(errbuf, " (%ld bytes security)", bytes);
+    zipmessage_nl(errbuf, 0);
+  }
+
+  if(DynBuffer) free(DynBuffer);
+}
+#endif /* NTSD_EAS */
+
+
+#ifdef USE_EF_UT_TIME
+
+#define EB_L_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(3))
+#define EB_C_UT_SIZE    (EB_HEADSIZE + EB_UT_LEN(1))
+
+local int GetExtraTime(struct zlist far *z, iztimes *z_utim)
+{
+  char *eb_l_ptr;
+  char *eb_c_ptr;
+  ulg ultime;
+  /* brain-dead IBM compiler defines time_t as "double", so we have to convert
+   * it into unsigned long integer number...
+   */
+
+#ifdef IZ_CHECK_TZ
+  if (!zp_tz_is_valid) return ZE_OK;    /* skip silently if no valid TZ info */
+#endif
+
+  if(z->ext)
+    eb_l_ptr = realloc(z->extra, (z->ext + EB_L_UT_SIZE));
+  else
+    eb_l_ptr = malloc(EB_L_UT_SIZE);
+
+  if (eb_l_ptr == NULL)
+    return ZE_MEM;
+
+  if(z->cext)
+    eb_c_ptr = realloc(z->cextra, (z->cext + EB_C_UT_SIZE));
+  else
+    eb_c_ptr = malloc(EB_C_UT_SIZE);
+
+  if (eb_c_ptr == NULL)
+    return ZE_MEM;
+
+  z->extra = eb_l_ptr;
+  eb_l_ptr += z->ext;
+  z->ext += EB_L_UT_SIZE;
+
+  eb_l_ptr[0]  = 'U';
+  eb_l_ptr[1]  = 'T';
+  eb_l_ptr[2]  = EB_UT_LEN(3);          /* length of data part of e.f. */
+  eb_l_ptr[3]  = 0;
+  eb_l_ptr[4]  = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME;
+  ultime = (ulg)z_utim->mtime;
+  eb_l_ptr[5]  = (char)(ultime);
+  eb_l_ptr[6]  = (char)(ultime >> 8);
+  eb_l_ptr[7]  = (char)(ultime >> 16);
+  eb_l_ptr[8]  = (char)(ultime >> 24);
+  ultime = (ulg)z_utim->atime;
+  eb_l_ptr[9]  = (char)(ultime);
+  eb_l_ptr[10] = (char)(ultime >> 8);
+  eb_l_ptr[11] = (char)(ultime >> 16);
+  eb_l_ptr[12] = (char)(ultime >> 24);
+  ultime = (ulg)z_utim->ctime;
+  eb_l_ptr[13] = (char)(ultime);
+  eb_l_ptr[14] = (char)(ultime >> 8);
+  eb_l_ptr[15] = (char)(ultime >> 16);
+  eb_l_ptr[16] = (char)(ultime >> 24);
+
+  z->cextra = eb_c_ptr;
+  eb_c_ptr += z->cext;
+  z->cext += EB_C_UT_SIZE;
+
+  memcpy(eb_c_ptr, eb_l_ptr, EB_C_UT_SIZE);
+  eb_c_ptr[EB_LEN] = EB_UT_LEN(1);
+
+  return ZE_OK;
+}
+
+#endif /* USE_EF_UT_TIME */
+
+
+
+int set_extra_field(z, z_utim)
+  struct zlist far *z;
+  iztimes *z_utim;
+  /* create extra field and change z->att if desired */
+{
+
+#ifdef NTSD_EAS
+  if(ZipIsWinNT()) {
+    /* store SECURITY_DECRIPTOR data in local header,
+       and size only in central headers */
+    GetSD(z->name, &z->extra, &z->ext, &z->cextra, &z->cext);
+  }
+#endif /* NTSD_EAS */
+
+#ifdef USE_EF_UT_TIME
+  /* store extended time stamps in both headers */
+  return GetExtraTime(z, z_utim);
+#else /* !USE_EF_UT_TIME */
+  return ZE_OK;
+#endif /* ?USE_EF_UT_TIME */
+}
+
+int deletedir(d)
+char *d;                /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+   Return the result of rmdir(), delete(), or system().
+   For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
+ */
+{
+    return rmdir(d);
+}
+
+#endif /* !UTIL */
diff --git a/win32/win32zip.h b/win32/win32zip.h
new file mode 100644 (file)
index 0000000..3d8bca5
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+  win32/win32zip.h - Zip 3
+
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef _WIN32ZIP_H
+#define _WIN32ZIP_H
+
+/*
+ * NT specific functions for ZIP.
+ */
+
+int GetFileMode(char *name);
+#ifdef UNICODE_SUPPORT
+int GetFileModeW(wchar_t *name);
+#endif
+long GetTheFileTime(char *name, iztimes *z_times);
+
+int IsFileNameValid(char *name);
+int IsFileSystemOldFAT(char *dir);
+#ifdef UNICODE_SUPPORT
+int IsFileSystemOldFATW(wchar_t *dir);
+#endif
+void ChangeNameForFAT(char *name);
+
+char *getVolumeLabel(int drive, ulg *vtime, ulg *vmode, time_t *vutim);
+
+#if 0 /* never used ?? */
+char *StringLower(char *);
+#endif
+
+char *GetLongPathEA(char *name);
+#ifdef UNICODE_SUPPORT
+wchar_t *GetLongPathEAW(wchar_t *name);
+#endif
+
+#endif /* _WIN32ZIP_H */
diff --git a/win32/zip.def b/win32/zip.def
new file mode 100644 (file)
index 0000000..105e4b9
--- /dev/null
@@ -0,0 +1,4 @@
+;module-definition file for Windows Zip DLL -- used by link.exe
+DESCRIPTION 'The world-famous zip utilities from Info-ZIP'
+
+
diff --git a/win32/zip.rc b/win32/zip.rc
new file mode 100644 (file)
index 0000000..3ecb961
--- /dev/null
@@ -0,0 +1,53 @@
+#include <windows.h>\r
+#if (defined(WIN32) && !defined(__EMX__) && !defined(__MINGW32__))\r
+#include <winver.h>\r
+#endif\r
+#define IZ_VERSION_SYMBOLS_ONLY\r
+#include "../revision.h"\r
+#undef IZ_VERSION_SYMBOLS_ONLY\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION Z_MAJORVER,Z_MINORVER,Z_PATCHLEVEL,0\r
+ PRODUCTVERSION Z_MAJORVER,Z_MINORVER,Z_PATCHLEVEL,0\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS VOS__WINDOWS32\r
+ FILETYPE VFT_APP\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+#ifdef _UNICODE\r
+        BLOCK "040904B0"\r
+#else\r
+        BLOCK "040904E4"\r
+#endif\r
+        BEGIN\r
+            VALUE "CompanyName", IZ_COMPANY_NAME "\0"\r
+            VALUE "FileDescription", "Info-ZIP Zip for Win32 console\0"\r
+            VALUE "FileVersion", VERSION "\0"\r
+            VALUE "InternalName", "zip\0"\r
+            VALUE "LegalCopyright", "Copyright Â© Info-ZIP 1997 - 2008\0"\r
+            VALUE "OriginalFilename", "zip.exe\0"\r
+            VALUE "ProductName", "Zip\0"\r
+            VALUE "ProductVersion", VERSION "\0"\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+#ifdef _UNICODE\r
+        VALUE "Translation", 0x409, 1200\r
+#else\r
+        VALUE "Translation", 0x409, 1252\r
+#endif\r
+    END\r
+END\r
diff --git a/win32/zipup.h b/win32/zipup.h
new file mode 100644 (file)
index 0000000..9505b56
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  win32/zipup.h - Zip 3
+
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __CYGWIN__
+#  include <share.h>
+#endif
+#ifndef O_RDONLY
+#  define O_RDONLY   0
+#endif
+#ifndef O_BINARY
+#  define O_BINARY   0
+#endif
+#if (defined(_SH_DENYNO) && !defined(SH_DENYNO))
+#  define SH_DENYNO _SH_DENYNO
+#endif
+#if (defined(SH_DENYNO) && !defined(_SH_DENYNO))
+#  define _SH_DENYNO SH_DENYNO
+#endif
+#define fhow         (O_RDONLY|O_BINARY)
+#define fbad         (-1)
+typedef int          ftype;
+
+#if defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__EMX__)
+#  define zopen(n,p) sopen(n,p,SH_DENYNO)
+#elif defined(__CYGWIN__) || defined(__IBMC__)
+#  define zopen(n,p) open(n,p)
+#else
+#  define zopen(n,p) _sopen(n,p,_SH_DENYNO)
+#endif
+#ifdef UNICODE_SUPPORT
+# if defined(__CYGWIN__) || defined(__IBMC__)
+#  define zwopen(n,p) wopen(n,p)
+# else
+#  define zwopen(n,p) _wsopen(n,p,_SH_DENYNO)
+# endif
+#endif
+
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f)    close(f)
+#define zerr(f)      (k == (extent)(-1L))
+#define zstdin       0
diff --git a/windll/VBz64/VBZIP.VBP b/windll/VBz64/VBZIP.VBP
new file mode 100644 (file)
index 0000000..4161be5
--- /dev/null
@@ -0,0 +1,33 @@
+Type=Exe\r
+Form=Vbzipfrm.frm\r
+Module=VBZipBas; VBZipBas.bas\r
+IconForm="Form1"\r
+Startup="Form1"\r
+HelpFile=""\r
+Title="VBZIP"\r
+ExeName32="VBZIP.exe"\r
+Command32=""\r
+Name="Project1"\r
+HelpContextID="0"\r
+CompatibleMode="0"\r
+MajorVer=1\r
+MinorVer=0\r
+RevisionVer=0\r
+AutoIncrementVer=0\r
+ServerSupportFiles=0\r
+VersionCompanyName="Mike"\r
+CompilationType=-1\r
+OptimizationType=0\r
+FavorPentiumPro(tm)=0\r
+CodeViewDebugInfo=0\r
+NoAliasing=0\r
+BoundsCheck=0\r
+OverflowCheck=0\r
+FlPointCheck=0\r
+FDIVCheck=0\r
+UnroundedFP=0\r
+StartMode=0\r
+Unattended=0\r
+Retained=0\r
+ThreadPerObject=0\r
+MaxNumberOfThreads=1\r
diff --git a/windll/VBz64/VBZIP.vbw b/windll/VBz64/VBZIP.vbw
new file mode 100644 (file)
index 0000000..7b4e7f5
--- /dev/null
@@ -0,0 +1,2 @@
+Form1 = 7, 9, 712, 539, , 22, 22, 660, 466, C\r
+VBZipBas = 26, -4, 716, 492, \r
diff --git a/windll/VBz64/VBZipBas.bas b/windll/VBz64/VBZipBas.bas
new file mode 100644 (file)
index 0000000..99547a0
--- /dev/null
@@ -0,0 +1,737 @@
+Attribute VB_Name = "VBZipBas"
+
+Option Explicit
+
+'---------------------------------------------------------------
+'-- Please Do Not Remove These Comments!!!
+'---------------------------------------------------------------
+'-- Sample VB 6 code to drive zip32z64.dll
+'-- Based on the code contributed to the Info-ZIP project
+'-- by Mike Le Voi
+'--
+'-- See the original VB example in a separate directory for
+'-- more information
+'--
+'-- Use this code at your own risk. Nothing implied or warranted
+'-- to work on your machine :-)
+'---------------------------------------------------------------
+'--
+'-- The Source Code Is Freely Available From Info-ZIP At:
+'-- ftp://ftp.info-zip.org/pub/infozip/infozip.html
+'--
+'-- A Very Special Thanks To Mr. Mike Le Voi
+'-- And Mr. Mike White Of The Info-ZIP
+'-- For Letting Me Use And Modify His Orginal
+'-- Visual Basic 5.0 Code! Thank You Mike Le Voi.
+'---------------------------------------------------------------
+
+'---------------------------------------------------------------
+' This example is redesigned to work with Zip32z64.dll compiled from
+' Zip 3.0 with Zip64 enabled.  This allows for archives with more
+' and larger files than allowed in previous versions.
+'
+' Modified 4/24/2004, 12/4/2007 by Ed Gordon
+'---------------------------------------------------------------
+
+'---------------------------------------------------------------
+' Usage notes:
+'
+' This code uses Zip32z64.dll.  You DO NOT need to register the
+' DLL to use it.  You also DO NOT need to reference it in your
+' VB project.  You DO have to copy the DLL to your SYSTEM
+' directory, your VB project directory, or place it in a directory
+' on your command PATH.
+'
+' Note that Zip32z64 is probably not thread safe so you should avoid
+' using the dll in multiple threads at the same time without first
+' testing for interaction.
+'
+' All code provided under the Info-Zip license.  If you have
+' any questions please contact Info-Zip.
+'
+' April 24 2004 EG
+'
+'---------------------------------------------------------------
+
+'-- C Style argv
+'-- Holds The Zip Archive Filenames
+'
+' Max for zFiles just over 8000 as each pointer takes up 4 bytes and
+' VB only allows 32 kB of local variables and that includes function
+' parameters.  - 3/19/2004 EG
+'
+' Can put names in strZipFileNames instead of using this array,
+' which avoids this limit.  File names are separated by spaces.
+' Enclose names in quotes if include spaces.
+Public Type ZIPnames
+  zFiles(1 To 100) As String
+End Type
+
+'-- Call Back "String"
+Public Type ZipCBChar
+  ch(4096) As Byte
+End Type
+
+'-- Version Structure
+Public Type VerType
+  Major As Byte
+  Minor As Byte
+  PatchLevel As Byte
+  NotUsed As Byte
+End Type
+Public Type ZipVerType
+  structlen       As Long         ' Length Of The Structure Being Passed
+  flag            As Long         ' Bit 0: is_beta  bit 1: uses_zlib
+  Beta            As String * 10  ' e.g., "g BETA" or ""
+  date            As String * 20  ' e.g., "4 Sep 95" (beta) or "4 September 1995"
+  ZLIB            As String * 10  ' e.g., "1.0.5" or NULL
+  encryption      As Long         ' 0 if encryption not available
+  ZipVersion      As VerType
+  os2dllVersion   As VerType
+  windllVersion   As VerType
+End Type
+
+'-- ZPOPT Is Used To Set The Options In The ZIP32z64.DLL
+Public Type ZpOpt
+  date           As String ' Date in either US 12/31/98 or 1998-12-31 format
+  szRootDir      As String ' Root Directory Pathname (Up To 256 Bytes Long)
+  szTempDir      As String ' Temp Directory Pathname (Up To 256 Bytes Long)
+  fTemp          As Long   ' 1 If Temp dir Wanted, Else 0
+  fSuffix        As Long   ' Include Suffixes (Not Yet Implemented!)
+  fEncrypt       As Long   ' 1 If Encryption Wanted, Else 0
+  fSystem        As Long   ' 1 To Include System/Hidden Files, Else 0
+  fVolume        As Long   ' 1 If Storing Volume Label, Else 0
+  fExtra         As Long   ' 1 If Excluding Extra Attributes, Else 0
+  fNoDirEntries  As Long   ' 1 If Ignoring Directory Entries (end with /), Else 0
+  fExcludeDate   As Long   ' 1 If Excluding Files After Specified Date, Else 0
+  fIncludeDate   As Long   ' 1 If Including Files After Specified Date, Else 0
+  fVerbose       As Long   ' 1 If Full Messages Wanted, Else 0
+  fQuiet         As Long   ' 1 If Minimum Messages Wanted, Else 0
+  fCRLF_LF       As Long   ' 1 If Translate CR/LF To LF, Else 0
+  fLF_CRLF       As Long   ' 1 If Translate LF To CR/LF, Else 0
+  fJunkDir       As Long   ' 1 If Junking Directory Names on entries, Else 0
+  fGrow          As Long   ' 1 If Allow Appending To Zip File, Else 0
+  fForce         As Long   ' 1 If Making Entries Using DOS File Names, Else 0
+  fMove          As Long   ' 1 If Deleting Files Added Or Updated, Else 0
+  fDeleteEntries As Long   ' 1 If Files Passed Have To Be Deleted, Else 0
+  fUpdate        As Long   ' 1 If Updating Zip File-Overwrite Only If Newer, Else 0
+  fFreshen       As Long   ' 1 If Freshing Zip File-Overwrite Only, Else 0
+  fJunkSFX       As Long   ' 1 If Junking SFX Prefix, Else 0
+  fLatestTime    As Long   ' 1 If Setting Zip File Time To Time Of Latest File In Archive, Else 0
+  fComment       As Long   ' 1 If Putting Comment In Zip File, Else 0
+  fOffsets       As Long   ' 1 If Updating Archive Offsets For SFX Files, Else 0
+  fPrivilege     As Long   ' 1 If Not Saving Privileges, Else 0
+  fEncryption    As Long   ' Read Only Property!!!
+  szSplitSize    As String ' Size of split if splitting, Else NULL (empty string)
+                           ' This string contains the size that you want to
+                           ' split the archive into. i.e. 100 for 100 bytes,
+                           ' 2K for 2 k bytes, where K is 1024, m for meg
+                           ' and g for gig.
+  szIncludeList  As String ' If used, space separated list of Include filename
+                           ' patterns where match includes file - put quotes
+                           ' around each filename pattern.
+  IncludeListCount As Long ' place filler (not for VB) - (inits to 0) DO NOT USE
+  IncludeList    As Long   ' place filler (not for VB) - (inits to 0) DO NOT USE
+  szExcludeList  As String ' If used, space separated list of Exclude filename
+                           ' patterns where match excludes file - put quotes
+                           ' around each filename pattern.
+  ExcludeListCount As Long ' place filler (not for VB) - (inits to 0) DO NOT USE
+  ExcludeList    As Long   ' place filler (not for VB) - (inits to 0) DO NOT USE
+  fRecurse       As Long   ' 1 (-r), 2 (-R) If Recursing Into Sub-Directories, Else 0
+  fRepair        As Long   ' 1 = Fix Archive, 2 = Try Harder To Fix, Else 0
+  flevel         As Byte   ' Compression Level - 0 = Stored 6 = Default 9 = Max
+End Type
+
+
+' Used by SetZipOptions
+Public Enum ZipModeType
+    Add = 0
+    Delete = 1
+    Update = 2
+    Freshen = 3
+End Enum
+Public Enum CompressionLevelType
+    c0_NoCompression = 0
+    c1_Fast = 1
+    c2_Fast = 2
+    c3_Fast = 3
+    c4_Med = 4
+    c5_Med = 5
+    c6_Default = 6
+    c7_Extra = 7
+    c8_Extra = 8
+    c9_Max = 9
+End Enum
+Public Enum Translate_LF_Type
+    No_Line_End_Trans = 0
+    LF_To_CRLF = 1
+    CRLF_To_LF = 2
+End Enum
+Public Enum RepairType
+    NoRepair = 0
+    TryFix = 1
+    TryFixHarder = 2
+End Enum
+Public Enum VerbosenessType
+    Quiet = 0
+    Normal = 1
+    Verbose = 2
+End Enum
+Public Enum RecurseType
+    NoRecurse = 0
+    r_RecurseIntoSubdirectories = 1
+    R_RecurseUsingPatterns = 2
+End Enum
+
+
+'-- This Structure Is Used For The ZIP32z64.DLL Function Callbacks
+'   Assumes Zip32z64.dll with Zip64 enabled
+Public Type ZIPUSERFUNCTIONS
+  ZDLLPrnt     As Long           ' Callback ZIP32z64.DLL Print Function
+  ZDLLCOMMENT  As Long           ' Callback ZIP32z64.DLL Comment Function
+  ZDLLPASSWORD As Long           ' Callback ZIP32z64.DLL Password Function
+  ZDLLSPLIT    As Long           ' Callback ZIP32z64.DLL Split Select Function
+  ' There are 2 versions of SERVICE, we use one does not need 64-bit data type
+  ZDLLSERVICE  As Long           ' Callback ZIP32z64.DLL Service Function
+  ZDLLSERVICE_NO_INT64  As Long  ' Callback ZIP32z64.DLL Service Function
+End Type
+
+'-- Default encryption password (used in callback if not empty string)
+Public EncryptionPassword As String
+
+'-- For setting the archive comment
+Public ArchiveCommentText
+
+'-- version info
+Public ZipVersion As ZipVerType
+
+'-- Local Declarations
+Public ZOPT  As ZpOpt
+Public ZUSER As ZIPUSERFUNCTIONS
+
+'-- This Assumes ZIP32z64.DLL Is In Your \windows\system directory
+'-- or a copy is in the program directory or in some other directory
+'-- listed in PATH
+Private Declare Function ZpInit Lib "zip32z64.dll" _
+  (ByRef Zipfun As ZIPUSERFUNCTIONS) As Long '-- Set Zip Callbacks
+
+Private Declare Function ZpArchive Lib "zip32z64.dll" _
+  (ByVal argc As Long, ByVal funame As String, _
+   ByRef argv As ZIPnames, ByVal strNames As String, ByRef Opts As ZpOpt) As Long '-- Real Zipping Action
+
+Private Declare Sub ZpVersion Lib "zip32z64.dll" _
+  (ByRef ZipVersion As ZipVerType) '-- Version of DLL
+
+
+'-------------------------------------------------------
+'-- Public Variables For Setting The ZPOPT Structure...
+'-- (WARNING!!!) You Must Set The Options That You
+'-- Want The ZIP32.DLL To Do!
+'-- Before Calling VBZip32!
+'--
+'-- NOTE: See The Above ZPOPT Structure Or The VBZip32
+'--       Function, For The Meaning Of These Variables
+'--       And How To Use And Set Them!!!
+'-- These Parameters Must Be Set Before The Actual Call
+'-- To The VBZip32 Function!
+'-------------------------------------------------------
+
+'-- Public Program Variables
+Public zArgc           As Integer     ' Number Of Files To Zip Up
+Public zZipArchiveName As String      ' The Zip File Name ie: Myzip.zip
+Public zZipFileNames   As ZIPnames    ' File Names To Zip Up
+Public strZipFileNames As String      ' String of names to Zip Up
+Public zZipInfo        As String      ' Holds The Zip File Information
+
+'-- Public Constants
+'-- For Zip & UnZip Error Codes!
+Public Const ZE_OK = 0              ' Success (No Error)
+Public Const ZE_EOF = 2             ' Unexpected End Of Zip File Error
+Public Const ZE_FORM = 3            ' Zip File Structure Error
+Public Const ZE_MEM = 4             ' Out Of Memory Error
+Public Const ZE_LOGIC = 5           ' Internal Logic Error
+Public Const ZE_BIG = 6             ' Entry Too Large To Split Error
+Public Const ZE_NOTE = 7            ' Invalid Comment Format Error
+Public Const ZE_TEST = 8            ' Zip Test (-T) Failed Or Out Of Memory Error
+Public Const ZE_ABORT = 9           ' User Interrupted Or Termination Error
+Public Const ZE_TEMP = 10           ' Error Using A Temp File
+Public Const ZE_READ = 11           ' Read Or Seek Error
+Public Const ZE_NONE = 12           ' Nothing To Do Error
+Public Const ZE_NAME = 13           ' Missing Or Empty Zip File Error
+Public Const ZE_WRITE = 14          ' Error Writing To A File
+Public Const ZE_CREAT = 15          ' Could't Open To Write Error
+Public Const ZE_PARMS = 16          ' Bad Command Line Argument Error
+Public Const ZE_OPEN = 18           ' Could Not Open A Specified File To Read Error
+
+'-- These Functions Are For The ZIP32z64.DLL
+'--
+'-- Puts A Function Pointer In A Structure
+'-- For Use With Callbacks...
+Public Function FnPtr(ByVal lp As Long) As Long
+    
+  FnPtr = lp
+
+End Function
+
+'-- Callback For ZIP32z64.DLL - DLL Print Function
+Public Function ZDLLPrnt(ByRef fname As ZipCBChar, ByVal x As Long) As Long
+    
+  Dim s0 As String
+  Dim xx As Long
+    
+  '-- Always Put This In Callback Routines!
+  On Error Resume Next
+    
+  s0 = ""
+    
+  '-- Get Zip32.DLL Message For processing
+  For xx = 0 To x
+    If fname.ch(xx) = 0 Then
+      Exit For
+    Else
+      s0 = s0 + Chr(fname.ch(xx))
+    End If
+  Next
+    
+  '----------------------------------------------
+  '-- This Is Where The DLL Passes Back Messages
+  '-- To You! You Can Change The Message Printing
+  '-- Below Here!
+  '----------------------------------------------
+  
+  '-- Display Zip File Information
+  '-- zZipInfo = zZipInfo & s0
+  Form1.Print s0;
+    
+  DoEvents
+    
+  ZDLLPrnt = 0
+
+End Function
+
+'-- Callback For ZIP32z64.DLL - DLL Service Function
+Public Function ZDLLServ(ByRef mname As ZipCBChar, _
+                         ByVal LowSize As Long, _
+                         ByVal HighSize As Long) As Long
+
+    Dim s0 As String
+    Dim xx As Long
+    Dim FS As Currency  ' for large file sizes
+    
+    '-- Always Put This In Callback Routines!
+    On Error Resume Next
+    
+    FS = (HighSize * &H10000 * &H10000) + LowSize
+ '   Form1.Print "ZDLLServ returned File Size High " & HighSize & _
+ '               " Low " & LowSize & " = " & FS & " bytes"
+    
+    s0 = ""
+    '-- Get Zip32.DLL Message For processing
+    For xx = 0 To 4096 ' x
+    If mname.ch(xx) = 0 Then
+        Exit For
+    Else
+        s0 = s0 + Chr(mname.ch(xx))
+    End If
+    Next
+    ' At this point, s0 contains the message passed from the DLL
+    ' It is up to the developer to code something useful here :)
+    ZDLLServ = 0 ' Setting this to 1 will abort the zip!
+    
+End Function
+
+'-- Callback For ZIP32z64.DLL - DLL Password Function
+Public Function ZDLLPass(ByRef p As ZipCBChar, _
+  ByVal n As Long, ByRef m As ZipCBChar, _
+  ByRef Name As ZipCBChar) As Integer
+  
+  Dim filename   As String
+  Dim prompt     As String
+  Dim xx         As Integer
+  Dim szpassword As String
+  
+  '-- Always Put This In Callback Routines!
+  On Error Resume Next
+    
+  ZDLLPass = 1
+  
+  '-- User Entered A Password So Proccess It
+  
+  '-- Enter or Verify
+  For xx = 0 To 255
+    If m.ch(xx) = 0 Then
+      Exit For
+    Else
+      prompt = prompt & Chr(m.ch(xx))
+    End If
+  Next
+  
+  '-- If There Is A Password Have The User Enter It!
+  '-- This Can Be Changed
+  
+  '-- Now skip asking if default password set
+  If EncryptionPassword <> "" Then
+    szpassword = EncryptionPassword
+  Else
+    szpassword = InputBox("Please Enter The Password!", prompt)
+  End If
+  
+  '-- The User Did Not Enter A Password So Exit The Function
+  If szpassword = "" Then Exit Function
+  
+  For xx = 0 To n - 1
+    p.ch(xx) = 0
+  Next
+  
+  For xx = 0 To Len(szpassword) - 1
+    p.ch(xx) = Asc(Mid(szpassword, xx + 1, 1))
+  Next
+  
+  p.ch(xx) = Chr(0) ' Put Null Terminator For C
+  
+  ZDLLPass = 0
+    
+End Function
+
+'-- Callback For ZIP32z64.DLL - DLL Comment Function
+Public Function ZDLLComm(ByRef s1 As ZipCBChar) As Integer
+    
+    Dim comment As String
+    Dim xx%, szcomment$
+    
+    '-- Always Put This In Callback Routines!
+    On Error Resume Next
+    
+    ZDLLComm = 1
+    If Not IsEmpty(ArchiveCommentText) Then
+      ' use text given to SetZipOptions
+      szcomment = ArchiveCommentText
+    Else
+      For xx = 0 To 4095
+        szcomment = szcomment & Chr(s1.ch(xx))
+        If s1.ch(xx) = 0 Then
+          Exit For
+        End If
+      Next
+      comment = InputBox("Enter or edit the comment", Default:=szcomment)
+      If comment = "" Then
+        ' either empty comment or Cancel button
+        If MsgBox("Remove comment?" & Chr(13) & "Hit No to keep existing comment", vbYesNo) = vbYes Then
+            szcomment = comment
+        Else
+          Exit Function
+        End If
+      End If
+      szcomment = comment
+    End If
+    'If szcomment = "" Then Exit Function
+    For xx = 0 To Len(szcomment) - 1
+        s1.ch(xx) = Asc(Mid$(szcomment, xx + 1, 1))
+    Next xx
+    s1.ch(xx) = 0 ' Put null terminator for C
+
+End Function
+
+' This function can be used to set options in VB
+Public Function SetZipOptions(ByRef ZipOpts As ZpOpt, _
+  Optional ByVal ZipMode As ZipModeType = Add, _
+  Optional ByVal RootDirToZipFrom As String = "", _
+  Optional ByVal CompressionLevel As CompressionLevelType = c6_Default, _
+  Optional ByVal RecurseSubdirectories As RecurseType = NoRecurse, _
+  Optional ByVal Verboseness As VerbosenessType = Normal, _
+  Optional ByVal i_IncludeFiles As String = "", _
+  Optional ByVal x_ExcludeFiles As String = "", _
+  Optional ByVal UpdateSFXOffsets As Boolean = False, Optional ByVal JunkDirNames As Boolean = False, _
+  Optional ByVal Encrypt As Boolean = False, Optional ByVal Password As String = "", _
+  Optional ByVal Repair As RepairType = NoRepair, Optional ByVal NoDirEntries As Boolean = False, _
+  Optional ByVal GrowExistingArchive As Boolean = False, _
+  Optional ByVal JunkSFXPrefix As Boolean = False, Optional ByVal ForceUseOfDOSNames As Boolean = False, _
+  Optional ByVal Translate_LF As Translate_LF_Type = No_Line_End_Trans, _
+  Optional ByVal Move_DeleteAfterAddedOrUpdated As Boolean = False, _
+  Optional ByVal SetZipTimeToLatestTime As Boolean = False, _
+  Optional ByVal IncludeSystemAndHiddenFiles As Boolean = False, _
+  Optional ByVal ExcludeEarlierThanDate As String = "", _
+  Optional ByVal IncludeEarlierThanDate As String = "", _
+  Optional ByVal IncludeVolumeLabel As Boolean = False, _
+  Optional ByVal ArchiveComment As Boolean = False, _
+  Optional ByVal ArchiveCommentTextString = Empty, _
+  Optional ByVal UsePrivileges As Boolean = False, _
+  Optional ByVal ExcludeExtraAttributes As Boolean = False, Optional ByVal SplitSize As String = "", _
+  Optional ByVal TempDirPath As String = "") As Boolean
+
+  Dim SplitNum As Long
+  Dim SplitMultS As String
+  Dim SplitMult As Long
+  
+  ' set some defaults
+  ZipOpts.date = vbNullString
+  ZipOpts.szRootDir = vbNullString
+  ZipOpts.szTempDir = vbNullString
+  ZipOpts.fTemp = 0
+  ZipOpts.fSuffix = 0
+  ZipOpts.fEncrypt = 0
+  ZipOpts.fSystem = 0
+  ZipOpts.fVolume = 0
+  ZipOpts.fExtra = 0
+  ZipOpts.fNoDirEntries = 0
+  ZipOpts.fExcludeDate = 0
+  ZipOpts.fIncludeDate = 0
+  ZipOpts.fVerbose = 0
+  ZipOpts.fQuiet = 0
+  ZipOpts.fCRLF_LF = 0
+  ZipOpts.fLF_CRLF = 0
+  ZipOpts.fJunkDir = 0
+  ZipOpts.fGrow = 0
+  ZipOpts.fForce = 0
+  ZipOpts.fMove = 0
+  ZipOpts.fDeleteEntries = 0
+  ZipOpts.fUpdate = 0
+  ZipOpts.fFreshen = 0
+  ZipOpts.fJunkSFX = 0
+  ZipOpts.fLatestTime = 0
+  ZipOpts.fComment = 0
+  ZipOpts.fOffsets = 0
+  ZipOpts.fPrivilege = 0
+  ZipOpts.szSplitSize = vbNullString
+  ZipOpts.IncludeListCount = 0
+  ZipOpts.szIncludeList = vbNullString
+  ZipOpts.ExcludeListCount = 0
+  ZipOpts.szExcludeList = vbNullString
+  ZipOpts.fRecurse = 0
+  ZipOpts.fRepair = 0
+  ZipOpts.flevel = 0
+  
+  If RootDirToZipFrom <> "" Then
+    ZipOpts.szRootDir = RootDirToZipFrom
+  End If
+  ZipOpts.flevel = Asc(CompressionLevel)
+  If UpdateSFXOffsets Then ZipOpts.fOffsets = 1
+  
+  If i_IncludeFiles <> "" Then
+    ZipOpts.szIncludeList = i_IncludeFiles
+  End If
+  If x_ExcludeFiles <> "" Then
+    ZipOpts.szExcludeList = x_ExcludeFiles
+  End If
+  
+  If ZipMode = Add Then
+    ' default
+  ElseIf ZipMode = Delete Then
+    ZipOpts.fDeleteEntries = 1
+  ElseIf ZipMode = Update Then
+    ZipOpts.fUpdate = 1
+  Else
+    ZipOpts.fFreshen = 1
+  End If
+  ZipOpts.fRepair = Repair
+  If GrowExistingArchive Then ZipOpts.fGrow = 1
+  If Move_DeleteAfterAddedOrUpdated Then ZipOpts.fMove = 1
+    
+  If Verboseness = Quiet Then
+    ZipOpts.fQuiet = 1
+  ElseIf Verboseness = Verbose Then
+    ZipOpts.fVerbose = 1
+  End If
+  
+  If ArchiveComment = False And Not IsEmpty(ArchiveCommentTextString) Then
+    MsgBox "Must set ArchiveComment = True to set ArchiveCommentTextString"
+    Exit Function
+  End If
+  If IsEmpty(ArchiveCommentTextString) Then
+    ArchiveCommentText = Empty
+  Else
+    ArchiveCommentText = ArchiveCommentTextString
+  End If
+  If ArchiveComment Then ZipOpts.fComment = 1
+  
+  If NoDirEntries Then ZipOpts.fNoDirEntries = 1
+  If JunkDirNames Then ZipOpts.fJunkDir = 1
+  If Encrypt Then ZipOpts.fEncrypt = 1
+  EncryptionPassword = Password
+  If JunkSFXPrefix Then ZipOpts.fJunkSFX = 1
+  If ForceUseOfDOSNames Then ZipOpts.fForce = 1
+  If Translate_LF = LF_To_CRLF Then ZipOpts.fLF_CRLF = 1
+  If Translate_LF = CRLF_To_LF Then ZipOpts.fCRLF_LF = 1
+  ZipOpts.fRecurse = RecurseSubdirectories
+  If IncludeSystemAndHiddenFiles Then ZipOpts.fSystem = 1
+  
+  If SetZipTimeToLatestTime Then ZipOpts.fLatestTime = 1
+  If ExcludeEarlierThanDate <> "" And IncludeEarlierThanDate <> "" Then
+    MsgBox "Both ExcludeEarlierThanDate and IncludeEarlierThanDate not " & Chr(10) & _
+           "supported at same time"
+    Exit Function
+  End If
+  If ExcludeEarlierThanDate <> "" Then
+    ZipOpts.fIncludeDate = 1
+    ZipOpts.date = ExcludeEarlierThanDate
+  End If
+  If IncludeEarlierThanDate <> "" Then
+    ZipOpts.fExcludeDate = 1
+    ZipOpts.date = IncludeEarlierThanDate
+  End If
+  
+  If TempDirPath <> "" Then
+    ZipOpts.szTempDir = TempDirPath
+    ZipOpts.fTemp = 1
+  End If
+  
+  If SplitSize <> "" Then
+    SplitSize = Trim(SplitSize)
+    SplitMultS = Right(SplitSize, 1)
+    SplitMultS = UCase(SplitMultS)
+    If (SplitMultS = "K") Then
+        SplitMult = 1024
+        SplitNum = Val(Left(SplitSize, Len(SplitSize) - 1))
+    ElseIf SplitMultS = "M" Then
+        SplitMult = 1024 * 1024&
+        SplitNum = Val(Left(SplitSize, Len(SplitSize) - 1))
+    ElseIf SplitMultS = "G" Then
+        SplitMult = 1024 * 1024 * 1024&
+        SplitNum = Val(Left(SplitSize, Len(SplitSize) - 1))
+    Else
+        SplitMult = 1024 * 1024&
+        SplitNum = Val(SplitSize)
+    End If
+    SplitNum = SplitNum * SplitMult
+    If SplitNum = 0 Then
+        MsgBox "SplitSize of 0 not supported"
+        Exit Function
+    ElseIf SplitNum < 64 * 1024& Then
+        MsgBox "SplitSize must be at least 64k"
+        Exit Function
+    End If
+    ZipOpts.szSplitSize = SplitSize
+  End If
+  
+  If IncludeVolumeLabel Then ZipOpts.fVolume = 1
+  If UsePrivileges Then ZipOpts.fPrivilege = 1
+  If ExcludeExtraAttributes Then ZipOpts.fExtra = 1
+  
+  SetZipOptions = True
+    
+End Function
+
+Function ChopNulls(ByVal Str) As String
+  Dim A As Integer
+  Dim C As String
+    
+  For A = 1 To Len(Str)
+    If Mid(Str, A, 1) = Chr(0) Then
+      ChopNulls = Left(Str, A - 1)
+      Exit Function
+    End If
+  Next
+  ChopNulls = Str
+    
+End Function
+Sub DisplayVersion()
+  
+  ' display version of DLL
+  Dim Beta As Boolean
+  Dim ZLIB As Boolean
+  Dim Zip64 As Boolean
+  Dim Flags As String
+  Dim A As Integer
+  
+  ZipVersion.structlen = Len(ZipVersion)
+  ZpVersion ZipVersion
+  ' Check flag
+  If ZipVersion.flag And 1 Then
+    Flags = Flags & " Beta,"
+    Beta = True
+  Else
+    Flags = Flags & " No Beta,"
+  End If
+  If ZipVersion.flag And 2 Then
+    Flags = Flags & " ZLIB,"
+    ZLIB = True
+  Else
+    Flags = Flags & " No ZLIB,"
+  End If
+  If ZipVersion.flag And 4 Then
+    Flags = Flags & " Zip64, "
+    Zip64 = True
+  Else
+    Flags = Flags & " No Zip64, "
+  End If
+  If ZipVersion.encryption Then
+    Flags = Flags & "Encryption"
+  Else
+    Flags = Flags & " No encryption"
+  End If
+  
+  Form1.Caption = "Using Zip32z64.DLL Version " & _
+                  ZipVersion.ZipVersion.Major & "." & ZipVersion.ZipVersion.Minor & " " & _
+                  ChopNulls(ZipVersion.Beta) & "  [" & ChopNulls(ZipVersion.date) & "]" & _
+                  " - FLAGS: " & Flags
+
+  If Not Zip64 Then
+    A = MsgBox("Zip32z64.dll not compiled with Zip64 enabled - continue?", _
+               vbOKCancel, _
+               "Wrong dll")
+    If A = vbCancel Then
+        End
+    End If
+  End If
+  
+End Sub
+
+'-- Main ZIP32.DLL Subroutine.
+'-- This Is Where It All Happens!!!
+'--
+'-- (WARNING!) Do Not Change This Function!!!
+'--
+Public Function VBZip32() As Long
+    
+  Dim retcode As Long
+  Dim FileNotFound As Boolean
+    
+  ' On Error Resume Next '-- Nothing Will Go Wrong :-)
+  On Error GoTo ZipError
+    
+  retcode = 0
+    
+  '-- Set Address Of ZIP32.DLL Callback Functions
+  '-- (WARNING!) Do Not Change!!! (except as noted below)
+  ZUSER.ZDLLPrnt = FnPtr(AddressOf ZDLLPrnt)
+  ZUSER.ZDLLPASSWORD = FnPtr(AddressOf ZDLLPass)
+  ZUSER.ZDLLCOMMENT = FnPtr(AddressOf ZDLLComm)
+  ZUSER.ZDLLSERVICE_NO_INT64 = FnPtr(AddressOf ZDLLServ)
+  
+  ' If you need to set destination of each split set this
+  'ZUSER.ZDLLSPLIT = FnPtr(AddressOf ZDLLSplitSelect)
+
+  '-- Set ZIP32.DLL Callbacks - return 1 if DLL loaded 0 if not
+  retcode = ZpInit(ZUSER)
+  If retcode = 0 And FileNotFound Then
+    MsgBox "Probably could not find Zip32z64.DLL - have you copied" & Chr(10) & _
+           "it to the System directory, your program directory, " & Chr(10) & _
+           "or a directory on your command PATH?"
+    VBZip32 = retcode
+    Exit Function
+  End If
+  
+  DisplayVersion
+    
+  If strZipFileNames = "" Then
+    ' not using string of names to zip (so using array of names)
+    strZipFileNames = vbNullString
+  End If
+  
+  '-- Go Zip It Them Up!
+  retcode = ZpArchive(zArgc, zZipArchiveName, zZipFileNames, strZipFileNames, ZOPT)
+  
+  '-- Return The Function Code
+  VBZip32 = retcode
+
+  Exit Function
+
+ZipError:
+  MsgBox "Error:  " & Err.Description
+  If Err = 48 Then
+    FileNotFound = True
+  End If
+  Resume Next
+
+End Function
+
diff --git a/windll/VBz64/Vbzipfrm.frm b/windll/VBz64/Vbzipfrm.frm
new file mode 100644 (file)
index 0000000..57c4df4
--- /dev/null
@@ -0,0 +1,183 @@
+VERSION 5.00\r
+Begin VB.Form Form1 \r
+   AutoRedraw      =   -1  'True\r
+   Caption         =   "Form1"\r
+   ClientHeight    =   3150\r
+   ClientLeft      =   60\r
+   ClientTop       =   345\r
+   ClientWidth     =   6570\r
+   BeginProperty Font \r
+      Name            =   "MS Sans Serif"\r
+      Size            =   9.75\r
+      Charset         =   0\r
+      Weight          =   700\r
+      Underline       =   0   'False\r
+      Italic          =   0   'False\r
+      Strikethrough   =   0   'False\r
+   EndProperty\r
+   LinkTopic       =   "Form1"\r
+   ScaleHeight     =   3150\r
+   ScaleWidth      =   6570\r
+   StartUpPosition =   1  'CenterOwner\r
+End\r
+Attribute VB_Name = "Form1"\r
+Attribute VB_GlobalNameSpace = False\r
+Attribute VB_Creatable = False\r
+Attribute VB_PredeclaredId = True\r
+Attribute VB_Exposed = False\r
+\r
+Option Explicit\r
+\r
+'---------------------------------------------------------------\r
+'-- Sample VB 6 code to drive zip32z64.dll\r
+'--\r
+'-- Based on code contributed to the Info-ZIP project by Mike Le Voi\r
+'--\r
+'-- See the Original VB example in a separate directory for\r
+'-- more information\r
+'--\r
+'-- Use this code at your own risk. Nothing implied or warranted\r
+'-- to work on your machine :-)\r
+'---------------------------------------------------------------\r
+'--\r
+'-- The Source Code Is Freely Available From Info-ZIP At:\r
+'--   ftp://ftp.info-zip.org/pub/infozip/infozip.html\r
+'-- and\r
+'--   http://sourceforge.net/projects/infozip/\r
+'--\r
+'-- A Very Special Thanks To Mr. Mike Le Voi\r
+'-- And Mr. Mike White Of The Info-ZIP project\r
+'-- For Letting Me Use And Modify His Orginal\r
+'-- Visual Basic 5.0 Code! Thank You Mike Le Voi.\r
+'---------------------------------------------------------------\r
+'--\r
+'-- Contributed To The Info-ZIP Project By Raymond L. King\r
+'-- Modified June 21, 1998\r
+'-- By Raymond L. King\r
+'-- Custom Software Designers\r
+'--\r
+'-- Contact Me At: king@ntplx.net\r
+'-- ICQ 434355\r
+'-- Or Visit Our Home Page At: http://www.ntplx.net/~king\r
+'--\r
+'---------------------------------------------------------------\r
+\r
+'---------------------------------------------------------------\r
+' Zip32z64.dll is the new Zip32.dll based on Zip 3.0 and compiled\r
+' with Zip64 support enabled.  See windll.txt in the windll directory\r
+' for more on Zip32z64 and the comments in VBZipBas.bas.\r
+'\r
+' Contact Info-Zip if problems.  This code is\r
+' provided under the Info-Zip license.\r
+'\r
+' 4/24/2004, 12/4/2007 EG\r
+'---------------------------------------------------------------\r
+\r
+Private Sub Form_Click()\r
+\r
+  Dim retcode As Integer  ' For Return Code From ZIP32.DLL\r
+  Dim iFiles As String\r
+  Dim FilesToZip() As String\r
+  Dim i As Long\r
+\r
+  Cls\r
+\r
+  '-- Set Options - Only The Common Ones Are Shown Here\r
+  '-- These Must Be Set Before Calling The VBZip32 Function\r
+  \r
+  ' In VB 6 you can see the list of possible options and the defaults\r
+  ' by adding a space between any parameters which should make the tip box\r
+  ' appear.  Delete a := and retype to see a list of choices.\r
+\r
+  ' Be warned:  There are bugs in the previous dll.  See the Original VB\r
+  ' example in the VB directory for details.\r
+  \r
+  If Not SetZipOptions(ZOPT, _\r
+                       ZipMode:=Add, _\r
+                       CompressionLevel:=c6_Default) Then\r
+           ' Some additional options ...\r
+           '            RootDirToZipFrom:="", _\r
+           '   strip paths and just store names:\r
+           '            JunkDirNames:=False, _\r
+           '   do not store entries for the directories themselves:\r
+           '            NoDirEntries:=True _\r
+           '   include files only if match one of these patterns:\r
+           '            i_IncludeFiles:="*.vbp *.frm", _\r
+           '   exclude files that match these patterns:\r
+           '            x_ExcludeFiles:="*.bas", _\r
+           '            Verboseness:=Verbose, _\r
+           '            IncludeEarlierThanDate:="2004-4-1", _\r
+           '            RecurseSubdirectories:=r_RecurseIntoSubdirectories, _\r
+           '            Encrypt:=False, _\r
+           '            ArchiveComment:=False\r
+           ' date example (format mmddyyyy or yyyy-mm-dd):\r
+           '           ExcludeEarlierThanDate:="2002-12-10", _\r
+           ' split example (can only create, can't update split archives in VB):\r
+           '            SplitSize:="110k", _\r
+' Delete\r
+ ' If Not SetZipOptions(ZOPT, _\r
+ '                      ZipMode:=Delete) Then\r
\r
+    ' a problem if get here - error message already displayed so just exit\r
+    Exit Sub\r
+  End If\r
+  \r
+\r
+  '-- Select Some Files - Wildcards Are Supported\r
+  '-- Change The Paths Here To Your Directory\r
+  '-- And Files!!!\r
+\r
+  ' default to current (VB project) directory and zip up project files\r
+  zZipArchiveName = "MyFirst.zip"\r
+  \r
+  \r
+  ' Files to zip - use one of below\r
+  \r
+  '---------------\r
+  ' Example using file name array\r
+  \r
+  ' Store the file paths\r
+  ' Change Dim of zFiles at top of VBZipBas.bas if more than 100 files\r
+  ' See note at top of VBZipBas.bas for limit on number of files\r
+  \r
+'  zArgc = 2           ' Number Of file paths below\r
+'  zZipFileNames.zFiles(1) = "*.bas"\r
+'  zZipFileNames.zFiles(2) = "*.frm"\r
+  \r
+  '---------------\r
+  ' Example using file list string\r
+  \r
+  ' List of files to zip as string of names with space between\r
+  ' Set zArgc = 0 as not using array\r
+  ' Using string for file list avoids above array limit\r
+  \r
+  zArgc = 0\r
+'  ReDim FilesToZip(1)      ' dim to number of files below\r
+'  FilesToZip(1) = "x:*.*"\r
+  ReDim FilesToZip(2)      ' dim to number of files below\r
+  FilesToZip(1) = "*.bas"\r
+  FilesToZip(2) = "*.frm"\r
\r
+  ' Build string of file names\r
+  ' Best to put double quotes around each in case of spaces\r
+  strZipFileNames = ""\r
+  For i = 1 To UBound(FilesToZip)\r
+    strZipFileNames = strZipFileNames & """" & FilesToZip(i) & """ "\r
+  Next\r
+  '---------------\r
+  \r
+  '-- Go Zip Them Up!\r
+  retcode = VBZip32()\r
+\r
+  '-- Display The Returned Code Or Error!\r
+  Print "Return code:" & Str(retcode)\r
+\r
+End Sub\r
+\r
+Private Sub Form_Load()\r
+\r
+  Me.Show\r
+\r
+  Print "Click me!"\r
+\r
+End Sub\r
diff --git a/windll/VBz64/readVB64.txt b/windll/VBz64/readVB64.txt
new file mode 100644 (file)
index 0000000..2876b44
--- /dev/null
@@ -0,0 +1,25 @@
+On Windows open this file in WordPad.
+
+Contents of the "windll/vbz64" sub-archive
+
+This directory contains a Visual Basic project example for using the
+zip32z64.dll library (Zip 3.0 with Zip64 enabled).  See the comments in
+the form and project files for details.
+
+This new project and the new zip32z64.dll library are not compatible
+with previous VB examples using the zip32.dll interface as this new
+interface supports more files and handles file sizes larger than 2 GB.
+It should be simple to convert a VB program using zip32.dll to
+zip32z64.dll but the program may need some changes.  For a compatible
+replacement use the dll compiled from Zip 2.32 (released separately)
+and see the zip32.dll example in the VB directory of this source tree.
+
+Note that the files may be saved in unix format with carriage returns
+stripped.  These must be restored before the project can be successfully
+used.  This can be done by using the -a option to unzip.  Another way to
+do this is to open each file in WordPad, select and cut a line, paste
+the line back, and save the file.  This will force WordPad to change the
+line ends in the entire file.  Newer versions of WordPad may not do this.
+
+Ed Gordon
+4/26/2008
diff --git a/windll/Vb/VBZIP.vbw b/windll/Vb/VBZIP.vbw
new file mode 100644 (file)
index 0000000..2f8339a
--- /dev/null
@@ -0,0 +1,2 @@
+Form1 = 0, 0, 0, 0, C, 22, 22, 563, 389, C\r
+VBZipBas = 44, 44, 659, 489, \r
diff --git a/windll/Vb/VBZipBas.bas b/windll/Vb/VBZipBas.bas
new file mode 100644 (file)
index 0000000..2b766e9
--- /dev/null
@@ -0,0 +1,458 @@
+Attribute VB_Name = "VBZipBas"\r
+\r
+Option Explicit\r
+\r
+'---------------------------------------------------------------\r
+'-- Please Do Not Remove These Comments!!!\r
+'---------------------------------------------------------------\r
+'-- Sample VB 5 code to drive zip32.dll\r
+'-- Contributed to the Info-ZIP project by Mike Le Voi\r
+'--\r
+'-- Contact me at: mlevoi@modemss.brisnet.org.au\r
+'--\r
+'-- Visit my home page at: http://modemss.brisnet.org.au/~mlevoi\r
+'--\r
+'-- Use this code at your own risk. Nothing implied or warranted\r
+'-- to work on your machine :-)\r
+'---------------------------------------------------------------\r
+'--\r
+'-- The Source Code Is Freely Available From Info-ZIP At:\r
+'-- http://www.cdrom.com/pub/infozip/infozip.html\r
+'--\r
+'-- A Very Special Thanks To Mr. Mike Le Voi\r
+'-- And Mr. Mike White Of The Info-ZIP\r
+'-- For Letting Me Use And Modify His Orginal\r
+'-- Visual Basic 5.0 Code! Thank You Mike Le Voi.\r
+'---------------------------------------------------------------\r
+'--\r
+'-- Contributed To The Info-ZIP Project By Raymond L. King\r
+'-- Modified June 21, 1998\r
+'-- By Raymond L. King\r
+'-- Custom Software Designers\r
+'--\r
+'-- Contact Me At: king@ntplx.net\r
+'-- ICQ 434355\r
+'-- Or Visit Our Home Page At: http://www.ntplx.net/~king\r
+'--\r
+'---------------------------------------------------------------\r
+'\r
+' This is the original example with some small changes.  Only\r
+' use with the original Zip32.dll (compiled from Zip 2.31 or\r
+' later).  Do not use this VB example with Zip32z64.dll\r
+' (compiled from Zip 3.0).  To check the version of a dll,\r
+' right click on the file and check properties.\r
+'\r
+' 6/24/2008 Ed Gordon\r
+\r
+'---------------------------------------------------------------\r
+' Usage notes:\r
+'\r
+' This code uses Zip32.dll.  You DO NOT need to register the\r
+' DLL to use it.  You also DO NOT need to reference it in your\r
+' VB project.  You DO have to copy the DLL to your SYSTEM\r
+' directory, your VB project directory, or place it in a directory\r
+' on your command PATH.\r
+'\r
+' A bug has been found in the Zip32.dll when called from VB.  If\r
+' you try to pass any values other than NULL in the ZPOPT strings\r
+' Date, szRootDir, or szTempDir they get converted from the\r
+' VB internal wide character format to temporary byte strings by\r
+' the calling interface as they are supposed to.  However when\r
+' ZpSetOptions returns the passed strings are deallocated unless the\r
+' VB debugger prevents it by a break between ZpSetOptions and\r
+' ZpArchive.  When Zip32.dll uses these pointers later it\r
+' can result in unpredictable behavior.  A kluge is available\r
+' for Zip32.dll, just replacing api.c in Zip 2.3, but better to just\r
+' use the new Zip32z64.dll where these bugs are fixed.  However,\r
+' the kluge has been added to Zip 2.31 and later and these are\r
+' now stable.  To determine the version of the dll you have\r
+' right click on it, select the Version tab, and verify the\r
+' Product Version is at least 2.31.\r
+'\r
+' Another bug is where -R is used with some other options and can\r
+' crash the dll.  This is a bug in how zip processes the command\r
+' line and should be mostly fixed in Zip 2.31.  If you run into\r
+' problems try using -r instead for recursion.  The bug is fixed\r
+' in Zip 3.0 but note that Zip 3.0 creates dll zip32z64.dll and\r
+' it is not compatible with older VB including this example.  See\r
+' the new VB example code included with Zip 3.0 for calling\r
+' interface changes.\r
+'\r
+' Note that Zip32 is probably not thread safe.  It may be made\r
+' thread safe in a later version, but for now only one thread in\r
+' one program should use the DLL at a time.  Unlike Zip, UnZip is\r
+' probably thread safe, but an exception to this has been\r
+' found.  See the UnZip documentation for the latest on this.\r
+'\r
+' All code in this VB project is provided under the Info-Zip license.\r
+'\r
+' If you have any questions please contact Info-Zip at\r
+' http://www.info-zip.org.\r
+'\r
+' 4/29/2004 EG (Updated 3/1/2005, 6/24/2008 EG)\r
+'\r
+'---------------------------------------------------------------\r
+\r
+\r
+'-- C Style argv\r
+'-- Holds The Zip Archive Filenames\r
+' Max for this just over 8000 as each pointer takes up 4 bytes and\r
+' VB only allows 32 kB of local variables and that includes function\r
+' parameters.  - 3/19/2004 EG\r
+'\r
+Public Type ZIPnames\r
+  zFiles(0 To 99) As String\r
+End Type\r
+\r
+'-- Call Back "String"\r
+Public Type ZipCBChar\r
+  ch(4096) As Byte\r
+End Type\r
+\r
+'-- ZPOPT Is Used To Set The Options In The ZIP32.DLL\r
+Public Type ZPOPT\r
+  Date           As String ' US Date (8 Bytes Long) "12/31/98"?\r
+  szRootDir      As String ' Root Directory Pathname (Up To 256 Bytes Long)\r
+  szTempDir      As String ' Temp Directory Pathname (Up To 256 Bytes Long)\r
+  fTemp          As Long   ' 1 If Temp dir Wanted, Else 0\r
+  fSuffix        As Long   ' Include Suffixes (Not Yet Implemented!)\r
+  fEncrypt       As Long   ' 1 If Encryption Wanted, Else 0\r
+  fSystem        As Long   ' 1 To Include System/Hidden Files, Else 0\r
+  fVolume        As Long   ' 1 If Storing Volume Label, Else 0\r
+  fExtra         As Long   ' 1 If Excluding Extra Attributes, Else 0\r
+  fNoDirEntries  As Long   ' 1 If Ignoring Directory Entries, Else 0\r
+  fExcludeDate   As Long   ' 1 If Excluding Files Earlier Than Specified Date, Else 0\r
+  fIncludeDate   As Long   ' 1 If Including Files Earlier Than Specified Date, Else 0\r
+  fVerbose       As Long   ' 1 If Full Messages Wanted, Else 0\r
+  fQuiet         As Long   ' 1 If Minimum Messages Wanted, Else 0\r
+  fCRLF_LF       As Long   ' 1 If Translate CR/LF To LF, Else 0\r
+  fLF_CRLF       As Long   ' 1 If Translate LF To CR/LF, Else 0\r
+  fJunkDir       As Long   ' 1 If Junking Directory Names, Else 0\r
+  fGrow          As Long   ' 1 If Allow Appending To Zip File, Else 0\r
+  fForce         As Long   ' 1 If Making Entries Using DOS File Names, Else 0\r
+  fMove          As Long   ' 1 If Deleting Files Added Or Updated, Else 0\r
+  fDeleteEntries As Long   ' 1 If Files Passed Have To Be Deleted, Else 0\r
+  fUpdate        As Long   ' 1 If Updating Zip File-Overwrite Only If Newer, Else 0\r
+  fFreshen       As Long   ' 1 If Freshing Zip File-Overwrite Only, Else 0\r
+  fJunkSFX       As Long   ' 1 If Junking SFX Prefix, Else 0\r
+  fLatestTime    As Long   ' 1 If Setting Zip File Time To Time Of Latest File In Archive, Else 0\r
+  fComment       As Long   ' 1 If Putting Comment In Zip File, Else 0\r
+  fOffsets       As Long   ' 1 If Updating Archive Offsets For SFX Files, Else 0\r
+  fPrivilege     As Long   ' 1 If Not Saving Privileges, Else 0\r
+  fEncryption    As Long   ' Read Only Property!!!\r
+  fRecurse       As Long   ' 1 (-r), 2 (-R) If Recursing Into Sub-Directories, Else 0\r
+  fRepair        As Long   ' 1 = Fix Archive, 2 = Try Harder To Fix, Else 0\r
+  flevel         As Byte   ' Compression Level - 0 = Stored 6 = Default 9 = Max\r
+End Type\r
+\r
+'-- This Structure Is Used For The ZIP32.DLL Function Callbacks\r
+Public Type ZIPUSERFUNCTIONS\r
+  ZDLLPrnt     As Long        ' Callback ZIP32.DLL Print Function\r
+  ZDLLCOMMENT  As Long        ' Callback ZIP32.DLL Comment Function\r
+  ZDLLPASSWORD As Long        ' Callback ZIP32.DLL Password Function\r
+  ZDLLSERVICE  As Long        ' Callback ZIP32.DLL Service Function\r
+End Type\r
+\r
+'-- Local Declarations\r
+Public ZOPT  As ZPOPT\r
+Public ZUSER As ZIPUSERFUNCTIONS\r
+\r
+'-- This Assumes ZIP32.DLL Is In Your \Windows\System Directory!\r
+'-- (alternatively, a copy of ZIP32.DLL needs to be located in the program\r
+'-- directory or in some other directory listed in PATH.)\r
+Private Declare Function ZpInit Lib "zip32.dll" _\r
+  (ByRef Zipfun As ZIPUSERFUNCTIONS) As Long '-- Set Zip Callbacks\r
+\r
+Private Declare Function ZpSetOptions Lib "zip32.dll" _\r
+  (ByRef Opts As ZPOPT) As Long '-- Set Zip Options\r
+\r
+Private Declare Function ZpGetOptions Lib "zip32.dll" _\r
+  () As ZPOPT '-- Used To Check Encryption Flag Only\r
+\r
+Private Declare Function ZpArchive Lib "zip32.dll" _\r
+  (ByVal argc As Long, ByVal funame As String, _\r
+   ByRef argv As ZIPnames) As Long '-- Real Zipping Action\r
+\r
+'-------------------------------------------------------\r
+'-- Public Variables For Setting The ZPOPT Structure...\r
+'-- (WARNING!!!) You Must Set The Options That You\r
+'-- Want The ZIP32.DLL To Do!\r
+'-- Before Calling VBZip32!\r
+'--\r
+'-- NOTE: See The Above ZPOPT Structure Or The VBZip32\r
+'--       Function, For The Meaning Of These Variables\r
+'--       And How To Use And Set Them!!!\r
+'-- These Parameters Must Be Set Before The Actual Call\r
+'-- To The VBZip32 Function!\r
+'-------------------------------------------------------\r
+Public zDate         As String\r
+Public zRootDir      As String\r
+Public zTempDir      As String\r
+Public zSuffix       As Integer\r
+Public zEncrypt      As Integer\r
+Public zSystem       As Integer\r
+Public zVolume       As Integer\r
+Public zExtra        As Integer\r
+Public zNoDirEntries As Integer\r
+Public zExcludeDate  As Integer\r
+Public zIncludeDate  As Integer\r
+Public zVerbose      As Integer\r
+Public zQuiet        As Integer\r
+Public zCRLF_LF      As Integer\r
+Public zLF_CRLF      As Integer\r
+Public zJunkDir      As Integer\r
+Public zRecurse      As Integer\r
+Public zGrow         As Integer\r
+Public zForce        As Integer\r
+Public zMove         As Integer\r
+Public zDelEntries   As Integer\r
+Public zUpdate       As Integer\r
+Public zFreshen      As Integer\r
+Public zJunkSFX      As Integer\r
+Public zLatestTime   As Integer\r
+Public zComment      As Integer\r
+Public zOffsets      As Integer\r
+Public zPrivilege    As Integer\r
+Public zEncryption   As Integer\r
+Public zRepair       As Integer\r
+Public zLevel        As Integer\r
+\r
+'-- Public Program Variables\r
+Public zArgc         As Integer     ' Number Of Files To Zip Up\r
+Public zZipFileName  As String      ' The Zip File Name ie: Myzip.zip\r
+Public zZipFileNames As ZIPnames    ' File Names To Zip Up\r
+Public zZipInfo      As String      ' Holds The Zip File Information\r
+\r
+'-- Public Constants\r
+'-- For Zip & UnZip Error Codes!\r
+Public Const ZE_OK = 0              ' Success (No Error)\r
+Public Const ZE_EOF = 2             ' Unexpected End Of Zip File Error\r
+Public Const ZE_FORM = 3            ' Zip File Structure Error\r
+Public Const ZE_MEM = 4             ' Out Of Memory Error\r
+Public Const ZE_LOGIC = 5           ' Internal Logic Error\r
+Public Const ZE_BIG = 6             ' Entry Too Large To Split Error\r
+Public Const ZE_NOTE = 7            ' Invalid Comment Format Error\r
+Public Const ZE_TEST = 8            ' Zip Test (-T) Failed Or Out Of Memory Error\r
+Public Const ZE_ABORT = 9           ' User Interrupted Or Termination Error\r
+Public Const ZE_TEMP = 10           ' Error Using A Temp File\r
+Public Const ZE_READ = 11           ' Read Or Seek Error\r
+Public Const ZE_NONE = 12           ' Nothing To Do Error\r
+Public Const ZE_NAME = 13           ' Missing Or Empty Zip File Error\r
+Public Const ZE_WRITE = 14          ' Error Writing To A File\r
+Public Const ZE_CREAT = 15          ' Could't Open To Write Error\r
+Public Const ZE_PARMS = 16          ' Bad Command Line Argument Error\r
+Public Const ZE_OPEN = 18           ' Could Not Open A Specified File To Read Error\r
+\r
+'-- These Functions Are For The ZIP32.DLL\r
+'--\r
+'-- Puts A Function Pointer In A Structure\r
+'-- For Use With Callbacks...\r
+Public Function FnPtr(ByVal lp As Long) As Long\r
+    \r
+  FnPtr = lp\r
+\r
+End Function\r
+\r
+'-- Callback For ZIP32.DLL - DLL Print Function\r
+Public Function ZDLLPrnt(ByRef fname As ZipCBChar, ByVal x As Long) As Long\r
+    \r
+  Dim s0 As String\r
+  Dim xx As Long\r
+    \r
+  '-- Always Put This In Callback Routines!\r
+  On Error Resume Next\r
+    \r
+  s0 = ""\r
+    \r
+  '-- Get Zip32.DLL Message For processing\r
+  For xx = 0 To x\r
+    If fname.ch(xx) = 0 Then\r
+      Exit For\r
+    Else\r
+      s0 = s0 + Chr(fname.ch(xx))\r
+    End If\r
+  Next\r
+    \r
+  '----------------------------------------------\r
+  '-- This Is Where The DLL Passes Back Messages\r
+  '-- To You! You Can Change The Message Printing\r
+  '-- Below Here!\r
+  '----------------------------------------------\r
+  \r
+  '-- Display Zip File Information\r
+  '-- zZipInfo = zZipInfo & s0\r
+  Form1.Print s0;\r
+    \r
+  DoEvents\r
+    \r
+  ZDLLPrnt = 0\r
+\r
+End Function\r
+\r
+'-- Callback For ZIP32.DLL - DLL Service Function\r
+Public Function ZDLLServ(ByRef mname As ZipCBChar, ByVal x As Long) As Long\r
+\r
+    ' x is the size of the file\r
+    \r
+    Dim s0 As String\r
+    Dim xx As Long\r
+    \r
+    '-- Always Put This In Callback Routines!\r
+    On Error Resume Next\r
+    \r
+    s0 = ""\r
+    '-- Get Zip32.DLL Message For processing\r
+    For xx = 0 To 4096\r
+    If mname.ch(xx) = 0 Then\r
+        Exit For\r
+    Else\r
+        s0 = s0 + Chr(mname.ch(xx))\r
+    End If\r
+    Next\r
+    ' Form1.Print "-- " & s0 & " - " & x & " bytes"\r
+    \r
+    ' This is called for each zip entry.\r
+    ' mname is usually the null terminated file name and x the file size.\r
+    ' s0 has trimmed file name as VB string.\r
+\r
+    ' At this point, s0 contains the message passed from the DLL\r
+    ' It is up to the developer to code something useful here :)\r
+    ZDLLServ = 0 ' Setting this to 1 will abort the zip!\r
+    \r
+End Function\r
+\r
+'-- Callback For ZIP32.DLL - DLL Password Function\r
+Public Function ZDLLPass(ByRef p As ZipCBChar, _\r
+  ByVal n As Long, ByRef m As ZipCBChar, _\r
+  ByRef Name As ZipCBChar) As Integer\r
+  \r
+  Dim prompt     As String\r
+  Dim xx         As Integer\r
+  Dim szpassword As String\r
+  \r
+  '-- Always Put This In Callback Routines!\r
+  On Error Resume Next\r
+    \r
+  ZDLLPass = 1\r
+  \r
+  '-- If There Is A Password Have The User Enter It!\r
+  '-- This Can Be Changed\r
+  szpassword = InputBox("Please Enter The Password!")\r
+  \r
+  '-- The User Did Not Enter A Password So Exit The Function\r
+  If szpassword = "" Then Exit Function\r
+  \r
+  '-- User Entered A Password So Proccess It\r
+  For xx = 0 To 255\r
+    If m.ch(xx) = 0 Then\r
+      Exit For\r
+    Else\r
+      prompt = prompt & Chr(m.ch(xx))\r
+    End If\r
+  Next\r
+  \r
+  For xx = 0 To n - 1\r
+    p.ch(xx) = 0\r
+  Next\r
+  \r
+  For xx = 0 To Len(szpassword) - 1\r
+    p.ch(xx) = Asc(Mid(szpassword, xx + 1, 1))\r
+  Next\r
+  \r
+  p.ch(xx) = Chr(0) ' Put Null Terminator For C\r
+  \r
+  ZDLLPass = 0\r
+    \r
+End Function\r
+\r
+'-- Callback For ZIP32.DLL - DLL Comment Function\r
+Public Function ZDLLComm(ByRef s1 As ZipCBChar) As Integer\r
+    \r
+    Dim xx%, szcomment$\r
+    \r
+    '-- Always Put This In Callback Routines!\r
+    On Error Resume Next\r
+    \r
+    ZDLLComm = 1\r
+    szcomment = InputBox("Enter the comment")\r
+    If szcomment = "" Then Exit Function\r
+    For xx = 0 To Len(szcomment) - 1\r
+        s1.ch(xx) = Asc(Mid$(szcomment, xx + 1, 1))\r
+    Next xx\r
+    s1.ch(xx) = Chr(0) ' Put null terminator for C\r
+\r
+End Function\r
+\r
+'-- Main ZIP32.DLL Subroutine.\r
+'-- This Is Where It All Happens!!!\r
+'--\r
+'-- (WARNING!) Do Not Change This Function!!!\r
+'--\r
+Public Function VBZip32() As Long\r
+    \r
+  Dim retcode As Long\r
+    \r
+  On Error Resume Next '-- Nothing Will Go Wrong :-)\r
+    \r
+  retcode = 0\r
+    \r
+  '-- Set Address Of ZIP32.DLL Callback Functions\r
+  '-- (WARNING!) Do Not Change!!!\r
+  ZUSER.ZDLLPrnt = FnPtr(AddressOf ZDLLPrnt)\r
+  ZUSER.ZDLLPASSWORD = FnPtr(AddressOf ZDLLPass)\r
+  ZUSER.ZDLLCOMMENT = FnPtr(AddressOf ZDLLComm)\r
+  ZUSER.ZDLLSERVICE = FnPtr(AddressOf ZDLLServ)\r
+    \r
+  '-- Set ZIP32.DLL Callbacks\r
+  retcode = ZpInit(ZUSER)\r
+  If retcode = 0 Then\r
+    MsgBox "Zip32.dll did not initialize.  Is it in the current directory " & _\r
+                "or on the command path?", vbOKOnly, "VB Zip"\r
+    Exit Function\r
+  End If\r
+    \r
+  '-- Setup ZIP32 Options\r
+  '-- (WARNING!) Do Not Change!\r
+  ZOPT.Date = zDate                  ' "12/31/79"? US Date?\r
+  ZOPT.szRootDir = zRootDir          ' Root Directory Pathname\r
+  ZOPT.szTempDir = zTempDir          ' Temp Directory Pathname\r
+  ZOPT.fSuffix = zSuffix             ' Include Suffixes (Not Yet Implemented)\r
+  ZOPT.fEncrypt = zEncrypt           ' 1 If Encryption Wanted\r
+  ZOPT.fSystem = zSystem             ' 1 To Include System/Hidden Files\r
+  ZOPT.fVolume = zVolume             ' 1 If Storing Volume Label\r
+  ZOPT.fExtra = zExtra               ' 1 If Including Extra Attributes\r
+  ZOPT.fNoDirEntries = zNoDirEntries ' 1 If Ignoring Directory Entries\r
+  ZOPT.fExcludeDate = zExcludeDate   ' 1 If Excluding Files Earlier Than A Specified Date\r
+  ZOPT.fIncludeDate = zIncludeDate   ' 1 If Including Files Earlier Than A Specified Date\r
+  ZOPT.fVerbose = zVerbose           ' 1 If Full Messages Wanted\r
+  ZOPT.fQuiet = zQuiet               ' 1 If Minimum Messages Wanted\r
+  ZOPT.fCRLF_LF = zCRLF_LF           ' 1 If Translate CR/LF To LF\r
+  ZOPT.fLF_CRLF = zLF_CRLF           ' 1 If Translate LF To CR/LF\r
+  ZOPT.fJunkDir = zJunkDir           ' 1 If Junking Directory Names\r
+  ZOPT.fGrow = zGrow                 ' 1 If Allow Appending To Zip File\r
+  ZOPT.fForce = zForce               ' 1 If Making Entries Using DOS Names\r
+  ZOPT.fMove = zMove                 ' 1 If Deleting Files Added Or Updated\r
+  ZOPT.fDeleteEntries = zDelEntries  ' 1 If Files Passed Have To Be Deleted\r
+  ZOPT.fUpdate = zUpdate             ' 1 If Updating Zip File-Overwrite Only If Newer\r
+  ZOPT.fFreshen = zFreshen           ' 1 If Freshening Zip File-Overwrite Only\r
+  ZOPT.fJunkSFX = zJunkSFX           ' 1 If Junking SFX Prefix\r
+  ZOPT.fLatestTime = zLatestTime     ' 1 If Setting Zip File Time To Time Of Latest File In Archive\r
+  ZOPT.fComment = zComment           ' 1 If Putting Comment In Zip File\r
+  ZOPT.fOffsets = zOffsets           ' 1 If Updating Archive Offsets For SFX Files\r
+  ZOPT.fPrivilege = zPrivilege       ' 1 If Not Saving Privelages\r
+  ZOPT.fEncryption = zEncryption     ' Read Only Property!\r
+  ZOPT.fRecurse = zRecurse           ' 1 or 2 If Recursing Into Subdirectories\r
+  ZOPT.fRepair = zRepair             ' 1 = Fix Archive, 2 = Try Harder To Fix\r
+  ZOPT.flevel = zLevel               ' Compression Level - (0 To 9) Should Be 0!!!\r
+    \r
+  '-- Set ZIP32.DLL Options\r
+  retcode = ZpSetOptions(ZOPT)\r
+    \r
+  '-- Go Zip It Them Up!\r
+  retcode = ZpArchive(zArgc, zZipFileName, zZipFileNames)\r
+  \r
+  '-- Return The Function Code\r
+  VBZip32 = retcode\r
+\r
+End Function\r
+\r
diff --git a/windll/Vb/Vbzip.vbp b/windll/Vb/Vbzip.vbp
new file mode 100644 (file)
index 0000000..b5e5827
--- /dev/null
@@ -0,0 +1,34 @@
+Type=Exe\r
+Form=Vbzipfrm.frm\r
+Module=VBZipBas; VBZipBas.bas\r
+IconForm="Form1"\r
+Startup="Form1"\r
+HelpFile=""\r
+Title="VBZIP"\r
+ExeName32="VBZIP.exe"\r
+Path32="..\..\.."\r
+Command32=""\r
+Name="Project1"\r
+HelpContextID="0"\r
+CompatibleMode="0"\r
+MajorVer=1\r
+MinorVer=0\r
+RevisionVer=0\r
+AutoIncrementVer=0\r
+ServerSupportFiles=0\r
+VersionCompanyName="Mike"\r
+CompilationType=-1\r
+OptimizationType=0\r
+FavorPentiumPro(tm)=0\r
+CodeViewDebugInfo=0\r
+NoAliasing=0\r
+BoundsCheck=0\r
+OverflowCheck=0\r
+FlPointCheck=0\r
+FDIVCheck=0\r
+UnroundedFP=0\r
+StartMode=0\r
+Unattended=0\r
+Retained=0\r
+ThreadPerObject=0\r
+MaxNumberOfThreads=1\r
diff --git a/windll/Vb/Vbzipfrm.frm b/windll/Vb/Vbzipfrm.frm
new file mode 100644 (file)
index 0000000..de323cd
--- /dev/null
@@ -0,0 +1,130 @@
+VERSION 5.00\r
+Begin VB.Form Form1 \r
+   AutoRedraw      =   -1  'True\r
+   Caption         =   "Form1"\r
+   ClientHeight    =   3150\r
+   ClientLeft      =   60\r
+   ClientTop       =   345\r
+   ClientWidth     =   6570\r
+   BeginProperty Font \r
+      Name            =   "MS Sans Serif"\r
+      Size            =   9.75\r
+      Charset         =   0\r
+      Weight          =   700\r
+      Underline       =   0   'False\r
+      Italic          =   0   'False\r
+      Strikethrough   =   0   'False\r
+   EndProperty\r
+   LinkTopic       =   "Form1"\r
+   ScaleHeight     =   3150\r
+   ScaleWidth      =   6570\r
+   StartUpPosition =   1  'CenterOwner\r
+End\r
+Attribute VB_Name = "Form1"\r
+Attribute VB_GlobalNameSpace = False\r
+Attribute VB_Creatable = False\r
+Attribute VB_PredeclaredId = True\r
+Attribute VB_Exposed = False\r
+\r
+Option Explicit\r
+\r
+'---------------------------------------------------------------\r
+'-- Please Do Not Remove These Comments!!!\r
+'---------------------------------------------------------------\r
+'-- Sample VB 5 code to drive zip32.dll\r
+'-- Contributed to the Info-ZIP project by Mike Le Voi\r
+'--\r
+'-- Contact me at: mlevoi@modemss.brisnet.org.au\r
+'--\r
+'-- Visit my home page at: http://modemss.brisnet.org.au/~mlevoi\r
+'--\r
+'-- Use this code at your own risk. Nothing implied or warranted\r
+'-- to work on your machine :-)\r
+'---------------------------------------------------------------\r
+'--\r
+'-- The Source Code Is Freely Available From Info-ZIP At:\r
+'-- http://www.cdrom.com/pub/infozip/infozip.html\r
+'--\r
+'-- A Very Special Thanks To Mr. Mike Le Voi\r
+'-- And Mr. Mike White Of The Info-ZIP project\r
+'-- For Letting Me Use And Modify His Orginal\r
+'-- Visual Basic 5.0 Code! Thank You Mike Le Voi.\r
+'---------------------------------------------------------------\r
+'--\r
+'-- Contributed To The Info-ZIP Project By Raymond L. King\r
+'-- Modified June 21, 1998\r
+'-- By Raymond L. King\r
+'-- Custom Software Designers\r
+'--\r
+'-- Contact Me At: king@ntplx.net\r
+'-- ICQ 434355\r
+'-- Or Visit Our Home Page At: http://www.ntplx.net/~king\r
+'--\r
+'---------------------------------------------------------------\r
+' This is the original VB example (with some changes) for use\r
+' with Zip32.dll (Zip 2.31) but not Zip32z64.dll (Zip 3.0).\r
+'\r
+' Minor changes to use current directory and VB project files\r
+' for the example and to turn off encryption.\r
+'\r
+' The VB example provided with Zip 3.0 is more extensive.  Even\r
+' if you plan to use the updated zip32.dll instead of the new\r
+' zip32z64.dll (Zip 3.0), there may be some things you might find\r
+' useful in the VB example there.\r
+'\r
+' 2/27/2005 Ed Gordon\r
+'---------------------------------------------------------------\r
+\r
+Private Sub Form_Click()\r
+\r
+  Dim retcode As Integer  ' For Return Code From ZIP32.DLL\r
+\r
+  Cls\r
+\r
+  '-- Set Options - Only The Common Ones Are Shown Here\r
+  '-- These Must Be Set Before Calling The VBZip32 Function\r
+  zDate = vbNullString\r
+  'zDate = "2005-1-31"\r
+  'zExcludeDate = 1\r
+  'zIncludeDate = 0\r
+  zJunkDir = 0     ' 1 = Throw Away Path Names\r
+  zRecurse = 0     ' 1 = Recurse -r 2 = Recurse -R 2 = Most Useful :)\r
+  zUpdate = 0      ' 1 = Update Only If Newer\r
+  zFreshen = 0     ' 1 = Freshen - Overwrite Only\r
+  zLevel = Asc(9)  ' Compression Level (0 - 9)\r
+  zEncrypt = 0     ' Encryption = 1 For Password Else 0\r
+  zComment = 0     ' Comment = 1 if required\r
+\r
+  '-- Select Some Files - Wildcards Are Supported\r
+  '-- Change The Paths Here To Your Directory\r
+  '-- And Files!!!\r
+  ' Change ZIPnames in VBZipBas.bas if need more than 100 files\r
+  zArgc = 2           ' Number Of Elements Of mynames Array\r
+  zZipFileName = "MyFirst.zip"\r
+  zZipFileNames.zFiles(0) = "vbzipfrm.frm"\r
+  zZipFileNames.zFiles(1) = "vbzip.vbp"\r
+  zRootDir = ""    ' This Affects The Stored Path Name\r
+  \r
+  ' Older versions of Zip32.dll do not handle setting\r
+  ' zRootDir to anything other than "".  If you need to\r
+  ' change root directory an alternative is to just change\r
+  ' directory.  This requires Zip32.dll to be on the command\r
+  ' path.  This should be fixed in Zip 2.31.  1/31/2005 EG\r
+\r
+  ' ChDir "a"\r
+\r
+  '-- Go Zip Them Up!\r
+  retcode = VBZip32\r
+\r
+  '-- Display The Returned Code Or Error!\r
+  Print "Return code:" & Str(retcode)\r
+\r
+End Sub\r
+\r
+Private Sub Form_Load()\r
+\r
+  Me.Show\r
+\r
+  Print "Click me!"\r
+\r
+End Sub\r
diff --git a/windll/Vb/readmeVB.txt b/windll/Vb/readmeVB.txt
new file mode 100644 (file)
index 0000000..1c36949
--- /dev/null
@@ -0,0 +1,34 @@
+On Windows open this file in WordPad.
+
+Contents of the "windll/vb" sub-archive
+
+This directory contains a Visual Basic project example for
+using the zip32.dll library.  This project updates the Zip 2.3 VB
+project example and includes some bug fixes and many additional notes
+but is still compatible with zip32.dll.  See the comments in the form
+and project files for details.  It has been tested on VB 5 and VB 6.
+
+Zip 2.31 itself had bug fixes as well, including some related to the
+dll, and you should now use a version of zip32.dll from that or later.
+This dll includes a fix for the VB dll bug where Date, szRootDir, and
+szTempDir were not passed in correctly and setting these to anything
+but NULL could impact the dll and maybe crash it.  You can tell which
+version you have by right clicking on zip32.dll in a file listing,
+looking at properties, selecting the Version tab, and verifying the
+Product Version is at least 2.31.
+
+A new dll is available as part of this Zip 3.0 release and a
+new VB project is included in the VBz64 directory.  This dll and
+project supports Zip64 and large files but is not backward compatible
+with Zip32.dll.  You will need the new zip32z64.dll to use this project,
+which can be compiled from Zip 3.0.  See windll/VBz64 for details.
+
+Note that the files may saved in unix format with carriage returns
+stripped.  These must be restored before the project can be successfully
+used.  This can be done by using the -a option to unzip.  Another way to
+do this is to open each file in WordPad, select and cut a line, paste
+the line back, and save the file.  This will force WordPad to format
+the entire file.
+
+Ed Gordon
+2/2/2007
diff --git a/windll/contents b/windll/contents
new file mode 100644 (file)
index 0000000..36da176
--- /dev/null
@@ -0,0 +1,42 @@
+Contents of the "windll" sub-archive for Zip 2.2 and later:
+
+  contents       this file
+  windll16.def   definition file for 16-bit Zip DLL
+  windll32.def   definition file for 32-bit Zip DLL
+  windll.c       Contains the entry point for the DLL, "fake" printing,
+                 and password functions.
+  windll.h       header file for both 16 and 32-bit DLLs.
+  zipver.h       versioning information for resource file, and also
+                 used by WiZ application itself.
+  windll.rc      resource file for both 16 and 32-bit DLLs
+  windll.txt     simplistic explanation of how to use DLL.
+  structs.h      header file used by both the dll and by WiZ which defines
+                 several structures passed to the dll.
+  example.c      a very simplistic example of how to load the dll, and make
+                 a call into it.
+  example.h      header file for example.c
+
+  borland\dll <dir> contains 16 and 32 bit make files for the zip dlls.
+  borland\lib <dir> contains 32 bit make files for the zip32 static library
+  visualc\dll <dir> contains Visual C++ 5.0 project and make files for
+                    zip32 dll.
+  visualc\lib <dir> contains Visual C++ 5.0 project and make files for
+                    zip32 static library.
+
+The Microsoft C port has not been tested as completely as the Borland port.
+Note that Borland C++ 5.0 is full of bugs version 4.5 is recommended instead.
+If you must use Borland C++ 5.0, using the Intel optimizing compiler is
+required to avoid crashes (possibly due to a bug in the stat() function
+in the normal Borland compiler.) This does have the advantage of giving you
+a smaller code size than the 4.52 compiler.
+
+Borland C++ 5.01 has resolved many of the problems seen with 5.0, and
+can now reliably be used.
+
+Note that I have been singularly unsuccessful in getting this to compile
+and run under MSVC 1.52c.
+
+Last updated October 13, 1997
+
+Mike White
+
diff --git a/windll/example.c b/windll/example.c
new file mode 100644 (file)
index 0000000..f1a1936
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ A very simplistic example of how to load the zip dll and make a call into it.
+ Note that none of the command line options are implemented in this example.
+
+ */
+
+#ifndef WIN32
+#  define WIN32
+#endif
+#define API
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <string.h>
+#ifdef __BORLANDC__
+#include <dir.h>
+#else
+#include <direct.h>
+#endif
+#include "example.h"
+#include "zipver.h"
+
+#ifdef WIN32
+#include <commctrl.h>
+#include <winver.h>
+#else
+#include <ver.h>
+#endif
+
+#ifdef WIN32
+#define ZIP_DLL_NAME "ZIP32.DLL\0"
+#else
+#define ZIP_DLL_NAME "ZIP16.DLL\0"
+#endif
+
+#define DLL_WARNING "Cannot find %s."\
+            " The Dll must be in the application directory, the path, "\
+            "the Windows directory or the Windows System directory."
+#define DLL_VERSION_WARNING "%s has the wrong version number."\
+            " Insure that you have the correct dll's installed, and that "\
+            "an older dll is not in your path or Windows System directory."
+
+int hFile;              /* file handle */
+
+ZCL ZpZCL;
+LPZIPUSERFUNCTIONS lpZipUserFunctions;
+HANDLE hZUF = (HANDLE)NULL;
+HINSTANCE hUnzipDll;
+HANDLE hFileList;
+ZPOPT ZpOpt;
+#ifdef WIN32
+DWORD dwPlatformId = 0xFFFFFFFF;
+#endif
+HINSTANCE hZipDll;
+
+
+/* Forward References */
+_DLL_ZIP ZipArchive;
+_ZIP_USER_FUNCTIONS ZipInit;
+ZIPSETOPTIONS ZipSetOptions;
+
+void FreeUpMemory(void);
+int WINAPI DummyPassword(LPSTR, int, LPCSTR, LPCSTR);
+int WINAPI DummyPrint(char far *, unsigned long);
+int WINAPI WINAPI DummyComment(char far *);
+
+#ifdef WIN32
+BOOL IsNT(VOID);
+#endif
+
+/****************************************************************************
+
+    FUNCTION: Main(int argc, char **argv)
+
+****************************************************************************/
+#ifdef __BORLANDC__
+#  ifdef WIN32
+#pragma argsused
+#  endif
+#endif
+int main(int argc, char **argv)
+{
+LPSTR szFileList;
+char **index, *sz;
+int retcode, i, cc;
+DWORD dwVerInfoSize;
+DWORD dwVerHnd;
+char szFullPath[PATH_MAX];
+#ifdef WIN32
+char *ptr;
+#else
+HFILE hfile;
+OFSTRUCT ofs;
+#endif
+HANDLE  hMem;         /* handle to mem alloc'ed */
+
+if (argc < 3)
+   return 0;           /* Exits if not proper number of arguments */
+
+hZUF = GlobalAlloc( GPTR, (DWORD)sizeof(ZIPUSERFUNCTIONS));
+if (!hZUF)
+   {
+   return 0;
+   }
+lpZipUserFunctions = (LPZIPUSERFUNCTIONS)GlobalLock(hZUF);
+
+if (!lpZipUserFunctions)
+   {
+   GlobalFree(hZUF);
+   return 0;
+   }
+
+lpZipUserFunctions->print = DummyPrint;
+lpZipUserFunctions->password = DummyPassword;
+lpZipUserFunctions->comment = DummyComment;
+
+/* Let's go find the dll */
+#ifdef WIN32
+if (SearchPath(
+    NULL,               /* address of search path               */
+    ZIP_DLL_NAME,       /* address of filename                  */
+    NULL,               /* address of extension                 */
+    PATH_MAX,           /* size, in characters, of buffer       */
+    szFullPath,         /* address of buffer for found filename */
+    &ptr                /* address of pointer to file component */
+   ) == 0)
+#else
+hfile = OpenFile(ZIP_DLL_NAME,  &ofs, OF_SEARCH);
+if (hfile == HFILE_ERROR)
+#endif
+   {
+   char str[256];
+   wsprintf (str, DLL_WARNING, ZIP_DLL_NAME);
+   printf("%s\n", str);
+   FreeUpMemory();
+   return 0;
+   }
+#ifndef WIN32
+else
+   lstrcpy(szFullPath, ofs.szPathName);
+_lclose(hfile);
+#endif
+
+/* Now we'll check the zip dll version information */
+dwVerInfoSize =
+    GetFileVersionInfoSize(szFullPath, &dwVerHnd);
+
+if (dwVerInfoSize)
+   {
+   BOOL  fRet, fRetName;
+   char str[256];
+   LPSTR   lpstrVffInfo; /* Pointer to block to hold info */
+   LPSTR lszVer = NULL;
+   LPSTR lszVerName = NULL;
+   UINT  cchVer = 0;
+
+   /* Get a block big enough to hold the version information */
+   hMem          = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
+   lpstrVffInfo  = GlobalLock(hMem);
+
+   /* Get the version information */
+   GetFileVersionInfo(szFullPath, 0L, dwVerInfoSize, lpstrVffInfo);
+   fRet = VerQueryValue(lpstrVffInfo,
+              TEXT("\\StringFileInfo\\040904E4\\FileVersion"),
+               (LPVOID)&lszVer,
+               &cchVer);
+   fRetName = VerQueryValue(lpstrVffInfo,
+               TEXT("\\StringFileInfo\\040904E4\\CompanyName"),
+              (LPVOID)&lszVerName,
+              &cchVer);
+   if (!fRet || !fRetName ||
+      (lstrcmpi(lszVer, ZIP_DLL_VERSION) != 0) ||
+      (lstrcmpi(lszVerName, COMPANY_NAME) != 0))
+      {
+      wsprintf (str, DLL_VERSION_WARNING, ZIP_DLL_NAME);
+      printf("%s\n", str);
+      FreeUpMemory();
+      return 0;
+      }
+   /* free memory */
+   GlobalUnlock(hMem);
+   GlobalFree(hMem);
+   }
+else
+   {
+   char str[256];
+   wsprintf (str, DLL_VERSION_WARNING, ZIP_DLL_NAME);
+   printf("%s\n", str);
+   FreeUpMemory();
+   return 0;
+   }
+/* Okay, now we know that the dll exists, and has the proper version
+ * information in it. We can go ahead and load it.
+ */
+hZipDll = LoadLibrary(ZIP_DLL_NAME);
+#ifndef WIN32
+if (hZipDll > HINSTANCE_ERROR)
+#else
+if (hZipDll != NULL)
+#endif
+   {
+   (_DLL_ZIP)ZipArchive = (_DLL_ZIP)GetProcAddress(hZipDll, "ZpArchive");
+   (ZIPSETOPTIONS)ZipSetOptions = (ZIPSETOPTIONS)GetProcAddress(hZipDll, "ZpSetOptions");
+   if (!ZipArchive || !ZipSetOptions)
+      {
+      char str[256];
+      wsprintf (str, "Could not get entry point to %s", ZIP_DLL_NAME);
+      MessageBox((HWND)NULL, str, "Info-ZIP Example", MB_ICONSTOP | MB_OK);
+      FreeUpMemory();
+      return 0;
+      }
+   }
+else
+   {
+   char str[256];
+   wsprintf (str, "Could not load %s", ZIP_DLL_NAME);
+   printf("%s\n", str);
+   FreeUpMemory();
+   return 0;
+   }
+
+(_ZIP_USER_FUNCTIONS)ZipInit = (_ZIP_USER_FUNCTIONS)GetProcAddress(hZipDll, "ZpInit");
+if (!ZipInit)
+   {
+   printf("Cannot get address of ZpInit in Zip dll. Terminating...");
+   FreeLibrary(hZipDll);
+   FreeUpMemory();
+   return 0;
+   }
+if (!(*ZipInit)(lpZipUserFunctions))
+   {
+   printf("Application functions not set up properly. Terminating...");
+   FreeLibrary(hZipDll);
+   FreeUpMemory();
+   return 0;
+   }
+
+/* Here is where the action starts */
+ZpOpt.fSuffix = FALSE;        /* include suffixes (not yet implemented) */
+ZpOpt.fEncrypt = FALSE;       /* true if encryption wanted */
+ZpOpt.fSystem = FALSE;        /* true to include system/hidden files */
+ZpOpt.fVolume = FALSE;        /* true if storing volume label */
+ZpOpt.fExtra = FALSE;         /* true if including extra attributes */
+ZpOpt.fNoDirEntries = FALSE;  /* true if ignoring directory entries */
+ZpOpt.fVerbose = FALSE;       /* true if full messages wanted */
+ZpOpt.fQuiet = FALSE;         /* true if minimum messages wanted */
+ZpOpt.fCRLF_LF = FALSE;       /* true if translate CR/LF to LF */
+ZpOpt.fLF_CRLF = FALSE;       /* true if translate LF to CR/LF */
+ZpOpt.fJunkDir = FALSE;       /* true if junking directory names */
+ZpOpt.fGrow = FALSE;          /* true if allow appending to zip file */
+ZpOpt.fForce = FALSE;         /* true if making entries using DOS names */
+ZpOpt.fMove = FALSE;          /* true if deleting files added or updated */
+ZpOpt.fUpdate = FALSE;        /* true if updating zip file--overwrite only
+                                  if newer */
+ZpOpt.fFreshen = FALSE;       /* true if freshening zip file--overwrite only */
+ZpOpt.fJunkSFX = FALSE;       /* true if junking sfx prefix*/
+ZpOpt.fLatestTime = FALSE;    /* true if setting zip file time to time of
+                                  latest file in archive */
+ZpOpt.fComment = FALSE;       /* true if putting comment in zip file */
+ZpOpt.fOffsets = FALSE;       /* true if updating archive offsets for sfx
+                                  files */
+ZpOpt.fDeleteEntries = FALSE; /* true if deleting files from archive */
+ZpOpt.fRecurse = 0;           /* subdir recursing mode: 1 = "-r", 2 = "-R" */
+ZpOpt.fRepair = 0;            /* archive repair mode: 1 = "-F", 2 = "-FF" */
+ZpOpt.Date = NULL;            /* Not using, set to NULL pointer */
+getcwd(szFullPath, PATH_MAX); /* Set directory to current directory */
+ZpOpt.szRootDir = szFullPath;
+
+ZpZCL.argc = argc - 2;        /* number of files to archive - adjust for the
+                                  actual number of file names to be added */
+ZpZCL.lpszZipFN = argv[1];    /* archive to be created/updated */
+
+/* Copy over the appropriate portions of argv, basically stripping out argv[0]
+   (name of the executable) and argv[1] (name of the archive file)
+ */
+hFileList = GlobalAlloc( GPTR, 0x10000L);
+if ( hFileList )
+   {
+   szFileList = (char far *)GlobalLock(hFileList);
+   }
+index = (char **)szFileList;
+cc = (sizeof(char *) * ZpZCL.argc);
+sz = szFileList + cc;
+
+for (i = 0; i < ZpZCL.argc; i++)
+    {
+    cc = lstrlen(argv[i+2]);
+    lstrcpy(sz, argv[i+2]);
+    index[i] = sz;
+    sz += (cc + 1);
+    }
+ZpZCL.FNV = (char **)szFileList;  /* list of files to archive */
+
+/* Set the options */
+ZipSetOptions(&ZpOpt);
+
+/* Go zip 'em up */
+retcode = ZipArchive(ZpZCL);
+if (retcode != 0)
+   printf("Error in archiving\n");
+
+GlobalUnlock(hFileList);
+GlobalFree(hFileList);
+FreeUpMemory();
+FreeLibrary(hZipDll);
+return 1;
+}
+
+void FreeUpMemory(void)
+{
+if (hZUF)
+   {
+   GlobalUnlock(hZUF);
+   GlobalFree(hZUF);
+   }
+}
+
+#ifdef WIN32
+/* This simply determines if we are running on NT */
+BOOL IsNT(VOID)
+{
+if(dwPlatformId != 0xFFFFFFFF)
+   return dwPlatformId;
+else
+/* note: GetVersionEx() doesn't exist on WinNT 3.1 */
+   {
+   if(GetVersion() < 0x80000000)
+      {
+      (BOOL)dwPlatformId = TRUE;
+      }
+   else
+      {
+      (BOOL)dwPlatformId = FALSE;
+      }
+    }
+return dwPlatformId;
+}
+#endif
+
+/* Password entry routine - see password.c in the wiz directory for how
+   this is actually implemented in Wiz. If you have an encrypted file,
+   this will probably give you great pain. Note that none of the
+   parameters are being used here, and this will give you warnings.
+ */
+int WINAPI DummyPassword(LPSTR p, int n, LPCSTR m, LPCSTR name)
+{
+return 1;
+}
+
+/* Dummy "print" routine that simply outputs what is sent from the dll */
+int WINAPI DummyPrint(char far *buf, unsigned long size)
+{
+printf("%s", buf);
+return (unsigned int) size;
+}
+
+
+/* Dummy "comment" routine. See comment.c in the wiz directory for how
+   this is actually implemented in Wiz. This will probably cause you
+   great pain if you ever actually make a call into it.
+ */
+int WINAPI DummyComment(char far *szBuf)
+{
+szBuf[0] = '\0';
+return TRUE;
+}
diff --git a/windll/example.h b/windll/example.h
new file mode 100644 (file)
index 0000000..da52598
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 1999-Oct-05 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, both of these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ Example header file
+*/
+#ifndef _EXAMPLE_H
+#define _EXAMPLE_H
+
+#include <windows.h>
+#include <assert.h>    /* required for all Windows applications */
+#include <stdlib.h>
+#include <stdio.h>
+#include <commdlg.h>
+#include <dlgs.h>
+#include <windowsx.h>
+
+#ifndef EXPENTRY
+#define EXPENTRY WINAPI
+#endif
+
+#include "structs.h"
+
+/* Defines */
+#ifndef MSWIN
+#define MSWIN
+#endif
+
+typedef int (WINAPI * _DLL_ZIP)(ZCL);
+typedef int (WINAPI * _ZIP_USER_FUNCTIONS)(LPZIPUSERFUNCTIONS);
+typedef BOOL (WINAPI * ZIPSETOPTIONS)(LPZPOPT);
+
+/* Global variables */
+
+extern LPZIPUSERFUNCTIONS lpZipUserFunctions;
+
+extern HINSTANCE hZipDll;
+
+extern int hFile;                 /* file handle             */
+
+/* Global functions */
+
+int WINAPI DisplayBuf(char far *, unsigned long int);
+extern _DLL_ZIP ZipArchive;
+extern _ZIP_USER_FUNCTIONS ZipInit;
+extern ZIPSETOPTIONS ZipSetOptions;
+
+#endif /* _EXAMPLE_H */
+
diff --git a/windll/structs.h b/windll/structs.h
new file mode 100644 (file)
index 0000000..0f36df6
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+  windll/structs.h - Zip 3
+
+  Copyright (c) 1990-2003 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2003-May-08 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef _ZIP_STRUCTS_H
+#define _ZIP_STRUCTS_H
+
+#ifndef Far
+#  define Far far
+#endif
+
+/* Porting definations between Win 3.1x and Win32 */
+#ifdef WIN32
+#  define far
+#  define _far
+#  define __far
+#  define near
+#  define _near
+#  define __near
+#endif
+
+#include "../api.h"
+
+#endif /* _ZIP_STRUCTS_H */
diff --git a/windll/visualc/dll/zip32z64.dsp b/windll/visualc/dll/zip32z64.dsp
new file mode 100644 (file)
index 0000000..46bea99
--- /dev/null
@@ -0,0 +1,168 @@
+# Microsoft Developer Studio Project File - Name="zip32z64" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
+\r
+CFG=zip32z64 - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "zip32z64.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "zip32z64.mak" CFG="zip32z64 - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "zip32z64 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "zip32z64 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "zip32z64 - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\Release\app"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /YX /FD /c\r
+# ADD CPP /nologo /Zp4 /MT /W3 /GX /O2 /I "..\..\.." /I "..\..\..\WINDLL" /I "..\..\..\WIN32" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "NO_ASM" /D "WINDLL" /D "MSDOS" /D "USE_ZIPMAIN" /YX /FD /c\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG" /d "WIN32"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:windows /dll /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:windows /dll /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "zip32z64 - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\Debug\app"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /YX /FD /c\r
+# ADD CPP /nologo /Zp4 /MTd /W3 /Gm /GX /ZI /Od /I "..\..\..\ZIP" /I "..\..\..\WINDLL" /I "..\..\..\WIN32" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "NO_ASM" /D "WINDLL" /D "MSDOS" /D "USE_ZIPMAIN" /FR /YX /FD /c\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG" /d "WIN32"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"..\Debug\app/zip32z64.dll" /pdbtype:sept\r
+# SUBTRACT LINK32 /map\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "zip32z64 - Win32 Release"\r
+# Name "zip32z64 - Win32 Debug"\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\api.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\crc32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\crypt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\deflate.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\fileio.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\globals.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\win32\nt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\trees.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\ttyio.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\util.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\win32\win32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\win32\win32i64.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\win32\win32zip.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\windll\windll.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\windll\windll.rc\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\windll\windll32.def\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\zip.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\zipfile.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\zipup.c\r
+# End Source File\r
+# End Target\r
+# End Project\r
diff --git a/windll/visualc/dll/zip32z64.dsw b/windll/visualc/dll/zip32z64.dsw
new file mode 100644 (file)
index 0000000..4643105
--- /dev/null
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
+\r
+###############################################################################\r
+\r
+Project: "zip32z64"=.\zip32z64.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
diff --git a/windll/visualc/lib/zip32z64.dsp b/windll/visualc/lib/zip32z64.dsp
new file mode 100644 (file)
index 0000000..a610912
--- /dev/null
@@ -0,0 +1,158 @@
+# Microsoft Developer Studio Project File - Name="zip32z64" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=zip32z64 - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "zip32z64.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "zip32z64.mak" CFG="zip32z64 - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "zip32z64 - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "zip32z64 - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "zip32z64 - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "..\Release\libs"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "..\..\.." /I "..\..\..\win32" /I "..\..\..\windll" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "NO_ASM" /D "WINDLL" /D "MSDOS" /D "USE_ZIPMAIN" /D "ZIPLIB" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x409\r
+# ADD RSC /l 0x409\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ELSEIF  "$(CFG)" == "zip32z64 - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "..\Debug\libs"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /Z7 /Od /I "..\..\.." /I "..\..\..\win32" /I "..\..\..\windll" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "NO_ASM" /D "WINDLL" /D "MSDOS" /D "USE_ZIPMAIN" /D "ZIPLIB" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x409\r
+# ADD RSC /l 0x409\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "zip32z64 - Win32 Release"\r
+# Name "zip32z64 - Win32 Debug"\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\api.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\crc32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\crypt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\deflate.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\fileio.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\globals.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\win32\nt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\trees.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\ttyio.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\util.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\win32\win32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\win32\win32zip.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\windll\windll.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\windll\windll.rc\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\zip.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\zipfile.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\windll\ziplib.def\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\zipup.c\r
+# End Source File\r
+# End Target\r
+# End Project\r
diff --git a/windll/visualc/lib/zip32z64.dsw b/windll/visualc/lib/zip32z64.dsw
new file mode 100644 (file)
index 0000000..4643105
--- /dev/null
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
+\r
+###############################################################################\r
+\r
+Project: "zip32z64"=.\zip32z64.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
diff --git a/windll/windll.aps b/windll/windll.aps
new file mode 100644 (file)
index 0000000..73e3468
Binary files /dev/null and b/windll/windll.aps differ
diff --git a/windll/windll.c b/windll/windll.c
new file mode 100644 (file)
index 0000000..f825108
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+  windll/windll.c - Zip 3
+
+  Copyright (c) 1990-2004 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2003-May-08 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  windll.c by Mike White loosly based on Mark Adler's zip.c
+ */
+#include <windows.h>
+#include <process.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include "../zip.h"
+#include "windll.h"
+
+HINSTANCE hCurrentInst;
+#ifdef ZIPLIB
+/*  DLL Entry Point */
+#ifdef __BORLANDC__
+#pragma argsused
+/* Borland seems to want DllEntryPoint instead of DllMain like MSVC */
+#define DllMain DllEntryPoint
+#endif
+#ifdef WIN32
+BOOL WINAPI DllMain( HINSTANCE hInstance,
+                     DWORD dwReason,
+                     LPVOID plvReserved)
+#else
+int WINAPI LibMain( HINSTANCE hInstance,
+                        WORD wDataSegment,
+                        WORD wHeapSize,
+                        LPSTR lpszCmdLine )
+#endif
+{
+#ifndef WIN32
+/* The startup code for the DLL initializes the local heap(if there is one)
+ with a call to LocalInit which locks the data segment. */
+
+if ( wHeapSize != 0 )
+   {
+   UnlockData( 0 );
+   }
+hCurrentInst = hInstance;
+return 1;   /* Indicate that the DLL was initialized successfully. */
+#else
+BOOL rc = TRUE;
+switch( dwReason )
+   {
+   case DLL_PROCESS_ATTACH:
+      // DLL is loaded. Do your initialization here.
+      // If cannot init, set rc to FALSE.
+      hCurrentInst = hInstance;
+      break;
+
+   case DLL_PROCESS_DETACH:
+      // DLL is unloaded. Do your cleanup here.
+      break;
+   default:
+      break;
+   }
+return rc;
+#endif
+}
+
+#ifdef __BORLANDC__
+#pragma argsused
+#endif
+int FAR PASCAL WEP ( int bSystemExit )
+{
+return 1;
+}
+#endif /* ZIPLIB */
+
+LPSTR szCommentBuf;
+HANDLE hStr;
+
+void comment(unsigned int comlen)
+{
+unsigned int i;
+if (comlen > 65534L)
+   comlen = (unsigned int) 65534L;
+hStr = GlobalAlloc( GPTR, (DWORD)65535L);
+if ( !hStr )
+   {
+   hStr = GlobalAlloc( GPTR, (DWORD) 2);
+   szCommentBuf = GlobalLock(hStr);
+   szCommentBuf[0] = '\0';
+   return;
+   }
+
+szCommentBuf = GlobalLock(hStr);
+if (comlen)
+   {
+   for (i = 0; i < comlen; i++)
+       szCommentBuf[i] = zcomment[i];
+   szCommentBuf[comlen] = '\0';
+   }
+else
+   szCommentBuf[0] = '\0';
+free(zcomment);
+zcomment = malloc(1);
+*zcomment = 0;
+lpZipUserFunctions->comment(szCommentBuf);
+return;
+}
+
+#define STDIO_BUF_SIZE 16384
+
+int __far __cdecl printf(const char *format, ...)
+{
+va_list argptr;
+HANDLE hMemory;
+LPSTR pszBuffer;
+int len;
+
+va_start(argptr, format);
+hMemory = GlobalAlloc(GMEM_MOVEABLE, STDIO_BUF_SIZE);
+WinAssert(hMemory);
+if (!hMemory)
+   {
+   return 0;
+   }
+pszBuffer = (LPSTR)GlobalLock(hMemory);
+WinAssert(pszBuffer);
+len = wvsprintf(pszBuffer, format, argptr);
+va_end(argptr);
+WinAssert(strlen(pszBuffer) < STDIO_BUF_SIZE);
+len = lpZipUserFunctions->print(pszBuffer, len);
+GlobalUnlock(hMemory);
+GlobalFree(hMemory);
+return len;
+}
+
+/* fprintf clone for code in zip.c, etc. */
+int __far __cdecl fprintf(FILE *file, const char *format, ...)
+{
+va_list argptr;
+HANDLE hMemory;
+LPSTR pszBuffer;
+int len;
+
+va_start(argptr, format);
+hMemory = GlobalAlloc(GMEM_MOVEABLE, STDIO_BUF_SIZE);
+WinAssert(hMemory);
+if (!hMemory)
+   {
+   return 0;
+   }
+pszBuffer = GlobalLock(hMemory);
+WinAssert(pszBuffer);
+len = wvsprintf(pszBuffer, format, argptr);
+va_end(argptr);
+WinAssert(strlen(pszBuffer) < STDIO_BUF_SIZE);
+if ((file == stderr) || (file == stdout))
+   {
+   len = lpZipUserFunctions->print(pszBuffer, len);
+   }
+else
+   len = write(fileno(file),(char far *)(pszBuffer), len);
+GlobalUnlock(hMemory);
+GlobalFree(hMemory);
+return len;
+}
+
+void __far __cdecl perror(const char *parm1)
+{
+printf("%s", parm1);
+}
+
+
diff --git a/windll/windll.h b/windll/windll.h
new file mode 100644 (file)
index 0000000..0a45fc1
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+  windll/windll.h - Zip 3
+
+  Copyright (c) 1990-2004 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2003-May-08 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ WiZ 1.0 header file for zip dll
+*/
+#ifndef _WINDLL_H
+#define _WINDLL_H
+
+#include "structs.h"
+
+#ifndef MSWIN
+#define MSWIN
+#endif
+
+#ifndef USE_ZIPMAIN
+#   define USE_ZIPMAIN
+#endif
+
+#ifndef NDEBUG
+#  define WinAssert(exp) \
+        {\
+        if (!(exp))\
+            {\
+            char szBuffer[40];\
+            sprintf(szBuffer, "File %s, Line %d",\
+                    __FILE__, __LINE__) ;\
+            if (IDABORT == MessageBox((HWND)NULL, szBuffer,\
+                "Assertion Error",\
+                MB_ABORTRETRYIGNORE|MB_ICONSTOP))\
+                    FatalExit(-1);\
+            }\
+        }
+
+#else
+#  define WinAssert(exp)
+#endif
+
+#define cchFilesMax 4096
+
+extern int WINAPI ZpArchive(ZCL C, LPZPOPT Opts);
+extern HWND hGetFilesDlg;
+extern char szFilesToAdd[80];
+extern char rgszFiles[cchFilesMax];
+BOOL WINAPI CommentBoxProc(HWND hwndDlg, WORD wMessage, WPARAM wParam, LPARAM lParam);
+BOOL PasswordProc(HWND, WORD, WPARAM, LPARAM);
+void CenterDialog(HWND hwndParent, HWND hwndDlg);
+void comment(unsigned int);
+
+extern LPSTR szCommentBuf;
+extern HANDLE hStr;
+extern HWND hWndMain;
+void __far __cdecl perror(const char *);
+
+#endif /* _WINDLL_H */
+
diff --git a/windll/windll.rc b/windll/windll.rc
new file mode 100644 (file)
index 0000000..4fab86a
--- /dev/null
@@ -0,0 +1,57 @@
+#define APSTUDIO_READONLY_SYMBOLS\r
+#define APSTUDIO_HIDDEN_SYMBOLS\r
+#include <windows.h>\r
+#if (defined(WIN32) && !defined(__EMX__) && !defined(__MINGW32__))\r
+#include <winver.h>\r
+#endif\r
+#undef APSTUDIO_HIDDEN_SYMBOLS\r
+#include "../revision.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION Z_MAJORVER,Z_MINORVER,Z_PATCHLEVEL,0\r
+ PRODUCTVERSION Z_MAJORVER,Z_MINORVER,Z_PATCHLEVEL,0\r
+ FILEFLAGSMASK 0x3L\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS VOS__WINDOWS32\r
+ FILETYPE VFT_DLL\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+#ifdef _UNICODE\r
+        BLOCK "040904B0"\r
+#else\r
+        BLOCK "040904E4"\r
+#endif\r
+        BEGIN\r
+            VALUE "CompanyName", IZ_COMPANY_NAME "\0"\r
+            VALUE "FileDescription", "Info-ZIP's Zip dll\0"\r
+            VALUE "FileVersion", VERSION "\0"\r
+            VALUE "InternalName", "Zip32z64\0"\r
+            VALUE "LegalCopyright", "Info-ZIP 1997 - 2008\0"\r
+            VALUE "OriginalFilename", "ZIP32Z64.DLL\0"\r
+            VALUE "ProductName", "Info-ZIP's WiZ\0"\r
+            VALUE "ProductVersion", VERSION "\0"\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+#ifdef _UNICODE\r
+        VALUE "Translation", 0x409, 1200\r
+#else\r
+        VALUE "Translation", 0x409, 1252\r
+#endif\r
+    END\r
+END\r
diff --git a/windll/windll.txt b/windll/windll.txt
new file mode 100644 (file)
index 0000000..8df4bae
--- /dev/null
@@ -0,0 +1,147 @@
+The code set out below is not intended to be compiled, but is only intended as
+a very simplistic pointer to how to load and call the dll. You will have to
+look in the files referenced below for actual, working code.
+
+There is one entry point that uses the structure shown below:
+
+typedef struct {
+LPSTR Date;             /* Date to include after */
+LPSTR szRootDir;        /* Directory to use as base for zipping */
+LPSTR szTempDir;        /* Temporary directory used during zipping */
+BOOL fTemp;             /* Use temporary directory '-b' during zipping */
+BOOL fSuffix;           /* include suffixes (not implemented in WiZ) */
+BOOL fEncrypt;          /* encrypt files */
+BOOL fSystem;           /* include system and hidden files */
+BOOL fVolume;           /* Include volume label */
+BOOL fExtra;            /* Exclude extra attributes */
+BOOL fNoDirEntries;     /* Do not add directory entries */
+BOOL fExcludeDate;      /* Exclude files earlier than specified date */
+BOOL fIncludeDate;      /* Include only files earlier than specified date */
+BOOL fVerbose;          /* Mention oddities in zip file structure */
+BOOL fQuiet;            /* Quiet operation */
+BOOL fCRLF_LF;          /* Translate CR/LF to LF */
+BOOL fLF_CRLF;          /* Translate LF to CR/LF */
+BOOL fJunkDir;          /* Junk directory names */
+BOOL fGrow;             /* Allow appending to a zip file */
+BOOL fForce;            /* Make entries using DOS names (k for Katz) */
+BOOL fMove;             /* Delete files added or updated in zip file */
+BOOL fDeleteEntries;    /* Delete files from zip file */
+BOOL fUpdate;           /* Update zip file--overwrite only if newer */
+BOOL fFreshen;          /* Freshen zip file--overwrite only */
+BOOL fJunkSFX;          /* Junk SFX prefix */
+BOOL fLatestTime;       /* Set zip file time to time of latest file in it */
+BOOL fComment;          /* Put comment in zip file */
+BOOL fOffsets;          /* Update archive offsets for SFX files */
+BOOL fPrivilege;        /* Use privileges (WIN32 only) */
+BOOL fEncryption;       /* TRUE if encryption supported, else FALSE.
+                           this is a read-only flag */
+LPSTR szSplitSize;             /* This string contains the size that you want to 
+                                                  split the archive into. i.e. 100 for 100 bytes,
+                                                  2K for 2 k bytes, where K is 1024, m for meg
+                                                  and g for gig. If this string is not NULL it
+                                                  will automatically be assumed that you wish to
+                                                  split an archive. */
+LPSTR szIncludeList;    /* Pointer to include file list string (for VB) */
+long IncludeListCount;  /* Count of file names in the include list array */
+char **IncludeList;     /* Pointer to include file list array. Note that the last
+                           entry in the array must be NULL */
+LPSTR szExcludeList;    /* Pointer to exclude file list (for VB) */
+long ExcludeListCount;  /* Count of file names in the include list array */
+char **ExcludeList;     /* Pointer to exclude file list array. Note that the last
+                           entry in the array must be NULL */
+int  fRecurse;          /* Recurse into subdirectories. 1 => -r, 2 => -R */
+int  fRepair;           /* Repair archive. 1 => -F, 2 => -FF */
+char fLevel;            /* Compression level (0 - 9) */
+} ZPOPT, _far *LPZPOPT;
+
+The main entry point is ZpArchive(ZCL, *Opts) where the structure shown below
+is passed to the DLL when it is called.
+
+typedef struct {
+int  argc;              = Count of files to zip
+LPSTR lpszZipFN;        = Archive file name
+char **FNV;             = file names to zip up. Think of this an argv
+LPSTR lpszAltFNL;              /* pointer to a string containing a list of file names to zip up,
+                                                  separated by whitespace. Intended for use only by VB users, all
+                                                  others should set this to NULL. */
+} ZCL, _far *LPZCL;
+
+
+For examples of how the actual calls to the dll were set up in WiZ, look in
+the file makezip.c in the WiZ source directory.
+
+For examples of how the actual loading and unloading of the dll's themselves
+was done, look in wizmain.c in the WiZ source directory. Note that WiZ looks
+specifically for a particular version number of the dll, and also expects to
+find the company name to be Info-ZIP. This is to protect from getting different
+versions of the dll loaded, with resulting unknown behavior.
+
+There is a very simplistic example of how to load and call into the dll in
+example.c and example.h. Note that this example does not implement any
+command line switches at all, and is merely intended as a guide for those
+brave enough to enter a new world.
+
+There are three additional (at the moment) entry points:
+
+ZpInit, defined as
+
+int WINAPI ZpInit(ZIPUSERFUNCTIONS far * lpZipUserFunc);
+
+where ZIPUSERFUNCTIONS is defined as below.
+
+ZpVersion, defined as
+
+ZpVer * ZpVersion(void);
+
+where ZpVer is defined as:
+
+typedef struct _ZpVer {
+    ulg structlen;          /* length of the struct being passed */
+    ulg flag;               /* bit 0: is_beta   bit 1: uses_zlib */
+    char *betalevel;        /* e.g., "g BETA" or "" */
+    char *date;             /* e.g., "4 Sep 95" (beta) or "4 September 1995" */
+    char *zlib_version;     /* e.g., "0.95" or NULL */
+    BOOL fEncryption;       /* TRUE if encryption enabled, FALSE otherwise */
+    _zip_version_type zip;
+    _zip_version_type os2dll;
+    _zip_version_type windll;
+} ZpVer;
+
+See api.c for exactly what ZpVersion does, but the short version of
+what it does is return the zip and dll versions in the ZpVer structure.
+The structure typedef's are in api.h. It will also tell you if encryption
+is enabled.
+
+The typedef's for the function pointers in the structure ZIPUSERFUNCTIONS
+are shown immediately below.
+
+typedef int (WINAPI DLLPRNT) (LPSTR, unsigned long);
+typedef int (WINAPI DLLPASSWORD) (LPSTR, int, LPCSTR, LPCSTR);
+typedef int (WINAPI DLLSPLIT) (LPSTR);
+#ifdef ZIP64_SUPPORT
+typedef int (WINAPI DLLSERVICE) (LPCSTR, __int64);
+typedef int (WINAPI DLLSERVICE_NO_INT64) (LPCSTR, unsigned long, unsigned long);
+#else
+typedef int (WINAPI DLLSERVICE) (LPCSTR, unsigned long);
+#endif
+#endif
+typedef int (WINAPI DLLCOMMENT)(LPSTR);
+
+
+typedef struct {
+DLLPRNT *print;
+DLLCOMMENT *comment;
+DLLPASSWORD *password;
+DLLSPLIT *split;               /* This MUST be set to NULL unless you want to be queried
+                                                  for a destination for each split archive. */
+#ifdef ZIP64_SUPPORT
+DLLSERVICE *ServiceApplication64;
+DLLSERVICE_NO_INT64 *ServiceApplication64_No_Int64;
+#else
+DLLSERVICE *ServiceApplication;
+#endif
+} ZIPUSERFUNCTIONS, far * LPZIPUSERFUNCTIONS;
+
+Last revised April 26, 2004.
+
+Mike White
diff --git a/windll/windll16.def b/windll/windll16.def
new file mode 100644 (file)
index 0000000..1173b5f
--- /dev/null
@@ -0,0 +1,15 @@
+;module-definition file for Windows Zip DLL -- used by link.exe
+LIBRARY ZIP16 ; Library module name
+DESCRIPTION 'Windows Info-ZIP Zip DLL 1.01 by Info-ZIP, Mike White 1996'
+
+CODE  PRELOAD FIXED
+
+DATA  PRELOAD MOVEABLE
+
+EXPORTS
+     ZpArchive
+     ZpVersion
+     ZpInit
+     ZpSetOptions
+     ZpGetOptions
+
diff --git a/windll/windll32.def b/windll/windll32.def
new file mode 100644 (file)
index 0000000..f1426ee
--- /dev/null
@@ -0,0 +1,14 @@
+;module-definition file for Windows Zip DLL -- used by link.exe
+
+LIBRARY ZIP32Z64 ; Library module name
+DESCRIPTION 'Windows Info-ZIP Zip DLL 3.0 by Info-ZIP, Mike White 2004'
+
+;CODE  PRELOAD FIXED
+
+;DATA  PRELOAD MOVEABLE
+
+EXPORTS
+     ZpArchive
+     ZpVersion
+     ZpInit
+
diff --git a/windll/ziplib.def b/windll/ziplib.def
new file mode 100644 (file)
index 0000000..a768740
--- /dev/null
@@ -0,0 +1,15 @@
+;module-definition file for Windows Zip static library -- used by link.exe
+LIBRARY ZIP64 ; Library module name
+DESCRIPTION 'Windows Info-ZIP Zip Library 1.02 by Info-ZIP, Mike White 1997'
+
+CODE  PRELOAD FIXED
+
+DATA  PRELOAD MOVEABLE
+
+EXPORTS
+     ZpArchive
+     ZpVersion
+     ZpInit
+     ZpSetOptions
+     ZpGetOptions
+
diff --git a/zbz2err.c b/zbz2err.c
new file mode 100644 (file)
index 0000000..0e4f9f1
--- /dev/null
+++ b/zbz2err.c
@@ -0,0 +1,61 @@
+/*
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+  zbz2err.c
+
+  This file contains the "fatal error" callback routine required by the
+  "minimal" (silent, non-stdio) setup of the bzip2 compression library.
+
+  The fatal bzip2 error bail-out routine is provided in a separate code
+  module, so that it can be easily overridden when the Zip package is
+  used as a static link library. One example is the WinDLL static library
+  usage for building a monolithic binary of the Windows application "WiZ"
+  that supports bzip2 both in compression and decompression operations.
+
+  Contains:  bz_internal_error()      (BZIP2_SUPPORT only)
+
+  Adapted from UnZip ubz2err.c, with all the DLL fine print stripped
+  out.
+
+  ---------------------------------------------------------------------------*/
+
+
+#define __ZBZ2ERR_C     /* identifies this source module */
+
+#include "zip.h"
+
+#ifdef BZIP2_SUPPORT
+# ifdef BZIP2_USEBZIP2DIR
+#   include "bzip2/bzlib.h"
+# else
+    /* If IZ_BZIP2 is defined as the location of the bzip2 files then
+       assume the location has been added to include path.  For Unix
+       this is done by the configure script. */
+    /* Also do not need path for bzip2 include if OS includes support
+       for bzip2 library. */
+#   include "bzlib.h"
+# endif
+
+/**********************************/
+/*  Function bz_internal_error()  */
+/**********************************/
+
+/* Call-back function for the bzip2 decompression code (compiled with
+ * BZ_NO_STDIO), required to handle fatal internal bug-type errors of
+ * the bzip2 library.
+ */
+void bz_internal_error(errcode)
+    int errcode;
+{
+    sprintf(errbuf, "fatal error (code %d) in bzip2 library", errcode);
+    ziperr(ZE_LOGIC, errbuf);
+} /* end function bz_internal_error() */
+
+#endif /* def BZIP2_SUPPORT */
diff --git a/zip.c b/zip.c
new file mode 100644 (file)
index 0000000..439821f
--- /dev/null
+++ b/zip.c
@@ -0,0 +1,6018 @@
+/*
+  zip.c - Zip 3
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  zip.c by Mark Adler.
+ */
+#define __ZIP_C
+
+#include "zip.h"
+#include <time.h>       /* for tzset() declaration */
+#if defined(WIN32) || defined(WINDLL)
+#  define WIN32_LEAN_AND_MEAN
+#  include <windows.h>
+#endif
+#ifdef WINDLL
+#  include <setjmp.h>
+#  include "windll/windll.h"
+#endif
+#define DEFCPYRT        /* main module: enable copyright string defines! */
+#include "revision.h"
+#include "crc32.h"
+#include "crypt.h"
+#include "ttyio.h"
+#include <ctype.h>
+#include <errno.h>
+#ifdef VMS
+#  include <stsdef.h>
+#  include "vms/vmsmunch.h"
+#  include "vms/vms.h"
+#endif
+
+#ifdef MACOS
+#  include "macglob.h"
+   extern MacZipGlobals MacZip;
+   extern int error_level;
+#endif
+
+#if (defined(MSDOS) && !defined(__GO32__)) || defined(__human68k__)
+#  include <process.h>
+#  if (!defined(P_WAIT) && defined(_P_WAIT))
+#    define P_WAIT _P_WAIT
+#  endif
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+
+#ifdef UNICODE_TEST
+# ifdef WIN32
+#  include <direct.h>
+# endif
+#endif
+
+#ifdef BZIP2_SUPPORT
+  /* If IZ_BZIP2 is defined as the location of the bzip2 files then
+     assume the location has been added to include path.  For Unix
+     this is done by the configure script. */
+  /* Also do not need path for bzip2 include if OS includes support
+     for bzip2 library. */
+# include "bzlib.h"
+#endif
+
+#define MAXCOM 256      /* Maximum one-line comment size */
+
+
+/* Local option flags */
+#ifndef DELETE
+#define DELETE  0
+#endif
+#define ADD     1
+#define UPDATE  2
+#define FRESHEN 3
+#define ARCHIVE 4
+local int action = ADD; /* one of ADD, UPDATE, FRESHEN, DELETE, or ARCHIVE */
+local int comadd = 0;   /* 1=add comments for new files */
+local int zipedit = 0;  /* 1=edit zip comment and all file comments */
+local int latest = 0;   /* 1=set zip file time to time of latest file */
+local int test = 0;     /* 1=test zip file with unzip -t */
+local char *unzip_path = NULL; /* where to find unzip */
+local int tempdir = 0;  /* 1=use temp directory (-b) */
+local int junk_sfx = 0; /* 1=junk the sfx prefix */
+#if defined(AMIGA) || defined(MACOS)
+local int filenotes = 0; /* 1=take comments from AmigaDOS/MACOS filenotes */
+#endif
+
+#ifdef EBCDIC
+int aflag = __EBCDIC;   /* Convert EBCDIC to ASCII or stay EBCDIC ? */
+#endif
+#ifdef CMS_MVS
+int bflag = 0;          /* Use text mode as default */
+#endif
+
+#ifdef QDOS
+char _version[] = VERSION;
+#endif
+
+#ifdef WINDLL
+jmp_buf zipdll_error_return;
+#ifdef ZIP64_SUPPORT
+  unsigned long low, high; /* returning 64 bit values for systems without an _int64 */
+  uzoff_t filesize64;
+#endif
+#endif
+
+#if CRYPT
+/* Pointer to crc_table, needed in crypt.c */
+# if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB))
+ZCONST ulg near *crc_32_tab;
+# else
+ZCONST uLongf *crc_32_tab;
+# endif
+#endif /* CRYPT */
+
+/* Local functions */
+
+local void freeup  OF((void));
+local int  finish  OF((int));
+#if (!defined(MACOS) && !defined(WINDLL))
+local void handler OF((int));
+local void license OF((void));
+#ifndef VMSCLI
+local void help    OF((void));
+local void help_extended OF((void));
+#endif /* !VMSCLI */
+#endif /* !MACOS && !WINDLL */
+
+/* prereading of arguments is not supported in new command
+   line interpreter get_option() so read filters as arguments
+   are processed and convert to expected array later */
+local int add_filter OF((int flag, char *pattern));
+local int filterlist_to_patterns OF((void));
+/* not used
+ local int get_filters OF((int argc, char **argv));
+*/
+
+/* list to store file arguments */
+local long add_name OF((char *filearg));
+
+
+local int DisplayRunningStats OF((void));
+local int BlankRunningStats OF((void));
+
+#if !defined(WINDLL)
+local void version_info OF((void));
+# if !defined(MACOS)
+local void zipstdout OF((void));
+# endif /* !MACOS */
+local int check_unzip_version OF((char *unzippath));
+local void check_zipfile OF((char *zipname, char *zippath));
+#endif /* !WINDLL */
+
+/* structure used by add_filter to store filters */
+struct filterlist_struct {
+  char flag;
+  char *pattern;
+  struct filterlist_struct *next;
+};
+struct filterlist_struct *filterlist = NULL;  /* start of list */
+struct filterlist_struct *lastfilter = NULL;  /* last filter in list */
+
+/* structure used by add_filearg to store file arguments */
+struct filelist_struct {
+  char *name;
+  struct filelist_struct *next;
+};
+long filearg_count = 0;
+struct filelist_struct *filelist = NULL;  /* start of list */
+struct filelist_struct *lastfile = NULL;  /* last file in list */
+
+local void freeup()
+/* Free all allocations in the 'found' list, the 'zfiles' list and
+   the 'patterns' list. */
+{
+  struct flist far *f;  /* steps through found list */
+  struct zlist far *z;  /* pointer to next entry in zfiles list */
+
+  for (f = found; f != NULL; f = fexpel(f))
+    ;
+  while (zfiles != NULL)
+  {
+    z = zfiles->nxt;
+    if (zfiles->zname && zfiles->zname != zfiles->name)
+      free((zvoid *)(zfiles->zname));
+    if (zfiles->name)
+      free((zvoid *)(zfiles->name));
+    if (zfiles->iname)
+      free((zvoid *)(zfiles->iname));
+    if (zfiles->cext && zfiles->cextra && zfiles->cextra != zfiles->extra)
+      free((zvoid *)(zfiles->cextra));
+    if (zfiles->ext && zfiles->extra)
+      free((zvoid *)(zfiles->extra));
+    if (zfiles->com && zfiles->comment)
+      free((zvoid *)(zfiles->comment));
+    if (zfiles->oname)
+      free((zvoid *)(zfiles->oname));
+#ifdef UNICODE_SUPPORT
+    if (zfiles->uname)
+      free((zvoid *)(zfiles->uname));
+    if (zfiles->zuname)
+      free((zvoid *)(zfiles->zuname));
+    if (zfiles->ouname)
+      free((zvoid *)(zfiles->ouname));
+# ifdef WIN32
+    if (zfiles->namew)
+      free((zvoid *)(zfiles->namew));
+    if (zfiles->inamew)
+      free((zvoid *)(zfiles->inamew));
+    if (zfiles->znamew)
+      free((zvoid *)(zfiles->znamew));
+# endif
+#endif
+    farfree((zvoid far *)zfiles);
+    zfiles = z;
+    zcount--;
+  }
+
+  if (patterns != NULL) {
+    while (pcount-- > 0) {
+      if (patterns[pcount].zname != NULL)
+        free((zvoid *)(patterns[pcount].zname));
+    }
+    free((zvoid *)patterns);
+    patterns = NULL;
+  }
+
+  /* close logfile */
+  if (logfile) {
+    fclose(logfile);
+  }
+}
+
+local int finish(e)
+int e;                  /* exit code */
+/* Process -o and -m options (if specified), free up malloc'ed stuff, and
+   exit with the code e. */
+{
+  int r;                /* return value from trash() */
+  ulg t;                /* latest time in zip file */
+  struct zlist far *z;  /* pointer into zfile list */
+
+  /* If latest, set time to zip file to latest file in zip file */
+  if (latest && zipfile && strcmp(zipfile, "-"))
+  {
+    diag("changing time of zip file to time of latest file in it");
+    /* find latest time in zip file */
+    if (zfiles == NULL)
+       zipwarn("zip file is empty, can't make it as old as latest entry", "");
+    else {
+      t = 0;
+      for (z = zfiles; z != NULL; z = z->nxt)
+        /* Ignore directories in time comparisons */
+#ifdef USE_EF_UT_TIME
+        if (z->iname[z->nam-1] != (char)0x2f)   /* ascii '/' */
+        {
+          iztimes z_utim;
+          ulg z_tim;
+
+          z_tim = ((get_ef_ut_ztime(z, &z_utim) & EB_UT_FL_MTIME) ?
+                   unix2dostime(&z_utim.mtime) : z->tim);
+          if (t < z_tim)
+            t = z_tim;
+        }
+#else /* !USE_EF_UT_TIME */
+        if (z->iname[z->nam-1] != (char)0x2f    /* ascii '/' */
+            && t < z->tim)
+          t = z->tim;
+#endif /* ?USE_EF_UT_TIME */
+      /* set modified time of zip file to that time */
+      if (t != 0)
+        stamp(zipfile, t);
+      else
+        zipwarn(
+         "zip file has only directories, can't make it as old as latest entry",
+         "");
+    }
+  }
+  if (tempath != NULL)
+  {
+    free((zvoid *)tempath);
+    tempath = NULL;
+  }
+  if (zipfile != NULL)
+  {
+    free((zvoid *)zipfile);
+    zipfile = NULL;
+  }
+  if (in_file != NULL)
+  {
+    fclose(in_file);
+    in_file = NULL;
+  }
+  if (in_path != NULL)
+  {
+    free((zvoid *)in_path);
+    in_path = NULL;
+  }
+  if (out_path != NULL)
+  {
+    free((zvoid *)out_path);
+    out_path = NULL;
+  }
+  if (zcomment != NULL)
+  {
+    free((zvoid *)zcomment);
+    zcomment = NULL;
+  }
+
+
+  /* If dispose, delete all files in the zfiles list that are marked */
+  if (dispose)
+  {
+    diag("deleting files that were added to zip file");
+    if ((r = trash()) != ZE_OK)
+      ZIPERR(r, "was deleting moved files and directories");
+  }
+
+
+  /* Done! */
+  freeup();
+  return e;
+}
+
+void ziperr(c, h)
+int c;                  /* error code from the ZE_ class */
+ZCONST char *h;         /* message about how it happened */
+/* Issue a message for the error, clean up files and memory, and exit. */
+{
+#ifndef WINDLL
+#ifndef MACOS
+  static int error_level = 0;
+#endif
+
+  if (error_level++ > 0)
+     /* avoid recursive ziperr() printouts (his should never happen) */
+     EXIT(ZE_LOGIC);  /* ziperr recursion is an internal logic error! */
+#endif /* !WINDLL */
+
+  if (mesg_line_started) {
+    fprintf(mesg, "\n");
+    mesg_line_started = 0;
+  }
+  if (logfile && logfile_line_started) {
+    fprintf(logfile, "\n");
+    logfile_line_started = 0;
+  }
+  if (h != NULL) {
+    if (PERR(c))
+      fprintf(mesg, "zip I/O error: %s", strerror(errno));
+      /* perror("zip I/O error"); */
+    fflush(mesg);
+    fprintf(mesg, "\nzip error: %s (%s)\n", ZIPERRORS(c), h);
+#ifdef DOS
+    check_for_windows("Zip");
+#endif
+    if (logfile) {
+      if (PERR(c))
+        fprintf(logfile, "zip I/O error: %s\n", strerror(errno));
+      fprintf(logfile, "\nzip error: %s (%s)\n", ZIPERRORS(c), h);
+      logfile_line_started = 0;
+    }
+  }
+  if (tempzip != NULL)
+  {
+    if (tempzip != zipfile) {
+      if (current_local_file)
+        fclose(current_local_file);
+      if (y != current_local_file && y != NULL)
+        fclose(y);
+#ifndef DEBUG
+      destroy(tempzip);
+#endif
+      free((zvoid *)tempzip);
+    } else {
+      /* -g option, attempt to restore the old file */
+
+      /* zip64 support 09/05/2003 R.Nausedat */
+      uzoff_t k = 0;                        /* keep count for end header */
+      uzoff_t cb = cenbeg;                  /* get start of central */
+
+      struct zlist far *z;  /* steps through zfiles linked list */
+
+      fprintf(mesg, "attempting to restore %s to its previous state\n",
+         zipfile);
+      if (logfile)
+        fprintf(logfile, "attempting to restore %s to its previous state\n",
+           zipfile);
+
+      zfseeko(y, cenbeg, SEEK_SET);
+
+      tempzn = cenbeg;
+      for (z = zfiles; z != NULL; z = z->nxt)
+      {
+        putcentral(z);
+        tempzn += 4 + CENHEAD + z->nam + z->cext + z->com;
+        k++;
+      }
+      putend(k, tempzn - cb, cb, zcomlen, zcomment);
+      fclose(y);
+      y = NULL;
+    }
+  }
+
+  if (key != NULL) {
+    free((zvoid *)key);
+    key = NULL;
+  }
+  if (tempath != NULL) {
+    free((zvoid *)tempath);
+    tempath = NULL;
+  }
+  if (zipfile != NULL) {
+    free((zvoid *)zipfile);
+    zipfile = NULL;
+  }
+  if (out_path != NULL) {
+    free((zvoid *)out_path);
+    out_path = NULL;
+  }
+  if (zcomment != NULL) {
+    free((zvoid *)zcomment);
+    zcomment = NULL;
+  }
+
+  freeup();
+#ifndef WINDLL
+  EXIT(c);
+#else
+  longjmp(zipdll_error_return, c);
+#endif
+}
+
+
+void error(h)
+  ZCONST char *h;
+/* Internal error, should never happen */
+{
+  ziperr(ZE_LOGIC, h);
+}
+
+#if (!defined(MACOS) && !defined(WINDLL))
+local void handler(s)
+int s;                  /* signal number (ignored) */
+/* Upon getting a user interrupt, turn echo back on for tty and abort
+   cleanly using ziperr(). */
+{
+#if defined(AMIGA) && defined(__SASC)
+   _abort();
+#else
+#if !defined(MSDOS) && !defined(__human68k__) && !defined(RISCOS)
+  echon();
+  putc('\n', mesg);
+#endif /* !MSDOS */
+#endif /* AMIGA && __SASC */
+  ziperr(ZE_ABORT, "aborting");
+  s++;                                  /* keep some compilers happy */
+}
+#endif /* !MACOS && !WINDLL */
+
+void zipmessage_nl(a, nl)
+ZCONST char *a;     /* message string to output */
+int nl;             /* 1 = add nl to end */
+/* If nl false, print a message to mesg without new line.
+   If nl true, print and add new line.  If logfile is
+   open then also write message to log file. */
+{
+  if (noisy) {
+    if (a && strlen(a)) {
+      fprintf(mesg, "%s", a);
+      mesg_line_started = 1;
+    }
+    if (nl) {
+      if (mesg_line_started) {
+        fprintf(mesg, "\n");
+        mesg_line_started = 0;
+      }
+    } else if (a && strlen(a)) {
+      mesg_line_started = 1;
+    }
+    fflush(mesg);
+  }
+  if (logfile) {
+    if (a && strlen(a)) {
+      fprintf(logfile, "%s", a);
+      logfile_line_started = 1;
+    }
+    if (nl) {
+      if (logfile_line_started) {
+        fprintf(logfile, "\n");
+        logfile_line_started = 0;
+      }
+    } else if (a && strlen(a)) {
+      logfile_line_started = 1;
+    }
+    fflush(logfile);
+  }
+}
+
+void zipmessage(a, b)
+ZCONST char *a, *b;     /* message strings juxtaposed in output */
+/* Print a message to mesg and flush.  Also write to log file if
+   open.  Write new line first if current line has output already. */
+{
+  if (noisy) {
+    if (mesg_line_started)
+      fprintf(mesg, "\n");
+    fprintf(mesg, "%s%s\n", a, b);
+    mesg_line_started = 0;
+    fflush(mesg);
+  }
+  if (logfile) {
+    if (logfile_line_started)
+      fprintf(logfile, "\n");
+    fprintf(logfile, "%s%s\n", a, b);
+    logfile_line_started = 0;
+    fflush(logfile);
+  }
+}
+
+void zipwarn(a, b)
+ZCONST char *a, *b;     /* message strings juxtaposed in output */
+/* Print a warning message to mesg (usually stderr) and return. */
+{
+  if (noisy) {
+    if (mesg_line_started)
+      fprintf(mesg, "\n");
+    fprintf(mesg, "\tzip warning: %s%s\n", a, b);
+    mesg_line_started = 0;
+    fflush(mesg);
+  }
+  if (logfile) {
+    if (logfile_line_started)
+      fprintf(logfile, "\n");
+    fprintf(logfile, "\tzip warning: %s%s\n", a, b);
+    logfile_line_started = 0;
+    fflush(logfile);
+  }
+}
+
+#ifndef WINDLL
+local void license()
+/* Print license information to stdout. */
+{
+  extent i;             /* counter for copyright array */
+
+  for (i = 0; i < sizeof(swlicense)/sizeof(char *); i++)
+    puts(swlicense[i]);
+}
+
+#ifdef VMSCLI
+void help()
+#else
+local void help()
+#endif
+/* Print help (along with license info) to stdout. */
+{
+  extent i;             /* counter for help array */
+
+  /* help array */
+  static ZCONST char *text[] = {
+#ifdef VMS
+"Zip %s (%s). Usage: zip == \"$ disk:[dir]zip.exe\"",
+#else
+"Zip %s (%s). Usage:",
+#endif
+#ifdef MACOS
+"zip [-options] [-b fm] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list]",
+"  The default action is to add or replace zipfile entries from list.",
+" ",
+"  -f   freshen: only changed files  -u   update: only changed or new files",
+"  -d   delete entries in zipfile    -m   move into zipfile (delete OS files)",
+"  -r   recurse into directories     -j   junk (don't record) directory names",
+"  -0   store only                   -l   convert LF to CR LF (-ll CR LF to LF)",
+"  -1   compress faster              -9   compress better",
+"  -q   quiet operation              -v   verbose operation/print version info",
+"  -c   add one-line comments        -z   add zipfile comment",
+"                                    -o   make zipfile as old as latest entry",
+"  -F   fix zipfile (-FF try harder) -D   do not add directory entries",
+"  -T   test zipfile integrity       -X   eXclude eXtra file attributes",
+#  if CRYPT
+"  -e   encrypt                      -n   don't compress these suffixes"
+#  else
+"  -h   show this help               -n   don't compress these suffixes"
+#  endif
+," -h2  show more help",
+"  Macintosh specific:",
+"  -jj  record Fullpath (+ Volname)  -N store finder-comments as comments",
+"  -df  zip only datafork of a file  -S include finder invisible/system files"
+#else /* !MACOS */
+#ifdef VM_CMS
+"zip [-options] [-b fm] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list]",
+#else  /* !VM_CMS */
+"zip [-options] [-b path] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list]",
+#endif /* ?VM_CMS */
+"  The default action is to add or replace zipfile entries from list, which",
+"  can include the special name - to compress standard input.",
+"  If zipfile and list are omitted, zip compresses stdin to stdout.",
+"  -f   freshen: only changed files  -u   update: only changed or new files",
+"  -d   delete entries in zipfile    -m   move into zipfile (delete OS files)",
+"  -r   recurse into directories     -j   junk (don't record) directory names",
+#ifdef THEOS
+"  -0   store only                   -l   convert CR to CR LF (-ll CR LF to CR)",
+#else
+"  -0   store only                   -l   convert LF to CR LF (-ll CR LF to LF)",
+#endif
+"  -1   compress faster              -9   compress better",
+"  -q   quiet operation              -v   verbose operation/print version info",
+"  -c   add one-line comments        -z   add zipfile comment",
+"  -@   read names from stdin        -o   make zipfile as old as latest entry",
+"  -x   exclude the following names  -i   include only the following names",
+#ifdef EBCDIC
+#ifdef CMS_MVS
+"  -a   translate to ASCII           -B   force binary read (text is default)",
+#else  /* !CMS_MVS */
+"  -a   translate to ASCII",
+#endif /* ?CMS_MVS */
+#endif /* EBCDIC */
+#ifdef TANDEM
+"                                    -Bn  set Enscribe formatting options",
+#endif
+"  -F   fix zipfile (-FF try harder) -D   do not add directory entries",
+"  -A   adjust self-extracting exe   -J   junk zipfile prefix (unzipsfx)",
+"  -T   test zipfile integrity       -X   eXclude eXtra file attributes",
+#ifdef VMS
+"  -C   preserve case of file names  -C-  down-case all file names",
+"  -C2  preserve case of ODS2 names  -C2- down-case ODS2 file names* (*=default)",
+"  -C5  preserve case of ODS5 names* -C5- down-case ODS5 file names",
+"  -V   save VMS file attributes (-VV also save allocated blocks past EOF)",
+"  -w   store file version numbers\
+   -ww  store file version numbers as \".nnn\"",
+#endif /* def VMS */
+#ifdef NTSD_EAS
+"  -!   use privileges (if granted) to obtain all aspects of WinNT security",
+#endif /* NTSD_EAS */
+#ifdef OS2
+"  -E   use the .LONGNAME Extended attribute (if found) as filename",
+#endif /* OS2 */
+#ifdef S_IFLNK
+"  -y   store symbolic links as the link instead of the referenced file",
+#endif /* !S_IFLNK */
+/*
+"  -R   PKZIP recursion (see manual)",
+*/
+#if defined(MSDOS) || defined(OS2)
+"  -$   include volume label         -S   include system and hidden files",
+#endif
+#ifdef AMIGA
+#  if CRYPT
+"  -N   store filenotes as comments  -e   encrypt",
+"  -h   show this help               -n   don't compress these suffixes"
+#  else
+"  -N   store filenotes as comments  -n   don't compress these suffixes"
+#  endif
+#else /* !AMIGA */
+#  if CRYPT
+"  -e   encrypt                      -n   don't compress these suffixes"
+#  else
+"  -h   show this help               -n   don't compress these suffixes"
+#  endif
+#endif /* ?AMIGA */
+#ifdef RISCOS
+,"  -h2  show more help               -I   don't scan thru Image files"
+#else
+,"  -h2  show more help"
+#endif
+#endif /* ?MACOS */
+#ifdef VMS
+,"  (Must quote upper-case options, like \"-V\", unless SET PROC/PARSE=EXTEND)"
+#endif /* def VMS */
+,"  "
+  };
+
+  for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
+  {
+    printf(copyright[i], "zip");
+    putchar('\n');
+  }
+  for (i = 0; i < sizeof(text)/sizeof(char *); i++)
+  {
+    printf(text[i], VERSION, REVDATE);
+    putchar('\n');
+  }
+}
+
+#ifdef VMSCLI
+void help_extended()
+#else
+local void help_extended()
+#endif
+/* Print extended help to stdout. */
+{
+  extent i;             /* counter for help array */
+
+  /* help array */
+  static ZCONST char *text[] = {
+"",
+"Extended Help for Zip",
+"",
+"See the Zip Manual for more detailed help",
+"",
+"",
+"Zip stores files in zip archives.  The default action is to add or replace",
+"zipfile entries.",
+"",
+"Basic command line:",
+"  zip options archive_name file file ...",
+"",
+"Some examples:",
+"  Add file.txt to z.zip (create z if needed):      zip z file.txt",
+"  Zip all files in current dir:                    zip z *",
+"  Zip files in current dir and subdirs also:       zip -r z .",
+"",
+"Basic modes:",
+" External modes (selects files from file system):",
+"        add      - add new files/update existing files in archive (default)",
+"  -u    update   - add new files/update existing files only if later date",
+"  -f    freshen  - update existing files only (no files added)",
+"  -FS   filesync - update if date or size changed, delete if no OS match",
+" Internal modes (selects entries in archive):",
+"  -d    delete   - delete files from archive (see below)",
+"  -U    copy     - select files in archive to copy (use with --out)",
+"",
+"Basic options:",
+"  -r        recurse into directories (see Recursion below)",
+"  -m        after archive created, delete original files (move into archive)",
+"  -j        junk directory names (store just file names)",
+"  -q        quiet operation",
+"  -v        verbose operation (just \"zip -v\" shows version information)",
+"  -c        prompt for one-line comment for each entry",
+"  -z        prompt for comment for archive (end with just \".\" line or EOF)",
+"  -@        read names to zip from stdin (one path per line)",
+"  -o        make zipfile as old as latest entry",
+"",
+"",
+"Syntax:",
+"  The full command line syntax is:",
+"",
+"    zip [-shortopts ...] [--longopt ...] [zipfile [path path ...]] [-xi list]",
+"",
+"  Any number of short option and long option arguments are allowed",
+"  (within limits) as well as any number of path arguments for files",
+"  to zip up.  If zipfile exists, the archive is read in.  If zipfile",
+"  is \"-\", stream to stdout.  If any path is \"-\", zip stdin.",
+"",
+"Options and Values:",
+"  For short options that take values, use -ovalue or -o value or -o=value",
+"  For long option values, use either --longoption=value or --longoption value",
+"  For example:",
+"    zip -ds 10 --temp-dir=path zipfile path1 path2 --exclude pattern pattern",
+"  Avoid -ovalue (no space between) to avoid confusion",
+"  In particular, be aware of 2-character options.  For example:",
+"    -d -s is (delete, split size) while -ds is (dot size)",
+"  Usually better to break short options across multiple arguments by function",
+"    zip -r -dbdcds 10m -lilalf logfile archive input_directory -ll",
+"",
+"  All args after just \"--\" arg are read verbatim as paths and not options.",
+"    zip zipfile path path ... -- verbatimpath verbatimpath ...",
+"  Use -nw to also disable wildcards, so paths are read literally:",
+"    zip zipfile -nw -- \"-leadingdashpath\" \"a[path].c\" \"path*withwildcard\"",
+"  You may still have to escape or quote arguments to avoid shell expansion",
+"",
+"Wildcards:",
+"  Internally zip supports the following wildcards:",
+"    ?       (or %% or #, depending on OS) matches any single character",
+"    *       matches any number of characters, including zero",
+"    [list]  matches char in list (regex), can do range [ac-f], all but [!bf]",
+"  If port supports [], must escape [ as [[] or use -nw to turn off wildcards",
+"  For shells that expand wildcards, escape (\\* or \"*\") so zip can recurse",
+"    zip zipfile -r . -i \"*.h\"",
+"",
+"  Normally * crosses dir bounds in path, e.g. 'a*b' can match 'ac/db'.  If",
+"   -ws option used, * does not cross dir bounds but ** does",
+"",
+"  For DOS and Windows, [list] is now disabled unless the new option",
+"  -RE       enable [list] (regular expression) matching",
+"  is used to avoid problems with file paths containing \"[\" and \"]\":",
+"    zip files_ending_with_number -RE foo[0-9].c",
+"",
+"Include and Exclude:",
+"  -i pattern pattern ...   include files that match a pattern",
+"  -x pattern pattern ...   exclude files that match a pattern",
+"  Patterns are paths with optional wildcards and match paths as stored in",
+"  archive.  Exclude and include lists end at next option, @, or end of line.",
+"    zip -x pattern pattern @ zipfile path path ...",
+"",
+"Case matching:",
+"  On most OS the case of patterns must match the case in the archive, unless",
+"  the -ic option is used.",
+"  -ic       ignore case of archive entries",
+"  This option not available on case-sensitive file systems.  On others, case",
+"  ignored when matching files on file system but matching against archive",
+"  entries remains case sensitive for modes -f (freshen), -U (archive copy),",
+"  and -d (delete) because archive paths are always case sensitive.  With",
+"  -ic, all matching ignores case, but it's then possible multiple archive",
+"  entries that differ only in case will match.",
+"",
+"End Of Line Translation (text files only):",
+"  -l        change CR or LF (depending on OS) line end to CR LF (Unix->Win)",
+"  -ll       change CR LF to CR or LF (depending on OS) line end (Win->Unix)",
+"  If first buffer read from file contains binary the translation is skipped",
+"",
+"Recursion:",
+"  -r        recurse paths, include files in subdirs:  zip -r a path path ...",
+"  -R        recurse current dir and match patterns:   zip -R a ptn ptn ...",
+"  Use -i and -x with either to include or exclude paths",
+"  Path root in archive starts at current dir, so if /a/b/c/file and",
+"   current dir is /a/b, 'zip -r archive .' puts c/file in archive",
+"",
+"Date filtering:",
+"  -t date   exclude before (include files modified on this date and later)",
+"  -tt date  include before (include files modified before date)",
+"  Can use both at same time to set a date range",
+"  Dates are mmddyyyy or yyyy-mm-dd",
+"",
+"Deletion, File Sync:",
+"  -d        delete files",
+"  Delete archive entries matching internal archive paths in list",
+"    zip archive -d pattern pattern ...",
+"  Can use -t and -tt to select files in archive, but NOT -x or -i, so",
+"    zip archive -d \"*\" -t 2005-12-27",
+"  deletes all files from archive.zip with date of 27 Dec 2005 and later",
+"  Note the * (escape as \"*\" on Unix) to select all files in archive",
+"",
+"  -FS       file sync",
+"  Similar to update, but files updated if date or size of entry does not",
+"  match file on OS.  Also deletes entry from archive if no matching file",
+"  on OS.",
+"    zip archive_to_update -FS -r dir_used_before",
+"  Result generally same as creating new archive, but unchanged entries",
+"  are copied instead of being read and compressed so can be faster.",
+"      WARNING:  -FS deletes entries so make backup copy of archive first",
+"",
+"Compression:",
+"  -0        store files (no compression)",
+"  -1 to -9  compress fastest to compress best (default is 6)",
+"  -Z cm     set compression method to cm:",
+"              store   - store without compression, same as option -0",
+"              deflate - original zip deflate, same as -1 to -9 (default)",
+"            if bzip2 is enabled:",
+"              bzip2 - use bzip2 compression (need modern unzip)",
+"",
+"Encryption:",
+"  -e        use standard (weak) PKZip 2.0 encryption, prompt for password",
+"  -P pswd   use standard encryption, password is pswd",
+"",
+"Splits (archives created as a set of split files):",
+"  -s ssize  create split archive with splits of size ssize, where ssize nm",
+"              n number and m multiplier (kmgt, default m), 100k -> 100 kB",
+"  -sp       pause after each split closed to allow changing disks",
+"      WARNING:  Archives created with -sp use data descriptors and should",
+"                work with most unzips but may not work with some",
+"  -sb       ring bell when pause",
+"  -sv       be verbose about creating splits",
+"      Split archives CANNOT be updated, but see --out and Copy Mode below",
+"",
+"Using --out (output to new archive):",
+"  --out oa  output to new archive oa",
+"  Instead of updating input archive, create new output archive oa.",
+"  Result is same as without --out but in new archive.  Input archive",
+"  unchanged.",
+"      WARNING:  --out ALWAYS overwrites any existing output file",
+"  For example, to create new_archive like old_archive but add newfile1",
+"  and newfile2:",
+"    zip old_archive newfile1 newfile2 --out new_archive",
+"  Cannot update split archive, so use --out to out new archive:",
+"    zip in_split_archive newfile1 newfile2 --out out_split_archive",
+"  If input is split, output will default to same split size",
+"  Use -s=0 or -s- to turn off splitting to convert split to single file:",
+"    zip in_split_archive -s 0 --out out_single_file_archive",
+"      WARNING:  If overwriting old split archive but need less splits,",
+"                old splits not overwritten are not needed but remain",
+"",
+"Copy Mode (copying from archive to archive):",
+"  -U        (also --copy) select entries in archive to copy (reverse delete)",
+"  Copy Mode copies entries from old to new archive with --out and is used by",
+"  zip when either no input files on command line or -U (--copy) used.",
+"    zip inarchive --copy pattern pattern ... --out outarchive",
+"  To copy only files matching *.c into new archive, excluding foo.c:",
+"    zip old_archive --copy \"*.c\" --out new_archive -x foo.c",
+"  If no input files and --out, copy all entries in old archive:",
+"    zip old_archive --out new_archive",
+"",
+"Streaming and FIFOs:",
+"  prog1 | zip -ll z -      zip output of prog1 to zipfile z, converting CR LF",
+"  zip - -R \"*.c\" | prog2   zip *.c files in current dir and stream to prog2 ",
+"  prog1 | zip | prog2      zip in pipe with no in or out acts like zip - -",
+"  If Zip is Zip64 enabled, streaming stdin creates Zip64 archives by default",
+"   that need PKZip 4.5 unzipper like UnZip 6.0",
+"  WARNING:  Some archives created with streaming use data descriptors and",
+"            should work with most unzips but may not work with some",
+"  Can use -fz- to turn off Zip64 if input not large (< 4 GB):",
+"    prog_with_small_output | zip archive -fz-",
+"",
+"  Zip now can read Unix FIFO (named pipes).  Off by default to prevent zip",
+"  from stopping unexpectedly on unfed pipe, use -FI to enable:",
+"    zip -FI archive fifo",
+"",
+"Dots, counts:",
+"  -db       display running count of bytes processed and bytes to go",
+"              (uncompressed size, except delete and copy show stored size)",
+"  -dc       display running count of entries done and entries to go",
+"  -dd       display dots every 10 MB (or dot size) while processing files",
+"  -dg       display dots globally for archive instead of for each file",
+"    zip -qdgds 10m   will turn off most output except dots every 10 MB",
+"  -ds siz   each dot is siz processed where siz is nm as splits (0 no dots)",
+"  -du       display original uncompressed size for each entry as added",
+"  -dv       display volume (disk) number in format in_disk>out_disk",
+"  Dot size is approximate, especially for dot sizes less than 1 MB",
+"  Dot options don't apply to Scanning files dots (dot/2sec) (-q turns off)",
+"",
+"Logging:",
+"  -lf path  open file at path as logfile (overwrite existing file)",
+"  -la       append to existing logfile",
+"  -li       include info messages (default just warnings and errors)",
+"",
+"Testing archives:",
+"  -T        test completed temp archive with unzip before updating archive",
+"  -TT cmd   use command cmd instead of 'unzip -tqq' to test archive",
+"             On Unix, to use unzip in current directory, could use:",
+"               zip archive file1 file2 -T -TT \"./unzip -tqq\"",
+"             In cmd, {} replaced by temp archive path, else temp appended.",
+"             The return code is checked for success (0 on Unix)",
+"",
+"Fixing archives:",
+"  -F        attempt to fix a mostly intact archive (try this first)",
+"  -FF       try to salvage what can (may get more but less reliable)",
+"  Fix options copy entries from potentially bad archive to new archive.",
+"  -F tries to read archive normally and copy only intact entries, while",
+"  -FF tries to salvage what can and may result in incomplete entries.",
+"  Must use --out option to specify output archive:",
+"    zip -F bad.zip --out fixed.zip",
+"  Use -v (verbose) with -FF to see details:",
+"    zip reallybad.zip -FF -v --out fixed.zip",
+"  Currently neither option fixes bad entries, as from text mode ftp get.",
+"",
+"Difference mode:",
+"  -DF       (also --dif) only include files that have changed or are",
+"             new as compared to the input archive",
+"  Difference mode can be used to create incremental backups.  For example:",
+"    zip --dif full_backup.zip -r somedir --out diff.zip",
+"  will store all new files, as well as any files in full_backup.zip where",
+"  either file time or size have changed from that in full_backup.zip,",
+"  in new diff.zip.  Output archive not excluded automatically if exists,",
+"  so either use -x to exclude it or put outside what is being zipped.",
+"",
+"DOS Archive bit (Windows only):",
+"  -AS       include only files with the DOS Archive bit set",
+"  -AC       after archive created, clear archive bit of included files",
+"      WARNING: Once the archive bits are cleared they are cleared",
+"               Use -T to test the archive before the bits are cleared",
+"               Can also use -sf to save file list before zipping files",
+"",
+"Show files:",
+"  -sf       show files to operate on and exit (-sf- logfile only)",
+"  -su       as -sf but show escaped UTF-8 Unicode names also if exist",
+"  -sU       as -sf but show escaped UTF-8 Unicode names instead",
+"  Any character not in the current locale is escaped as #Uxxxx, where x",
+"  is hex digit, if 16-bit code is sufficient, or #Lxxxxxx if 24-bits",
+"  are needed.  If add -UN=e, Zip escapes all non-ASCII characters.",
+"",
+"Unicode:",
+"  If compiled with Unicode support, Zip stores UTF-8 path of entries.",
+"  This is backward compatible.  Unicode paths allow better conversion",
+"  of entry names between different character sets.",
+"",
+"  New Unicode extra field includes checksum to verify Unicode path",
+"  goes with standard path for that entry (as utilities like ZipNote",
+"  can rename entries).  If these do not match, use below options to",
+"  set what Zip does:",
+"      -UN=Quit     - if mismatch, exit with error",
+"      -UN=Warn     - if mismatch, warn, ignore UTF-8 (default)",
+"      -UN=Ignore   - if mismatch, quietly ignore UTF-8",
+"      -UN=No       - ignore any UTF-8 paths, use standard paths for all",
+"  An exception to -UN=N are entries with new UTF-8 bit set (instead",
+"  of using extra fields).  These are always handled as Unicode.",
+"",
+"  Normally Zip escapes all chars outside current char set, but leaves",
+"  as is supported chars, which may not be OK in path names.  -UN=Escape",
+"  escapes any character not ASCII:",
+"    zip -sU -UN=e archive",
+"  Can use either normal path or escaped Unicode path on command line",
+"  to match files in archive.",
+"",
+"  Zip now stores UTF-8 in entry path and comment fields on systems",
+"  where UTF-8 char set is default, such as most modern Unix, and",
+"  and on other systems in new extra fields with escaped versions in",
+"  entry path and comment fields for backward compatibility.",
+"  Option -UN=UTF8 will force storing UTF-8 in entry path and comment",
+"  fields:",
+"      -UN=UTF8     - store UTF-8 in entry path and comment fields",
+"  This option can be useful for multi-byte char sets on Windows where",
+"  escaped paths and comments can be too long to be valid as the UTF-8",
+"  versions tend to be shorter.",
+"",
+"  Only UTF-8 comments on UTF-8 native systems supported.  UTF-8 comments",
+"  for other systems planned in next release.",
+"",
+"Self extractor:",
+"  -A        Adjust offsets - a self extractor is created by prepending",
+"             the extractor executable to archive, but internal offsets",
+"             are then off.  Use -A to fix offsets.",
+"  -J        Junk sfx - removes prepended extractor executable from",
+"             self extractor, leaving a plain zip archive.",
+"",
+"More option highlights (see manual for additional options and details):",
+"  -b dir    when creating or updating archive, create the temp archive in",
+"             dir, which allows using seekable temp file when writing to a",
+"             write once CD, such archives compatible with more unzips",
+"             (could require additional file copy if on another device)",
+"  -MM       input patterns must match at least one file and matched files",
+"             must be readable or exit with OPEN error and abort archive",
+"             (without -MM, both are warnings only, and if unreadable files",
+"             are skipped OPEN error (18) returned after archive created)",
+"  -nw       no wildcards (wildcards are like any other character)",
+"  -sc       show command line arguments as processed and exit",
+"  -sd       show debugging as Zip does each step",
+"  -so       show all available options on this system",
+"  -X        default=strip old extra fields, -X- keep old, -X strip most",
+"  -ws       wildcards don't span directory boundaries in paths",
+""
+  };
+
+  for (i = 0; i < sizeof(text)/sizeof(char *); i++)
+  {
+    printf(text[i]);
+    putchar('\n');
+  }
+#ifdef DOS
+  check_for_windows("Zip");
+#endif
+}
+
+/*
+ * XXX version_info() in a separate file
+ */
+local void version_info()
+/* Print verbose info about program version and compile time options
+   to stdout. */
+{
+  extent i;             /* counter in text arrays */
+  char *envptr;
+
+  /* Bzip2 option string storage (with version). */
+
+#ifdef BZIP2_SUPPORT
+  static char bz_opt_ver[81];
+  static char bz_opt_ver2[81];
+  static char bz_opt_ver3[81];
+#endif
+
+  /* Options info array */
+  static ZCONST char *comp_opts[] = {
+#ifdef ASM_CRC
+    "ASM_CRC",
+#endif
+#ifdef ASMV
+    "ASMV",
+#endif
+#ifdef DYN_ALLOC
+    "DYN_ALLOC",
+#endif
+#ifdef MMAP
+    "MMAP",
+#endif
+#ifdef BIG_MEM
+    "BIG_MEM",
+#endif
+#ifdef MEDIUM_MEM
+    "MEDIUM_MEM",
+#endif
+#ifdef SMALL_MEM
+    "SMALL_MEM",
+#endif
+#ifdef DEBUG
+    "DEBUG",
+#endif
+#ifdef USE_EF_UT_TIME
+    "USE_EF_UT_TIME       (store Universal Time)",
+#endif
+#ifdef NTSD_EAS
+    "NTSD_EAS             (store NT Security Descriptor)",
+#endif
+#if defined(WIN32) && defined(NO_W32TIMES_IZFIX)
+    "NO_W32TIMES_IZFIX",
+#endif
+#ifdef VMS
+#ifdef VMSCLI
+    "VMSCLI",
+#endif
+#ifdef VMS_IM_EXTRA
+    "VMS_IM_EXTRA",
+#endif
+#ifdef VMS_PK_EXTRA
+    "VMS_PK_EXTRA",
+#endif
+#endif /* VMS */
+#ifdef WILD_STOP_AT_DIR
+    "WILD_STOP_AT_DIR     (wildcards do not cross directory boundaries)",
+#endif
+#ifdef WIN32_OEM
+    "WIN32_OEM            (store file paths on Windows as OEM)",
+#endif
+#ifdef BZIP2_SUPPORT
+    bz_opt_ver,
+    bz_opt_ver2,
+    bz_opt_ver3,
+#endif
+#ifdef S_IFLNK
+# ifdef VMS
+    "SYMLINK_SUPPORT      (symbolic links supported, if C RTL permits)",
+# else
+    "SYMLINK_SUPPORT      (symbolic links supported)",
+# endif
+#endif
+#ifdef LARGE_FILE_SUPPORT
+# ifdef USING_DEFAULT_LARGE_FILE_SUPPORT
+    "LARGE_FILE_SUPPORT (default settings)",
+# else
+    "LARGE_FILE_SUPPORT   (can read and write large files on file system)",
+# endif
+#endif
+#ifdef ZIP64_SUPPORT
+    "ZIP64_SUPPORT        (use Zip64 to store large files in archives)",
+#endif
+#ifdef UNICODE_SUPPORT
+    "UNICODE_SUPPORT      (store and read UTF-8 Unicode paths)",
+#endif
+
+#ifdef UNIX
+    "STORE_UNIX_UIDs_GIDs (store UID/GID sizes/values using new extra field)",
+# ifdef UIDGID_NOT_16BIT
+    "UIDGID_NOT_16BIT     (old Unix 16-bit UID/GID extra field not used)",
+# else
+    "UIDGID_16BIT         (old Unix 16-bit UID/GID extra field also used)",
+# endif
+#endif
+
+#if CRYPT && defined(PASSWD_FROM_STDIN)
+    "PASSWD_FROM_STDIN",
+#endif /* CRYPT & PASSWD_FROM_STDIN */
+    NULL
+  };
+
+  static ZCONST char *zipenv_names[] = {
+#ifndef VMS
+#  ifndef RISCOS
+    "ZIP"
+#  else /* RISCOS */
+    "Zip$Options"
+#  endif /* ?RISCOS */
+#else /* VMS */
+    "ZIP_OPTS"
+#endif /* ?VMS */
+    ,"ZIPOPT"
+#ifdef AZTEC_C
+    ,     /* extremely lame compiler bug workaround */
+#endif
+#ifndef __RSXNT__
+# ifdef __EMX__
+    ,"EMX"
+    ,"EMXOPT"
+# endif
+# if (defined(__GO32__) && (!defined(__DJGPP__) || __DJGPP__ < 2))
+    ,"GO32"
+    ,"GO32TMP"
+# endif
+# if (defined(__DJGPP__) && __DJGPP__ >= 2)
+    ,"TMPDIR"
+# endif
+#endif /* !__RSXNT__ */
+#ifdef RISCOS
+    ,"Zip$Exts"
+#endif
+  };
+
+  for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
+  {
+    printf(copyright[i], "zip");
+    putchar('\n');
+  }
+
+  for (i = 0; i < sizeof(versinfolines)/sizeof(char *); i++)
+  {
+    printf(versinfolines[i], "Zip", VERSION, REVDATE);
+    putchar('\n');
+  }
+
+  version_local();
+
+  puts("Zip special compilation options:");
+#if WSIZE != 0x8000
+  printf("\tWSIZE=%u\n", WSIZE);
+#endif
+
+  /* Fill in bzip2 version.  (32-char limit valid as of bzip 1.0.3.) */
+#ifdef BZIP2_SUPPORT
+  sprintf( bz_opt_ver,
+   "BZIP2_SUPPORT        (bzip2 library version %.32s)", BZ2_bzlibVersion());
+  sprintf( bz_opt_ver2,
+   "    bzip2 code and library copyright (c) Julian R Seward");
+  sprintf( bz_opt_ver3,
+   "    (See the bzip2 license for terms of use)");
+#endif
+
+  for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++)
+  {
+    printf("\t%s\n",comp_opts[i]);
+  }
+#ifdef USE_ZLIB
+  if (strcmp(ZLIB_VERSION, zlibVersion()) == 0)
+    printf("\tUSE_ZLIB [zlib version %s]\n", ZLIB_VERSION);
+  else
+    printf("\tUSE_ZLIB [compiled with version %s, using version %s]\n",
+      ZLIB_VERSION, zlibVersion());
+  i++;  /* zlib use means there IS at least one compilation option */
+#endif
+#if CRYPT
+  printf("\t[encryption, version %d.%d%s of %s] (modified for Zip 3)\n\n",
+            CR_MAJORVER, CR_MINORVER, CR_BETA_VER, CR_VERSION_DATE);
+  for (i = 0; i < sizeof(cryptnote)/sizeof(char *); i++)
+  {
+    printf(cryptnote[i]);
+    putchar('\n');
+  }
+  ++i;  /* crypt support means there IS at least one compilation option */
+#endif /* CRYPT */
+  if (i == 0)
+      puts("\t[none]");
+
+  puts("\nZip environment options:");
+  for (i = 0; i < sizeof(zipenv_names)/sizeof(char *); i++)
+  {
+    envptr = getenv(zipenv_names[i]);
+    printf("%16s:  %s\n", zipenv_names[i],
+           ((envptr == (char *)NULL || *envptr == 0) ? "[none]" : envptr));
+  }
+#ifdef DOS
+  check_for_windows("Zip");
+#endif
+}
+#endif /* !WINDLL */
+
+
+#ifndef PROCNAME
+/* Default to case-sensitive matching of archive entries for the modes
+   that specifically operate on archive entries, as this archive may
+   have come from a system that allows paths in the archive to differ
+   only by case.  Except for adding ARCHIVE (copy mode), this is how it
+   was done before.  Note that some case-insensitive ports (WIN32, VMS)
+   define their own PROCNAME() in their respective osdep.h that use the
+   filter_match_case flag set to FALSE by the -ic option to enable
+   case-insensitive archive entry mathing. */
+#  define PROCNAME(n) procname(n, (action == ARCHIVE || action == DELETE \
+                                   || action == FRESHEN) \
+                                  && filter_match_case)
+#endif /* PROCNAME */
+
+#ifndef WINDLL
+#ifndef MACOS
+local void zipstdout()
+/* setup for writing zip file on stdout */
+{
+  mesg = stderr;
+  if (isatty(1))
+    ziperr(ZE_PARMS, "cannot write zip file to terminal");
+  if ((zipfile = malloc(4)) == NULL)
+    ziperr(ZE_MEM, "was processing arguments");
+  strcpy(zipfile, "-");
+  /*
+  if ((r = readzipfile()) != ZE_OK)
+    ziperr(r, zipfile);
+  */
+}
+#endif /* !MACOS */
+
+local int check_unzip_version(unzippath)
+  char *unzippath;
+{
+#ifdef ZIP64_SUPPORT
+  /* Here is where we need to check for the version of unzip the user
+   * has.  If creating a Zip64 archive need UnZip 6 or may fail.
+   */
+    char cmd[4004];
+    FILE *unzip_out = NULL;
+    char buf[1001];
+    float UnZip_Version = 0.0;
+
+    cmd[0] = '\0';
+    strncat(cmd, unzippath, 4000);
+    strcat(cmd, " -v");
+
+    if ((unzip_out = popen(cmd, "r")) == NULL) {
+      perror("unzip pipe error");
+    } else {
+      if (fgets(buf, 1000, unzip_out) == NULL) {
+        zipwarn("failed to get information from UnZip", "");
+      } else {
+        /* the first line should start with the version */
+        if (sscanf(buf, "UnZip %f ", &UnZip_Version) < 1) {
+          zipwarn("unexpected output of UnZip -v", "");
+        } else {
+          /* printf("UnZip %f\n", UnZip_Version); */
+
+          while (fgets(buf, 1000, unzip_out)) {
+          }
+        }
+      }
+      pclose(unzip_out);
+    }
+    if (UnZip_Version < 6.0 && zip64_archive) {
+      sprintf(buf, "Found UnZip version %4.2f", UnZip_Version);
+      zipwarn(buf, "");
+      zipwarn("Need UnZip 6.00 or later to test this Zip64 archive", "");
+      return 0;
+    }
+#endif
+  return 1;
+}
+
+local void check_zipfile(zipname, zippath)
+  char *zipname;
+  char *zippath;
+  /* Invoke unzip -t on the given zip file */
+{
+#if (defined(MSDOS) && !defined(__GO32__)) || defined(__human68k__)
+  int status, len;
+  char *path, *p;
+  char *zipnam;
+
+  if ((zipnam = (char *)malloc(strlen(zipname) + 3)) == NULL)
+    ziperr(ZE_MEM, "was creating unzip zipnam");
+
+# ifdef MSDOS
+  /* Add quotes for MSDOS.  8/11/04 */
+  strcpy(zipnam, "\"");    /* accept spaces in name and path */
+  strcat(zipnam, zipname);
+  strcat(zipnam, "\"");
+# else
+  strcpy(zipnam, zipname);
+# endif
+
+  if (unzip_path) {
+    /* if user gave us the unzip to use go with it */
+    char *here;
+    int len;
+    char *cmd;
+
+    /* Replace first {} with archive name.  If no {} append name to string. */
+    here = strstr(unzip_path, "{}");
+
+    if ((cmd = (char *)malloc(strlen(unzip_path) + strlen(zipnam) + 3)) == NULL)
+      ziperr(ZE_MEM, "was creating unzip cmd");
+
+    if (here) {
+      /* have {} so replace with temp name */
+      len = here - unzip_path;
+      strcpy(cmd, unzip_path);
+      cmd[len] = '\0';
+      strcat(cmd, " ");
+      strcat(cmd, zipnam);
+      strcat(cmd, " ");
+      strcat(cmd, here + 2);
+    } else {
+      /* No {} so append temp name to end */
+      strcpy(cmd, unzip_path);
+      strcat(cmd, " ");
+      strcat(cmd, zipnam);
+    }
+
+    status = system(cmd);
+
+    free(unzip_path);
+    unzip_path = NULL;
+    free(cmd);
+  } else {
+    /* Here is where we need to check for the version of unzip the user
+     * has.  If creating a Zip64 archive need UnZip 6 or may fail.
+     */
+    if (check_unzip_version("unzip") == 0)
+      ZIPERR(ZE_TEST, zipfile);
+
+    status = spawnlp(P_WAIT, "unzip", "unzip", verbose ? "-t" : "-tqq",
+                     zipnam, NULL);
+# ifdef __human68k__
+    if (status == -1)
+      perror("unzip");
+# else
+/*
+ * unzip isn't in PATH range, assume an absolute path to zip in argv[0]
+ * and hope that unzip is in the same directory.
+ */
+    if (status == -1) {
+      p = MBSRCHR(zippath, '\\');
+      path = MBSRCHR((p == NULL ? zippath : p), '/');
+      if (path != NULL)
+        p = path;
+      if (p != NULL) {
+        len = (int)(p - zippath) + 1;
+        if ((path = malloc(len + sizeof("unzip.exe"))) == NULL)
+          ziperr(ZE_MEM, "was creating unzip path");
+        memcpy(path, zippath, len);
+        strcpy(&path[len], "unzip.exe");
+
+        if (check_unzip_version(path) == 0)
+          ZIPERR(ZE_TEST, zipfile);
+
+        status = spawnlp(P_WAIT, path, "unzip", verbose ? "-t" : "-tqq",
+                        zipnam, NULL);
+        free(path);
+      }
+      if (status == -1)
+        perror("unzip");
+    }
+  }
+# endif /* ?__human68k__ */
+  free(zipnam);
+  if (status != 0) {
+
+#else /* (MSDOS && !__GO32__) || __human68k__ */
+  char *cmd;
+  int result;
+
+  /* Tell picky compilers to shut up about unused variables */
+  zippath = zippath;
+
+  if (unzip_path) {
+    /* user gave us a path to some unzip (may not be UnZip) */
+    char *here;
+    int len;
+
+    /* Replace first {} with archive name.  If no {} append name to string. */
+    here = strstr(unzip_path, "{}");
+
+    if ((cmd = malloc(strlen(unzip_path) + strlen(zipname) + 3)) == NULL) {
+      ziperr(ZE_MEM, "building command string for testing archive");
+    }
+
+    if (here) {
+      /* have {} so replace with temp name */
+      len = here - unzip_path;
+      strcpy(cmd, unzip_path);
+      cmd[len] = '\0';
+      strcat(cmd, " ");
+# ifdef UNIX
+      strcat(cmd, "'");    /* accept space or $ in name */
+      strcat(cmd, zipname);
+      strcat(cmd, "'");
+# else
+      strcat(cmd, zipname);
+# endif
+      strcat(cmd, " ");
+      strcat(cmd, here + 2);
+    } else {
+      /* No {} so append temp name to end */
+      strcpy(cmd, unzip_path);
+      strcat(cmd, " ");
+# ifdef UNIX
+      strcat(cmd, "'");    /* accept space or $ in name */
+      strcat(cmd, zipname);
+      strcat(cmd, "'");
+# else
+      strcat(cmd, zipname);
+# endif
+    }
+    free(unzip_path);
+    unzip_path = NULL;
+
+  } else {
+    if ((cmd = malloc(20 + strlen(zipname))) == NULL) {
+      ziperr(ZE_MEM, "building command string for testing archive");
+    }
+
+    strcpy(cmd, "unzip -t ");
+# ifdef QDOS
+    strcat(cmd, "-Q4 ");
+# endif
+    if (!verbose) strcat(cmd, "-qq ");
+    if (check_unzip_version("unzip") == 0)
+      ZIPERR(ZE_TEST, zipfile);
+
+# ifdef UNIX
+    strcat(cmd, "'");    /* accept space or $ in name */
+    strcat(cmd, zipname);
+    strcat(cmd, "'");
+# else
+    strcat(cmd, zipname);
+# endif
+  }
+
+  result = system(cmd);
+# ifdef VMS
+  /* Convert success severity to 0, others to non-zero. */
+  result = ((result & STS$M_SEVERITY) != STS$M_SUCCESS);
+# endif /* def VMS */
+  free(cmd);
+  cmd = NULL;
+  if (result) {
+#endif /* ?((MSDOS && !__GO32__) || __human68k__) */
+
+    fprintf(mesg, "test of %s FAILED\n", zipfile);
+    ziperr(ZE_TEST, "original files unmodified");
+  }
+  if (noisy) {
+    fprintf(mesg, "test of %s OK\n", zipfile);
+    fflush(mesg);
+  }
+  if (logfile) {
+    fprintf(logfile, "test of %s OK\n", zipfile);
+    fflush(logfile);
+  }
+}
+#endif /* !WINDLL */
+
+/* get_filters() is replaced by the following
+local int get_filters(argc, argv)
+*/
+
+/* The filter patterns for options -x, -i, and -R are
+   returned by get_option() one at a time, so use a linked
+   list to store until all args are processed.  Then convert
+   to array for processing.
+ */
+
+/* add a filter to the linked list */
+local int add_filter(flag, pattern)
+  int flag;
+  char *pattern;
+{
+  char *iname, *p = NULL;
+  FILE *fp;
+  struct filterlist_struct *filter = NULL;
+
+  /* should never happen */
+  if (flag != 'R' && flag != 'x' && flag != 'i') {
+    ZIPERR(ZE_LOGIC, "bad flag to add_filter");
+  }
+  if (pattern == NULL) {
+    ZIPERR(ZE_LOGIC, "null pattern to add_filter");
+  }
+
+  if (pattern[0] == '@') {
+    /* read file with 1 pattern per line */
+    if (pattern[1] == '\0') {
+      ZIPERR(ZE_PARMS, "missing file after @");
+    }
+    fp = fopen(pattern + 1, "r");
+    if (fp == NULL) {
+      sprintf(errbuf, "%c pattern file '%s'", flag, pattern);
+      ZIPERR(ZE_OPEN, errbuf);
+    }
+    while ((p = getnam(fp)) != NULL) {
+      if ((filter = (struct filterlist_struct *) malloc(sizeof(struct filterlist_struct))) == NULL) {
+        ZIPERR(ZE_MEM, "adding filter");
+      }
+      if (filterlist == NULL) {
+        /* first filter */
+        filterlist = filter;         /* start of list */
+        lastfilter = filter;
+      } else {
+        lastfilter->next = filter;   /* link to last filter in list */
+        lastfilter = filter;
+      }
+      iname = ex2in(p, 0, (int *)NULL);
+      free(p);
+      if (iname != NULL) {
+        lastfilter->pattern = in2ex(iname);
+        free(iname);
+      } else {
+        lastfilter->pattern = NULL;
+      }
+      lastfilter->flag = flag;
+      pcount++;
+      lastfilter->next = NULL;
+    }
+    fclose(fp);
+  } else {
+    /* single pattern */
+    if ((filter = (struct filterlist_struct *) malloc(sizeof(struct filterlist_struct))) == NULL) {
+      ZIPERR(ZE_MEM, "adding filter");
+    }
+    if (filterlist == NULL) {
+      /* first pattern */
+      filterlist = filter;         /* start of list */
+      lastfilter = filter;
+    } else {
+      lastfilter->next = filter;   /* link to last filter in list */
+      lastfilter = filter;
+    }
+    iname = ex2in(pattern, 0, (int *)NULL);
+    if (iname != NULL) {
+       lastfilter->pattern = in2ex(iname);
+       free(iname);
+    } else {
+      lastfilter->pattern = NULL;
+    }
+    lastfilter->flag = flag;
+    pcount++;
+    lastfilter->next = NULL;
+  }
+
+  return pcount;
+}
+
+/* convert list to patterns array */
+local int filterlist_to_patterns()
+{
+  unsigned i;
+  struct filterlist_struct *next = NULL;
+
+  if (pcount == 0) {
+    patterns = NULL;
+    return 0;
+  }
+  if ((patterns = (struct plist *) malloc((pcount + 1) * sizeof(struct plist)))
+      == NULL) {
+    ZIPERR(ZE_MEM, "was creating pattern list");
+  }
+
+  for (i = 0; i < pcount && filterlist != NULL; i++) {
+    switch (filterlist->flag) {
+      case 'i':
+        icount++;
+        break;
+      case 'R':
+        Rcount++;
+        break;
+    }
+    patterns[i].select = filterlist->flag;
+    patterns[i].zname = filterlist->pattern;
+    next = filterlist->next;
+    free(filterlist);
+    filterlist = next;
+  }
+
+  return pcount;
+}
+
+
+/* add a file argument to linked list */
+local long add_name(filearg)
+  char *filearg;
+{
+  char *name = NULL;
+  struct filelist_struct *fileentry = NULL;
+
+  if ((fileentry = (struct filelist_struct *) malloc(sizeof(struct filelist_struct))) == NULL) {
+    ZIPERR(ZE_MEM, "adding file");
+  }
+  if ((name = malloc(strlen(filearg) + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "adding file");
+  }
+  strcpy(name, filearg);
+  fileentry->next = NULL;
+  fileentry->name = name;
+  if (filelist == NULL) {
+    /* first file argument */
+    filelist = fileentry;         /* start of list */
+    lastfile = fileentry;
+  } else {
+    lastfile->next = fileentry;   /* link to last filter in list */
+    lastfile = fileentry;
+  }
+  filearg_count++;
+
+  return filearg_count;
+}
+
+
+/* Running Stats
+   10/30/04 */
+
+local int DisplayRunningStats()
+{
+  char tempstrg[100];
+
+  if (mesg_line_started) {
+    fprintf(mesg, "\n");
+    mesg_line_started = 0;
+  }
+  if (logfile_line_started) {
+    fprintf(logfile, "\n");
+    logfile_line_started = 0;
+  }
+  if (display_volume) {
+    if (noisy) {
+      fprintf(mesg, "%lu>%lu: ", current_in_disk + 1, current_disk + 1);
+      mesg_line_started = 1;
+    }
+    if (logall) {
+      fprintf(logfile, "%lu>%lu: ", current_in_disk + 1, current_disk + 1);
+      logfile_line_started = 1;
+    }
+  }
+  if (display_counts) {
+    if (noisy) {
+      fprintf(mesg, "%3ld/%3ld ", files_so_far, files_total - files_so_far);
+      mesg_line_started = 1;
+    }
+    if (logall) {
+      fprintf(logfile, "%3ld/%3ld ", files_so_far, files_total - files_so_far);
+      logfile_line_started = 1;
+    }
+  }
+  if (display_bytes) {
+    /* since file sizes can change as we go, use bytes_so_far from
+       initial scan so all adds up */
+    WriteNumString(bytes_so_far, tempstrg);
+    if (noisy) {
+      fprintf(mesg, "[%4s", tempstrg);
+      mesg_line_started = 1;
+    }
+    if (logall) {
+      fprintf(logfile, "[%4s", tempstrg);
+      logfile_line_started = 1;
+    }
+    if (bytes_total >= bytes_so_far) {
+      WriteNumString(bytes_total - bytes_so_far, tempstrg);
+      if (noisy)
+        fprintf(mesg, "/%4s] ", tempstrg);
+      if (logall)
+        fprintf(logfile, "/%4s] ", tempstrg);
+    } else {
+      WriteNumString(bytes_so_far - bytes_total, tempstrg);
+      if (noisy)
+        fprintf(mesg, "-%4s] ", tempstrg);
+      if (logall)
+        fprintf(logfile, "-%4s] ", tempstrg);
+    }
+  }
+  if (noisy)
+      fflush(mesg);
+  if (logall)
+      fflush(logfile);
+
+  return 0;
+}
+
+local int BlankRunningStats()
+{
+  if (display_volume) {
+    if (noisy) {
+      fprintf(mesg, "%lu>%lu: ", current_in_disk + 1, current_disk + 1);
+      mesg_line_started = 1;
+    }
+    if (logall) {
+      fprintf(logfile, "%lu>%lu: ", current_in_disk + 1, current_disk + 1);
+      logfile_line_started = 1;
+    }
+  }
+  if (display_counts) {
+    if (noisy) {
+      fprintf(mesg, "   /    ");
+      mesg_line_started = 1;
+    }
+    if (logall) {
+      fprintf(logfile, "   /    ");
+      logfile_line_started = 1;
+    }
+  }
+  if (display_bytes) {
+    if (noisy) {
+      fprintf(mesg, "     /      ");
+      mesg_line_started = 1;
+    }
+    if (logall) {
+      fprintf(logfile, "     /      ");
+      logfile_line_started = 1;
+    }
+  }
+  if (noisy)
+      fflush(mesg);
+  if (logall)
+      fflush(logfile);
+
+  return 0;
+}
+
+#if CRYPT
+#ifndef WINDLL
+int encr_passwd(modeflag, pwbuf, size, zfn)
+int modeflag;
+char *pwbuf;
+int size;
+ZCONST char *zfn;
+{
+    char *prompt;
+
+    /* Tell picky compilers to shut up about unused variables */
+    zfn = zfn;
+
+    prompt = (modeflag == ZP_PW_VERIFY) ?
+              "Verify password: " : "Enter password: ";
+
+    if (getp(prompt, pwbuf, size) == NULL) {
+      ziperr(ZE_PARMS, "stderr is not a tty");
+    }
+    return IZ_PW_ENTERED;
+}
+#endif /* !WINDLL */
+#else /* !CRYPT */
+int encr_passwd(modeflag, pwbuf, size, zfn)
+int modeflag;
+char *pwbuf;
+int size;
+ZCONST char *zfn;
+{
+    /* Tell picky compilers to shut up about unused variables */
+    modeflag = modeflag; pwbuf = pwbuf; size = size; zfn = zfn;
+
+    return ZE_LOGIC;    /* This function should never be called! */
+}
+#endif /* CRYPT */
+
+
+/* rename a split
+ * A split has a tempfile name until it is closed, then
+ * here rename it as out_path the final name for the split.
+ */
+int rename_split(temp_name, out_path)
+  char *temp_name;
+  char *out_path;
+{
+  int r;
+  /* Replace old zip file with new zip file, leaving only the new one */
+  if ((r = replace(out_path, temp_name)) != ZE_OK)
+  {
+    zipwarn("new zip file left as: ", temp_name);
+    free((zvoid *)tempzip);
+    tempzip = NULL;
+    ZIPERR(r, "was replacing split file");
+  }
+  if (zip_attributes) {
+    setfileattr(out_path, zip_attributes);
+  }
+  return ZE_OK;
+}
+
+
+int set_filetype(out_path)
+  char *out_path;
+{
+#ifdef __BEOS__
+  /* Set the filetype of the zipfile to "application/zip" */
+  setfiletype( out_path, "application/zip" );
+#endif
+
+#ifdef __ATHEOS__
+  /* Set the filetype of the zipfile to "application/x-zip" */
+  setfiletype(out_path, "application/x-zip");
+#endif
+
+#ifdef MACOS
+  /* Set the Creator/Type of the zipfile to 'IZip' and 'ZIP ' */
+  setfiletype(out_path, 'IZip', 'ZIP ');
+#endif
+
+#ifdef RISCOS
+  /* Set the filetype of the zipfile to &DDC */
+  setfiletype(out_path, 0xDDC);
+#endif
+  return ZE_OK;
+}
+
+
+/*
+  -------------------------------------------------------
+  Command Line Options
+  -------------------------------------------------------
+
+  Valid command line options.
+
+  The function get_option() uses this table to check if an
+  option is valid and if it takes a value (also called an
+  option argument).  To add an option to zip just add it
+  to this table and add a case in the main switch to handle
+  it.  If either shortopt or longopt not used set to "".
+
+   The fields:
+       shortopt     - short option name (1 or 2 chars)
+       longopt      - long option name
+       value_type   - see zip.h for constants
+       negatable    - option is negatable with trailing -
+       ID           - unsigned long int returned for option
+       name         - short description of option which is
+                        returned on some errors and when options
+                        are listed with -so option, can be NULL
+*/
+
+/* Most option IDs are set to the shortopt char.  For
+   multichar short options set to arbitrary unused constant. */
+#define o_AC            0x101
+#define o_AS            0x102
+#define o_C2            0x103
+#define o_C5            0x104
+#define o_db            0x105
+#define o_dc            0x106
+#define o_dd            0x107
+#define o_des           0x108
+#define o_df            0x109
+#define o_DF            0x110
+#define o_dg            0x111
+#define o_ds            0x112
+#define o_du            0x113
+#define o_dv            0x114
+#define o_FF            0x115
+#define o_FI            0x116
+#define o_FS            0x117
+#define o_h2            0x118
+#define o_ic            0x119
+#define o_jj            0x120
+#define o_la            0x121
+#define o_lf            0x122
+#define o_li            0x123
+#define o_ll            0x124
+#define o_mm            0x125
+#define o_MM            0x126
+#define o_nw            0x127
+#define o_RE            0x128
+#define o_sb            0x129
+#define o_sc            0x130
+#define o_sd            0x131
+#define o_sf            0x132
+#define o_so            0x133
+#define o_sp            0x134
+#define o_su            0x135
+#define o_sU            0x136
+#define o_sv            0x137
+#define o_tt            0x138
+#define o_TT            0x139
+#define o_UN            0x140
+#define o_ve            0x141
+#define o_VV            0x142
+#define o_ws            0x143
+#define o_ww            0x144
+#define o_z64           0x145
+#ifdef UNICODE_TEST
+#define o_sC            0x146
+#endif
+
+
+/* the below is mainly from the old main command line
+   switch with a few changes */
+struct option_struct far options[] = {
+  /* short longopt        value_type        negatable        ID    name */
+#ifdef EBCDIC
+    {"a",  "ascii",       o_NO_VALUE,       o_NOT_NEGATABLE, 'a',  "to ascii"},
+#endif /* EBCDIC */
+#ifdef CMS_MVS
+    {"B",  "binary",      o_NO_VALUE,       o_NOT_NEGATABLE, 'B',  "binary"},
+#endif /* CMS_MVS */
+#ifdef TANDEM
+    {"B",  "",            o_NUMBER_VALUE,   o_NOT_NEGATABLE, 'B',  "nsk"},
+#endif
+    {"0",  "store",       o_NO_VALUE,       o_NOT_NEGATABLE, '0',  "store"},
+    {"1",  "compress-1",  o_NO_VALUE,       o_NOT_NEGATABLE, '1',  "compress 1"},
+    {"2",  "compress-2",  o_NO_VALUE,       o_NOT_NEGATABLE, '2',  "compress 2"},
+    {"3",  "compress-3",  o_NO_VALUE,       o_NOT_NEGATABLE, '3',  "compress 3"},
+    {"4",  "compress-4",  o_NO_VALUE,       o_NOT_NEGATABLE, '4',  "compress 4"},
+    {"5",  "compress-5",  o_NO_VALUE,       o_NOT_NEGATABLE, '5',  "compress 5"},
+    {"6",  "compress-6",  o_NO_VALUE,       o_NOT_NEGATABLE, '6',  "compress 6"},
+    {"7",  "compress-7",  o_NO_VALUE,       o_NOT_NEGATABLE, '7',  "compress 7"},
+    {"8",  "compress-8",  o_NO_VALUE,       o_NOT_NEGATABLE, '8',  "compress 8"},
+    {"9",  "compress-9",  o_NO_VALUE,       o_NOT_NEGATABLE, '9',  "compress 9"},
+    {"A",  "adjust-sfx",  o_NO_VALUE,       o_NOT_NEGATABLE, 'A',  "adjust self extractor offsets"},
+#if defined(WIN32)
+    {"AC", "archive-clear", o_NO_VALUE,     o_NOT_NEGATABLE, o_AC, "clear DOS archive bit of included files"},
+    {"AS", "archive-set", o_NO_VALUE,       o_NOT_NEGATABLE, o_AS, "include only files with archive bit set"},
+#endif
+    {"b",  "temp-path",   o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'b',  "dir to use for temp archive"},
+    {"c",  "entry-comments", o_NO_VALUE,    o_NOT_NEGATABLE, 'c',  "add comments for each entry"},
+#ifdef VMS
+    {"C",  "preserve-case", o_NO_VALUE,     o_NEGATABLE,     'C',  "Preserve (C-: down-) case all on VMS"},
+    {"C2", "preserve-case-2", o_NO_VALUE,   o_NEGATABLE,     o_C2, "Preserve (C2-: down-) case ODS2 on VMS"},
+    {"C5", "preserve-case-5", o_NO_VALUE,   o_NEGATABLE,     o_C5, "Preserve (C5-: down-) case ODS5 on VMS"},
+#endif /* VMS */
+    {"d",  "delete",      o_NO_VALUE,       o_NOT_NEGATABLE, 'd',  "delete entries from archive"},
+    {"db", "display-bytes", o_NO_VALUE,     o_NEGATABLE,     o_db, "display running bytes"},
+    {"dc", "display-counts", o_NO_VALUE,    o_NEGATABLE,     o_dc, "display running file count"},
+    {"dd", "display-dots", o_NO_VALUE,      o_NEGATABLE,     o_dd, "display dots as process each file"},
+    {"dg", "display-globaldots",o_NO_VALUE, o_NEGATABLE,     o_dg, "display dots for archive instead of files"},
+    {"ds", "dot-size",     o_REQUIRED_VALUE, o_NOT_NEGATABLE, o_ds, "set progress dot size - default 10M bytes"},
+    {"du", "display-usize", o_NO_VALUE,     o_NEGATABLE,     o_du, "display uncompressed size in bytes"},
+    {"dv", "display-volume", o_NO_VALUE,    o_NEGATABLE,     o_dv, "display volume (disk) number"},
+#ifdef MACOS
+    {"df", "datafork",    o_NO_VALUE,       o_NOT_NEGATABLE, o_df, "save datafork"},
+#endif /* MACOS */
+    {"D",  "no-dir-entries", o_NO_VALUE,    o_NOT_NEGATABLE, 'D',  "no entries for dirs themselves (-x */)"},
+    {"DF", "difference-archive",o_NO_VALUE, o_NOT_NEGATABLE, o_DF, "create diff archive with changed/new files"},
+    {"e",  "encrypt",     o_NO_VALUE,       o_NOT_NEGATABLE, 'e',  "encrypt entries, ask for password"},
+#ifdef OS2
+    {"E",  "longnames",   o_NO_VALUE,       o_NOT_NEGATABLE, 'E',  "use OS2 longnames"},
+#endif
+    {"F",  "fix",         o_NO_VALUE,       o_NOT_NEGATABLE, 'F',  "fix mostly intact archive (try first)"},
+    {"FF", "fixfix",      o_NO_VALUE,       o_NOT_NEGATABLE, o_FF, "try harder to fix archive (not as reliable)"},
+    {"FI", "fifo",        o_NO_VALUE,       o_NEGATABLE,     o_FI, "read Unix FIFO (zip will wait on open pipe)"},
+    {"FS", "filesync",    o_NO_VALUE,       o_NOT_NEGATABLE, o_FS, "add/delete entries to make archive match OS"},
+    {"f",  "freshen",     o_NO_VALUE,       o_NOT_NEGATABLE, 'f',  "freshen existing archive entries"},
+    {"fd", "force-descriptors", o_NO_VALUE, o_NOT_NEGATABLE, o_des,"force data descriptors as if streaming"},
+#ifdef ZIP64_SUPPORT
+    {"fz", "force-zip64", o_NO_VALUE,       o_NEGATABLE,     o_z64,"force use of Zip64 format, negate prevents"},
+#endif
+    {"g",  "grow",        o_NO_VALUE,       o_NOT_NEGATABLE, 'g',  "grow existing archive instead of replace"},
+#ifndef WINDLL
+    {"h",  "help",        o_NO_VALUE,       o_NOT_NEGATABLE, 'h',  "help"},
+    {"H",  "",            o_NO_VALUE,       o_NOT_NEGATABLE, 'h',  "help"},
+    {"?",  "",            o_NO_VALUE,       o_NOT_NEGATABLE, 'h',  "help"},
+    {"h2", "more-help",   o_NO_VALUE,       o_NOT_NEGATABLE, o_h2, "extended help"},
+#endif /* !WINDLL */
+    {"i",  "include",     o_VALUE_LIST,     o_NOT_NEGATABLE, 'i',  "include only files matching patterns"},
+#if defined(VMS) || defined(WIN32)
+    {"ic", "ignore-case", o_NO_VALUE,       o_NEGATABLE,     o_ic, "ignore case when matching archive entries"},
+#endif
+#ifdef RISCOS
+    {"I",  "no-image",    o_NO_VALUE,       o_NOT_NEGATABLE, 'I',  "no image"},
+#endif
+    {"j",  "junk-paths",  o_NO_VALUE,       o_NOT_NEGATABLE, 'j',  "strip paths and just store file names"},
+#ifdef MACOS
+    {"jj", "absolute-path", o_NO_VALUE,     o_NOT_NEGATABLE, o_jj, "MAC absolute path"},
+#endif /* ?MACOS */
+    {"J",  "junk-sfx",    o_NO_VALUE,       o_NOT_NEGATABLE, 'J',  "strip self extractor from archive"},
+    {"k",  "DOS-names",   o_NO_VALUE,       o_NOT_NEGATABLE, 'k',  "force use of 8.3 DOS names"},
+    {"l",  "to-crlf",     o_NO_VALUE,       o_NOT_NEGATABLE, 'l',  "convert text file line ends - LF->CRLF"},
+    {"ll", "from-crlf",   o_NO_VALUE,       o_NOT_NEGATABLE, o_ll, "convert text file line ends - CRLF->LF"},
+    {"lf", "logfile-path",o_REQUIRED_VALUE, o_NOT_NEGATABLE, o_lf, "log to log file at path (default overwrite)"},
+    {"la", "log-append",  o_NO_VALUE,       o_NEGATABLE,     o_la, "append to existing log file"},
+    {"li", "log-info",    o_NO_VALUE,       o_NEGATABLE,     o_li, "include informational messages in log"},
+#ifndef WINDLL
+    {"L",  "license",     o_NO_VALUE,       o_NOT_NEGATABLE, 'L',  "display license"},
+#endif
+    {"m",  "move",        o_NO_VALUE,       o_NOT_NEGATABLE, 'm',  "add files to archive then delete files"},
+    {"mm", "",            o_NO_VALUE,       o_NOT_NEGATABLE, o_mm, "not used"},
+    {"MM", "must-match",  o_NO_VALUE,       o_NOT_NEGATABLE, o_MM, "error if in file not matched/not readable"},
+    {"n",  "suffixes",    o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'n',  "suffixes to not compress: .gz:.zip"},
+    {"nw", "no-wild",     o_NO_VALUE,       o_NOT_NEGATABLE, o_nw, "no wildcards during add or update"},
+#if defined(AMIGA) || defined(MACOS)
+    {"N",  "notes",       o_NO_VALUE,       o_NOT_NEGATABLE, 'N',  "add notes as entry comments"},
+#endif
+    {"o",  "latest-time", o_NO_VALUE,       o_NOT_NEGATABLE, 'o',  "use latest entry time as archive time"},
+    {"O",  "output-file", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'O',  "set out zipfile different than in zipfile"},
+    {"p",  "paths",       o_NO_VALUE,       o_NOT_NEGATABLE, 'p',  "store paths"},
+    {"P",  "password",    o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'P',  "encrypt entries, option value is password"},
+#if defined(QDOS) || defined(QLZIP)
+    {"Q",  "Q-flag",      o_NUMBER_VALUE,   o_NOT_NEGATABLE, 'Q',  "Q flag"},
+#endif
+    {"q",  "quiet",       o_NO_VALUE,       o_NOT_NEGATABLE, 'q',  "quiet"},
+    {"r",  "recurse-paths", o_NO_VALUE,     o_NOT_NEGATABLE, 'r',  "recurse down listed paths"},
+    {"R",  "recurse-patterns", o_NO_VALUE,  o_NOT_NEGATABLE, 'R',  "recurse current dir and match patterns"},
+    {"RE", "regex",       o_NO_VALUE,       o_NOT_NEGATABLE, o_RE, "allow [list] matching (regex)"},
+    {"s",  "split-size",  o_REQUIRED_VALUE, o_NOT_NEGATABLE, 's',  "do splits, set split size (-s=0 no splits)"},
+    {"sp", "split-pause", o_NO_VALUE,       o_NOT_NEGATABLE, o_sp, "pause while splitting to select destination"},
+    {"sv", "split-verbose", o_NO_VALUE,     o_NOT_NEGATABLE, o_sv, "be verbose about creating splits"},
+    {"sb", "split-bell",  o_NO_VALUE,       o_NOT_NEGATABLE, o_sb, "when pause for next split ring bell"},
+    {"sc", "show-command",o_NO_VALUE,       o_NOT_NEGATABLE, o_sc, "show command line"},
+#ifdef UNICODE_TEST
+    {"sC", "create-files",o_NO_VALUE,       o_NOT_NEGATABLE, o_sC, "create empty files using archive names"},
+#endif
+    {"sd", "show-debug",  o_NO_VALUE,       o_NOT_NEGATABLE, o_sd, "show debug"},
+    {"sf", "show-files",  o_NO_VALUE,       o_NEGATABLE,     o_sf, "show files to operate on and exit"},
+    {"so", "show-options",o_NO_VALUE,       o_NOT_NEGATABLE, o_so, "show options"},
+#ifdef UNICODE_SUPPORT
+    {"su", "show-unicode", o_NO_VALUE,      o_NEGATABLE,     o_su, "as -sf but also show escaped Unicode"},
+    {"sU", "show-just-unicode", o_NO_VALUE, o_NEGATABLE,     o_sU, "as -sf but only show escaped Unicode"},
+#endif
+#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(ATARI)
+    {"S",  "",            o_NO_VALUE,       o_NOT_NEGATABLE, 'S',  "include system and hidden"},
+#endif /* MSDOS || OS2 || WIN32 || ATARI */
+    {"t",  "from-date",   o_REQUIRED_VALUE, o_NOT_NEGATABLE, 't',  "exclude before date"},
+    {"tt", "before-date", o_REQUIRED_VALUE, o_NOT_NEGATABLE, o_tt, "include before date"},
+    {"T",  "test",        o_NO_VALUE,       o_NOT_NEGATABLE, 'T',  "test updates before replacing archive"},
+    {"TT", "unzip-command", o_REQUIRED_VALUE,o_NOT_NEGATABLE,o_TT, "unzip command to use, name is added to end"},
+    {"u",  "update",      o_NO_VALUE,       o_NOT_NEGATABLE, 'u',  "update existing entries and add new"},
+    {"U",  "copy-entries", o_NO_VALUE,      o_NOT_NEGATABLE, 'U',  "select from archive instead of file system"},
+#ifdef UNICODE_SUPPORT
+    {"UN", "unicode",     o_REQUIRED_VALUE, o_NOT_NEGATABLE, o_UN, "UN=quit, warn, ignore, no, escape"},
+#endif
+    {"v",  "verbose",     o_NO_VALUE,       o_NOT_NEGATABLE, 'v',  "display additional information"},
+    {"",   "version",     o_NO_VALUE,       o_NOT_NEGATABLE, o_ve, "(if no other args) show version information"},
+#ifdef VMS
+    {"V",  "VMS-portable", o_NO_VALUE,      o_NOT_NEGATABLE, 'V',  "Store VMS attributes, portable file format"},
+    {"VV", "VMS-specific", o_NO_VALUE,      o_NOT_NEGATABLE, o_VV, "Store VMS attributes, VMS specific format"},
+    {"w",  "VMS-versions", o_NO_VALUE,      o_NOT_NEGATABLE, 'w',  "store VMS versions"},
+    {"ww", "VMS-dot-versions", o_NO_VALUE,  o_NOT_NEGATABLE, o_ww, "store VMS versions as \".nnn\""},
+#endif /* VMS */
+    {"ws", "wild-stop-dirs", o_NO_VALUE,    o_NOT_NEGATABLE, o_ws,  "* stops at /, ** includes any /"},
+    {"x",  "exclude",     o_VALUE_LIST,     o_NOT_NEGATABLE, 'x',  "exclude files matching patterns"},
+/*    {"X",  "no-extra",    o_NO_VALUE,       o_NOT_NEGATABLE, 'X',  "no extra"},
+*/
+    {"X",  "strip-extra", o_NO_VALUE,       o_NEGATABLE,     'X',  "-X- keep all ef, -X strip but critical ef"},
+#ifdef S_IFLNK
+    {"y",  "symlinks",    o_NO_VALUE,       o_NOT_NEGATABLE, 'y',  "store symbolic links"},
+#endif /* S_IFLNK */
+    {"z",  "archive-comment", o_NO_VALUE,   o_NOT_NEGATABLE, 'z',  "ask for archive comment"},
+    {"Z",  "compression-method", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'Z', "compression method"},
+#if defined(MSDOS) || defined(OS2)
+    {"$",  "volume-label", o_NO_VALUE,      o_NOT_NEGATABLE, '$',  "store volume label"},
+#endif
+#ifndef MACOS
+    {"@",  "names-stdin", o_NO_VALUE,       o_NOT_NEGATABLE, '@',  "get file names from stdin, one per line"},
+#endif /* !MACOS */
+#ifdef NTSD_EAS
+    {"!",  "use-privileges", o_NO_VALUE,    o_NOT_NEGATABLE, '!',  "use privileges"},
+#endif
+#ifdef RISCOS
+    {"/",  "exts-to-swap", o_REQUIRED_VALUE, o_NOT_NEGATABLE, '/',  "override Zip$Exts"},
+#endif
+    /* the end of the list */
+    {NULL, NULL,          o_NO_VALUE,       o_NOT_NEGATABLE, 0,    NULL} /* end has option_ID = 0 */
+  };
+
+
+
+#ifndef USE_ZIPMAIN
+int main(argc, argv)
+#else
+int zipmain(argc, argv)
+#endif
+int argc;               /* number of tokens in command line */
+char **argv;            /* command line tokens */
+/* Add, update, freshen, or delete zip entries in a zip file.  See the
+   command help in help() above. */
+{
+  int d;                /* true if just adding to a zip file */
+  char *e;              /* malloc'd comment buffer */
+  struct flist far *f;  /* steps through found linked list */
+  int i;                /* arg counter, root directory flag */
+  int kk;               /* next arg type (formerly another re-use of "k") */
+
+  /* zip64 support 09/05/2003 R.Nausedat */
+  uzoff_t c;            /* start of central directory */
+  uzoff_t t;            /* length of central directory */
+  zoff_t k;             /* marked counter, comment size, entry count */
+  uzoff_t n;            /* total of entry len's */
+
+  int o;                /* true if there were any ZE_OPEN errors */
+  char *p;              /* steps through option arguments */
+  char *pp;             /* temporary pointer */
+  int r;                /* temporary variable */
+  int s;                /* flag to read names from stdin */
+  uzoff_t csize;        /* compressed file size for stats */
+  uzoff_t usize;        /* uncompressed file size for stats */
+  ulg tf;               /* file time */
+  int first_listarg = 0;/* index of first arg of "process these files" list */
+  struct zlist far *v;  /* temporary variable */
+  struct zlist far * far *w;    /* pointer to last link in zfiles list */
+  FILE *x /*, *y */;    /* input and output zip files (y global) */
+  struct zlist far *z;  /* steps through zfiles linked list */
+  int bad_open_is_error = 0; /* if read fails, 0=warning, 1=error */
+#if 0
+  /* does not seem used */
+#ifdef WINDLL
+  int retcode;          /* return code for dll */
+#endif /* WINDLL */
+#endif
+#if (!defined(VMS) && !defined(CMS_MVS))
+  char *zipbuf;         /* stdio buffer for the zip file */
+#endif /* !VMS && !CMS_MVS */
+  FILE *comment_stream; /* set to stderr if anything is read from stdin */
+  int all_current;      /* used by File Sync to determine if all entries are current */
+
+  struct filelist_struct *filearg;
+
+/* used by get_option */
+  unsigned long option; /* option ID returned by get_option */
+  int argcnt = 0;       /* current argcnt in args */
+  int argnum = 0;       /* arg number */
+  int optchar = 0;      /* option state */
+  char *value = NULL;   /* non-option arg, option value or NULL */
+  int negated = 0;      /* 1 = option negated */
+  int fna = 0;          /* current first non-opt arg */
+  int optnum = 0;       /* index in table */
+
+  int show_options = 0; /* show options */
+  int show_what_doing = 0; /* show what doing */
+  int show_args = 0;    /* show command line */
+  int seen_doubledash = 0; /* seen -- argument */
+  int key_needed = 0;   /* prompt for encryption key */
+  int have_out = 0;     /* if set in_path and out_path different archive */
+#ifdef UNICODE_TEST
+  int create_files = 0;
+#endif
+
+  char **args = NULL;  /* could be wide argv */
+
+
+#ifdef THEOS
+  /* the argument expansion from the standard library is full of bugs */
+  /* use mine instead */
+  _setargv(&argc, &argv);
+  setlocale(LC_CTYPE, "I");
+#else
+  SETLOCALE(LC_CTYPE, "");
+#endif
+
+#ifdef UNICODE_SUPPORT
+# ifdef UNIX
+  /* For Unix, set the locale to UTF-8.  Any UTF-8 locale is
+     OK and they should all be the same.  This allows seeing,
+     writing, and displaying (if the fonts are loaded) all
+     characters in UTF-8. */
+  {
+    char *loc;
+
+    /*
+      loc = setlocale(LC_CTYPE, NULL);
+      printf("  Initial language locale = '%s'\n", loc);
+    */
+
+    loc = setlocale(LC_CTYPE, "en_US.UTF-8");
+
+    /*
+      printf("langinfo %s\n", nl_langinfo(CODESET));
+    */
+
+    if (loc != NULL) {
+      /* using UTF-8 character set so can set UTF-8 GPBF bit 11 */
+      using_utf8 = 1;
+      /*
+        printf("  Locale set to %s\n", loc);
+      */
+    } else {
+      /*
+        printf("  Could not set Unicode UTF-8 locale\n");
+      */
+    }
+  }
+# endif
+#endif
+
+#if defined(__IBMC__) && defined(__DEBUG_ALLOC__)
+  {
+    extern void DebugMalloc(void);
+    atexit(DebugMalloc);
+  }
+#endif
+
+#ifdef QDOS
+  {
+    extern void QDOSexit(void);
+    atexit(QDOSexit);
+  }
+#endif
+
+#ifdef NLM
+  {
+    extern void NLMexit(void);
+    atexit(NLMexit);
+  }
+#endif
+
+#ifdef RISCOS
+  set_prefix();
+#endif
+
+#ifdef __human68k__
+  fflush(stderr);
+  setbuf(stderr, NULL);
+#endif
+
+/* Re-initialize global variables to make the zip dll re-entrant. It is
+ * possible that we could get away with not re-initializing all of these
+ * but better safe than sorry.
+ */
+#if defined(MACOS) || defined(WINDLL) || defined(USE_ZIPMAIN)
+  action = ADD; /* one of ADD, UPDATE, FRESHEN, DELETE, or ARCHIVE */
+  comadd = 0;   /* 1=add comments for new files */
+  zipedit = 0;  /* 1=edit zip comment and all file comments */
+  latest = 0;   /* 1=set zip file time to time of latest file */
+  before = 0;   /* 0=ignore, else exclude files before this time */
+  after = 0;    /* 0=ignore, else exclude files newer than this time */
+  test = 0;     /* 1=test zip file with unzip -t */
+  unzip_path = NULL; /* where to look for unzip command path */
+  tempdir = 0;  /* 1=use temp directory (-b) */
+  junk_sfx = 0; /* 1=junk the sfx prefix */
+#if defined(AMIGA) || defined(MACOS)
+  filenotes = 0;/* 1=take comments from AmigaDOS/MACOS filenotes */
+#endif
+#ifndef USE_ZIPMAIN
+  zipstate = -1;
+#endif
+  tempzip = NULL;
+  fcount = 0;
+  recurse = 0;         /* 1=recurse into directories; 2=match filenames */
+  dispose = 0;         /* 1=remove files after put in zip file */
+  pathput = 1;         /* 1=store path with name */
+  method = BEST;       /* one of BEST, DEFLATE (only), or STORE (only) */
+  dosify = 0;          /* 1=make new entries look like MSDOS */
+  verbose = 0;         /* 1=report oddities in zip file structure */
+  fix = 0;             /* 1=fix the zip file */
+  adjust = 0;          /* 1=adjust offsets for sfx'd file (keep preamble) */
+  level = 6;           /* 0=fastest compression, 9=best compression */
+  translate_eol = 0;   /* Translate end-of-line LF -> CR LF */
+#if defined(OS2) || defined(WIN32)
+  use_longname_ea = 0; /* 1=use the .LONGNAME EA as the file's name */
+#endif
+#ifdef NTSD_EAS
+  use_privileges = 0;     /* 1=use security privileges overrides */
+#endif
+  no_wild = 0;            /* 1 = wildcards are disabled */
+#ifdef WILD_STOP_AT_DIR
+   wild_stop_at_dir = 1;  /* default wildcards do not include / in matches */
+#else
+   wild_stop_at_dir = 0;  /* default wildcards do include / in matches */
+#endif
+
+  skip_this_disk = 0;
+  des_good = 0;           /* Good data descriptor found */
+  des_crc = 0;            /* Data descriptor CRC */
+  des_csize = 0;          /* Data descriptor csize */
+  des_usize = 0;          /* Data descriptor usize */
+
+  dot_size = 0;           /* buffers processed in deflate per dot, 0 = no dots */
+  dot_count = 0;          /* buffers seen, recyles at dot_size */
+
+  display_counts = 0;     /* display running file count */
+  display_bytes = 0;      /* display running bytes remaining */
+  display_globaldots = 0; /* display dots for archive instead of each file */
+  display_volume = 0;     /* display current input and output volume (disk) numbers */
+  display_usize = 0;      /* display uncompressed bytes */
+
+  files_so_far = 0;       /* files processed so far */
+  bad_files_so_far = 0;   /* bad files skipped so far */
+  files_total = 0;        /* files total to process */
+  bytes_so_far = 0;       /* bytes processed so far (from initial scan) */
+  good_bytes_so_far = 0;  /* good bytes read so far */
+  bad_bytes_so_far = 0;   /* bad bytes skipped so far */
+  bytes_total = 0;        /* total bytes to process (from initial scan) */
+
+  logall = 0;             /* 0 = warnings/errors, 1 = all */
+  logfile = NULL;         /* pointer to open logfile or NULL */
+  logfile_append = 0;     /* append to existing logfile */
+  logfile_path = NULL;    /* pointer to path of logfile */
+
+  hidden_files = 0;       /* process hidden and system files */
+  volume_label = 0;       /* add volume label */
+  dirnames = 1;           /* include directory entries by default */
+#if defined(WIN32)
+  only_archive_set = 0;   /* only include if DOS archive bit set */
+  clear_archive_bits = 0; /* clear DOS archive bit of included files */
+#endif
+  linkput = 0;            /* 1=store symbolic links as such */
+  noisy = 1;              /* 0=quiet operation */
+  extra_fields = 1;       /* 0=create minimum, 1=don't copy old, 2=keep old */
+
+  use_descriptors = 0;    /* 1=use data descriptors 12/29/04 */
+  zip_to_stdout = 0;      /* output zipfile to stdout 12/30/04 */
+  allow_empty_archive = 0;/* if no files, create empty archive anyway 12/28/05 */
+  copy_only = 0;          /* 1=copying archive entries only */
+
+  output_seekable = 1;    /* 1 = output seekable 3/13/05 EG */
+
+#ifdef ZIP64_SUPPORT      /* zip64 support 10/4/03 */
+  force_zip64 = -1;       /* if 1 force entries to be zip64 */
+                          /* mainly for streaming from stdin */
+  zip64_entry = 0;        /* current entry needs Zip64 */
+  zip64_archive = 0;      /* if 1 then at least 1 entry needs zip64 */
+#endif
+
+#ifdef UNICODE_SUPPORT
+  utf8_force = 0;         /* 1=force storing UTF-8 as standard per AppNote bit 11 */
+#endif
+
+  unicode_escape_all = 0; /* 1=escape all non-ASCII characters in paths */
+  unicode_mismatch = 1;   /* unicode mismatch is 0=error, 1=warn, 2=ignore, 3=no */
+
+  scan_delay = 5;         /* seconds before display Scanning files message */
+  scan_dot_time = 2;      /* time in seconds between Scanning files dots */
+  scan_start = 0;         /* start of scan */
+  scan_last = 0;          /* time of last message */
+  scan_started = 0;       /* scan has started */
+  scan_count = 0;         /* Used for Scanning files ... message */
+
+  before = 0;             /* 0=ignore, else exclude files before this time */
+  after = 0;              /* 0=ignore, else exclude files newer than this time */
+
+  special = ".Z:.zip:.zoo:.arc:.lzh:.arj"; /* List of special suffixes */
+  key = NULL;             /* Scramble password if scrambling */
+  key_needed = 0;         /* Need scramble password */
+  tempath = NULL;         /* Path for temporary files */
+  patterns = NULL;        /* List of patterns to be matched */
+  pcount = 0;             /* number of patterns */
+  icount = 0;             /* number of include only patterns */
+  Rcount = 0;             /* number of -R include patterns */
+
+  found = NULL;           /* List of names found, or new found entry */
+  fnxt = &found;
+
+  /* used by get_option */
+  argcnt = 0;             /* size of args */
+  argnum = 0;             /* current arg number */
+  optchar = 0;            /* option state */
+  value = NULL;           /* non-option arg, option value or NULL */
+  negated = 0;            /* 1 = option negated */
+  fna = 0;                /* current first nonopt arg */
+  optnum = 0;             /* option index */
+
+  show_options = 0;       /* 1 = show options */
+  show_what_doing = 0;    /* 1 = show what zip doing */
+  show_args = 0;          /* 1 = show command line */
+  seen_doubledash = 0;    /* seen -- argument */
+
+  zipfile = NULL;         /* path of usual in and out zipfile */
+  tempzip = NULL;         /* name of temp file */
+  y = NULL;               /* output file now global so can change in splits */
+  in_file = NULL;         /* current input file for splits */
+  in_split_path = NULL;   /* current in split path */
+  in_path = NULL;         /* used by splits to track changing split locations */
+  out_path = NULL;        /* if set, use -O out_path as output */
+  have_out = 0;           /* if set, in_path and out_path not the same archive */
+
+  total_disks = 0;        /* total disks in archive */
+  current_in_disk = 0;    /* current read split disk */
+  current_in_offset = 0;  /* current offset in current read disk */
+  skip_current_disk = 0;  /* if != 0 and fix then skip entries on this disk */
+
+  zip64_eocd_disk = 0;    /* disk with Zip64 End Of Central Directory Record */
+  zip64_eocd_offset = 0;  /* offset for Zip64 EOCD Record */
+
+  current_local_disk = 0; /* disk with current local header */
+
+  current_disk = 0;           /* current disk number */
+  cd_start_disk = (ulg)-1;    /* central directory start disk */
+  cd_start_offset = 0;        /* offset of start of cd on cd start disk */
+  cd_entries_this_disk = 0;   /* cd entries this disk */
+  total_cd_entries = 0;       /* total cd entries in new/updated archive */
+
+  /* for split method 1 (keep split with local header open and update) */
+  current_local_tempname = NULL; /* name of temp file */
+  current_local_file = NULL;  /* file pointer for current local header */
+  current_local_offset = 0;   /* offset to start of current local header */
+
+  /* global */
+  bytes_this_split = 0;       /* bytes written to the current split */
+  read_split_archive = 0;     /* 1=scanzipf_reg detected spanning signature */
+  split_method = 0;           /* 0=no splits, 1=update LHs, 2=data descriptors */
+  split_size = 0;             /* how big each split should be */
+  split_bell = 0;             /* when pause for next split ring bell */
+  bytes_prev_splits = 0;      /* total bytes written to all splits before this */
+  bytes_this_entry = 0;       /* bytes written for this entry across all splits */
+  noisy_splits = 0;           /* be verbose about creating splits */
+  mesg_line_started = 0;      /* 1=started writing a line to mesg */
+  logfile_line_started = 0;   /* 1=started writing a line to logfile */
+
+  filelist = NULL;
+  filearg_count = 0;
+  allow_empty_archive = 0;    /* if no files, allow creation of empty archive anyway */
+  bad_open_is_error = 0;      /* if read fails, 0=warning, 1=error */
+  unicode_mismatch = 0;       /* unicode mismatch is 0=error, 1=warn, 2=ignore, 3=no */
+  show_files = 0;             /* show files to operate on and exit */
+  scan_delay = 5;             /* seconds before display Scanning files message */
+  scan_dot_time = 2;          /* time in seconds between Scanning files dots */
+  scan_started = 0;           /* space at start of scan has been displayed */
+  scan_last = 0;              /* Time last dot displayed for Scanning files message */
+  scan_start = 0;             /* Time scanning started for Scanning files message */
+#ifdef UNICODE_SUPPORT
+  use_wide_to_mb_default = 0;
+#endif
+  filter_match_case = 1;      /* default is to match case when matching archive entries */
+  allow_fifo = 0;             /* 1=allow reading Unix FIFOs, waiting if pipe open */
+
+#if !defined(MACOS) && !defined(USE_ZIPMAIN)
+  retcode = setjmp(zipdll_error_return);
+  if (retcode) {
+    return retcode;
+  }
+#endif /* !MACOS */
+#endif /* MACOS || WINDLL */
+
+#if !defined(ALLOW_REGEX) && (defined(MSDOS) || defined(WIN32))
+  allow_regex = 0;        /* 1 = allow [list] matching (regex) */
+#else
+  allow_regex = 1;
+#endif
+
+  mesg = (FILE *) stdout; /* cannot be made at link time for VMS */
+  comment_stream = (FILE *)stdin;
+
+  init_upper();           /* build case map table */
+
+#ifdef LARGE_FILE_SUPPORT
+  /* test if we can support large files - 9/29/04 */
+  if (sizeof(zoff_t) < 8) {
+    ZIPERR(ZE_COMPERR, "LARGE_FILE_SUPPORT enabled but OS not supporting it");
+  }
+#endif
+  /* test if sizes are the same - 12/30/04 */
+  if (sizeof(uzoff_t) != sizeof(zoff_t)){
+    ZIPERR(ZE_COMPERR, "uzoff_t not same size as zoff_t");
+  }
+
+#if (defined(WIN32) && defined(USE_EF_UT_TIME))
+  /* For the Win32 environment, we may have to "prepare" the environment
+     prior to the tzset() call, to work around tzset() implementation bugs.
+   */
+  iz_w32_prepareTZenv();
+#endif
+
+#if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
+#  ifndef VALID_TIMEZONE
+#     define VALID_TIMEZONE(tmp) \
+             (((tmp = getenv("TZ")) != NULL) && (*tmp != '\0'))
+#  endif
+  zp_tz_is_valid = VALID_TIMEZONE(p);
+#if (defined(AMIGA) || defined(DOS))
+  if (!zp_tz_is_valid)
+    extra_fields = 0;     /* disable storing "UT" time stamps */
+#endif /* AMIGA || DOS */
+#endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */
+
+/* For systems that do not have tzset() but supply this function using another
+   name (_tzset() or something similar), an appropiate "#define tzset ..."
+   should be added to the system specifc configuration section.  */
+#if (!defined(TOPS20) && !defined(VMS))
+#if (!defined(RISCOS) && !defined(MACOS) && !defined(QDOS))
+#if (!defined(BSD) && !defined(MTS) && !defined(CMS_MVS) && !defined(TANDEM))
+  tzset();
+#endif
+#endif
+#endif
+
+#ifdef VMSCLI
+  {
+      ulg status = vms_zip_cmdline(&argc, &argv);
+      if (!(status & 1))
+            return status;
+  }
+#endif /* VMSCLI */
+
+  /*    Substitutes the extended command line argument list produced by
+   *    the MKS Korn Shell in place of the command line info from DOS.
+   */
+
+  /* extract extended argument list from environment */
+  expand_args(&argc, &argv);
+
+#ifndef WINDLL
+  /* Process arguments */
+  diag("processing arguments");
+  /* First, check if just the help or version screen should be displayed */
+  if (argc == 1 && isatty(1))   /* no arguments, and output screen available */
+  {                             /* show help screen */
+# ifdef VMSCLI
+    VMSCLI_help();
+# else
+    help();
+# endif
+    EXIT(ZE_OK);
+  }
+  /* Check -v here as env arg can change argc.  Handle --version in main switch. */
+  else if (argc == 2 && strcmp(argv[1], "-v") == 0 &&
+           /* only "-v" as argument, and */
+           (isatty(1) || isatty(0)))
+           /* stdout or stdin is connected to console device */
+  {                             /* show diagnostic version info */
+    version_info();
+    EXIT(ZE_OK);
+  }
+# ifndef VMS
+#   ifndef RISCOS
+  envargs(&argc, &argv, "ZIPOPT", "ZIP");  /* get options from environment */
+#   else /* RISCOS */
+  envargs(&argc, &argv, "ZIPOPT", "Zip$Options");  /* get options from environment */
+  getRISCOSexts("Zip$Exts");        /* get the extensions to swap from environment */
+#   endif /* ? RISCOS */
+# else /* VMS */
+  envargs(&argc, &argv, "ZIPOPT", "ZIP_OPTS");  /* 4th arg for unzip compat. */
+# endif /* ?VMS */
+#endif /* !WINDLL */
+
+  zipfile = tempzip = NULL;
+  y = NULL;
+  d = 0;                        /* disallow adding to a zip file */
+#if (!defined(MACOS) && !defined(WINDLL) && !defined(NLM))
+  signal(SIGINT, handler);
+#ifdef SIGTERM                  /* AMIGADOS and others have no SIGTERM */
+  signal(SIGTERM, handler);
+#endif
+# if defined(SIGABRT) && !(defined(AMIGA) && defined(__SASC))
+   signal(SIGABRT, handler);
+# endif
+# ifdef SIGBREAK
+   signal(SIGBREAK, handler);
+# endif
+# ifdef SIGBUS
+   signal(SIGBUS, handler);
+# endif
+# ifdef SIGILL
+   signal(SIGILL, handler);
+# endif
+# ifdef SIGSEGV
+   signal(SIGSEGV, handler);
+# endif
+#endif /* !MACOS && !WINDLL && !NLM */
+#ifdef NLM
+  NLMsignals();
+#endif
+
+
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+  /* check if this Win32 OS has support for wide character calls */
+  has_win32_wide();
+#endif
+
+  /* make copy of args that can use with insert_arg() used by get_option() */
+  args = copy_args(argv, 0);
+
+  kk = 0;                       /* Next non-option argument type */
+  s = 0;                        /* set by -@ */
+
+  /*
+  -------------------------------------------
+  Process command line using get_option
+  -------------------------------------------
+
+  Each call to get_option() returns either a command
+  line option and possible value or a non-option argument.
+  Arguments are permuted so that all options (-r, -b temp)
+  are returned before non-option arguments (zipfile).
+  Returns 0 when nothing left to read.
+  */
+
+  /* set argnum = 0 on first call to init get_option */
+  argnum = 0;
+
+  /* get_option returns the option ID and updates parameters:
+         args    - usually same as argv if no argument file support
+         argcnt  - current argc for args
+         value   - char* to value (free() when done with it) or NULL if no value
+         negated - option was negated with trailing -
+  */
+
+  while ((option = get_option(&args, &argcnt, &argnum,
+                              &optchar, &value, &negated,
+                              &fna, &optnum, 0)))
+  {
+    switch (option)
+    {
+#ifdef EBCDIC
+      case 'a':
+        aflag = ASCII;
+        printf("Translating to ASCII...\n");
+        break;
+#endif /* EBCDIC */
+#ifdef CMS_MVS
+        case 'B':
+          bflag = 1;
+          printf("Using binary mode...\n");
+          break;
+#endif /* CMS_MVS */
+#ifdef TANDEM
+        case 'B':
+          nskformatopt(value);
+          free(value);
+          break;
+#endif
+
+        case '0':
+          method = STORE; level = 0; break;
+        case '1':  case '2':  case '3':  case '4':
+        case '5':  case '6':  case '7':  case '8':  case '9':
+          /* Set the compression efficacy */
+          level = (int)option - '0';  break;
+        case 'A':   /* Adjust unzipsfx'd zipfile:  adjust offsets only */
+          adjust = 1; break;
+#if defined(WIN32)
+        case o_AC:
+          clear_archive_bits = 1; break;
+        case o_AS:
+          /* Since some directories could be empty if no archive bits are
+             set for files in a directory, don't add directory entries (-D).
+             Just files with the archive bit set are added, including paths
+             (unless paths are excluded).  All major unzips should create
+             directories for the paths as needed. */
+          dirnames = 0;
+          only_archive_set = 1; break;
+#endif /* MSDOS || OS2 || WIN32 */
+        case 'b':   /* Specify path for temporary file */
+          tempdir = 1;
+          tempath = value;
+          break;
+        case 'c':   /* Add comments for new files in zip file */
+          comadd = 1;  break;
+
+        /* -C, -C2, and -C5 are with -V */
+
+        case 'd':   /* Delete files from zip file */
+          if (action != ADD) {
+            ZIPERR(ZE_PARMS, "specify just one action");
+          }
+          action = DELETE;
+          break;
+#ifdef MACOS
+        case o_df:
+          MacZip.DataForkOnly = true;
+          break;
+#endif /* MACOS */
+        case o_db:
+          if (negated)
+            display_bytes = 0;
+          else
+            display_bytes = 1;
+          break;
+        case o_dc:
+          if (negated)
+            display_counts = 0;
+          else
+            display_counts = 1;
+          break;
+        case o_dd:
+          /* display dots */
+          display_globaldots = 0;
+          if (negated) {
+            dot_count = 0;
+          } else {
+            /* set default dot size if dot_size not set (dot_count = 0) */
+            if (dot_count == 0)
+              /* default to 10 MB */
+              dot_size = 10 * 0x100000;
+            dot_count = -1;
+          }
+          break;
+        case o_dg:
+          /* display dots globally for archive instead of for each file */
+          if (negated) {
+            display_globaldots = 0;
+          } else {
+            display_globaldots = 1;
+            /* set default dot size if dot_size not set (dot_count = 0) */
+            if (dot_count == 0)
+              dot_size = 10 * 0x100000;
+            dot_count = -1;
+          }
+          break;
+        case o_ds:
+          /* input dot_size is now actual dot size to account for
+             different buffer sizes */
+          if (value == NULL)
+            dot_size = 10 * 0x100000;
+          else if (value[0] == '\0') {
+            /* default to 10 MB */
+            dot_size = 10 * 0x100000;
+            free(value);
+          } else {
+            dot_size = ReadNumString(value);
+            if (dot_size == (zoff_t)-1) {
+              sprintf(errbuf, "option -ds (--dot-size) has bad size:  '%s'",
+                      value);
+              free(value);
+              ZIPERR(ZE_PARMS, errbuf);
+            }
+            if (dot_size < 0x400) {
+              /* < 1 KB so there is no multiplier, assume MB */
+              dot_size *= 0x100000;
+
+            } else if (dot_size < 0x400L * 32) {
+              /* 1K <= dot_size < 32K */
+              sprintf(errbuf, "dot size must be at least 32 KB:  '%s'", value);
+              free(value);
+              ZIPERR(ZE_PARMS, errbuf);
+
+            } else {
+              /* 32K <= dot_size */
+            }
+            free(value);
+          }
+          dot_count = -1;
+          break;
+        case o_du:
+          if (negated)
+            display_usize = 0;
+          else
+            display_usize = 1;
+          break;
+        case o_dv:
+          if (negated)
+            display_volume = 0;
+          else
+            display_volume = 1;
+          break;
+        case 'D':   /* Do not add directory entries */
+          dirnames = 0; break;
+        case o_DF:  /* Create a difference archive */
+          diff_mode = 1;
+          allow_empty_archive = 1;
+          break;
+        case 'e':   /* Encrypt */
+#if !CRYPT
+          ZIPERR(ZE_PARMS, "encryption not supported");
+#else /* CRYPT */
+          if (key)
+            free(key);
+          key_needed = 1;
+#endif /* !CRYPT */
+          break;
+        case 'F':   /* fix the zip file */
+          fix = 1; break;
+        case o_FF:  /* try harder to fix file */
+          fix = 2; break;
+        case o_FI:
+          if (negated)
+            allow_fifo = 0;
+          else
+            allow_fifo = 1;
+          break;
+        case o_FS:  /* delete exiting entries in archive where there is
+                       no matching file on file system */
+          filesync = 1; break;
+        case 'f':   /* Freshen zip file--overwrite only */
+          if (action != ADD) {
+            ZIPERR(ZE_PARMS, "specify just one action");
+          }
+          action = FRESHEN;
+          break;
+        case 'g':   /* Allow appending to a zip file */
+          d = 1;  break;
+#ifndef WINDLL
+        case 'h': case 'H': case '?':  /* Help */
+#ifdef VMSCLI
+          VMSCLI_help();
+#else
+          help();
+#endif
+          RETURN(finish(ZE_OK));
+#endif /* !WINDLL */
+
+#ifndef WINDLL
+        case o_h2:  /* Extended Help */
+          help_extended();
+          RETURN(finish(ZE_OK));
+#endif /* !WINDLL */
+
+        /* -i is with -x */
+#if defined(VMS) || defined(WIN32)
+        case o_ic:  /* Ignore case (case-insensitive matching of archive entries) */
+          if (negated)
+            filter_match_case = 1;
+          else
+            filter_match_case = 0;
+          break;
+#endif
+#ifdef RISCOS
+        case 'I':   /* Don't scan through Image files */
+          scanimage = 0;
+          break;
+#endif
+#ifdef MACOS
+        case o_jj:   /* store absolute path including volname */
+            MacZip.StoreFullPath = true;
+            break;
+#endif /* ?MACOS */
+        case 'j':   /* Junk directory names */
+          pathput = 0;  break;
+        case 'J':   /* Junk sfx prefix */
+          junk_sfx = 1;  break;
+        case 'k':   /* Make entries using DOS names (k for Katz) */
+          dosify = 1;  break;
+        case 'l':   /* Translate end-of-line */
+          translate_eol = 1; break;
+        case o_ll:
+          translate_eol = 2; break;
+        case o_lf:
+          /* open a logfile */
+          /* allow multiple use of option but only last used */
+          if (logfile_path) {
+            free(logfile_path);
+          }
+          logfile_path = value;
+          break;
+        case o_la:
+          /* append to existing logfile */
+          if (negated)
+            logfile_append = 0;
+          else
+            logfile_append = 1;
+          break;
+        case o_li:
+          /* log all including informational messages */
+          if (negated)
+            logall = 0;
+          else
+            logall = 1;
+          break;
+#ifndef WINDLL
+        case 'L':   /* Show license */
+          license();
+          RETURN(finish(ZE_OK));
+#endif
+        case 'm':   /* Delete files added or updated in zip file */
+          dispose = 1;  break;
+        case o_mm:  /* To prevent use of -mm for -MM */
+          ZIPERR(ZE_PARMS, "-mm not supported, Must_Match is -MM");
+          dispose = 1;  break;
+        case o_MM:  /* Exit with error if input file can't be read */
+          bad_open_is_error = 1; break;
+        case 'n':   /* Don't compress files with a special suffix */
+          special = value;
+          /* special = NULL; */ /* will be set at next argument */
+          break;
+        case o_nw:  /* no wildcards - wildcards are handled like other characters */
+          no_wild = 1;
+          break;
+#if defined(AMIGA) || defined(MACOS)
+        case 'N':   /* Get zipfile comments from AmigaDOS/MACOS filenotes */
+          filenotes = 1; break;
+#endif
+        case 'o':   /* Set zip file time to time of latest file in it */
+          latest = 1;  break;
+        case 'O':   /* Set output file different than input archive */
+          out_path = ziptyp(value);
+          free(value);
+          have_out = 1;
+          break;
+        case 'p':   /* Store path with name */
+          break;            /* (do nothing as annoyance avoidance) */
+        case 'P':   /* password for encryption */
+          if (key != NULL) {
+            free(key);
+          }
+#if CRYPT
+          key = value;
+          key_needed = 0;
+#else
+          ZIPERR(ZE_PARMS, "encryption not supported");
+#endif /* CRYPT */
+          break;
+#if defined(QDOS) || defined(QLZIP)
+        case 'Q':
+          qlflag  = strtol(value, NULL, 10);
+       /* qlflag  = strtol((p+1), &p, 10); */
+       /* p--; */
+          if (qlflag == 0) qlflag = 4;
+          free(value);
+          break;
+#endif
+        case 'q':   /* Quiet operation */
+          noisy = 0;
+#ifdef MACOS
+          MacZip.MacZip_Noisy = false;
+#endif  /* MACOS */
+          if (verbose) verbose--;
+          break;
+        case 'r':   /* Recurse into subdirectories, match full path */
+          if (recurse == 2) {
+            ZIPERR(ZE_PARMS, "do not specify both -r and -R");
+          }
+          recurse = 1;  break;
+        case 'R':   /* Recurse into subdirectories, match filename */
+          if (recurse == 1) {
+            ZIPERR(ZE_PARMS, "do not specify both -r and -R");
+          }
+          recurse = 2;  break;
+
+        case o_RE:   /* Allow [list] matching (regex) */
+          allow_regex = 1; break;
+
+        case o_sc:  /* show command line args */
+          show_args = 1; break;
+#ifdef UNICODE_TEST
+        case o_sC:  /* create empty files from archive names */
+          create_files = 1;
+          show_files = 1; break;
+#endif
+        case o_sd:  /* show debugging */
+          show_what_doing = 1; break;
+        case o_sf:  /* show files to operate on */
+          if (!negated)
+            show_files = 1;
+          else
+            show_files = 2;
+          break;
+        case o_so:  /* show all options */
+          show_options = 1; break;
+#ifdef UNICODE_SUPPORT
+        case o_su:  /* -sf but also show Unicode if exists */
+          if (!negated)
+            show_files = 3;
+          else
+            show_files = 4;
+          break;
+        case o_sU:  /* -sf but only show Unicode if exists or normal if not */
+          if (!negated)
+            show_files = 5;
+          else
+            show_files = 6;
+          break;
+#endif
+
+        case 's':   /* enable split archives */
+          /* get the split size from value */
+          if (strcmp(value, "-") == 0) {
+            /* -s- do not allow splits */
+            split_method = -1;
+          } else {
+            split_size = ReadNumString(value);
+            if (split_size == (uzoff_t)-1) {
+              sprintf(errbuf, "bad split size:  '%s'", value);
+              ZIPERR(ZE_PARMS, errbuf);
+            }
+            if (split_size == 0) {
+              /* do not allow splits */
+              split_method = -1;
+            } else {
+              if (split_method == 0) {
+                split_method = 1;
+              }
+              if (split_size < 0x400) {
+                /* < 1 KB there is no multiplier, assume MB */
+                split_size *= 0x100000;
+              }
+              /* By setting the minimum split size to 64 KB we avoid
+                 not having enough room to write a header unsplit
+                 which is required */
+              if (split_size < 0x400L * 64) {
+                /* split_size < 64K */
+                sprintf(errbuf, "minimum split size is 64 KB:  '%s'", value);
+                free(value);
+                ZIPERR(ZE_PARMS, errbuf);
+              }
+            }
+          }
+          free(value);
+          break;
+        case o_sb:  /* when pause for next split ring bell */
+          split_bell = 1;
+          break;
+        case o_sp:  /* enable split select - pause splitting between splits */
+          use_descriptors = 1;
+          split_method = 2;
+          break;
+        case o_sv:  /* be verbose about creating splits */
+          noisy_splits = 1;
+          break;
+
+#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(ATARI)
+        case 'S':
+          hidden_files = 1; break;
+#endif /* MSDOS || OS2 || WIN32 || ATARI */
+#ifdef MACOS
+        case 'S':
+          MacZip.IncludeInvisible = true; break;
+#endif /* MACOS */
+        case 't':   /* Exclude files earlier than specified date */
+          {
+            int yyyy, mm, dd;       /* results of sscanf() */
+
+            /* Support ISO 8601 & American dates */
+            if ((sscanf(value, "%4d-%2d-%2d", &yyyy, &mm, &dd) != 3 &&
+                 sscanf(value, "%2d%2d%4d", &mm, &dd, &yyyy) != 3) ||
+                mm < 1 || mm > 12 || dd < 1 || dd > 31) {
+              ZIPERR(ZE_PARMS,
+                     "invalid date entered for -t option - use mmddyyyy or yyyy-mm-dd");
+            }
+            before = dostime(yyyy, mm, dd, 0, 0, 0);
+          }
+          free(value);
+          break;
+        case o_tt:  /* Exclude files at or after specified date */
+          {
+            int yyyy, mm, dd;       /* results of sscanf() */
+
+            /* Support ISO 8601 & American dates */
+            if ((sscanf(value, "%4d-%2d-%2d", &yyyy, &mm, &dd) != 3 &&
+                 sscanf(value, "%2d%2d%4d", &mm, &dd, &yyyy) != 3) ||
+                mm < 1 || mm > 12 || dd < 1 || dd > 31) {
+              ZIPERR(ZE_PARMS,
+                     "invalid date entered for -tt option - use mmddyyyy or yyyy-mm-dd");
+            }
+            after = dostime(yyyy, mm, dd, 0, 0, 0);
+          }
+          free(value);
+          break;
+        case 'T':   /* test zip file */
+          test = 1; break;
+        case o_TT:  /* command path to use instead of 'unzip -t ' */
+          if (unzip_path)
+            free(unzip_path);
+          unzip_path = value;
+          break;
+        case 'U':   /* Select archive entries to keep or operate on */
+          if (action != ADD) {
+            ZIPERR(ZE_PARMS, "specify just one action");
+          }
+          action = ARCHIVE;
+          break;
+#ifdef UNICODE_SUPPORT
+        case o_UN:   /* Unicode */
+          if (abbrevmatch("quit", value, 0, 1)) {
+            /* Unicode path mismatch is error */
+            unicode_mismatch = 0;
+          } else if (abbrevmatch("warn", value, 0, 1)) {
+            /* warn of mismatches and continue */
+            unicode_mismatch = 1;
+          } else if (abbrevmatch("ignore", value, 0, 1)) {
+            /* ignore mismatches and continue */
+            unicode_mismatch = 2;
+          } else if (abbrevmatch("no", value, 0, 1)) {
+            /* no use Unicode path */
+            unicode_mismatch = 3;
+          } else if (abbrevmatch("escape", value, 0, 1)) {
+            /* escape all non-ASCII characters */
+            unicode_escape_all = 1;
+
+          } else if (abbrevmatch("UTF8", value, 0, 1)) {
+            /* force storing UTF-8 as standard per AppNote bit 11 */
+            utf8_force = 1;
+
+          } else {
+            zipwarn("-UN must be Quit, Warn, Ignore, No, Escape, or UTF8: ", value);
+
+            free(value);
+            ZIPERR(ZE_PARMS, "-UN (unicode) bad value");
+          }
+          free(value);
+          break;
+#endif
+        case 'u':   /* Update zip file--overwrite only if newer */
+          if (action != ADD) {
+            ZIPERR(ZE_PARMS, "specify just one action");
+          }
+          action = UPDATE;
+          break;
+        case 'v':        /* Either display version information or */
+        case o_ve:       /* Mention oddities in zip file structure */
+          if (option == o_ve ||      /* --version */
+              (argcnt == 2 && strlen(args[1]) == 2)) { /* -v only */
+            /* display version */
+#ifndef WINDLL
+            version_info();
+#else
+            zipwarn("version information not supported for dll", "");
+#endif
+            RETURN(finish(ZE_OK));
+          } else {
+            noisy = 1;
+            verbose++;
+          }
+          break;
+#ifdef VMS
+        case 'C':  /* Preserve case (- = down-case) all. */
+          if (negated)
+          { /* Down-case all. */
+            if ((vms_case_2 > 0) || (vms_case_5 > 0))
+            {
+              ZIPERR( ZE_PARMS, "Conflicting case directives (-C-)");
+            }
+            vms_case_2 = -1;
+            vms_case_5 = -1;
+          }
+          else
+          { /* Not negated.  Preserve all. */
+            if ((vms_case_2 < 0) || (vms_case_5 < 0))
+            {
+              ZIPERR( ZE_PARMS, "Conflicting case directives (-C)");
+            }
+            vms_case_2 = 1;
+            vms_case_5 = 1;
+          }
+          break;
+        case o_C2:  /* Preserve case (- = down-case) ODS2. */
+          if (negated)
+          { /* Down-case ODS2. */
+            if (vms_case_2 > 0)
+            {
+              ZIPERR( ZE_PARMS, "Conflicting case directives (-C2-)");
+            }
+            vms_case_2 = -1;
+          }
+          else
+          { /* Not negated.  Preserve ODS2. */
+            if (vms_case_2 < 0)
+            {
+              ZIPERR( ZE_PARMS, "Conflicting case directives (-C2)");
+            }
+            vms_case_2 = 1;
+          }
+          break;
+        case o_C5:  /* Preserve case (- = down-case) ODS5. */
+          if (negated)
+          { /* Down-case ODS5. */
+            if (vms_case_5 > 0)
+            {
+              ZIPERR( ZE_PARMS, "Conflicting case directives (-C5-)");
+            }
+            vms_case_5 = -1;
+          }
+          else
+          { /* Not negated.  Preserve ODS5. */
+            if (vms_case_5 < 0)
+            {
+              ZIPERR( ZE_PARMS, "Conflicting case directives (-C5)");
+            }
+            vms_case_5 = 1;
+          }
+          break;
+        case 'V':   /* Store in VMS format.  (Record multiples.) */
+          vms_native = 1; break;
+          /* below does work with new parser but doesn't allow tracking
+             -VV separately, like adding a separate description */
+          /* vms_native++; break; */
+        case o_VV:  /* Store in VMS specific format */
+          vms_native = 2; break;
+        case 'w':   /* Append the VMS version number */
+          vmsver |= 1;  break;
+        case o_ww:   /* Append the VMS version number as ".nnn". */
+          vmsver |= 3;  break;
+#endif /* VMS */
+        case o_ws:  /* Wildcards do not include directory boundaries in matches */
+          wild_stop_at_dir = 1;
+          break;
+
+        case 'i':   /* Include only the following files */
+          /* if nothing matches include list then still create an empty archive */
+          allow_empty_archive = 1;
+        case 'x':   /* Exclude following files */
+          add_filter((int) option, value);
+          free(value);
+          break;
+#ifdef S_IFLNK
+        case 'y':   /* Store symbolic links as such */
+          linkput = 1;  break;
+#endif /* S_IFLNK */
+        case 'z':   /* Edit zip file comment */
+          zipedit = 1;  break;
+        case 'Z':   /* Compression method */
+          if (abbrevmatch("deflate", value, 0, 1)) {
+            /* deflate */
+            method = DEFLATE;
+          } else if (abbrevmatch("store", value, 0, 1)) {
+            /* store */
+            method = STORE;
+          } else if (abbrevmatch("bzip2", value, 0, 1)) {
+            /* bzip2 */
+#ifdef BZIP2_SUPPORT
+            method = BZIP2;
+#else
+            ZIPERR(ZE_COMPERR, "Compression method bzip2 not enabled");
+#endif
+          } else {
+#ifdef BZIP2_SUPPORT
+            zipwarn("valid compression methods are:  store, deflate, bzip2", "");
+#else
+            zipwarn("valid compression methods are:  store, deflate)", "");
+#endif
+            zipwarn("unknown compression method found:  ", value);
+            free(value);
+            ZIPERR(ZE_PARMS, "Option -Z (--compression-method):  unknown method");
+          }
+          free(value);
+          break;
+#if defined(MSDOS) || defined(OS2)
+        case '$':   /* Include volume label */
+          volume_label = 1; break;
+#endif
+#ifndef MACOS
+        case '@':   /* read file names from stdin */
+          comment_stream = NULL;
+          s = 1;          /* defer -@ until have zipfile name */
+          break;
+#endif /* !MACOS */
+        case 'X':
+          if (negated)
+            extra_fields = 2;
+          else
+            extra_fields = 0;
+          break;
+#ifdef OS2
+        case 'E':
+          /* use the .LONGNAME EA (if any) as the file's name. */
+          use_longname_ea = 1;
+          break;
+#endif
+#ifdef NTSD_EAS
+        case '!':
+          /* use security privilege overrides */
+          use_privileges = 1;
+          break;
+#endif
+#ifdef RISCOS
+        case '/':
+          exts2swap = value; /* override Zip$Exts */
+          break;
+#endif
+        case o_des:
+          use_descriptors = 1;
+          break;
+
+#ifdef ZIP64_SUPPORT
+        case o_z64:   /* Force creation of Zip64 entries */
+          if (negated) {
+            force_zip64 = 0;
+          } else {
+            force_zip64 = 1;
+          }
+          break;
+#endif
+
+        case o_NON_OPTION_ARG:
+          /* not an option */
+          /* no more options as permuting */
+          /* just dash also ends up here */
+
+          if (recurse != 2 && kk == 0 && patterns == NULL) {
+            /* have all filters so convert filterlist to patterns array
+               as PROCNAME needs patterns array */
+            filterlist_to_patterns();
+          }
+
+          /* "--" stops arg processing for remaining args */
+          /* ignore only first -- */
+          if (strcmp(value, "--") == 0 && seen_doubledash == 0) {
+            /* -- */
+            seen_doubledash = 1;
+            if (kk == 0) {
+              ZIPERR(ZE_PARMS, "can't use -- before archive name");
+            }
+
+            /* just ignore as just marks what follows as non-option arguments */
+
+          } else if (kk == 6) {
+            /* value is R pattern */
+            add_filter((int)'R', value);
+            free(value);
+            if (first_listarg == 0) {
+              first_listarg = argnum;
+            }
+          } else switch (kk)
+          {
+            case 0:
+              /* first non-option arg is zipfile name */
+#if (!defined(MACOS) && !defined(WINDLL))
+              if (strcmp(value, "-") == 0) {  /* output zipfile is dash */
+                /* just a dash */
+                zipstdout();
+              } else
+#endif /* !MACOS && !WINDLL */
+              {
+                /* name of zipfile */
+                if ((zipfile = ziptyp(value)) == NULL) {
+                  ZIPERR(ZE_MEM, "was processing arguments");
+                }
+                /* read zipfile if exists */
+                /*
+                if ((r = readzipfile()) != ZE_OK) {
+                  ZIPERR(r, zipfile);
+                }
+                */
+                free(value);
+              }
+              if (show_what_doing) {
+                fprintf(mesg, "sd: Zipfile name '%s'\n", zipfile);
+                fflush(mesg);
+              }
+              /* if in_path not set, use zipfile path as usual for input */
+              /* in_path is used as the base path to find splits */
+              if (in_path == NULL) {
+                if ((in_path = malloc(strlen(zipfile) + 1)) == NULL) {
+                  ZIPERR(ZE_MEM, "was processing arguments");
+                }
+                strcpy(in_path, zipfile);
+              }
+              /* if out_path not set, use zipfile path as usual for output */
+              /* out_path is where the output archive is written */
+              if (out_path == NULL) {
+                if ((out_path = malloc(strlen(zipfile) + 1)) == NULL) {
+                  ZIPERR(ZE_MEM, "was processing arguments");
+                }
+                strcpy(out_path, zipfile);
+              }
+              kk = 3;
+              if (s)
+              {
+                /* do -@ and get names from stdin */
+                /* should be able to read names from
+                   stdin and output to stdout, but
+                   this was not allowed in old code.
+                   This check moved to kk = 3 case to fix. */
+                /* if (strcmp(zipfile, "-") == 0) {
+                  ZIPERR(ZE_PARMS, "can't use - and -@ together");
+                }
+                */
+                while ((pp = getnam(stdin)) != NULL)
+                {
+                  kk = 4;
+                  if (recurse == 2) {
+                    /* reading patterns from stdin */
+                    add_filter((int)'R', pp);
+                  } else {
+                    /* file argument now processed later */
+                    add_name(pp);
+                  }
+                  /*
+                  if ((r = PROCNAME(pp)) != ZE_OK) {
+                    if (r == ZE_MISS)
+                      zipwarn("name not matched: ", pp);
+                    else {
+                      ZIPERR(r, pp);
+                    }
+                  }
+                  */
+                  free(pp);
+                }
+                s = 0;
+              }
+              if (recurse == 2) {
+                /* rest are -R patterns */
+                kk = 6;
+              }
+              break;
+
+            case 3:  case 4:
+              /* no recurse and -r file names */
+              /* can't read filenames -@ and input - from stdin at
+                 same time */
+              if (s == 1 && strcmp(value, "-") == 0) {
+                ZIPERR(ZE_PARMS, "can't read input (-) and filenames (-@) both from stdin");
+              }
+              /* add name to list for later processing */
+              add_name(value);
+              /*
+              if ((r = PROCNAME(value)) != ZE_OK) {
+                if (r == ZE_MISS)
+                  zipwarn("name not matched: ", value);
+                else {
+                  ZIPERR(r, value);
+                }
+              }
+              */
+              if (kk == 3) {
+                first_listarg = argnum;
+                kk = 4;
+              }
+              break;
+
+            } /* switch kk */
+            break;
+
+        default:
+          /* should never get here as get_option will exit if not in table */
+          sprintf(errbuf, "no such option ID: %ld", option);
+          ZIPERR(ZE_PARMS, errbuf);
+
+     }  /* switch */
+  }
+
+
+  /* do processing of command line and one-time tasks */
+
+  /* Key not yet specified.  If needed, get/verify it now. */
+  if (key_needed) {
+    if ((key = malloc(IZ_PWLEN+1)) == NULL) {
+      ZIPERR(ZE_MEM, "was getting encryption password");
+    }
+    r = encr_passwd(ZP_PW_ENTER, key, IZ_PWLEN+1, zipfile);
+    if (r != IZ_PW_ENTERED) {
+      if (r < IZ_PW_ENTERED)
+        r = ZE_PARMS;
+      ZIPERR(r, "was getting encryption password");
+    }
+    if (*key == '\0') {
+      ZIPERR(ZE_PARMS, "zero length password not allowed");
+    }
+    if ((e = malloc(IZ_PWLEN+1)) == NULL) {
+      ZIPERR(ZE_MEM, "was verifying encryption password");
+    }
+    r = encr_passwd(ZP_PW_VERIFY, e, IZ_PWLEN+1, zipfile);
+    if (r != IZ_PW_ENTERED && r != IZ_PW_SKIPVERIFY) {
+      free((zvoid *)e);
+      if (r < ZE_OK) r = ZE_PARMS;
+      ZIPERR(r, "was verifying encryption password");
+    }
+    r = ((r == IZ_PW_SKIPVERIFY) ? 0 : strcmp(key, e));
+    free((zvoid *)e);
+    if (r) {
+      ZIPERR(ZE_PARMS, "password verification failed");
+    }
+  }
+  if (key) {
+    /* if -P "" could get here */
+    if (*key == '\0') {
+      ZIPERR(ZE_PARMS, "zero length password not allowed");
+    }
+  }
+
+  if (show_what_doing) {
+    fprintf(mesg, "sd: Command line read\n");
+    fflush(mesg);
+  }
+
+  /* show command line args */
+  if (show_args) {
+    fprintf(mesg, "command line:\n");
+    for (i = 0; args[i]; i++) {
+      fprintf(mesg, "'%s'  ", args[i]);
+    }
+    fprintf(mesg, "\n");
+    ZIPERR(ZE_ABORT, "show command line");
+  }
+
+  /* show all options */
+  if (show_options) {
+    printf("available options:\n");
+    printf(" %-2s  %-18s %-4s %-3s %-30s\n", "sh", "long", "val", "neg", "description");
+    printf(" %-2s  %-18s %-4s %-3s %-30s\n", "--", "----", "---", "---", "-----------");
+    for (i = 0; options[i].option_ID; i++) {
+      printf(" %-2s  %-18s ", options[i].shortopt, options[i].longopt);
+      switch (options[i].value_type) {
+        case o_NO_VALUE:
+          printf("%-4s ", "");
+          break;
+        case o_REQUIRED_VALUE:
+          printf("%-4s ", "req");
+          break;
+        case o_OPTIONAL_VALUE:
+          printf("%-4s ", "opt");
+          break;
+        case o_VALUE_LIST:
+          printf("%-4s ", "list");
+          break;
+        case o_ONE_CHAR_VALUE:
+          printf("%-4s ", "char");
+          break;
+        case o_NUMBER_VALUE:
+          printf("%-4s ", "num");
+          break;
+        default:
+          printf("%-4s ", "unk");
+      }
+      switch (options[i].negatable) {
+        case o_NEGATABLE:
+          printf("%-3s ", "neg");
+          break;
+        case o_NOT_NEGATABLE:
+          printf("%-3s ", "");
+          break;
+        default:
+          printf("%-3s ", "unk");
+      }
+      if (options[i].name)
+        printf("%-30s\n", options[i].name);
+      else
+        printf("\n");
+    }
+    RETURN(finish(ZE_OK));
+  }
+
+
+  /* open log file */
+  if (logfile_path) {
+    char mode[10];
+    char *p;
+    char *lastp;
+
+    /* if no extension add .log */
+    p = logfile_path;
+    /* find last / */
+    lastp = NULL;
+    for (p = logfile_path; (p = MBSRCHR(p, '/')) != NULL; p++) {
+      lastp = p;
+    }
+    if (lastp == NULL)
+      lastp = logfile_path;
+    if (MBSRCHR(lastp, '.') == NULL) {
+      /* add .log */
+      if ((p = malloc(strlen(logfile_path) + 5)) == NULL) {
+        ZIPERR(ZE_MEM, "logpath");
+      }
+      strcpy(p, logfile_path);
+      strcat(p, ".log");
+      free(logfile_path);
+      logfile_path = p;
+    }
+
+    if (logfile_append) {
+      sprintf(mode, "a");
+    } else {
+      sprintf(mode, "w");
+    }
+    if ((logfile = zfopen(logfile_path, mode)) == NULL) {
+      sprintf(errbuf, "could not open logfile '%s'", logfile_path);
+      ZIPERR(ZE_PARMS, errbuf);
+    }
+    {
+      /* At top put start time and command line */
+
+      /* get current time */
+      struct tm *now;
+      time_t clocktime;
+
+      time(&clocktime);
+      now = localtime(&clocktime);
+
+      fprintf(logfile, "---------\n");
+      fprintf(logfile, "Zip log opened %s", asctime(now));
+      fprintf(logfile, "command line arguments:\n ");
+      for (i = 1; args[i]; i++) {
+        size_t j;
+        int has_space = 0;
+
+        for (j = 0; j < strlen(args[i]); j++) {
+          if (isspace(args[i][j])) {
+            has_space = 1;
+            break;
+          }
+        }
+        if (has_space)
+          fprintf(logfile, "\"%s\" ", args[i]);
+        else
+          fprintf(logfile, "%s ", args[i]);
+      }
+      fprintf(logfile, "\n\n");
+      fflush(logfile);
+    }
+  } else {
+    /* only set logall if logfile open */
+    logall = 0;
+  }
+
+
+  if (split_method && out_path) {
+    /* if splitting, the archive name must have .zip extension */
+    int plen = strlen(out_path);
+    char *out_path_ext;
+
+#ifdef VMS
+    /* On VMS, adjust plen (and out_path_ext) to avoid the file version. */
+    plen -= strlen( vms_file_version( out_path));
+#endif /* def VMS */
+    out_path_ext = out_path+ plen- 4;
+
+    if (plen < 4 ||
+        out_path_ext[0] != '.' ||
+        toupper(out_path_ext[1]) != 'Z' ||
+        toupper(out_path_ext[2]) != 'I' ||
+        toupper(out_path_ext[3]) != 'P') {
+      ZIPERR(ZE_PARMS, "archive name must end in .zip for splits");
+    }
+  }
+
+
+  if (verbose && (dot_size == 0) && (dot_count == 0)) {
+    /* now default to default 10 MB dot size */
+    dot_size = 10 * 0x100000;
+    /* show all dots as before if verbose set and dot_size not set (dot_count = 0) */
+    /* maybe should turn off dots in default verbose mode */
+    /* dot_size = -1; */
+  }
+
+  /* done getting -R filters so convert filterlist if not done */
+  if (pcount && patterns == NULL) {
+    filterlist_to_patterns();
+  }
+
+#if (defined(MSDOS) || defined(OS2)) && !defined(WIN32)
+  if ((kk == 3 || kk == 4) && volume_label == 1) {
+    /* read volume label */
+    PROCNAME(NULL);
+    kk = 4;
+  }
+#endif
+
+  if (have_out && kk == 3) {
+    copy_only = 1;
+    action = ARCHIVE;
+  }
+
+  if (have_out && namecmp(in_path, out_path) == 0) {
+    sprintf(errbuf, "--out path must be different than in path: %s", out_path);
+    ZIPERR(ZE_PARMS, errbuf);
+  }
+
+  if (fix && diff_mode) {
+    ZIPERR(ZE_PARMS, "can't use --diff (-DF) with fix (-F or -FF)");
+  }
+
+  if (action == ARCHIVE && !have_out && !show_files) {
+    ZIPERR(ZE_PARMS, "-U (--copy) requires -O (--out)");
+  }
+
+  if (fix && !have_out) {
+    zipwarn("fix options -F and -FF require --out:\n",
+            "                     zip -F indamagedarchive --out outfixedarchive");
+    ZIPERR(ZE_PARMS, "fix options require --out");
+  }
+
+  if (fix && !copy_only) {
+    ZIPERR(ZE_PARMS, "no other actions allowed when fixing archive (-F or -FF)");
+  }
+
+  if (!have_out && diff_mode) {
+    ZIPERR(ZE_PARMS, "-DF (--diff) requires -O (--out)");
+  }
+
+  if (diff_mode && (action == ARCHIVE || action == DELETE)) {
+    ZIPERR(ZE_PARMS, "can't use --diff (-DF) with -d or -U");
+  }
+
+  if (action != ARCHIVE && (recurse == 2 || pcount) && first_listarg == 0 &&
+      !filelist && (kk < 3 || (action != UPDATE && action != FRESHEN))) {
+    ZIPERR(ZE_PARMS, "nothing to select from");
+  }
+
+/*
+  -------------------------------------
+  end of new command line code
+  -------------------------------------
+*/
+
+#if (!defined(MACOS) && !defined(WINDLL))
+  if (kk < 3) {               /* zip used as filter */
+    zipstdout();
+    comment_stream = NULL;
+    if ((r = procname("-", 0)) != ZE_OK) {
+      if (r == ZE_MISS) {
+        if (bad_open_is_error) {
+          zipwarn("name not matched: ", "-");
+          ZIPERR(ZE_OPEN, "-");
+        } else {
+          zipwarn("name not matched: ", "-");
+        }
+      } else {
+        ZIPERR(r, "-");
+      }
+    }
+    kk = 4;
+    if (s) {
+      ZIPERR(ZE_PARMS, "can't use - and -@ together");
+    }
+  }
+#endif /* !MACOS && !WINDLL */
+
+  if (zipfile && !strcmp(zipfile, "-")) {
+    if (show_what_doing) {
+      fprintf(mesg, "sd: Zipping to stdout\n");
+      fflush(mesg);
+    }
+    zip_to_stdout = 1;
+  }
+
+  /* Check option combinations */
+  if (special == NULL) {
+    ZIPERR(ZE_PARMS, "missing suffix list");
+  }
+  if (level == 9 || !strcmp(special, ";") || !strcmp(special, ":"))
+    special = NULL; /* compress everything */
+
+  if (action == DELETE && (method != BEST || dispose || recurse ||
+      key != NULL || comadd || zipedit)) {
+    zipwarn("invalid option(s) used with -d; ignored.","");
+    /* reset flags - needed? */
+    method  = BEST;
+    dispose = 0;
+    recurse = 0;
+    if (key != NULL) {
+      free((zvoid *)key);
+      key   = NULL;
+    }
+    comadd  = 0;
+    zipedit = 0;
+  }
+  if (action == ARCHIVE && (method != BEST || dispose || recurse ||
+      comadd || zipedit)) {
+    zipwarn("can't set method, move, recurse, or comments with copy mode.","");
+    /* reset flags - needed? */
+    method  = BEST;
+    dispose = 0;
+    recurse = 0;
+    comadd  = 0;
+    zipedit = 0;
+  }
+  if (linkput && dosify)
+    {
+      zipwarn("can't use -y with -k, -y ignored", "");
+      linkput = 0;
+    }
+  if (fix == 1 && adjust)
+    {
+      zipwarn("can't use -F with -A, -F ignored", "");
+      fix = 0;
+    }
+  if (fix == 2 && adjust)
+    {
+      zipwarn("can't use -FF with -A, -FF ignored", "");
+      fix = 0;
+    }
+  if (test && zip_to_stdout) {
+    test = 0;
+    zipwarn("can't use -T on stdout, -T ignored", "");
+  }
+  if (split_method && (fix || adjust)) {
+    ZIPERR(ZE_PARMS, "can't create split archive while fixing or adjusting\n");
+  }
+  if (split_method && (d || zip_to_stdout)) {
+    ZIPERR(ZE_PARMS, "can't create split archive with -d or -g or on stdout\n");
+  }
+  if ((action != ADD || d) && filesync) {
+    ZIPERR(ZE_PARMS, "can't use -d, -f, -u, -U, or -g with filesync -FS\n");
+  }
+  if ((action != ADD || d) && zip_to_stdout) {
+    ZIPERR(ZE_PARMS, "can't use -d, -f, -u, -U, or -g on stdout\n");
+  }
+#if defined(EBCDIC)  && !defined(OS390)
+  if (aflag==ASCII && !translate_eol) {
+    /* Translation to ASCII implies EOL translation!
+     * (on OS390, consistent EOL translation is controlled separately)
+     * The default translation mode is "UNIX" mode (single LF terminators).
+     */
+    translate_eol = 2;
+  }
+#endif
+#ifdef CMS_MVS
+  if (aflag==ASCII && bflag)
+    ZIPERR(ZE_PARMS, "can't use -a with -B");
+#endif
+#ifdef VMS
+  if (!extra_fields && vms_native)
+    {
+      zipwarn("can't use -V with -X, -V ignored", "");
+      vms_native = 0;
+    }
+  if (vms_native && translate_eol)
+    ZIPERR(ZE_PARMS, "can't use -V with -l or -ll");
+#endif
+
+  if (noisy) {
+    if (fix == 1)
+      zipmessage("Fix archive (-F) - assume mostly intact archive", "");
+    else if (fix == 2)
+      zipmessage("Fix archive (-FF) - salvage what can", "");
+  }
+
+  /* Read old archive */
+
+  /* Now read the zip file here instead of when doing args above */
+  /* Only read the central directory and build zlist */
+  if (show_what_doing) {
+    fprintf(mesg, "sd: Reading archive\n");
+    fflush(mesg);
+  }
+
+
+
+
+  /* If -FF we do it all here */
+  if (fix == 2) {
+
+    /* Open zip file and temporary output file */
+    if (show_what_doing) {
+      fprintf(mesg, "sd: Open zip file and create temp file (-FF)\n");
+      fflush(mesg);
+    }
+    diag("opening zip file and creating temporary zip file");
+    x = NULL;
+    tempzn = 0;
+    if (show_what_doing) {
+      fprintf(mesg, "sd: Creating new zip file (-FF)\n");
+      fflush(mesg);
+    }
+#if defined(UNIX) && !defined(NO_MKSTEMP)
+    {
+      int yd;
+      int i;
+
+      /* use mkstemp to avoid race condition and compiler warning */
+
+      if (tempath != NULL)
+      {
+        /* if -b used to set temp file dir use that for split temp */
+        if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
+          ZIPERR(ZE_MEM, "allocating temp filename");
+        }
+        strcpy(tempzip, tempath);
+        if (lastchar(tempzip) != '/')
+          strcat(tempzip, "/");
+      }
+      else
+      {
+        /* create path by stripping name and appending template */
+        if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
+        ZIPERR(ZE_MEM, "allocating temp filename");
+        }
+        strcpy(tempzip, zipfile);
+        for(i = strlen(tempzip); i > 0; i--) {
+          if (tempzip[i - 1] == '/')
+            break;
+        }
+        tempzip[i] = '\0';
+      }
+      strcat(tempzip, "ziXXXXXX");
+
+      if ((yd = mkstemp(tempzip)) == EOF) {
+        ZIPERR(ZE_TEMP, tempzip);
+      }
+      if ((y = fdopen(yd, FOPW_TMP)) == NULL) {
+        ZIPERR(ZE_TEMP, tempzip);
+      }
+    }
+#else
+    if ((tempzip = tempname(zipfile)) == NULL) {
+      ZIPERR(ZE_MEM, "allocating temp filename");
+    }
+    if ((y = zfopen(tempzip, FOPW_TMP)) == NULL) {
+      ZIPERR(ZE_TEMP, tempzip);
+    }
+#endif
+
+#if (!defined(VMS) && !defined(CMS_MVS))
+    /* Use large buffer to speed up stdio: */
+#if (defined(_IOFBF) || !defined(BUFSIZ))
+    zipbuf = (char *)malloc(ZBSZ);
+#else
+    zipbuf = (char *)malloc(BUFSIZ);
+#endif
+    if (zipbuf == NULL) {
+      ZIPERR(ZE_MEM, tempzip);
+    }
+# ifdef _IOFBF
+    setvbuf(y, zipbuf, _IOFBF, ZBSZ);
+# else
+    setbuf(y, zipbuf);
+# endif /* _IOBUF */
+#endif /* !VMS  && !CMS_MVS */
+
+
+    if ((r = readzipfile()) != ZE_OK) {
+      ZIPERR(r, zipfile);
+    }
+
+    /* Write central directory and end header to temporary zip */
+    if (show_what_doing) {
+      fprintf(mesg, "sd: Writing central directory (-FF)\n");
+      fflush(mesg);
+    }
+    diag("writing central directory");
+    k = 0;                        /* keep count for end header */
+    c = tempzn;                   /* get start of central */
+    n = t = 0;
+    for (z = zfiles; z != NULL; z = z->nxt)
+    {
+      if ((r = putcentral(z)) != ZE_OK) {
+        ZIPERR(r, tempzip);
+      }
+      tempzn += 4 + CENHEAD + z->nam + z->cext + z->com;
+      n += z->len;
+      t += z->siz;
+      k++;
+    }
+    if (zcount == 0)
+      zipwarn("zip file empty", "");
+    t = tempzn - c;               /* compute length of central */
+    diag("writing end of central directory");
+    if ((r = putend(k, t, c, zcomlen, zcomment)) != ZE_OK) {
+      ZIPERR(r, tempzip);
+    }
+    if (fclose(y)) {
+      ZIPERR(d ? ZE_WRITE : ZE_TEMP, tempzip);
+    }
+    if (in_file != NULL) {
+      fclose(in_file);
+      in_file = NULL;
+    }
+
+    /* Replace old zip file with new zip file, leaving only the new one */
+    if (strcmp(zipfile, "-") && !d)
+    {
+      diag("replacing old zip file with new zip file");
+      if ((r = replace(out_path, tempzip)) != ZE_OK)
+      {
+        zipwarn("new zip file left as: ", tempzip);
+        free((zvoid *)tempzip);
+        tempzip = NULL;
+        ZIPERR(r, "was replacing the original zip file");
+      }
+      free((zvoid *)tempzip);
+    }
+    tempzip = NULL;
+    if (zip_attributes && strcmp(zipfile, "-")) {
+      setfileattr(out_path, zip_attributes);
+#ifdef VMS
+      /* If the zip file existed previously, restore its record format: */
+      if (x != NULL)
+        (void)VMSmunch(out_path, RESTORE_RTYPE, NULL);
+#endif
+    }
+
+    set_filetype(out_path);
+
+    /* finish logfile (it gets closed in freeup() called by finish()) */
+    if (logfile) {
+        struct tm *now;
+        time_t clocktime;
+
+        fprintf(logfile, "\nTotal %ld entries (", files_total);
+        DisplayNumString(logfile, bytes_total);
+        fprintf(logfile, " bytes)");
+
+        /* get current time */
+        time(&clocktime);
+        now = localtime(&clocktime);
+        fprintf(logfile, "\nDone %s", asctime(now));
+        fflush(logfile);
+    }
+
+    RETURN(finish(ZE_OK));
+  }
+
+
+
+  /* read zipfile if exists */
+  if ((r = readzipfile()) != ZE_OK) {
+    ZIPERR(r, zipfile);
+  }
+
+#ifndef UTIL
+  if (split_method == -1) {
+    split_method = 0;
+  } else if (!fix && split_method == 0 && total_disks > 1) {
+    /* if input archive is multi-disk and splitting has not been
+       enabled or disabled (split_method == -1), then automatically
+       set split size to same as first input split */
+    zoff_t size = 0;
+
+    in_split_path = get_in_split_path(in_path, 0);
+
+    if (filetime(in_split_path, NULL, &size, NULL) == 0) {
+      zipwarn("Could not get info for input split: ", in_split_path);
+      return ZE_OPEN;
+    }
+    split_method = 1;
+    split_size = (uzoff_t) size;
+
+    free(in_split_path);
+    in_split_path = NULL;
+  }
+
+  if (noisy_splits && split_size > 0)
+    zipmessage("splitsize = ", zip_fuzofft(split_size, NULL, NULL));
+#endif
+
+  /* so disk display starts at 1, will be updated when entries are read */
+  current_in_disk = 0;
+
+  /* no input zipfile and showing contents */
+  if (!zipfile_exists && show_files && (kk == 3 || action == ARCHIVE)) {
+    ZIPERR(ZE_OPEN, zipfile);
+  }
+
+  if (zcount == 0 && (action != ADD || d)) {
+    zipwarn(zipfile, " not found or empty");
+  }
+
+  if (have_out && kk == 3) {
+    /* no input paths so assume copy mode and match everything if --out */
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      z->mark = pcount ? filter(z->zname, filter_match_case) : 1;
+    }
+  }
+
+  /* Scan for new files */
+
+  /* Process file arguments from command line */
+  if (filelist) {
+    if (action == ARCHIVE) {
+      /* find in archive */
+      if (show_what_doing) {
+        fprintf(mesg, "sd: Scanning archive entries\n");
+        fflush(mesg);
+      }
+      for (; filelist; ) {
+        if ((r = proc_archive_name(filelist->name, filter_match_case)) != ZE_OK) {
+          if (r == ZE_MISS) {
+            char *n = NULL;
+#ifdef WIN32
+            /* Win9x console always uses OEM character coding, and
+               WinNT console is set to OEM charset by default, too */
+            if ((n = malloc(strlen(filelist->name) + 1)) == NULL)
+              ZIPERR(ZE_MEM, "name not matched error");
+            INTERN_TO_OEM(filelist->name, n);
+#else
+            n = filelist->name;
+#endif
+            zipwarn("not in archive: ", n);
+#ifdef WIN32
+            free(n);
+#endif
+          }
+          else {
+            ZIPERR(r, filelist->name);
+          }
+        }
+        free(filelist->name);
+        filearg = filelist;
+        filelist = filelist->next;
+        free(filearg);
+      }
+    } else {
+      /* try find matching files on OS first then try find entries in archive */
+      if (show_what_doing) {
+        fprintf(mesg, "sd: Scanning files\n");
+        fflush(mesg);
+      }
+      for (; filelist; ) {
+        if ((r = PROCNAME(filelist->name)) != ZE_OK) {
+          if (r == ZE_MISS) {
+            if (bad_open_is_error) {
+              zipwarn("name not matched: ", filelist->name);
+              ZIPERR(ZE_OPEN, filelist->name);
+            } else {
+              zipwarn("name not matched: ", filelist->name);
+            }
+          } else {
+            ZIPERR(r, filelist->name);
+          }
+        }
+        free(filelist->name);
+        filearg = filelist;
+        filelist = filelist->next;
+        free(filearg);
+      }
+    }
+  }
+
+  /* recurse from current directory for -R */
+  if (recurse == 2) {
+#ifdef AMIGA
+    if ((r = PROCNAME("")) != ZE_OK)
+#else
+    if ((r = PROCNAME(".")) != ZE_OK)
+#endif
+    {
+      if (r == ZE_MISS) {
+        if (bad_open_is_error) {
+          zipwarn("name not matched: ", "current directory for -R");
+          ZIPERR(ZE_OPEN, "-R");
+        } else {
+          zipwarn("name not matched: ", "current directory for -R");
+        }
+      } else {
+        ZIPERR(r, "-R");
+      }
+    }
+  }
+
+
+  if (show_what_doing) {
+    fprintf(mesg, "sd: Applying filters\n");
+    fflush(mesg);
+  }
+  /* Clean up selections ("3 <= kk <= 5" now) */
+  if (kk != 4 && first_listarg == 0 &&
+      (action == UPDATE || action == FRESHEN)) {
+    /* if -u or -f with no args, do all, but, when present, apply filters */
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      z->mark = pcount ? filter(z->zname, filter_match_case) : 1;
+#ifdef DOS
+      if (z->mark) z->dosflag = 1;      /* force DOS attribs for incl. names */
+#endif
+    }
+  }
+  if (show_what_doing) {
+    fprintf(mesg, "sd: Checking dups\n");
+    fflush(mesg);
+  }
+  if ((r = check_dup()) != ZE_OK) {     /* remove duplicates in found list */
+    if (r == ZE_PARMS) {
+      ZIPERR(r, "cannot repeat names in zip file");
+    }
+    else {
+      ZIPERR(r, "was processing list of files");
+    }
+  }
+
+  if (zcount)
+    free((zvoid *)zsort);
+
+
+/*
+ * XXX make some kind of mktemppath() function for each OS.
+ */
+
+#ifndef VM_CMS
+/* For CMS, leave tempath NULL.  A-disk will be used as default. */
+  /* If -b not specified, make temporary path the same as the zip file */
+#if defined(MSDOS) || defined(__human68k__) || defined(AMIGA)
+  if (tempath == NULL && ((p = MBSRCHR(zipfile, '/')) != NULL ||
+#  ifdef MSDOS
+                          (p = MBSRCHR(zipfile, '\\')) != NULL ||
+#  endif /* MSDOS */
+                          (p = MBSRCHR(zipfile, ':')) != NULL))
+  {
+    if (*p == ':')
+      p++;
+#else
+#ifdef RISCOS
+  if (tempath == NULL && (p = MBSRCHR(zipfile, '.')) != NULL)
+  {
+#else
+#ifdef QDOS
+  if (tempath == NULL && (p = LastDir(zipfile)) != NULL)
+  {
+#else
+  if (tempath == NULL && (p = MBSRCHR(zipfile, '/')) != NULL)
+  {
+#endif /* QDOS */
+#endif /* RISCOS */
+#endif /* MSDOS || __human68k__ || AMIGA */
+    if ((tempath = (char *)malloc((int)(p - zipfile) + 1)) == NULL) {
+      ZIPERR(ZE_MEM, "was processing arguments");
+    }
+    r = *p;  *p = 0;
+    strcpy(tempath, zipfile);
+    *p = (char)r;
+  }
+#endif /* VM_CMS */
+
+#if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
+  if (!zp_tz_is_valid) {
+    zipwarn("TZ environment variable not found, cannot use UTC times!!","");
+  }
+#endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */
+
+  /* For each marked entry, if not deleting, check if it exists, and if
+     updating or freshening, compare date with entry in old zip file.
+     Unmark if it doesn't exist or is too old, else update marked count. */
+  if (show_what_doing) {
+    fprintf(mesg, "sd: Scanning files to update\n");
+    fflush(mesg);
+  }
+#ifdef MACOS
+  PrintStatProgress("Getting file information ...");
+#endif
+  diag("stating marked entries");
+  k = 0;                        /* Initialize marked count */
+  scan_started = 0;
+  scan_count = 0;
+  all_current = 1;
+  for (z = zfiles; z != NULL; z = z->nxt) {
+    /* if already displayed Scanning files in newname() then continue dots */
+    if (noisy && scan_last) {
+      scan_count++;
+      if (scan_count % 100 == 0) {
+        time_t current = time(NULL);
+
+        if (current - scan_last > scan_dot_time) {
+          if (scan_started == 0) {
+            scan_started = 1;
+            fprintf(mesg, " ");
+            fflush(mesg);
+          }
+          scan_last = current;
+          fprintf(mesg, ".");
+          fflush(mesg);
+        }
+      }
+    }
+    z->current = 0;
+    if (!(z->mark)) {
+      /* if something excluded run through the list to catch deletions */
+      all_current = 0;
+    }
+    if (z->mark) {
+#ifdef USE_EF_UT_TIME
+      iztimes f_utim, z_utim;
+      ulg z_tim;
+#endif /* USE_EF_UT_TIME */
+      Trace((stderr, "zip diagnostics: marked file=%s\n", z->oname));
+
+      csize = z->siz;
+      usize = z->len;
+      if (action == DELETE) {
+        /* only delete files in date range */
+#ifdef USE_EF_UT_TIME
+        z_tim = (get_ef_ut_ztime(z, &z_utim) & EB_UT_FL_MTIME) ?
+                unix2dostime(&z_utim.mtime) : z->tim;
+#else /* !USE_EF_UT_TIME */
+#       define z_tim  z->tim
+#endif /* ?USE_EF_UT_TIME */
+        if (z_tim < before || (after && z_tim >= after)) {
+          /* include in archive */
+          z->mark = 0;
+        } else {
+          /* delete file */
+          files_total++;
+          /* ignore len in old archive and update to current size */
+          z->len = usize;
+          if (csize != (uzoff_t) -1 && csize != (uzoff_t) -2)
+            bytes_total += csize;
+          k++;
+        }
+      } else if (action == ARCHIVE) {
+        /* only keep files in date range */
+#ifdef USE_EF_UT_TIME
+        z_tim = (get_ef_ut_ztime(z, &z_utim) & EB_UT_FL_MTIME) ?
+                unix2dostime(&z_utim.mtime) : z->tim;
+#else /* !USE_EF_UT_TIME */
+#       define z_tim  z->tim
+#endif /* ?USE_EF_UT_TIME */
+        if (z_tim < before || (after && z_tim >= after)) {
+          /* exclude from archive */
+          z->mark = 0;
+        } else {
+          /* keep file */
+          files_total++;
+          /* ignore len in old archive and update to current size */
+          z->len = usize;
+          if (csize != (uzoff_t) -1 && csize != (uzoff_t) -2)
+            bytes_total += csize;
+          k++;
+        }
+      } else {
+        int isdirname = 0;
+
+        if (z->name && (z->name)[strlen(z->name) - 1] == '/') {
+          isdirname = 1;
+        }
+
+# if defined(UNICODE_SUPPORT) && defined(WIN32)
+        if (!no_win32_wide) {
+          if (z->namew == NULL) {
+            if (z->uname != NULL)
+              z->namew = utf8_to_wchar_string(z->uname);
+            else
+              z->namew = local_to_wchar_string(z->name);
+          }
+        }
+# endif
+
+#ifdef USE_EF_UT_TIME
+# if defined(UNICODE_SUPPORT) && defined(WIN32)
+        if (!no_win32_wide)
+          tf = filetimew(z->namew, (ulg *)NULL, (zoff_t *)&usize, &f_utim);
+        else
+          tf = filetime(z->name, (ulg *)NULL, (zoff_t *)&usize, &f_utim);
+# else
+        tf = filetime(z->name, (ulg *)NULL, (zoff_t *)&usize, &f_utim);
+# endif
+#else /* !USE_EF_UT_TIME */
+# if defined(UNICODE_SUPPORT) && defined(WIN32)
+        if (!no_win32_wide)
+          tf = filetimew(z->namew, (ulg *)NULL, (zoff_t *)&usize, NULL);
+        else
+          tf = filetime(z->name, (ulg *)NULL, (zoff_t *)&usize, NULL);
+# else
+        tf = filetime(z->name, (ulg *)NULL, (zoff_t *)&usize, NULL);
+# endif
+#endif /* ?USE_EF_UT_TIME */
+        if (tf == 0)
+          /* entry that is not on OS */
+          all_current = 0;
+        if (tf == 0 ||
+            tf < before || (after && tf >= after) ||
+            ((action == UPDATE || action == FRESHEN) &&
+#ifdef USE_EF_UT_TIME
+             ((get_ef_ut_ztime(z, &z_utim) & EB_UT_FL_MTIME) ?
+              f_utim.mtime <= ROUNDED_TIME(z_utim.mtime) : tf <= z->tim)
+#else /* !USE_EF_UT_TIME */
+             tf <= z->tim
+#endif /* ?USE_EF_UT_TIME */
+           ))
+        {
+          z->mark = comadd ? 2 : 0;
+          z->trash = tf && tf >= before &&
+                     (after ==0 || tf < after);   /* delete if -um or -fm */
+          if (verbose)
+            fprintf(mesg, "zip diagnostic: %s %s\n", z->oname,
+                   z->trash ? "up to date" : "missing or early");
+          if (logfile)
+            fprintf(logfile, "zip diagnostic: %s %s\n", z->oname,
+                   z->trash ? "up to date" : "missing or early");
+        }
+        else if (diff_mode && tf == z->tim &&
+                 ((isdirname && (zoff_t)usize == -1) || (usize == z->len))) {
+          /* if in diff mode only include if file time or size changed */
+          /* usize is -1 for directories */
+          z->mark = 0;
+        }
+        else {
+          /* usize is -1 for directories and -2 for devices */
+          if (tf == z->tim &&
+              ((z->len == 0 && (zoff_t)usize == -1)
+               || usize == z->len)) {
+            /* FileSync uses the current flag */
+            /* Consider an entry current if file time is the same
+               and entry size is 0 and a directory on the OS
+               or the entry size matches the OS size */
+            z->current = 1;
+          } else {
+            all_current = 0;
+          }
+          files_total++;
+          if (usize != (uzoff_t) -1 && usize != (uzoff_t) -2)
+            /* ignore len in old archive and update to current size */
+            z->len = usize;
+          else
+            z->len = 0;
+          if (usize != (uzoff_t) -1 && usize != (uzoff_t) -2)
+            bytes_total += usize;
+          k++;
+        }
+      }
+    }
+  }
+
+  /* Remove entries from found list that do not exist or are too old */
+  if (show_what_doing) {
+    fprintf(mesg, "sd: fcount = %u\n", (unsigned)fcount);
+    fflush(mesg);
+  }
+
+  diag("stating new entries");
+  scan_count = 0;
+  scan_started = 0;
+  Trace((stderr, "zip diagnostic: fcount=%u\n", (unsigned)fcount));
+  for (f = found; f != NULL;) {
+    Trace((stderr, "zip diagnostic: new file=%s\n", f->oname));
+
+    if (noisy) {
+      /* if updating archive and update was quick, scanning for new files
+         can still take a long time */
+      if (!zip_to_stdout && scan_last == 0 && scan_count % 100 == 0) {
+        time_t current = time(NULL);
+
+        if (current - scan_start > scan_delay) {
+          fprintf(mesg, "Scanning files ");
+          fflush(mesg);
+          mesg_line_started = 1;
+          scan_last = current;
+        }
+      }
+      /* if already displayed Scanning files in newname() or above then continue dots */
+      if (scan_last) {
+        scan_count++;
+        if (scan_count % 100 == 0) {
+          time_t current = time(NULL);
+
+          if (current - scan_last > scan_dot_time) {
+            if (scan_started == 0) {
+              scan_started = 1;
+              fprintf(mesg, " ");
+              fflush(mesg);
+            }
+            scan_last = current;
+            fprintf(mesg, ".");
+            fflush(mesg);
+          }
+        }
+      }
+    }
+    tf = 0;
+    if (action != DELETE && action != FRESHEN) {
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+      if (!no_win32_wide)
+        tf = filetimew(f->namew, (ulg *)NULL, (zoff_t *)&usize, NULL);
+      else
+        tf = filetime(f->name, (ulg *)NULL, (zoff_t *)&usize, NULL);
+#else
+      tf = filetime(f->name, (ulg *)NULL, (zoff_t *)&usize, NULL);
+#endif
+    }
+
+    if (action == DELETE || action == FRESHEN ||
+        tf == 0 ||
+        tf < before || (after && tf >= after) ||
+        (namecmp(f->zname, zipfile) == 0 && !zip_to_stdout)
+       )
+      f = fexpel(f);
+    else {
+      /* ??? */
+      files_total++;
+      f->usize = 0;
+      if (usize != (uzoff_t) -1 && usize != (uzoff_t) -2) {
+        bytes_total += usize;
+        f->usize = usize;
+      }
+      f = f->nxt;
+    }
+  }
+  if (mesg_line_started) {
+    fprintf(mesg, "\n");
+    mesg_line_started = 0;
+  }
+#ifdef MACOS
+  PrintStatProgress("done");
+#endif
+
+  if (show_files) {
+    uzoff_t count = 0;
+    uzoff_t bytes = 0;
+
+    if (noisy) {
+      fflush(mesg);
+    }
+
+    if (noisy && (show_files == 1 || show_files == 3 || show_files == 5)) {
+      /* sf, su, sU */
+      if (mesg_line_started) {
+        fprintf(mesg, "\n");
+        mesg_line_started = 0;
+      }
+      if (kk == 3)
+        /* -sf alone */
+        fprintf(mesg, "Archive contains:\n");
+      else if (action == DELETE)
+        fprintf(mesg, "Would Delete:\n");
+      else if (action == FRESHEN)
+        fprintf(mesg, "Would Freshen:\n");
+      else if (action == ARCHIVE)
+        fprintf(mesg, "Would Copy:\n");
+      else
+        fprintf(mesg, "Would Add/Update:\n");
+      fflush(mesg);
+    }
+
+    if (logfile) {
+      if (logfile_line_started) {
+        fprintf(logfile, "\n");
+        logfile_line_started = 0;
+      }
+      if (kk == 3)
+        /* -sf alone */
+        fprintf(logfile, "Archive contains:\n");
+      else if (action == DELETE)
+        fprintf(logfile, "Would Delete:\n");
+      else if (action == FRESHEN)
+        fprintf(logfile, "Would Freshen:\n");
+      else if (action == ARCHIVE)
+        fprintf(logfile, "Would Copy:\n");
+      else
+        fprintf(logfile, "Would Add/Update:\n");
+      fflush(logfile);
+    }
+
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (z->mark || kk == 3) {
+        count++;
+        if ((zoff_t)z->len > 0)
+          bytes += z->len;
+        if (noisy && (show_files == 1 || show_files == 3))
+          /* sf, su */
+          fprintf(mesg, "  %s\n", z->oname);
+        if (logfile && !(show_files == 5 || show_files == 6))
+          /* not sU or sU- show normal name in log */
+          fprintf(logfile, "  %s\n", z->oname);
+
+#ifdef UNICODE_TEST
+        if (create_files) {
+          int r;
+          int dir = 0;
+          FILE *f;
+
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+          char *fn = NULL;
+          wchar_t *fnw = NULL;
+
+          if (!no_win32_wide) {
+            if ((fnw = malloc((wcslen(z->znamew) + 120) * sizeof(wchar_t))) == NULL)
+              ZIPERR(ZE_MEM, "sC");
+            wcscpy(fnw, L"testdir/");
+            wcscat(fnw, z->znamew);
+            if (fnw[wcslen(fnw) - 1] == '/')
+              dir = 1;
+            if (dir)
+              r = _wmkdir(fnw);
+            else
+              f = _wfopen(fnw, L"w");
+          } else {
+            if ((fn = malloc(strlen(z->zname) + 120)) == NULL)
+              ZIPERR(ZE_MEM, "sC");
+            strcpy(fn, "testdir/");
+            strcat(fn, z->zname);
+            if (fn[strlen(fn) - 1] == '/')
+              dir = 1;
+            if (dir)
+              r = mkdir(fn);
+            else
+              f = fopen(fn, "w");
+          }
+#else
+          char *fn = NULL;
+          if ((fn = malloc(strlen(z->zname) + 120)) == NULL)
+            ZIPERR(ZE_MEM, "sC");
+          strcpy(fn, "testdir/");
+          if (z->uname)
+            strcat(fn, z->uname);
+          else
+            strcat(fn, z->zname);
+
+          if (fn[strlen(fn) - 1] == '/')
+            dir = 1;
+          if (dir)
+            r = mkdir(fn, 0777);
+          else
+            f = fopen(fn, "w");
+#endif
+          if (dir) {
+            if (r) {
+              if (errno != 17) {
+                printf(" - could not create directory testdir/%s\n", z->oname);
+                perror("    dir");
+              }
+            } else {
+              printf(" - created directory testdir/%s\n", z->oname);
+            }
+          } else {
+            if (f == NULL) {
+              printf(" - could not open testdir/%s\n", z->oname);
+              perror("    file");
+            } else {
+              fclose(f);
+              printf(" - created testdir/%s\n", z->oname);
+              if (z->uname)
+                printf("   u - created testdir/%s\n", z->uname);
+            }
+          }
+        }
+#endif
+#ifdef UNICODE_SUPPORT
+        if (show_files == 3 || show_files == 4) {
+          /* su, su- */
+          /* Include escaped Unicode name if exists under standard name */
+          if (z->ouname) {
+            if (noisy && show_files == 3)
+              fprintf(mesg, "     Escaped Unicode:  %s\n", z->ouname);
+            if (logfile)
+              fprintf(logfile, "     Escaped Unicode:  %s\n", z->ouname);
+          }
+        }
+        if (show_files == 5 || show_files == 6) {
+          /* sU, sU- */
+          /* Display only escaped Unicode name if exists or standard name */
+          if (z->ouname) {
+            /* Unicode name */
+            if (noisy && show_files == 5) {
+              fprintf(mesg, "  %s\n", z->ouname);
+            }
+            if (logfile) {
+              fprintf(logfile, "  %s\n", z->ouname);
+            }
+          } else {
+            /* No Unicode name so use standard name */
+            if (noisy && show_files == 5) {
+              fprintf(mesg, "  %s\n", z->oname);
+            }
+            if (logfile) {
+              fprintf(logfile, "  %s\n", z->oname);
+            }
+          }
+        }
+#endif
+      }
+    }
+    for (f = found; f != NULL; f = f->nxt) {
+      count++;
+      if ((zoff_t)f->usize > 0)
+        bytes += f->usize;
+#ifdef UNICODE_SUPPORT
+      if (unicode_escape_all) {
+        char *escaped_unicode;
+        escaped_unicode = local_to_escape_string(f->zname);
+        if (noisy && (show_files == 1 || show_files == 3 || show_files == 5))
+          /* sf, su, sU */
+          fprintf(mesg, "  %s\n", escaped_unicode);
+        if (logfile)
+          fprintf(logfile, "  %s\n", escaped_unicode);
+        free(escaped_unicode);
+      } else {
+#endif
+        if (noisy && (show_files == 1 || show_files == 3 || show_files == 5))
+          /* sf, su, sU */
+          fprintf(mesg, "  %s\n", f->oname);
+        if (logfile)
+          fprintf(logfile, "  %s\n", f->oname);
+#ifdef UNICODE_SUPPORT
+      }
+#endif
+    }
+    if (noisy || logfile == NULL)
+      fprintf(mesg, "Total %s entries (%s bytes)\n",
+                                          zip_fuzofft(count, NULL, NULL),
+                                          zip_fuzofft(bytes, NULL, NULL));
+    if (logfile)
+      fprintf(logfile, "Total %s entries (%s bytes)\n",
+                                          zip_fuzofft(count, NULL, NULL),
+                                          zip_fuzofft(bytes, NULL, NULL));
+    RETURN(finish(ZE_OK));
+  }
+
+  /* Make sure there's something left to do */
+  if (k == 0 && found == NULL && !diff_mode &&
+      !(zfiles == NULL && allow_empty_archive) &&
+      !(zfiles != NULL &&
+        (latest || fix || adjust || junk_sfx || comadd || zipedit))) {
+    if (test && (zfiles != NULL || zipbeg != 0)) {
+#ifndef WINDLL
+      check_zipfile(zipfile, argv[0]);
+#endif
+      RETURN(finish(ZE_OK));
+    }
+    if (action == UPDATE || action == FRESHEN) {
+      RETURN(finish(ZE_NONE));
+    }
+    else if (zfiles == NULL && (latest || fix || adjust || junk_sfx)) {
+      ZIPERR(ZE_NAME, zipfile);
+    }
+#ifndef WINDLL
+    else if (recurse && (pcount == 0) && (first_listarg > 0)) {
+#ifdef VMS
+      strcpy(errbuf, "try: zip \"");
+      for (i = 1; i < (first_listarg - 1); i++)
+        strcat(strcat(errbuf, args[i]), "\" ");
+      strcat(strcat(errbuf, args[i]), " *.* -i");
+#else /* !VMS */
+      strcpy(errbuf, "try: zip");
+      for (i = 1; i < first_listarg; i++)
+        strcat(strcat(errbuf, " "), args[i]);
+#  ifdef AMIGA
+      strcat(errbuf, " \"\" -i");
+#  else
+      strcat(errbuf, " . -i");
+#  endif
+#endif /* ?VMS */
+      for (i = first_listarg; i < argc; i++)
+        strcat(strcat(errbuf, " "), args[i]);
+      ZIPERR(ZE_NONE, errbuf);
+    }
+    else {
+      ZIPERR(ZE_NONE, zipfile);
+    }
+#endif /* !WINDLL */
+  }
+
+  if (filesync && all_current && fcount == 0) {
+    zipmessage("Archive is current", "");
+    RETURN(finish(ZE_OK));
+  }
+
+  d = (d && k == 0 && (zipbeg || zfiles != NULL)); /* d true if appending */
+
+#if CRYPT
+  /* Initialize the crc_32_tab pointer, when encryption was requested. */
+  if (key != NULL) {
+    crc_32_tab = get_crc_table();
+#ifdef EBCDIC
+    /* convert encryption key to ASCII (ISO variant for 8-bit ASCII chars) */
+    strtoasc(key, key);
+#endif /* EBCDIC */
+  }
+#endif /* CRYPT */
+
+  /* Just ignore the spanning signature if a multi-disk archive */
+  if (zfiles && total_disks != 1 && zipbeg == 4) {
+    zipbeg = 0;
+  }
+
+  /* Before we get carried away, make sure zip file is writeable. This
+   * has the undesired side effect of leaving one empty junk file on a WORM,
+   * so when the zipfile does not exist already and when -b is specified,
+   * the writability check is made in replace().
+   */
+  if (strcmp(zipfile, "-"))
+  {
+    if (tempdir && zfiles == NULL && zipbeg == 0) {
+      zip_attributes = 0;
+    } else {
+      x = (have_out || (zfiles == NULL && zipbeg == 0)) ? zfopen(out_path, FOPW) :
+                                                          zfopen(out_path, FOPM);
+      /* Note: FOPW and FOPM expand to several parameters for VMS */
+      if (x == NULL) {
+        ZIPERR(ZE_CREAT, out_path);
+      }
+      fclose(x);
+      zip_attributes = getfileattr(out_path);
+      if (zfiles == NULL && zipbeg == 0)
+        destroy(out_path);
+    }
+  }
+  else
+    zip_attributes = 0;
+
+  /* Throw away the garbage in front of the zip file for -J */
+  if (junk_sfx) zipbeg = 0;
+
+  /* Open zip file and temporary output file */
+  if (show_what_doing) {
+    fprintf(mesg, "sd: Open zip file and create temp file\n");
+    fflush(mesg);
+  }
+  diag("opening zip file and creating temporary zip file");
+  x = NULL;
+  tempzn = 0;
+  if (strcmp(zipfile, "-") == 0)
+  {
+#ifdef MSDOS
+    /* It is nonsense to emit the binary data stream of a zipfile to
+     * the (text mode) console.  This case should already have been caught
+     * in a call to zipstdout() far above.  Therefore, if the following
+     * failsafe check detects a console attached to stdout, zip is stopped
+     * with an "internal logic error"!  */
+    if (isatty(fileno(stdout)))
+      ZIPERR(ZE_LOGIC, "tried to write binary zipfile data to console!");
+    /* Set stdout mode to binary for MSDOS systems */
+#  ifdef __HIGHC__
+    setmode(stdout, _BINARY);
+#  else
+    setmode(fileno(stdout), O_BINARY);
+#  endif
+    y = zfdopen(fileno(stdout), FOPW);
+#else
+    y = stdout;
+#endif
+    /* tempzip must be malloced so a later free won't barf */
+    tempzip = malloc(4);
+    if (tempzip == NULL) {
+      ZIPERR(ZE_MEM, "allocating temp filename");
+    }
+    strcpy(tempzip, "-");
+  }
+  else if (d) /* d true if just appending (-g) */
+  {
+    if (total_disks > 1) {
+      ZIPERR(ZE_PARMS, "cannot grow split archive");
+    }
+    if ((y = zfopen(zipfile, FOPM)) == NULL) {
+      ZIPERR(ZE_NAME, zipfile);
+    }
+    tempzip = zipfile;
+    /*
+    tempzf = y;
+    */
+
+    if (zfseeko(y, cenbeg, SEEK_SET)) {
+      ZIPERR(ferror(y) ? ZE_READ : ZE_EOF, zipfile);
+    }
+    bytes_this_split = cenbeg;
+    tempzn = cenbeg;
+  }
+  else
+  {
+    if (show_what_doing) {
+      fprintf(mesg, "sd: Creating new zip file\n");
+      fflush(mesg);
+    }
+    /* See if there is something at beginning of disk 1 to copy.
+       If not, do nothing as zipcopy() will open files to read
+       as needed. */
+    if (zipbeg) {
+      in_split_path = get_in_split_path(in_path, 0);
+
+      while ((in_file = zfopen(in_split_path, FOPR_EX)) == NULL) {
+        /* could not open split */
+
+        /* Ask for directory with split.  Updates in_path */
+        if (ask_for_split_read_path(0) != ZE_OK) {
+          ZIPERR(ZE_ABORT, "could not open archive to read");
+        }
+        free(in_split_path);
+        in_split_path = get_in_split_path(in_path, 1);
+      }
+    }
+#if defined(UNIX) && !defined(NO_MKSTEMP)
+    {
+      int yd;
+      int i;
+
+      /* use mkstemp to avoid race condition and compiler warning */
+
+      if (tempath != NULL)
+      {
+        /* if -b used to set temp file dir use that for split temp */
+        if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
+          ZIPERR(ZE_MEM, "allocating temp filename");
+        }
+        strcpy(tempzip, tempath);
+        if (lastchar(tempzip) != '/')
+          strcat(tempzip, "/");
+      }
+      else
+      {
+        /* create path by stripping name and appending template */
+        if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
+        ZIPERR(ZE_MEM, "allocating temp filename");
+        }
+        strcpy(tempzip, zipfile);
+        for(i = strlen(tempzip); i > 0; i--) {
+          if (tempzip[i - 1] == '/')
+            break;
+        }
+        tempzip[i] = '\0';
+      }
+      strcat(tempzip, "ziXXXXXX");
+
+      if ((yd = mkstemp(tempzip)) == EOF) {
+        ZIPERR(ZE_TEMP, tempzip);
+      }
+      if ((y = fdopen(yd, FOPW_TMP)) == NULL) {
+        ZIPERR(ZE_TEMP, tempzip);
+      }
+    }
+#else
+    if ((tempzip = tempname(zipfile)) == NULL) {
+      ZIPERR(ZE_MEM, "allocating temp filename");
+    }
+    if ((y = zfopen(tempzip, FOPW_TMP)) == NULL) {
+      ZIPERR(ZE_TEMP, tempzip);
+    }
+#endif
+  }
+
+#if (!defined(VMS) && !defined(CMS_MVS))
+  /* Use large buffer to speed up stdio: */
+#if (defined(_IOFBF) || !defined(BUFSIZ))
+  zipbuf = (char *)malloc(ZBSZ);
+#else
+  zipbuf = (char *)malloc(BUFSIZ);
+#endif
+  if (zipbuf == NULL) {
+    ZIPERR(ZE_MEM, tempzip);
+  }
+# ifdef _IOFBF
+  setvbuf(y, zipbuf, _IOFBF, ZBSZ);
+# else
+  setbuf(y, zipbuf);
+# endif /* _IOBUF */
+#endif /* !VMS  && !CMS_MVS */
+
+  /* If not seekable set some flags 3/14/05 EG */
+  output_seekable = 1;
+  if (!is_seekable(y)) {
+    output_seekable = 0;
+    use_descriptors = 1;
+  }
+
+  /* Not needed.  Only need Zip64 when input file is larger than 2 GB or reading
+     stdin and writing stdout.  This is set in putlocal() for each file. */
+#if 0
+  /* If using descriptors and Zip64 enabled force Zip64 3/13/05 EG */
+# ifdef ZIP64_SUPPORT
+  if (use_descriptors && force_zip64 != 0) {
+    force_zip64 = 1;
+  }
+# endif
+#endif
+
+  /* if archive exists, not streaming and not deleting or growing, copy
+     any bytes at beginning */
+  if (strcmp(zipfile, "-") != 0 && !d)  /* this must go *after* set[v]buf */
+  {
+    /* copy anything before archive */
+    if (in_file && zipbeg && (r = bfcopy(zipbeg)) != ZE_OK) {
+      ZIPERR(r, r == ZE_TEMP ? tempzip : zipfile);
+    }
+    if (in_file) {
+      fclose(in_file);
+      in_file = NULL;
+      free(in_split_path);
+    }
+    tempzn = zipbeg;
+    if (split_method) {
+      /* add spanning signature */
+      if (show_what_doing) {
+        fprintf(mesg, "sd: Adding spanning/splitting signature at top of archive\n");
+        fflush(mesg);
+      }
+      /* write the spanning signature at the top of the archive */
+      errbuf[0] = 0x50 /*'P' except for EBCDIC*/;
+      errbuf[1] = 0x4b /*'K' except for EBCDIC*/;
+      errbuf[2] = 7;
+      errbuf[3] = 8;
+      bfwrite(errbuf, 1, 4, BFWRITE_DATA);
+      /* tempzn updated below */
+      tempzn += 4;
+    }
+  }
+
+  o = 0;                                /* no ZE_OPEN errors yet */
+
+
+  /* Process zip file, updating marked files */
+#ifdef DEBUG
+  if (zfiles != NULL)
+    diag("going through old zip file");
+#endif
+  if (zfiles != NULL && show_what_doing) {
+    fprintf(mesg, "sd: Going through old zip file\n");
+    fflush(mesg);
+  }
+  w = &zfiles;
+  while ((z = *w) != NULL) {
+    if (z->mark == 1)
+    {
+      uzoff_t len;
+      if ((zoff_t)z->len == -1)
+        /* device */
+        len = 0;
+      else
+        len = z->len;
+
+      /* if not deleting, zip it up */
+      if (action != ARCHIVE && action != DELETE)
+      {
+        struct zlist far *localz; /* local header */
+
+        if (verbose || !(filesync && z->current))
+          DisplayRunningStats();
+        if (noisy)
+        {
+          if (action == FRESHEN) {
+            fprintf(mesg, "freshening: %s", z->oname);
+            mesg_line_started = 1;
+            fflush(mesg);
+          } else if (filesync && z->current) {
+            if (verbose) {
+              fprintf(mesg, "      ok: %s", z->oname);
+              mesg_line_started = 1;
+              fflush(mesg);
+            }
+          } else if (!(filesync && z->current)) {
+            fprintf(mesg, "updating: %s", z->oname);
+            mesg_line_started = 1;
+            fflush(mesg);
+          }
+        }
+        if (logall)
+        {
+          if (action == FRESHEN) {
+            fprintf(logfile, "freshening: %s", z->oname);
+            logfile_line_started = 1;
+            fflush(logfile);
+          } else if (filesync && z->current) {
+            if (verbose) {
+              fprintf(logfile, " current: %s", z->oname);
+              logfile_line_started = 1;
+              fflush(logfile);
+            }
+          } else {
+            fprintf(logfile, "updating: %s", z->oname);
+            logfile_line_started = 1;
+            fflush(logfile);
+          }
+        }
+
+        /* Get local header flags and extra fields */
+        if (readlocal(&localz, z) != ZE_OK) {
+          zipwarn("could not read local entry information: ", z->oname);
+          z->lflg = z->flg;
+          z->ext = 0;
+        } else {
+          z->lflg = localz->lflg;
+          z->ext = localz->ext;
+          z->extra = localz->extra;
+          if (localz->nam) free(localz->iname);
+          if (localz->nam) free(localz->name);
+#ifdef UNICODE_SUPPORT
+          if (localz->uname) free(localz->uname);
+#endif
+          free(localz);
+        }
+
+        if (!(filesync && z->current) &&
+             (r = zipup(z)) != ZE_OK && r != ZE_OPEN && r != ZE_MISS)
+        {
+          zipmessage_nl("", 1);
+          /*
+          if (noisy)
+          {
+            if (mesg_line_started) {
+#if (!defined(MACOS) && !defined(WINDLL))
+              putc('\n', mesg);
+              fflush(mesg);
+#else
+              fprintf(stdout, "\n");
+              fflush(stdout);
+#endif
+              mesg_line_started = 0;
+            }
+          }
+          if (logall) {
+            if (logfile_line_started) {
+              fprintf(logfile, "\n");
+              logfile_line_started = 0;
+              fflush(logfile);
+            }
+          }
+          */
+          sprintf(errbuf, "was zipping %s", z->name);
+          ZIPERR(r, errbuf);
+        }
+        if (filesync && z->current)
+        {
+          /* if filesync if entry matches OS just copy */
+          if ((r = zipcopy(z)) != ZE_OK)
+          {
+            sprintf(errbuf, "was copying %s", z->oname);
+            ZIPERR(r, errbuf);
+          }
+          zipmessage_nl("", 1);
+          /*
+          if (noisy)
+          {
+            if (mesg_line_started) {
+#if (!defined(MACOS) && !defined(WINDLL))
+              putc('\n', mesg);
+              fflush(mesg);
+#else
+              fprintf(stdout, "\n");
+              fflush(stdout);
+#endif
+              mesg_line_started = 0;
+            }
+          }
+          if (logall) {
+            if (logfile_line_started) {
+              fprintf(logfile, "\n");
+              logfile_line_started = 0;
+              fflush(logfile);
+            }
+          }
+          */
+        }
+        if (r == ZE_OPEN || r == ZE_MISS)
+        {
+          o = 1;
+          zipmessage_nl("", 1);
+          /*
+          if (noisy)
+          {
+#if (!defined(MACOS) && !defined(WINDLL))
+            putc('\n', mesg);
+            fflush(mesg);
+#else
+            fprintf(stdout, "\n");
+#endif
+            mesg_line_started = 0;
+          }
+          if (logall) {
+            fprintf(logfile, "\n");
+            logfile_line_started = 0;
+            fflush(logfile);
+          }
+          */
+          if (r == ZE_OPEN) {
+            perror(z->oname);
+            zipwarn("could not open for reading: ", z->oname);
+            if (bad_open_is_error) {
+              sprintf(errbuf, "was zipping %s", z->name);
+              ZIPERR(r, errbuf);
+            }
+          } else {
+            zipwarn("file and directory with the same name: ", z->oname);
+          }
+          zipwarn("will just copy entry over: ", z->oname);
+          if ((r = zipcopy(z)) != ZE_OK)
+          {
+            sprintf(errbuf, "was copying %s", z->oname);
+            ZIPERR(r, errbuf);
+          }
+          z->mark = 0;
+        }
+        files_so_far++;
+        good_bytes_so_far += z->len;
+        bytes_so_far += len;
+        w = &z->nxt;
+      }
+      else if (action == ARCHIVE)
+      {
+#ifdef DEBUG
+        zoff_t here = zftello(y);
+#endif
+
+        DisplayRunningStats();
+        if (skip_this_disk - 1 != z->dsk)
+          /* moved to another disk so start copying again */
+          skip_this_disk = 0;
+        if (skip_this_disk - 1 == z->dsk) {
+          /* skipping this disk */
+          if (noisy) {
+            fprintf(mesg, " skipping: %s", z->oname);
+            mesg_line_started = 1;
+            fflush(mesg);
+          }
+          if (logall) {
+            fprintf(logfile, " skipping: %s", z->oname);
+            logfile_line_started = 1;
+            fflush(logfile);
+          }
+        } else {
+          /* copying this entry */
+          if (noisy) {
+            fprintf(mesg, " copying: %s", z->oname);
+            if (display_usize) {
+              fprintf(mesg, " (");
+              DisplayNumString(mesg, z->len );
+              fprintf(mesg, ")");
+            }
+            mesg_line_started = 1;
+            fflush(mesg);
+          }
+          if (logall)
+          {
+            fprintf(logfile, " copying: %s", z->oname);
+            if (display_usize) {
+              fprintf(logfile, " (");
+              DisplayNumString(logfile, z->len );
+              fprintf(logfile, ")");
+            }
+            logfile_line_started = 1;
+            fflush(logfile);
+          }
+        }
+
+        if (skip_this_disk - 1 == z->dsk)
+          /* skip entries on this disk */
+          z->mark = 0;
+        else if ((r = zipcopy(z)) != ZE_OK)
+        {
+          if (r == ZE_ABORT) {
+            ZIPERR(r, "user requested abort");
+          } else if (fix != 1) {
+            /* exit */
+            sprintf(errbuf, "was copying %s", z->oname);
+            zipwarn("(try -F to attempt to fix)", "");
+            ZIPERR(r, errbuf);
+          }
+          else /* if (r == ZE_FORM) */ {
+#ifdef DEBUG
+            zoff_t here = zftello(y);
+#endif
+
+            /* seek back in output to start of this entry so can overwrite */
+            if (zfseeko(y, current_local_offset, SEEK_SET) != 0){
+              ZIPERR(r, "could not seek in output file");
+            }
+            zipwarn("bad - skipping: ", z->oname);
+#ifdef DEBUG
+            here = zftello(y);
+#endif
+            tempzn = current_local_offset;
+            bytes_this_split = current_local_offset;
+          }
+        }
+        if (skip_this_disk || !(fix == 1 && r != ZE_OK))
+        {
+          if (noisy && mesg_line_started) {
+            fprintf(mesg, "\n");
+            mesg_line_started = 0;
+            fflush(mesg);
+          }
+          if (logall && logfile_line_started) {
+            fprintf(logfile, "\n");
+            logfile_line_started = 0;
+            fflush(logfile);
+          }
+        }
+        /* input counts */
+        files_so_far++;
+        if (r != ZE_OK)
+          bad_bytes_so_far += z->siz;
+        else
+          good_bytes_so_far += z->siz;
+        bytes_so_far += z->siz;
+
+        if (r != ZE_OK && fix == 1) {
+          /* remove bad entry from list */
+          v = z->nxt;                     /* delete entry from list */
+          free((zvoid *)(z->iname));
+          free((zvoid *)(z->zname));
+          free(z->oname);
+#ifdef UNICODE_SUPPORT
+          if (z->uname) free(z->uname);
+#endif /* def UNICODE_SUPPORT */
+          if (z->ext)
+            /* don't have local extra until zipcopy reads it */
+            if (z->extra) free((zvoid *)(z->extra));
+          if (z->cext && z->cextra != z->extra)
+            free((zvoid *)(z->cextra));
+          if (z->com)
+            free((zvoid *)(z->comment));
+          farfree((zvoid far *)z);
+          *w = v;
+          zcount--;
+        } else {
+          w = &z->nxt;
+        }
+
+#ifdef WINDLL
+#ifdef ZIP64_SUPPORT
+        /* int64 support in caller */
+        if (lpZipUserFunctions->ServiceApplication64 != NULL)
+        {
+          if ((*lpZipUserFunctions->ServiceApplication64)(z->zname, z->siz))
+                    ZIPERR(ZE_ABORT, "User terminated operation");
+        }
+        else
+        {
+          /* no int64 support in caller */
+          filesize64 = z->siz;
+          low = (unsigned long)(filesize64 & 0x00000000FFFFFFFF);
+          high = (unsigned long)((filesize64 >> 32) & 0x00000000FFFFFFFF);
+          if (lpZipUserFunctions->ServiceApplication64_No_Int64 != NULL) {
+            if ((*lpZipUserFunctions->ServiceApplication64_No_Int64)(z->zname, low, high))
+                      ZIPERR(ZE_ABORT, "User terminated operation");
+          }
+        }
+#else
+        if (lpZipUserFunctions->ServiceApplication != NULL) {
+          if ((*lpZipUserFunctions->ServiceApplication)(z->zname, z->siz))
+            ZIPERR(ZE_ABORT, "User terminated operation");
+        }
+#endif /* ZIP64_SUPPORT - I added comments around // comments - does that help below? EG */
+/* strange but true: if I delete this and put these two endifs adjacent to
+   each other, the Aztec Amiga compiler never sees the second endif!  WTF?? PK */
+#endif /* WINDLL */
+      }
+      else
+      {
+        DisplayRunningStats();
+        if (noisy)
+        {
+          fprintf(mesg, "deleting: %s", z->oname);
+          if (display_usize) {
+            fprintf(mesg, " (");
+            DisplayNumString(mesg, z->len );
+            fprintf(mesg, ")");
+          }
+          fflush(mesg);
+          fprintf(mesg, "\n");
+        }
+        if (logall)
+        {
+          fprintf(logfile, "deleting: %s", z->oname);
+          if (display_usize) {
+            fprintf(logfile, " (");
+            DisplayNumString(logfile, z->len );
+            fprintf(logfile, ")");
+          }
+          fprintf(logfile, "\n");
+          fflush(logfile);
+        }
+        files_so_far++;
+        good_bytes_so_far += z->siz;
+        bytes_so_far += z->siz;
+#ifdef WINDLL
+#ifdef ZIP64_SUPPORT
+        /* int64 support in caller */
+        if (lpZipUserFunctions->ServiceApplication64 != NULL)
+        {
+          if ((*lpZipUserFunctions->ServiceApplication64)(z->zname, z->siz))
+                    ZIPERR(ZE_ABORT, "User terminated operation");
+        }
+        else
+        {
+          /* no int64 support in caller */
+          filesize64 = z->siz;
+          low = (unsigned long)(filesize64 & 0x00000000FFFFFFFF);
+          high = (unsigned long)((filesize64 >> 32) & 0x00000000FFFFFFFF);
+          if (lpZipUserFunctions->ServiceApplication64_No_Int64 != NULL) {
+            if ((*lpZipUserFunctions->ServiceApplication64_No_Int64)(z->zname, low, high))
+                      ZIPERR(ZE_ABORT, "User terminated operation");
+          }
+        }
+#else
+        if (lpZipUserFunctions->ServiceApplication != NULL) {
+          if ((*lpZipUserFunctions->ServiceApplication)(z->zname, z->siz))
+            ZIPERR(ZE_ABORT, "User terminated operation");
+        }
+#endif /* ZIP64_SUPPORT - I added comments around // comments - does that help below? EG */
+/* strange but true: if I delete this and put these two endifs adjacent to
+   each other, the Aztec Amiga compiler never sees the second endif!  WTF?? PK */
+#endif /* WINDLL */
+
+        v = z->nxt;                     /* delete entry from list */
+        free((zvoid *)(z->iname));
+        free((zvoid *)(z->zname));
+        free(z->oname);
+#ifdef UNICODE_SUPPORT
+        if (z->uname) free(z->uname);
+#endif /* def UNICODE_SUPPORT */
+        if (z->ext)
+          /* don't have local extra until zipcopy reads it */
+          if (z->extra) free((zvoid *)(z->extra));
+        if (z->cext && z->cextra != z->extra)
+          free((zvoid *)(z->cextra));
+        if (z->com)
+          free((zvoid *)(z->comment));
+        farfree((zvoid far *)z);
+        *w = v;
+        zcount--;
+      }
+    }
+    else
+    {
+      if (action == ARCHIVE) {
+        v = z->nxt;                     /* delete entry from list */
+        free((zvoid *)(z->iname));
+        free((zvoid *)(z->zname));
+        free(z->oname);
+#ifdef UNICODE_SUPPORT
+        if (z->uname) free(z->uname);
+#endif /* def UNICODE_SUPPORT */
+        if (z->ext)
+          /* don't have local extra until zipcopy reads it */
+          if (z->extra) free((zvoid *)(z->extra));
+        if (z->cext && z->cextra != z->extra)
+          free((zvoid *)(z->cextra));
+        if (z->com)
+          free((zvoid *)(z->comment));
+        farfree((zvoid far *)z);
+        *w = v;
+        zcount--;
+      }
+      else
+      {
+        if (filesync) {
+          /* Delete entries if don't match a file on OS */
+          BlankRunningStats();
+          if (noisy)
+          {
+            fprintf(mesg, "deleting: %s", z->oname);
+            if (display_usize) {
+              fprintf(mesg, " (");
+              DisplayNumString(mesg, z->len );
+              fprintf(mesg, ")");
+            }
+            fflush(mesg);
+            fprintf(mesg, "\n");
+            mesg_line_started = 0;
+          }
+          if (logall)
+          {
+            fprintf(logfile, "deleting: %s", z->oname);
+            if (display_usize) {
+              fprintf(logfile, " (");
+              DisplayNumString(logfile, z->len );
+              fprintf(logfile, ")");
+            }
+            fprintf(logfile, "\n");
+            fflush(logfile);
+            logfile_line_started = 0;
+          }
+        }
+        /* copy the original entry */
+        else if (!d && !diff_mode && (r = zipcopy(z)) != ZE_OK)
+        {
+          sprintf(errbuf, "was copying %s", z->oname);
+          ZIPERR(r, errbuf);
+        }
+        w = &z->nxt;
+      }
+    }
+  }
+
+
+  /* Process the edited found list, adding them to the zip file */
+  if (show_what_doing) {
+    fprintf(mesg, "sd: Zipping up new entries\n");
+    fflush(mesg);
+  }
+  diag("zipping up new entries, if any");
+  Trace((stderr, "zip diagnostic: fcount=%u\n", (unsigned)fcount));
+  for (f = found; f != NULL; f = fexpel(f))
+  {
+    uzoff_t len;
+    /* add a new zfiles entry and set the name */
+    if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) {
+      ZIPERR(ZE_MEM, "was adding files to zip file");
+    }
+    z->nxt = NULL;
+    z->name = f->name;
+    f->name = NULL;
+#ifdef UNICODE_SUPPORT
+    z->uname = NULL;          /* UTF-8 name for extra field */
+    z->zuname = NULL;         /* externalized UTF-8 name for matching */
+    z->ouname = NULL;         /* display version of UTF-8 name with OEM */
+
+#if 0
+    /* New AppNote bit 11 allowing storing UTF-8 in path */
+    if (utf8_force && f->uname) {
+      if (f->iname)
+        free(f->iname);
+      if ((f->iname = malloc(strlen(f->uname) + 1)) == NULL)
+        ZIPERR(ZE_MEM, "Unicode bit 11");
+      strcpy(f->iname, f->uname);
+# ifdef WIN32
+      if (f->inamew)
+        free(f->inamew);
+      f->inamew = utf8_to_wchar_string(f->iname);
+# endif
+    }
+#endif
+
+    /* Only set z->uname if have a non-ASCII Unicode name */
+    /* The Unicode path extra field is created if z->uname is not NULL,
+       unless on a UTF-8 system, then instead of creating the extra field
+       set bit 11 in the General Purpose Bit Flag */
+    {
+      int is_ascii = 0;
+
+# ifdef WIN32
+      if (!no_win32_wide)
+        is_ascii = is_ascii_stringw(f->inamew);
+      else
+        is_ascii = is_ascii_string(f->uname);
+# else
+      is_ascii = is_ascii_string(f->uname);
+# endif
+
+      if (z->uname == NULL) {
+        if (!is_ascii)
+          z->uname = f->uname;
+        else
+          free(f->uname);
+      } else {
+        free(f->uname);
+      }
+    }
+    f->uname = NULL;
+
+#endif
+    z->iname = f->iname;
+    f->iname = NULL;
+    z->zname = f->zname;
+    f->zname = NULL;
+    z->oname = f->oname;
+    f->oname = NULL;
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+    z->namew = f->namew;
+    f->namew = NULL;
+    z->inamew = f->inamew;
+    f->inamew = NULL;
+    z->znamew = f->znamew;
+    f->znamew = NULL;
+#endif
+    z->ext = z->cext = z->com = 0;
+    z->extra = z->cextra = NULL;
+    z->mark = 1;
+    z->dosflag = f->dosflag;
+    /* zip it up */
+    DisplayRunningStats();
+    if (noisy)
+    {
+      fprintf(mesg, "  adding: %s", z->oname);
+      mesg_line_started = 1;
+      fflush(mesg);
+    }
+    if (logall)
+    {
+      fprintf(logfile, "  adding: %s", z->oname);
+      logfile_line_started = 1;
+      fflush(logfile);
+    }
+    /* initial scan */
+    len = f->usize;
+    if ((r = zipup(z)) != ZE_OK  && r != ZE_OPEN && r != ZE_MISS)
+    {
+      zipmessage_nl("", 1);
+      /*
+      if (noisy)
+      {
+#if (!defined(MACOS) && !defined(WINDLL))
+        putc('\n', mesg);
+        fflush(mesg);
+#else
+        fprintf(stdout, "\n");
+#endif
+        mesg_line_started = 0;
+        fflush(mesg);
+      }
+      if (logall) {
+        fprintf(logfile, "\n");
+        logfile_line_started = 0;
+        fflush(logfile);
+      }
+      */
+      sprintf(errbuf, "was zipping %s", z->oname);
+      ZIPERR(r, errbuf);
+    }
+    if (r == ZE_OPEN || r == ZE_MISS)
+    {
+      o = 1;
+      zipmessage_nl("", 1);
+      /*
+      if (noisy)
+      {
+#if (!defined(MACOS) && !defined(WINDLL))
+        putc('\n', mesg);
+        fflush(mesg);
+#else
+        fprintf(stdout, "\n");
+#endif
+        mesg_line_started = 0;
+        fflush(mesg);
+      }
+      if (logall) {
+        fprintf(logfile, "\n");
+        logfile_line_started = 0;
+        fflush(logfile);
+      }
+      */
+      if (r == ZE_OPEN) {
+        perror("zip warning");
+        if (logfile)
+          fprintf(logfile, "zip warning: %s\n", strerror(errno));
+        zipwarn("could not open for reading: ", z->oname);
+        if (bad_open_is_error) {
+          sprintf(errbuf, "was zipping %s", z->name);
+          ZIPERR(r, errbuf);
+        }
+      } else {
+        zipwarn("file and directory with the same name: ", z->oname);
+      }
+      files_so_far++;
+      bytes_so_far += len;
+      bad_files_so_far++;
+      bad_bytes_so_far += len;
+      free((zvoid *)(z->name));
+      free((zvoid *)(z->iname));
+      free((zvoid *)(z->zname));
+      free(z->oname);
+#ifdef UNICODE_SUPPORT
+      if (z->uname)
+        free(z->uname);
+# ifdef WIN32
+      if (z->namew)
+        free((zvoid *)(z->namew));
+      if (z->inamew)
+        free((zvoid *)(z->inamew));
+      if (z->znamew)
+        free((zvoid *)(z->znamew));
+# endif
+#endif
+      farfree((zvoid far *)z);
+    }
+    else
+    {
+      files_so_far++;
+      /* current size of file (just before reading) */
+      good_bytes_so_far += z->len;
+      /* size of file on initial scan */
+      bytes_so_far += len;
+      *w = z;
+      w = &z->nxt;
+      zcount++;
+    }
+  }
+  if (key != NULL)
+  {
+    free((zvoid *)key);
+    key = NULL;
+  }
+
+  /* final status 3/17/05 EG */
+  if (noisy && bad_files_so_far)
+  {
+    char tempstrg[100];
+
+    fprintf(mesg, "\nzip warning: Not all files were readable\n");
+    fprintf(mesg, "  files/entries read:  %lu", files_total - bad_files_so_far);
+    WriteNumString(good_bytes_so_far, tempstrg);
+    fprintf(mesg, " (%s bytes)", tempstrg);
+    fprintf(mesg, "  skipped:  %lu", bad_files_so_far);
+    WriteNumString(bad_bytes_so_far, tempstrg);
+    fprintf(mesg, " (%s bytes)\n", tempstrg);
+    fflush(mesg);
+  }
+  if (logfile && bad_files_so_far)
+  {
+    char tempstrg[100];
+
+    fprintf(logfile, "\nzip warning: Not all files were readable\n");
+    fprintf(logfile, "  files/entries read:  %lu", files_total - bad_files_so_far);
+    WriteNumString(good_bytes_so_far, tempstrg);
+    fprintf(logfile, " (%s bytes)", tempstrg);
+    fprintf(logfile, "  skipped:  %lu", bad_files_so_far);
+    WriteNumString(bad_bytes_so_far, tempstrg);
+    fprintf(logfile, " (%s bytes)", tempstrg);
+  }
+
+  /* Get one line comment for each new entry */
+  if (show_what_doing) {
+    fprintf(mesg, "sd: Get comment if any\n");
+    fflush(mesg);
+  }
+#if defined(AMIGA) || defined(MACOS)
+  if (comadd || filenotes)
+  {
+    if (comadd)
+#else
+  if (comadd)
+  {
+#endif
+    {
+      if (comment_stream == NULL) {
+#ifndef RISCOS
+        comment_stream = (FILE*)fdopen(fileno(stderr), "r");
+#else
+        comment_stream = stderr;
+#endif
+      }
+      if ((e = malloc(MAXCOM + 1)) == NULL) {
+        ZIPERR(ZE_MEM, "was reading comment lines");
+      }
+    }
+#ifdef __human68k__
+    setmode(fileno(comment_stream), O_TEXT);
+#endif
+#ifdef MACOS
+    if (noisy) fprintf(mesg, "\nStart commenting files ...\n");
+#endif
+    for (z = zfiles; z != NULL; z = z->nxt)
+      if (z->mark)
+#if defined(AMIGA) || defined(MACOS)
+        if (filenotes && (p = GetComment(z->zname)))
+        {
+          if (z->comment = malloc(k = strlen(p)+1))
+          {
+            z->com = k;
+            strcpy(z->comment, p);
+          }
+          else
+          {
+            free((zvoid *)e);
+            ZIPERR(ZE_MEM, "was reading filenotes");
+          }
+        }
+        else if (comadd)
+#endif /* AMIGA || MACOS */
+        {
+          if (noisy)
+            fprintf(mesg, "Enter comment for %s:\n", z->oname);
+          if (fgets(e, MAXCOM+1, comment_stream) != NULL)
+          {
+            if ((p = malloc((extent)(k = strlen(e))+1)) == NULL)
+            {
+              free((zvoid *)e);
+              ZIPERR(ZE_MEM, "was reading comment lines");
+            }
+            strcpy(p, e);
+            if (p[k-1] == '\n')
+              p[--k] = 0;
+            z->comment = p;
+            /* zip64 support 09/05/2003 R.Nausedat */
+            z->com = (extent)k;
+          }
+        }
+#ifdef MACOS
+    if (noisy) fprintf(mesg, "\n...done");
+#endif
+#if defined(AMIGA) || defined(MACOS)
+    if (comadd)
+      free((zvoid *)e);
+    GetComment(NULL);           /* makes it free its internal storage */
+#else
+    free((zvoid *)e);
+#endif
+  }
+
+  /* Get multi-line comment for the zip file */
+  if (zipedit)
+  {
+#ifndef WINDLL
+    if (comment_stream == NULL) {
+#ifndef RISCOS
+      comment_stream = (FILE*)fdopen(fileno(stderr), "r");
+#else
+      comment_stream = stderr;
+#endif
+    }
+    if ((e = malloc(MAXCOM + 1)) == NULL) {
+      ZIPERR(ZE_MEM, "was reading comment lines");
+    }
+    if (noisy && zcomlen)
+    {
+      fputs("current zip file comment is:\n", mesg);
+      fwrite(zcomment, 1, zcomlen, mesg);
+      if (zcomment[zcomlen-1] != '\n')
+        putc('\n', mesg);
+      free((zvoid *)zcomment);
+    }
+    if ((zcomment = malloc(1)) == NULL)
+      ZIPERR(ZE_MEM, "was setting comments to null");
+    zcomment[0] = '\0';
+    if (noisy)
+      fputs("enter new zip file comment (end with .):\n", mesg);
+#if (defined(AMIGA) && (defined(LATTICE)||defined(__SASC)))
+    flushall();  /* tty input/output is out of sync here */
+#endif
+#ifdef __human68k__
+    setmode(fileno(comment_stream), O_TEXT);
+#endif
+#ifdef MACOS
+    printf("\n enter new zip file comment \n");
+    if (fgets(e, MAXCOM+1, comment_stream) != NULL) {
+        if ((p = malloc((k = strlen(e))+1)) == NULL) {
+            free((zvoid *)e);
+            ZIPERR(ZE_MEM, "was reading comment lines");
+        }
+        strcpy(p, e);
+        if (p[k-1] == '\n') p[--k] = 0;
+        zcomment = p;
+    }
+#else /* !MACOS */
+    while (fgets(e, MAXCOM+1, comment_stream) != NULL && strcmp(e, ".\n"))
+    {
+      if (e[(r = strlen(e)) - 1] == '\n')
+        e[--r] = 0;
+      if ((p = malloc((*zcomment ? strlen(zcomment) + 3 : 1) + r)) == NULL)
+      {
+        free((zvoid *)e);
+        ZIPERR(ZE_MEM, "was reading comment lines");
+      }
+      if (*zcomment)
+        strcat(strcat(strcpy(p, zcomment), "\r\n"), e);
+      else
+        strcpy(p, *e ? e : "\r\n");
+      free((zvoid *)zcomment);
+      zcomment = p;
+    }
+#endif /* ?MACOS */
+    free((zvoid *)e);
+#else /* WINDLL */
+    comment(zcomlen);
+    if ((p = malloc(strlen(szCommentBuf)+1)) == NULL) {
+      ZIPERR(ZE_MEM, "was setting comments to null");
+    }
+    if (szCommentBuf[0] != '\0')
+       lstrcpy(p, szCommentBuf);
+    else
+       p[0] = '\0';
+    free((zvoid *)zcomment);
+    GlobalUnlock(hStr);
+    GlobalFree(hStr);
+    zcomment = p;
+#endif /* WINDLL */
+    zcomlen = strlen(zcomment);
+  }
+
+  if (display_globaldots) {
+#ifndef WINDLL
+    putc('\n', mesg);
+#else
+    fprintf(stdout,"%c",'\n');
+#endif
+    mesg_line_started = 0;
+  }
+
+  /* Write central directory and end header to temporary zip */
+  if (show_what_doing) {
+    fprintf(mesg, "sd: Writing central directory\n");
+    fflush(mesg);
+  }
+  diag("writing central directory");
+  k = 0;                        /* keep count for end header */
+  c = tempzn;                   /* get start of central */
+  n = t = 0;
+  for (z = zfiles; z != NULL; z = z->nxt)
+  {
+    if (z->mark || !(diff_mode || filesync)) {
+      if ((r = putcentral(z)) != ZE_OK) {
+        ZIPERR(r, tempzip);
+      }
+      tempzn += 4 + CENHEAD + z->nam + z->cext + z->com;
+      n += z->len;
+      t += z->siz;
+      k++;
+    }
+  }
+
+  if (k == 0)
+    zipwarn("zip file empty", "");
+  if (verbose) {
+    fprintf(mesg, "total bytes=%s, compressed=%s -> %d%% savings\n",
+            zip_fzofft(n, NULL, "u"), zip_fzofft(t, NULL, "u"), percent(n, t));
+    fflush(mesg);
+  }
+  if (logall) {
+    fprintf(logfile, "total bytes=%s, compressed=%s -> %d%% savings\n",
+            zip_fzofft(n, NULL, "u"), zip_fzofft(t, NULL, "u"), percent(n, t));
+    fflush(logfile);
+  }
+  t = tempzn - c;               /* compute length of central */
+  diag("writing end of central directory");
+  if (show_what_doing) {
+    fprintf(mesg, "sd: Writing end of central directory\n");
+    fflush(mesg);
+  }
+
+  if ((r = putend(k, t, c, zcomlen, zcomment)) != ZE_OK) {
+    ZIPERR(r, tempzip);
+  }
+
+  /*
+  tempzf = NULL;
+  */
+  if (fclose(y)) {
+    ZIPERR(d ? ZE_WRITE : ZE_TEMP, tempzip);
+  }
+  y = NULL;
+  if (in_file != NULL) {
+    fclose(in_file);
+    in_file = NULL;
+  }
+  /*
+  if (x != NULL)
+    fclose(x);
+  */
+
+  /* Free some memory before spawning unzip */
+#ifdef USE_ZLIB
+  zl_deflate_free();
+#else
+  lm_free();
+#endif
+#ifdef BZIP2_SUPPORT
+  bz_compress_free();
+#endif
+
+#ifndef WINDLL
+  /* Test new zip file before overwriting old one or removing input files */
+  if (test)
+    check_zipfile(tempzip, argv[0]);
+#endif
+  /* Replace old zip file with new zip file, leaving only the new one */
+  if (strcmp(zipfile, "-") && !d)
+  {
+    diag("replacing old zip file with new zip file");
+    if (show_what_doing) {
+      fprintf(mesg, "sd: Replacing old zip file\n");
+      fflush(mesg);
+    }
+    if ((r = replace(out_path, tempzip)) != ZE_OK)
+    {
+      zipwarn("new zip file left as: ", tempzip);
+      free((zvoid *)tempzip);
+      tempzip = NULL;
+      ZIPERR(r, "was replacing the original zip file");
+    }
+    free((zvoid *)tempzip);
+  }
+  tempzip = NULL;
+  if (zip_attributes && strcmp(zipfile, "-")) {
+    setfileattr(out_path, zip_attributes);
+#ifdef VMS
+    /* If the zip file existed previously, restore its record format: */
+    if (x != NULL)
+      (void)VMSmunch(out_path, RESTORE_RTYPE, NULL);
+#endif
+  }
+  if (strcmp(zipfile, "-")) {
+    if (show_what_doing) {
+      fprintf(mesg, "sd: Setting file type\n");
+      fflush(mesg);
+    }
+
+    set_filetype(out_path);
+  }
+
+#if defined(WIN32)
+  /* All looks good so, if requested, clear the DOS archive bits */
+  if (clear_archive_bits) {
+    if (noisy)
+      zipmessage("Clearing archive bits...", "");
+    for (z = zfiles; z != NULL; z = z->nxt)
+    {
+# ifdef UNICODE_SUPPORT
+      if (z->mark) {
+        if (!no_win32_wide) {
+          if (!ClearArchiveBitW(z->namew)){
+            zipwarn("Could not clear archive bit for: ", z->oname);
+          }
+        } else {
+          if (!ClearArchiveBit(z->name)){
+            zipwarn("Could not clear archive bit for: ", z->oname);
+          }
+        }
+      }
+# else
+      if (!ClearArchiveBit(z->name)){
+        zipwarn("Could not clear archive bit for: ", z->oname);
+      }
+# endif
+    }
+  }
+#endif
+
+  /* finish logfile (it gets closed in freeup() called by finish()) */
+  if (logfile) {
+      struct tm *now;
+      time_t clocktime;
+
+      fprintf(logfile, "\nTotal %ld entries (", files_total);
+      if (good_bytes_so_far != bytes_total) {
+        fprintf(logfile, "planned ");
+        DisplayNumString(logfile, bytes_total);
+        fprintf(logfile, " bytes, actual ");
+        DisplayNumString(logfile, good_bytes_so_far);
+        fprintf(logfile, " bytes)");
+      } else {
+        DisplayNumString(logfile, bytes_total);
+        fprintf(logfile, " bytes)");
+      }
+
+      /* get current time */
+
+      time(&clocktime);
+      now = localtime(&clocktime);
+      fprintf(logfile, "\nDone %s", asctime(now));
+  }
+
+  /* Finish up (process -o, -m, clean up).  Exit code depends on o. */
+#if (!defined(VMS) && !defined(CMS_MVS))
+  free((zvoid *) zipbuf);
+#endif /* !VMS && !CMS_MVS */
+  RETURN(finish(o ? ZE_OPEN : ZE_OK));
+}
diff --git a/zip.h b/zip.h
new file mode 100644 (file)
index 0000000..ba03160
--- /dev/null
+++ b/zip.h
@@ -0,0 +1,1081 @@
+/*
+  zip.h - Zip 3
+
+/---------------------------------------------------------------------/
+
+Info-ZIP Licence
+
+This is version 2007-Mar-4 of the Info-ZIP license.
+The definitive version of this document should be available at
+ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely and
+a copy at http://www.info-zip.org/pub/infozip/license.html.
+
+
+Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+For the purposes of this copyright and license, "Info-ZIP" is defined as
+the following set of individuals:
+
+   Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
+   Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth,
+   Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,
+   David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,
+   Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,
+   Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda,
+   Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren,
+   Rich Wales, Mike White.
+
+This software is provided "as is," without warranty of any kind, express
+or implied.  In no event shall Info-ZIP or its contributors be held liable
+for any direct, indirect, incidental, special or consequential damages
+arising out of the use of or inability to use this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the above disclaimer and the following restrictions:
+
+    1. Redistributions of source code (in whole or in part) must retain
+       the above copyright notice, definition, disclaimer, and this list
+       of conditions.
+
+    2. Redistributions in binary form (compiled executables and libraries)
+       must reproduce the above copyright notice, definition, disclaimer,
+       and this list of conditions in documentation and/or other materials
+       provided with the distribution.  The sole exception to this condition
+       is redistribution of a standard UnZipSFX binary (including SFXWiz) as
+       part of a self-extracting archive; that is permitted without inclusion
+       of this license, as long as the normal SFX banner has not been removed
+       from the binary or disabled.
+
+    3. Altered versions--including, but not limited to, ports to new operating
+       systems, existing ports with new graphical interfaces, versions with
+       modified or added functionality, and dynamic, shared, or static library
+       versions not from Info-ZIP--must be plainly marked as such and must not
+       be misrepresented as being the original source or, if binaries,
+       compiled from the original source.  Such altered versions also must not
+       be misrepresented as being Info-ZIP releases--including, but not
+       limited to, labeling of the altered versions with the names "Info-ZIP"
+       (or any variation thereof, including, but not limited to, different
+       capitalizations), "Pocket UnZip," "WiZ" or "MacZip" without the
+       explicit permission of Info-ZIP.  Such altered versions are further
+       prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP
+       e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP
+       will provide support for the altered versions.
+
+    4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip,"
+       "UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its
+       own source and binary releases.
+
+/---------------------------------------------------------------------/
+
+*/
+
+/*
+ *  zip.h by Mark Adler
+ */
+#ifndef __zip_h
+#define __zip_h 1
+
+#define ZIP   /* for crypt.c:  include zip password functions, not unzip */
+
+/* Types centralized here for easy modification */
+#define local static            /* More meaningful outside functions */
+typedef unsigned char uch;      /* unsigned 8-bit value */
+typedef unsigned short ush;     /* unsigned 16-bit value */
+typedef unsigned long ulg;      /* unsigned 32-bit value */
+
+/* Set up portability */
+#include "tailor.h"
+
+#ifdef USE_ZLIB
+#  include "zlib.h"
+#endif
+
+/* In the utilities, the crc32() function is only used for UNICODE_SUPPORT. */
+#if defined(UTIL) && !defined(UNICODE_SUPPORT)
+#  define CRC_TABLE_ONLY
+#endif
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#ifndef WSIZE
+#  define WSIZE  (0x8000)
+#endif
+/* Maximum window size = 32K. If you are really short of memory, compile
+ * with a smaller WSIZE but this reduces the compression ratio for files
+ * of size > WSIZE. WSIZE must be a power of two in the current implementation.
+ */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST  (WSIZE-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+/* Forget FILENAME_MAX (incorrectly = 14 on some System V) */
+#ifdef DOS
+#  define FNMAX 256
+#else
+#  define FNMAX 1024
+#endif
+
+#ifndef MATCH
+#  define MATCH shmatch         /* Default for pattern matching: UNIX style */
+#endif
+
+/* Structure carrying extended timestamp information */
+typedef struct iztimes {
+   time_t atime;                /* new access time */
+   time_t mtime;                /* new modification time */
+   time_t ctime;                /* new creation time (!= Unix st.ctime) */
+} iztimes;
+
+/* Lengths of headers after signatures in bytes */
+#define LOCHEAD 26
+#define CENHEAD 42
+#define ENDHEAD 18
+#define EC64LOC 16
+#define EC64REC 52
+
+/* Structures for in-memory file information */
+struct zlist {
+  /* See central header in zipfile.c for what vem..off are */
+  /* Do not rearrange these as less than smart coding in zipfile.c
+     in scanzipf_reg() depends on u being set to ver and then stepping
+     through as a byte array.  Ack.  Should be fixed.  5/25/2005 EG */
+  /* All the new read code does not rely on this order.  */
+  ush vem, ver, flg, how;
+  ulg tim, crc;
+  uzoff_t siz, len;             /* zip64 support 08/29/2003 R.Nausedat */
+  /* changed from extent to ush 3/10/2005 EG */
+  ush nam, ext, cext, com;      /* offset of ext must be >= LOCHEAD */
+  ulg dsk;                      /* disk number was ush but now ulg */
+  ush att, lflg;                /* offset of lflg must be >= LOCHEAD */
+  uzoff_t off;
+  ulg atx;
+  char *name;                   /* File name in zip file */
+  char *extra;                  /* Extra field (set only if ext != 0) */
+  char *cextra;                 /* Extra in central (set only if cext != 0) */
+  char *comment;                /* Comment (set only if com != 0) */
+  char *iname;                  /* Internal file name after cleanup (stored in archive) */
+  char *zname;                  /* External version of internal name */
+  char *oname;                  /* Display version of name used in messages */
+#ifdef UNICODE_SUPPORT
+  /* Unicode support */
+  char *uname;                  /* UTF-8 version of iname */
+  /* if uname has chars not in local char set, zuname can be different than zname */
+  char *zuname;                 /* Escaped Unicode zname from uname */
+  char *ouname;                 /* Display version of zuname */
+# ifdef WIN32
+  char *wuname;                 /* Converted back ouname for Win32 */
+  wchar_t *namew;               /* Windows wide character version of name */
+  wchar_t *inamew;              /* Windows wide character version of iname */
+  wchar_t *znamew;              /* Windows wide character version of zname */
+# endif
+#endif
+  int mark;                     /* Marker for files to operate on */
+  int trash;                    /* Marker for files to delete */
+  int current;                  /* Marker for files that are current to what is on OS (filesync) */
+  int dosflag;                  /* Set to force MSDOS file attributes */
+  struct zlist far *nxt;        /* Pointer to next header in list */
+};
+struct flist {
+  char *name;                   /* Raw internal file name */
+  char *iname;                  /* Internal file name after cleanup */
+  char *zname;                  /* External version of internal name */
+  char *oname;                  /* Display version of internal name */
+#ifdef UNICODE_SUPPORT
+  char *uname;                  /* UTF-8 name */
+# ifdef WIN32
+  wchar_t *namew;               /* Windows wide character version of name */
+  wchar_t *inamew;              /* Windows wide character version of iname */
+  wchar_t *znamew;              /* Windows wide character version of zname */
+# endif
+#endif
+  int dosflag;                  /* Set to force MSDOS file attributes */
+  uzoff_t usize;                /* usize from initial scan */
+  struct flist far *far *lst;   /* Pointer to link pointing here */
+  struct flist far *nxt;        /* Link to next name */
+};
+struct plist {
+  char *zname;                  /* External version of internal name */
+  int select;                   /* Selection flag ('i' or 'x') */
+};
+
+/* internal file attribute */
+#define UNKNOWN (-1)
+#define BINARY  0
+#define ASCII   1
+#define __EBCDIC 2
+
+/* extra field definitions */
+#define EF_VMCMS     0x4704   /* VM/CMS Extra Field ID ("G")*/
+#define EF_MVS       0x470f   /* MVS Extra Field ID ("G")   */
+#define EF_IZUNIX    0x5855   /* UNIX Extra Field ID ("UX") */
+#define EF_IZUNIX2   0x7855   /* Info-ZIP's new Unix ("Ux") */
+#define EF_TIME      0x5455   /* universal timestamp ("UT") */
+#define EF_OS2EA     0x0009   /* OS/2 Extra Field ID (extended attributes) */
+#define EF_ACL       0x4C41   /* ACL Extra Field ID (access control list, "AL") */
+#define EF_NTSD      0x4453   /* NT Security Descriptor Extra Field ID, ("SD") */
+#define EF_BEOS      0x6542   /* BeOS Extra Field ID ("Be") */
+#define EF_ATHEOS    0x7441   /* AtheOS Extra Field ID ("At") */
+#define EF_QDOS      0xfb4a   /* SMS/QDOS ("J\373") */
+#define EF_AOSVS     0x5356   /* AOS/VS ("VS") */
+#define EF_SPARK     0x4341   /* David Pilling's Acorn/SparkFS ("AC") */
+#define EF_THEOS     0x6854   /* THEOS ("Th") */
+#define EF_TANDEM    0x4154   /* Tandem NSK ("TA") */
+
+/* Definitions for extra field handling: */
+#define EF_SIZE_MAX  ((unsigned)0xFFFF) /* hard limit of total e.f. length */
+#define EB_HEADSIZE       4     /* length of a extra field block header */
+#define EB_ID             0     /* offset of block ID in header */
+#define EB_LEN            2     /* offset of data length field in header */
+#define EB_MEMCMPR_HSIZ   6     /* header length for memcompressed data */
+#define EB_DEFLAT_EXTRA  10     /* overhead for 64kByte "undeflatable" data */
+
+#define EB_UX_MINLEN      8     /* minimal "UX" field contains atime, mtime */
+#define EB_UX_ATIME       0     /* offset of atime in "UX" extra field data */
+#define EB_UX_MTIME       4     /* offset of mtime in "UX" extra field data */
+
+#define EB_UX_FULLSIZE    12    /* full "UX" field (atime, mtime, uid, gid) */
+#define EB_UX_UID         8     /* byte offset of UID in "UX" field data */
+#define EB_UX_GID         10    /* byte offset of GID in "UX" field data */
+
+#define EB_UT_MINLEN      1     /* minimal UT field contains Flags byte */
+#define EB_UT_FLAGS       0     /* byte offset of Flags field */
+#define EB_UT_TIME1       1     /* byte offset of 1st time value */
+#define EB_UT_FL_MTIME    (1 << 0)      /* mtime present */
+#define EB_UT_FL_ATIME    (1 << 1)      /* atime present */
+#define EB_UT_FL_CTIME    (1 << 2)      /* ctime present */
+#define EB_UT_LEN(n)      (EB_UT_MINLEN + 4 * (n))
+
+#define EB_UX2_MINLEN     4     /* minimal Ux field contains UID/GID */
+#define EB_UX2_UID        0     /* byte offset of UID in "Ux" field data */
+#define EB_UX2_GID        2     /* byte offset of GID in "Ux" field data */
+#define EB_UX2_VALID      (1 << 8)      /* UID/GID present */
+
+/* ASCII definitions for line terminators in text files: */
+#define LF     10        /* '\n' on ASCII machines; must be 10 due to EBCDIC */
+#define CR     13        /* '\r' on ASCII machines; must be 13 due to EBCDIC */
+#define CTRLZ  26        /* DOS & OS/2 EOF marker (used in fileio.c, vms.c) */
+
+/* return codes of password fetches (negative: user abort; positive: error) */
+#define IZ_PW_ENTERED   0       /* got some PWD string, use/try it */
+#define IZ_PW_CANCEL    -1      /* no password available (for this entry) */
+#define IZ_PW_CANCELALL -2      /* no password, skip any further PWD request */
+#define IZ_PW_ERROR     5       /* = PK_MEM2 : failure (no mem, no tty, ...) */
+#define IZ_PW_SKIPVERIFY IZ_PW_CANCEL   /* skip encrypt. passwd verification */
+
+/* mode flag values of password prompting function */
+#define ZP_PW_ENTER     0       /* request for encryption password */
+#define ZP_PW_VERIFY    1       /* request for reentering password */
+
+/* Error return codes and PERR macro */
+#include "ziperr.h"
+
+#if 0            /* Optimization: use the (const) result of crc32(0L,NULL,0) */
+#  define CRCVAL_INITIAL  crc32(0L, (uch *)NULL, 0)
+# if 00 /* not used, should be removed !! */
+#  define ADLERVAL_INITIAL adler16(0U, (uch *)NULL, 0)
+# endif /* 00 */
+#else
+#  define CRCVAL_INITIAL  0L
+# if 00 /* not used, should be removed !! */
+#  define ADLERVAL_INITIAL 1
+# endif /* 00 */
+#endif
+
+#define DOSTIME_MINIMUM         ((ulg)0x00210000L)
+#define DOSTIME_2038_01_18      ((ulg)0x74320000L)
+
+
+/* Public globals */
+extern uch upper[256];          /* Country dependent case map table */
+extern uch lower[256];
+#ifdef EBCDIC
+extern ZCONST uch ascii[256];   /* EBCDIC <--> ASCII translation tables */
+extern ZCONST uch ebcdic[256];
+#endif /* EBCDIC */
+#if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB))
+  extern ZCONST ulg near *crc_32_tab;
+#else
+  extern ZCONST ulg Far *crc_32_tab;
+#endif
+
+/* Are these ever used?  6/12/05 EG */
+#ifdef IZ_ISO2OEM_ARRAY         /* ISO 8859-1 (Win CP 1252) --> OEM CP 850 */
+extern ZCONST uch Far iso2oem[128];
+#endif
+#ifdef IZ_OEM2ISO_ARRAY         /* OEM CP 850 --> ISO 8859-1 (Win CP 1252) */
+extern ZCONST uch Far oem2iso[128];
+#endif
+
+extern char errbuf[FNMAX+4081]; /* Handy place to build error messages */
+extern int recurse;             /* Recurse into directories encountered */
+extern int dispose;             /* Remove files after put in zip file */
+extern int pathput;             /* Store path with name */
+
+#ifdef RISCOS
+extern int scanimage;           /* Scan through image files */
+#endif
+
+#define BEST -1                 /* Use best method (deflation or store) */
+#define STORE 0                 /* Store method */
+#define DEFLATE 8               /* Deflation method*/
+#define BZIP2 12                /* BZIP2 method */
+#ifdef BZIP2_SUPPORT
+#define LAST_KNOWN_COMPMETHOD   BZIP2
+#else
+#define LAST_KNOWN_COMPMETHOD   DEFLATE
+#endif
+
+extern int method;              /* Restriction on compression method */
+
+extern ulg skip_this_disk;
+extern int des_good;            /* Good data descriptor found */
+extern ulg des_crc;             /* Data descriptor CRC */
+extern uzoff_t des_csize;       /* Data descriptor csize */
+extern uzoff_t des_usize;       /* Data descriptor usize */
+extern int dosify;              /* Make new entries look like MSDOS */
+extern char *special;           /* Don't compress special suffixes */
+extern int verbose;             /* Report oddities in zip file structure */
+extern int fix;                 /* Fix the zip file */
+extern int filesync;            /* 1=file sync, delete entries not on file system */
+extern int adjust;              /* Adjust the unzipsfx'd zip file */
+extern int level;               /* Compression level */
+extern int translate_eol;       /* Translate end-of-line LF -> CR LF */
+#ifdef VMS
+   extern int vmsver;           /* Append VMS version number to file names */
+   extern int vms_native;       /* Store in VMS format */
+   extern int vms_case_2;       /* ODS2 file name case in VMS. -1: down. */
+   extern int vms_case_5;       /* ODS5 file name case in VMS. +1: preserve. */
+
+/* Accomodation for /NAMES = AS_IS with old header files. */
+# define cma$tis_errno_get_addr CMA$TIS_ERRNO_GET_ADDR
+# define lib$establish LIB$ESTABLISH
+# define lib$get_foreign LIB$GET_FOREIGN
+# define lib$get_input LIB$GET_INPUT
+# define lib$sig_to_ret LIB$SIG_TO_RET
+# define ots$cvt_tu_l OTS$CVT_TU_L
+# define str$concat STR$CONCAT
+# define str$find_first_substring STR$FIND_FIRST_SUBSTRING
+# define str$free1_dx STR$FREE1_DX
+# define sys$asctim SYS$ASCTIM
+# define sys$assign SYS$ASSIGN
+# define sys$bintim SYS$BINTIM
+# define sys$close SYS$CLOSE
+# define sys$connect SYS$CONNECT
+# define sys$dassgn SYS$DASSGN
+# define sys$display SYS$DISPLAY
+# define sys$getjpiw SYS$GETJPIW
+# define sys$open SYS$OPEN
+# define sys$parse SYS$PARSE
+# define sys$qiow SYS$QIOW
+# define sys$read SYS$READ
+# define sys$search SYS$SEARCH
+#endif /* VMS */
+#if defined(OS2) || defined(WIN32)
+   extern int use_longname_ea;   /* use the .LONGNAME EA as the file's name */
+#endif
+#if defined (QDOS) || defined(QLZIP)
+extern short qlflag;
+#endif
+/* 9/26/04 EG */
+extern int no_wild;             /* wildcards are disabled */
+extern int allow_regex;         /* 1 = allow [list] matching (regex) */
+extern int wild_stop_at_dir;    /* wildcards do not include / in matches */
+#ifdef UNICODE_SUPPORT
+  extern int using_utf8;        /* 1 if current character set is UTF-8 */
+# ifdef WIN32
+   extern int no_win32_wide;    /* 1 = no wide functions, like GetFileAttributesW() */
+# endif
+#endif
+/* 10/20/04 */
+extern zoff_t dot_size;         /* if not 0 then display dots every size buffers */
+extern zoff_t dot_count;        /* if dot_size not 0 counts buffers */
+/* status 10/30/04 */
+extern int display_counts;      /* display running file count */
+extern int display_bytes;       /* display running bytes remaining */
+extern int display_globaldots;  /* display dots for archive instead of for each file */
+extern int display_volume;      /* display current input and output volume (disk) numbers */
+extern int display_usize;       /* display uncompressed bytes */
+extern ulg files_so_far;        /* files processed so far */
+extern ulg bad_files_so_far;    /* files skipped so far */
+extern ulg files_total;         /* files total to process */
+extern uzoff_t bytes_so_far;    /* bytes processed so far (from initial scan) */
+extern uzoff_t good_bytes_so_far;/* good bytes read so far */
+extern uzoff_t bad_bytes_so_far;/* bad bytes skipped so far */
+extern uzoff_t bytes_total;     /* total bytes to process (from initial scan) */
+/* logfile 6/5/05 */
+extern int logall;          /* 0 = warnings/errors, 1 = all */
+extern FILE *logfile;           /* pointer to open logfile or NULL */
+extern int logfile_append;      /* append to existing logfile */
+extern char *logfile_path;      /* pointer to path of logfile */
+#ifdef WIN32
+extern int nonlocal_name;       /* Name has non-local characters */
+extern int nonlocal_path;       /* Path has non-local characters */
+#endif
+#ifdef UNICODE_SUPPORT
+/* Unicode 10/12/05 */
+extern int use_wide_to_mb_default;/* use the default MB char instead of escape */
+#endif
+
+extern int hidden_files;        /* process hidden and system files */
+extern int volume_label;        /* add volume label */
+extern int dirnames;            /* include directory names */
+extern int filter_match_case;   /* 1=match case when filter() */
+extern int diff_mode;           /* 1=require --out and only store changed and add */
+#if defined(WIN32)
+extern int only_archive_set;    /* only include if DOS archive bit set */
+extern int clear_archive_bits;   /* clear DOS archive bit of included files */
+#endif
+extern int linkput;             /* Store symbolic links as such */
+extern int noisy;               /* False for quiet operation */
+extern int extra_fields;        /* 0=create minimum, 1=don't copy old, 2=keep old */
+#ifdef NTSD_EAS
+ extern int use_privileges;     /* use security privilege overrides */
+#endif
+extern int use_descriptors;     /* use data descriptors (extended headings) */
+extern int allow_empty_archive; /* if no files, create empty archive anyway */
+extern int copy_only;           /* 1 = copy archive with no changes */
+extern int zip_to_stdout;       /* output to stdout */
+extern int output_seekable;     /* 1 = output seekable 3/13/05 EG */
+#ifdef ZIP64_SUPPORT            /* zip64 globals 10/4/03 E. Gordon */
+ extern int force_zip64;        /* force use of zip64 when streaming from stdin */
+ extern int zip64_entry;        /* current entry needs Zip64 */
+ extern int zip64_archive;      /* at least 1 entry needs zip64 */
+#endif
+extern int allow_fifo;          /* Allow reading Unix FIFOs, waiting if pipe open */
+extern int show_files;          /* show files to operate on and exit (=2 log only) */
+
+extern char *tempzip;           /* temp file name */
+extern FILE *y;                 /* output file now global for splits */
+
+#ifdef UNICODE_SUPPORT
+  extern int utf8_force;         /* 1=store UTF-8 as standard per AppNote bit 11 */
+#endif
+extern int unicode_escape_all;  /* 1=escape all non-ASCII characters in paths */
+extern int unicode_mismatch;    /* unicode mismatch is 0=error, 1=warn, 2=ignore, 3=no */
+
+extern time_t scan_delay;       /* seconds before display Scanning files message */
+extern time_t scan_dot_time;    /* time in seconds between Scanning files dots */
+extern time_t scan_start;       /* start of file scan */
+extern time_t scan_last;        /* time of last message */
+extern int scan_started;        /* scan has started */
+extern uzoff_t scan_count;      /* Used for "Scanning files..." message */
+
+extern ulg before;              /* 0=ignore, else exclude files before this time */
+extern ulg after;               /* 0=ignore, else exclude files newer than this time */
+
+/* in split globals */
+
+extern ulg total_disks;
+
+extern ulg current_in_disk;
+extern uzoff_t current_in_offset;
+extern ulg skip_current_disk;
+
+
+/* out split globals */
+
+extern ulg    current_local_disk; /* disk with current local header */
+
+extern ulg     current_disk;     /* current disk number */
+extern ulg     cd_start_disk;    /* central directory start disk */
+extern uzoff_t cd_start_offset;  /* offset of start of cd on cd start disk */
+extern uzoff_t cd_entries_this_disk; /* cd entries this disk */
+extern uzoff_t total_cd_entries; /* total cd entries in new/updated archive */
+extern ulg     zip64_eocd_disk;  /* disk with Zip64 EOCD Record */
+extern uzoff_t zip64_eocd_offset; /* offset of Zip64 EOCD Record */
+/* for split method 1 (keep split with local header open and update) */
+extern char *current_local_tempname; /* name of temp file */
+extern FILE  *current_local_file; /* file pointer for current local header */
+extern uzoff_t current_local_offset; /* offset to start of current local header */
+/* global */
+extern uzoff_t bytes_this_split; /* bytes written to current split */
+extern int read_split_archive;   /* 1=scanzipf_reg detected spanning signature */
+extern int split_method;         /* 0=no splits, 1=seekable, 2=data descs, -1=no */
+extern uzoff_t split_size;       /* how big each split should be */
+extern int split_bell;           /* when pause for next split ring bell */
+extern uzoff_t bytes_prev_splits; /* total bytes written to all splits before this */
+extern uzoff_t bytes_this_entry; /* bytes written for this entry across all splits */
+extern int noisy_splits;         /* note when splits are being created */
+extern int mesg_line_started;    /* 1=started writing a line to mesg */
+extern int logfile_line_started; /* 1=started writing a line to logfile */
+extern char *key;               /* Scramble password or NULL */
+extern char *tempath;           /* Path for temporary files */
+extern FILE *mesg;              /* Where informational output goes */
+extern char *zipfile;           /* New or existing zip archive (zip file) */
+extern FILE *in_file;           /* Current input file for spits */
+extern char *in_path;           /* Name of input archive, used to track reading splits */
+extern char *in_split_path;     /* in split path */
+extern char *out_path;          /* Name of output file, usually same as zipfile */
+extern int zip_attributes;
+
+/* zip64 support 08/31/2003 R.Nausedat */
+extern uzoff_t zipbeg;          /* Starting offset of zip structures */
+extern uzoff_t cenbeg;          /* Starting offset of central directory */
+extern uzoff_t tempzn;          /* Count of bytes written to output zip file */
+
+/* NOTE: zcount and fcount cannot exceed "size_t" (resp. "extent") range.
+   This is an internal limitation built into Zip's action handling:
+   Zip keeps "{z|f}count * struct {z|f}list" arrays in (flat) memory,
+   for sorting, file matching, and building the central-dir structures.
+ */
+
+extern struct zlist far *zfiles;/* Pointer to list of files in zip file */
+extern extent zcount;           /* Number of files in zip file */
+extern int zipfile_exists;      /* 1 if zipfile exists */
+extern ush zcomlen;             /* Length of zip file comment */
+extern char *zcomment;          /* Zip file comment (not zero-terminated) */
+extern struct flist far **fsort;/* List of files sorted by name */
+extern struct zlist far **zsort;/* List of files sorted by name */
+#ifdef UNICODE_SUPPORT
+extern struct zlist far **zusort;/* List of files sorted by zuname */
+#endif
+extern struct flist far *found; /* List of names found */
+extern struct flist far *far *fnxt;     /* Where to put next in found list */
+extern extent fcount;           /* Count of names in found list */
+
+extern struct plist *patterns;  /* List of patterns to be matched */
+extern unsigned pcount;         /* number of patterns */
+extern unsigned icount;         /* number of include only patterns */
+extern unsigned Rcount;         /* number of -R include patterns */
+
+#ifdef IZ_CHECK_TZ
+extern int zp_tz_is_valid;      /* signals "timezone info is available" */
+#endif
+#if (defined(MACOS) || defined(WINDLL))
+extern int zipstate;            /* flag "zipfile has been stat()'ed */
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# ifdef MSDOS
+#  undef  stderr
+#  define stderr stdout
+# endif
+#  define diag(where) fprintf(stderr, "zip diagnostic: %s\n", where)
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+# ifdef THEOS
+#  define Trace(x) _fprintf x
+#  define Tracev(x) {if (verbose) _fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) _fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) _fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) _fprintf x ;}
+# else
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+# endif
+#else
+#  define diag(where)
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+#ifdef DEBUGNAMES
+#  define free(x) { int *v;Free(x); v=x;*v=0xdeadbeef;x=(void *)0xdeadbeef; }
+#endif
+
+/* Public function prototypes */
+
+#ifndef UTIL
+#ifdef USE_ZIPMAIN
+int zipmain OF((int, char **));
+#else
+int main OF((int, char **));
+#endif /* USE_ZIPMAIN */
+#endif
+
+#ifdef EBCDIC
+extern int aflag;
+#endif /* EBCDIC */
+#ifdef CMS_MVS
+extern int bflag;
+#endif /* CMS_MVS */
+void zipmessage_nl OF((ZCONST char *, int));
+void zipmessage OF((ZCONST char *, ZCONST char *));
+void zipwarn OF((ZCONST char *, ZCONST char *));
+void ziperr OF((int, ZCONST char *));
+#ifdef UTIL
+#  define error(msg)    ziperr(ZE_LOGIC, msg)
+#else
+   void error OF((ZCONST char *));
+#  ifdef VMSCLI
+     void help OF((void));
+#  endif
+   int encr_passwd OF((int, char *, int, ZCONST char *));
+#endif
+
+        /* in zipup.c */
+#ifndef UTIL
+  /* zip64 support 08/31/2003 R.Nausedat */
+   int percent OF((uzoff_t, uzoff_t));
+
+   int zipup OF((struct zlist far *));
+#  ifdef USE_ZLIB
+     void zl_deflate_free OF((void));
+#  else
+     void flush_outbuf OF((char *, unsigned *));
+     int seekable OF((void));
+     extern unsigned (*read_buf) OF((char *, unsigned int));
+#  endif /* !USE_ZLIB */
+#  ifdef ZP_NEED_MEMCOMPR
+     ulg memcompress OF((char *, ulg, char *, ulg));
+#  endif
+#  ifdef BZIP2_SUPPORT
+   void bz_compress_free OF((void));
+#  endif
+#endif /* !UTIL */
+
+        /* in zipfile.c */
+#ifndef UTIL
+   struct zlist far *zsearch OF((ZCONST char *));
+#  ifdef USE_EF_UT_TIME
+     int get_ef_ut_ztime OF((struct zlist far *, iztimes *));
+#  endif /* USE_EF_UT_TIME */
+   int trash OF((void));
+#endif /* !UTIL */
+char *ziptyp OF((char *));
+int readzipfile OF((void));
+int putlocal OF((struct zlist far *, int));
+int putextended OF((struct zlist far *));
+int putcentral OF((struct zlist far *));
+/* zip64 support 09/05/2003 R.Nausedat */
+int putend OF((uzoff_t, uzoff_t, uzoff_t, extent, char *));
+/* moved seekable to separate function 3/14/05 EG */
+int is_seekable OF((FILE *));
+int zipcopy OF((struct zlist far *));
+int readlocal OF((struct zlist far **, struct zlist far *));
+/* made global for handling extra fields */
+char *get_extra_field OF((ush, char *, unsigned));
+char *copy_nondup_extra_fields OF((char *, unsigned, char *, unsigned, unsigned *));
+
+        /* in fileio.c */
+#ifndef UTIL
+   char *getnam OF((FILE *));
+   struct flist far *fexpel OF((struct flist far *));
+   char *last OF((char *, int));
+# ifdef UNICODE_SUPPORT
+   wchar_t *lastw OF((wchar_t *, wchar_t));
+# endif
+   char *msname OF((char *));
+# ifdef UNICODE_SUPPORT
+   wchar_t *msnamew OF((wchar_t *));
+# endif
+   int check_dup OF((void));
+   int filter OF((char *, int));
+   int newname OF((char *, int, int));
+# ifdef UNICODE_SUPPORT
+#  ifdef WIN32
+   int newnamew OF((wchar_t *, int, int));
+#  endif
+# endif
+   /* used by copy mode */
+   int proc_archive_name OF((char *, int));
+#endif /* !UTIL */
+#if (!defined(UTIL) || defined(W32_STATROOT_FIX))
+   time_t dos2unixtime OF((ulg));
+#endif
+#ifndef UTIL
+   ulg dostime OF((int, int, int, int, int, int));
+   ulg unix2dostime OF((time_t *));
+   int issymlnk OF((ulg a));
+#  ifdef S_IFLNK
+#    define rdsymlnk(p,b,n) readlink(p,b,n)
+/*   extern int readlink OF((char *, char *, int)); */
+#  else /* !S_IFLNK */
+#    define rdsymlnk(p,b,n) (0)
+#  endif /* !S_IFLNK */
+#endif /* !UTIL */
+
+int destroy OF((char *));
+int replace OF((char *, char *));
+int getfileattr OF((char *));
+int setfileattr OF((char *, int));
+char *tempname OF((char *));
+
+/* for splits */
+int close_split OF((ulg, FILE *, char *));
+int ask_for_split_read_path OF((ulg));
+int ask_for_split_write_path OF((ulg));
+char *get_in_split_path OF((char *, ulg));
+char *find_in_split_path OF((char *, ulg));
+char *get_out_split_path OF((char *, ulg));
+int rename_split OF((char *, char *));
+int set_filetype OF((char *));
+
+int bfcopy OF((uzoff_t));
+
+int fcopy OF((FILE *, FILE *, uzoff_t));
+
+#ifdef ZMEM
+   char *memset OF((char *, int, unsigned int));
+   char *memcpy OF((char *, char *, unsigned int));
+   int memcmp OF((char *, char *, unsigned int));
+#endif /* ZMEM */
+
+        /* in system dependent fileio code (<system>.c) */
+#ifndef UTIL
+# ifdef PROCNAME
+   int wild OF((char *));
+# endif
+   char *in2ex OF((char *));
+   char *ex2in OF((char *, int, int *));
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+   int has_win32_wide OF((void));
+   wchar_t *in2exw OF((wchar_t *));
+   wchar_t *ex2inw OF((wchar_t *, int, int *));
+   int procnamew OF((wchar_t *, int));
+#endif
+   int procname OF((char *, int));
+   void stamp OF((char *, ulg));
+
+   ulg filetime OF((char *, ulg *, zoff_t *, iztimes *));
+   /* Windows Unicode */
+# ifdef UNICODE_SUPPORT
+# ifdef WIN32
+   ulg filetimew OF((wchar_t *, ulg *, zoff_t *, iztimes *));
+   char *get_win32_utf8path OF((char *));
+   wchar_t *local_to_wchar_string OF ((char *));
+# endif
+# endif
+
+# if !(defined(VMS) && defined(VMS_PK_EXTRA))
+   int set_extra_field OF((struct zlist far *, iztimes *));
+# endif /* ?(VMS && VMS_PK_EXTRA) */
+   int deletedir OF((char *));
+# ifdef MY_ZCALLOC
+     zvoid far *zcalloc OF((unsigned int, unsigned int));
+     zvoid zcfree       OF((zvoid far *));
+# endif /* MY_ZCALLOC */
+#endif /* !UTIL */
+void version_local OF((void));
+
+        /* in util.c */
+#ifndef UTIL
+int   fseekable    OF((FILE *));
+char *isshexp      OF((char *));
+#ifdef UNICODE_SUPPORT
+# ifdef WIN32
+   wchar_t *isshexpw     OF((wchar_t *));
+   int dosmatchw   OF((ZCONST wchar_t *, ZCONST wchar_t *, int));
+# endif
+#endif
+int   shmatch      OF((ZCONST char *, ZCONST char *, int));
+# if defined(DOS) || defined(WIN32)
+   int dosmatch    OF((ZCONST char *, ZCONST char *, int));
+# endif /* DOS || WIN32 */
+#endif /* !UTIL */
+
+/* functions to convert zoff_t to a string */
+char *zip_fuzofft      OF((uzoff_t, char *, char*));
+char *zip_fzofft       OF((zoff_t, char *, char*));
+
+/* read and write number strings like 10M */
+int DisplayNumString OF ((FILE *file, uzoff_t i));
+int WriteNumString OF((uzoff_t num, char *outstring));
+uzoff_t ReadNumString OF((char *numstring));
+
+/* returns true if abbrev is abbreviation for string */
+int abbrevmatch OF((char *, char *, int, int));
+
+void init_upper    OF((void));
+int  namecmp       OF((ZCONST char *string1, ZCONST char *string2));
+
+#ifdef EBCDIC
+  char *strtoasc     OF((char *str1, ZCONST char *str2));
+  char *strtoebc     OF((char *str1, ZCONST char *str2));
+  char *memtoasc     OF((char *mem1, ZCONST char *mem2, unsigned len));
+  char *memtoebc     OF((char *mem1, ZCONST char *mem2, unsigned len));
+#endif /* EBCDIC */
+#ifdef IZ_ISO2OEM_ARRAY
+  char *str_iso_to_oem    OF((char *dst, ZCONST char *src));
+#endif
+#ifdef IZ_OEM2ISO_ARRAY
+  char *str_oem_to_iso    OF((char *dst, ZCONST char *src));
+#endif
+
+zvoid far **search OF((ZCONST zvoid *, ZCONST zvoid far **, extent,
+                       int (*)(ZCONST zvoid *, ZCONST zvoid far *)));
+void envargs       OF((int *, char ***, char *, char *));
+void expand_args   OF((int *, char ***));
+
+int  is_text_buf   OF((ZCONST char *buf_ptr, unsigned buf_size));
+/* this is no longer used ...
+unsigned int adler16 OF((unsigned int, ZCONST uch *, extent));
+*/
+        /*  crc functions are now declared in crc32.h */
+
+#ifndef UTIL
+#ifndef USE_ZLIB
+        /* in deflate.c */
+void lm_init OF((int, ush *));
+void lm_free OF((void));
+
+uzoff_t deflate OF((void));
+
+        /* in trees.c */
+void     ct_init      OF((ush *, int *));
+int      ct_tally     OF((int, int));
+uzoff_t  flush_block  OF((char far *, ulg, int));
+void     bi_init      OF((char *, unsigned int, int));
+#endif /* !USE_ZLIB */
+#endif /* !UTIL */
+
+        /* in system specific assembler code, replacing C code in trees.c */
+#if defined(ASMV) && defined(RISCOS)
+  void     send_bits    OF((int, int));
+  unsigned bi_reverse   OF((unsigned int, int));
+#endif /* ASMV && RISCOS */
+
+/*---------------------------------------------------------------------------
+    VMS-only functions:
+  ---------------------------------------------------------------------------*/
+#ifdef VMS
+   int    vms_stat        OF((char *, stat_t *));              /* vms.c */
+   void   vms_exit        OF((int));                           /* vms.c */
+#ifndef UTIL
+#ifdef VMSCLI
+   ulg    vms_zip_cmdline OF((int *, char ***));                /* cmdline.c */
+   void   VMSCLI_help     OF((void));                           /* cmdline.c */
+#endif /* VMSCLI */
+#endif /* !UTIL */
+#endif /* VMS */
+
+/*
+#ifdef ZIP64_SUPPORT
+   update_local_Zip64_extra_field OF((struct zlist far *, FILE *));
+#endif
+*/
+
+/*---------------------------------------------------------------------------
+    WIN32-only functions:
+  ---------------------------------------------------------------------------*/
+#ifdef WIN32
+   int ZipIsWinNT         OF((void));                         /* win32.c */
+   int ClearArchiveBit    OF((char *));                       /* win32.c */
+# ifdef UNICODE_SUPPORT
+   int ClearArchiveBitW   OF((wchar_t *));                    /* win32.c */
+# endif
+#endif /* WIN32 */
+
+#if (defined(WINDLL) || defined(DLL_ZIPAPI))
+/*---------------------------------------------------------------------------
+    Prototypes for public Zip API (DLL) functions.
+  ---------------------------------------------------------------------------*/
+#include "api.h"
+#endif /* WINDLL || DLL_ZIPAPI */
+
+
+   /* WIN32_OEM */
+#ifdef WIN32
+/*
+# if defined(UNICODE_SUPPORT) || defined(WIN32_OEM)
+*/
+  /* convert oem to ansi string */
+  char *oem_to_local_string OF((char *, char *));
+/*
+# endif
+*/
+#endif
+
+#ifdef WIN32
+/*
+# if defined(UNICODE_SUPPORT) || defined(WIN32_OEM)
+*/
+  /* convert local string to oem string */
+  char *local_to_oem_string OF((char *, char *));
+/*
+# endif
+*/
+#endif
+
+
+
+/*---------------------------------------------------------------------
+    Unicode Support
+    28 August 2005
+  ---------------------------------------------------------------------*/
+#ifdef UNICODE_SUPPORT
+
+  /* Default character when a zwchar too big for wchar_t */
+# define zwchar_to_wchar_t_default_char '_'
+
+  /* Default character string when wchar_t does not convert to mb */
+# define wide_to_mb_default_string "_"
+
+  /* wide character type */
+  typedef unsigned long zwchar;
+
+  /* check if string is all ASCII */
+  int is_ascii_string OF((char *));
+#ifdef WIN32
+  int is_ascii_stringw OF((wchar_t *));
+  zwchar *wchar_to_wide_string OF((wchar_t *));
+#endif
+
+  /* convert UTF-8 string to multi-byte string */
+  char *utf8_to_local_string OF((char *));
+  char *utf8_to_escape_string OF((char *));
+
+  /* convert UTF-8 string to wide string */
+  zwchar *utf8_to_wide_string OF((char *));
+
+  /* convert wide string to multi-byte string */
+  char *wide_to_local_string OF((zwchar *));
+  char *wide_to_escape_string OF((zwchar *));
+  char *local_to_escape_string OF((char *));
+#ifdef WIN32
+  /* convert UTF-8 to wchar */
+  wchar_t *utf8_to_wchar_string OF ((char *));
+
+  char *wchar_to_local_string OF((wchar_t *));
+#endif
+
+  /* convert local string to multi-byte display string */
+  char *local_to_display_string OF((char *));
+
+  /* convert wide character to escape string */
+  char *wide_char_to_escape_string OF((unsigned long));
+
+#if 0
+  /* convert escape string to wide character */
+  unsigned long escape_string_to_wide OF((char *));
+#endif
+
+  /* convert local to UTF-8 */
+  char *local_to_utf8_string OF ((char *));
+
+  /* convert local to wide string */
+  zwchar *local_to_wide_string OF ((char *));
+
+  /* convert wide string to UTF-8 */
+  char *wide_to_utf8_string OF((zwchar *));
+#ifdef WIN32
+  char *wchar_to_utf8_string OF((wchar_t *));
+#endif
+
+#endif /* UNICODE_SUPPORT */
+
+
+/*---------------------------------------------------
+ * Split archives
+ *
+ * 10/20/05 EG
+ */
+
+#define BFWRITE_DATA 0
+#define BFWRITE_LOCALHEADER 1
+#define BFWRITE_CENTRALHEADER 2
+#define BFWRITE_HEADER 3 /* data descriptor or end records */
+
+size_t bfwrite OF((ZCONST void *buffer, size_t size, size_t count,
+                   int));
+
+/* for putlocal() */
+#define PUTLOCAL_WRITE 0
+#define PUTLOCAL_REWRITE 1
+
+
+/*--------------------------------------------------------------------
+    Long option support
+    23 August 2003
+    See fileio.c
+  --------------------------------------------------------------------*/
+
+/* The below is for use in the caller-provided options table */
+
+/* value_type - value is always returned as a string. */
+#define o_NO_VALUE        0   /* this option does not take a value */
+#define o_REQUIRED_VALUE  1   /* this option requires a value */
+#define o_OPTIONAL_VALUE  2   /* value is optional (see get_option() for details) */
+#define o_VALUE_LIST      3   /* this option takes a list of values */
+#define o_ONE_CHAR_VALUE  4   /* next char is value (does not end short opt string) */
+#define o_NUMBER_VALUE    5   /* value is integer (does not end short opt string) */
+
+
+/* negatable - a dash following the option (but before any value) sets negated. */
+#define o_NOT_NEGATABLE   0   /* trailing '-' to negate either starts value or generates error */
+#define o_NEGATABLE       1   /* trailing '-' sets negated to TRUE */
+
+
+/* option_num can be this when option not in options table */
+#define o_NO_OPTION_MATCH     -1
+
+/* special values returned by get_option - do not use these as option IDs */
+#define o_NON_OPTION_ARG      ((unsigned long) 0xFFFF)    /* returned for non-option
+                                                             args */
+#define o_ARG_FILE_ERR        ((unsigned long) 0xFFFE)    /* internal recursion
+                                                             return (user never sees) */
+
+/* options array is set in zip.c */
+struct option_struct {
+  char *shortopt;           /* char * to sequence of char that is short option */
+  char Far *longopt;        /* char * to long option string */
+  int  value_type;          /* from above */
+  int  negatable;           /* from above */
+  unsigned long option_ID;  /* value returned by get_option when this option is found */
+  char Far *name;           /* optional string for option returned on some errors */
+};
+extern struct option_struct far options[];
+
+
+/* moved here from fileio.c to make global - 10/6/05 EG */
+
+/* If will support wide for Unicode then need to add */
+  /* multi-byte */
+#ifdef _MBCS
+# ifndef MULTIBYTE_GETOPTNS
+#   define MULTIBYTE_GETOPTNS
+# endif
+#endif
+#ifdef MULTIBYTE_GETOPTNS
+  int mb_clen OF((ZCONST char *));
+# define MB_CLEN(ptr) mb_clen(ptr)
+# define MB_NEXTCHAR(ptr) ((ptr) += MB_CLEN(ptr))
+#else
+  /* no multi-byte */
+# define MB_CLEN(ptr) (1)
+# define MB_NEXTCHAR(ptr) ((ptr)++)
+#endif
+
+
+/* function prototypes */
+
+/* get the next option from args */
+unsigned long get_option OF((char ***pargs, int *argc, int *argnum, int *optchar,
+                             char **value, int *negated, int *first_nonopt_arg,
+                             int *option_num, int recursion_depth));
+
+/* copy args - copy an args array, allocating space as needed */
+char **copy_args OF((char **args, int max_args));
+
+/* free args - free args created with one of these functions */
+int free_args OF ((char **args));
+
+/* insert arg - copy an arg into args */
+int insert_arg OF ((char ***args, ZCONST char *arg, int insert_at,
+                    int free_args));
+
+
+/*--------------------------------------------------------------------
+    End of Long option support
+  --------------------------------------------------------------------*/
+
+
+#endif /* !__zip_h */
+/* end of zip.h */
diff --git a/zip.txt b/zip.txt
new file mode 100644 (file)
index 0000000..85f89b5
--- /dev/null
+++ b/zip.txt
@@ -0,0 +1,2027 @@
+ZIP(1L)                                                                ZIP(1L)
+
+NAME
+       zip - package and compress (archive) files
+
+SYNOPSIS
+       zip  [-aABcdDeEfFghjklLmoqrRSTuvVwXyz!@$] [--longoption ...]  [-b path]
+       [-n suffixes] [-t date] [-tt date] [zipfile [file ...]]  [-xi list]
+
+       zipcloak (see separate man page)
+
+       zipnote (see separate man page)
+
+       zipsplit (see separate man page)
+
+       Note:  Command line processing in zip has been changed to support  long
+       options  and  handle all options and arguments more consistently.  Some
+       old command lines that depend on command line  inconsistencies  may  no
+       longer work.
+
+DESCRIPTION
+       zip  is  a compression and file packaging utility for Unix, VMS, MSDOS,
+       OS/2, Windows 9x/NT/XP, Minix, Atari, Macintosh, Amiga, and Acorn  RISC
+       OS.   It  is analogous to a combination of the Unix commands tar(1) and
+       compress(1) and is compatible with PKZIP (Phil  Katz's  ZIP  for  MSDOS
+       systems).
+
+       A  companion  program  (unzip(1L))  unpacks  zip archives.  The zip and
+       unzip(1L) programs can work with archives produced by PKZIP (supporting
+       most PKZIP features up to PKZIP version 4.6), and PKZIP and PKUNZIP can
+       work with archives produced  by  zip  (with  some  exceptions,  notably
+       streamed  archives,  but  recent  changes  in the zip file standard may
+       facilitate better compatibility).  zip version 3.0 is  compatible  with
+       PKZIP  2.04  and  also supports the Zip64 extensions of PKZIP 4.5 which
+       allow archives as well as files to exceed the previous 2 GB limit (4 GB
+       in  some  cases).  zip also now supports bzip2 compression if the bzip2
+       library is included when zip is compiled.  Note that PKUNZIP 1.10  can-
+       not extract files produced by PKZIP 2.04 or zip 3.0. You must use PKUN-
+       ZIP 2.04g or unzip 5.0p1 (or later versions) to extract them.
+
+       See the EXAMPLES section at the bottom of this  page  for  examples  of
+       some typical uses of zip.
+
+       Large Archives and Zip64.   zip automatically uses the Zip64 extensions
+       when files larger than 4 GB are added to an archive,  an  archive  con-
+       taining  Zip64 entries is updated (if the resulting archive still needs
+       Zip64), the size of the archive will exceed 4 GB, or when the number of
+       entries  in  the archive will exceed about 64K.  Zip64 is also used for
+       archives streamed from standard input as the size of such archives  are
+       not  known  in advance, but the option -fz- can be used to force zip to
+       create PKZIP 2 compatible archives (as long as Zip64 extensions are not
+       needed).   You must use a PKZIP 4.5 compatible unzip, such as unzip 6.0
+       or later, to extract files using the Zip64 extensions.
+
+       In addition, streamed archives, entries encrypted with standard encryp-
+       tion,  or  split archives created with the pause option may not be com-
+       patible with PKZIP as data descriptors are used and PKZIP at  the  time
+       of  this  writing does not support data descriptors (but recent changes
+       in the PKWare published zip standard now include some support  for  the
+       data descriptor format zip uses).
+
+       Mac  OS  X.   Though  previous Mac versions had their own zip port, zip
+       supports Mac OS X as part of the  Unix  port  and  most  Unix  features
+       apply.   References  to "MacOS" below generally refer to MacOS versions
+       older than OS X.  Support for some Mac OS features in the Unix Mac OS X
+       port, such as resource forks, is expected in the next zip release.
+
+       For  a  brief  help  on  zip and unzip, run each without specifying any
+       parameters on the command line.
+
+USE
+       The program is useful for packaging a set of  files  for  distribution;
+       for archiving files; and for saving disk space by temporarily compress-
+       ing unused files or directories.
+
+       The zip program puts one or more compressed files  into  a  single  zip
+       archive, along with information about the files (name, path, date, time
+       of last modification, protection, and check information to verify  file
+       integrity).   An  entire  directory  structure can be packed into a zip
+       archive with a single command.  Compression ratios of 2:1  to  3:1  are
+       common  for text files.  zip has one compression method (deflation) and
+       can also store files without compression.  (If bzip2 support is  added,
+       zip can also compress using bzip2 compression, but such entries require
+       a reasonably modern unzip to decompress.   When  bzip2  compression  is
+       selected,  it replaces deflation as the default method.)  zip automati-
+       cally chooses the better of the two (deflation or store or, if bzip2 is
+       selected, bzip2 or store) for each file to be compressed.
+
+       Command format.  The basic command format is
+
+              zip options archive inpath inpath ...
+
+       where  archive  is a new or existing zip archive and inpath is a direc-
+       tory or file path optionally including wildcards.  When given the  name
+       of  an existing zip archive, zip will replace identically named entries
+       in the zip archive (matching  the  relative  names  as  stored  in  the
+       archive)  or add entries for new names.  For example, if foo.zip exists
+       and contains foo/file1 and foo/file2, and the  directory  foo  contains
+       the files foo/file1 and foo/file3, then:
+
+              zip -r foo.zip foo
+
+       or more concisely
+
+              zip -r foo foo
+
+       will  replace foo/file1 in foo.zip and add foo/file3 to foo.zip.  After
+       this,  foo.zip  contains  foo/file1,  foo/file2,  and  foo/file3,  with
+       foo/file2 unchanged from before.
+
+       So if before the zip command is executed foo.zip has:
+
+               foo/file1 foo/file2
+
+       and directory foo has:
+
+               file1 file3
+
+       then foo.zip will have:
+
+               foo/file1 foo/file2 foo/file3
+
+       where foo/file1 is replaced and foo/file3 is new.
+
+       -@ file lists.   If  a file list is specified as -@ [Not on MacOS], zip
+       takes the list of input files from standard input instead of  from  the
+       command line.  For example,
+
+              zip -@ foo
+
+       will store the files listed one per line on stdin in foo.zip.
+
+       Under  Unix,  this option can be used to powerful effect in conjunction
+       with the find (1) command.  For example, to archive all  the  C  source
+       files in the current directory and its subdirectories:
+
+              find . -name "*.[ch]" -print | zip source -@
+
+       (note  that the pattern must be quoted to keep the shell from expanding
+       it).
+
+       Streaming input and output.  zip will also accept a single  dash  ("-")
+       as the zip file name, in which case it will write the zip file to stan-
+       dard output, allowing the output to be piped to  another  program.  For
+       example:
+
+              zip -r - . | dd of=/dev/nrst0 obs=16k
+
+       would  write the zip output directly to a tape with the specified block
+       size for the purpose of backing up the current directory.
+
+       zip also accepts a single dash ("-") as the name of a file to  be  com-
+       pressed,  in  which  case  it  will  read the file from standard input,
+       allowing zip to take input from another program. For example:
+
+              tar cf - . | zip backup -
+
+       would compress the output of the tar command for the purpose of backing
+       up  the  current  directory. This generally produces better compression
+       than the previous example using the -r  option  because  zip  can  take
+       advantage of redundancy between files. The backup can be restored using
+       the command
+
+              unzip -p backup | tar xf -
+
+       When no zip file name is given and stdout is not a terminal,  zip  acts
+       as  a filter, compressing standard input to standard output.  For exam-
+       ple,
+
+              tar cf - . | zip | dd of=/dev/nrst0 obs=16k
+
+       is equivalent to
+
+              tar cf - . | zip - - | dd of=/dev/nrst0 obs=16k
+
+       zip archives created in this manner can be extracted with  the  program
+       funzip  which  is  provided in the unzip package, or by gunzip which is
+       provided in the gzip package (but some gunzip may not support  this  if
+       zip used the Zip64 extensions). For example:
+
+              dd if=/dev/nrst0  ibs=16k | funzip | tar xvf -
+
+       The stream can also be saved to a file and unzip used.
+
+       If  Zip64  support  for  large files and archives is enabled and zip is
+       used as a filter, zip creates a Zip64 archive that requires a PKZIP 4.5
+       or  later compatible unzip to read it.  This is to avoid amgibuities in
+       the zip file structure as defined in the current zip  standard  (PKWARE
+       AppNote)  where  the decision to use Zip64 needs to be made before data
+       is written for the entry, but for a stream the size of the data is  not
+       known at that point.  If the data is known to be smaller than 4 GB, the
+       option -fz- can be used to prevent use of Zip64, but zip will exit with
+       an  error if Zip64 was in fact needed.  zip 3 and unzip 6 and later can
+       read archives with Zip64 entries.  Also, zip removes the  Zip64  exten-
+       sions  if  not  needed  when  archive  entries  are  copied (see the -U
+       (--copy) option).
+
+       When directing the output to another file, note that all options should
+       be before the redirection including -x.  For example:
+
+              zip archive "*.h" "*.c" -x donotinclude.h orthis.h > tofile
+
+       Zip files.   When  changing  an  existing zip archive, zip will write a
+       temporary file with the new contents, and only replace the old one when
+       the  process  of  creating  the  new version has been completed without
+       error.
+
+       If the name of the zip archive  does  not  contain  an  extension,  the
+       extension  .zip  is  added.  If  the name already contains an extension
+       other than .zip, the existing extension is  kept  unchanged.   However,
+       split  archives  (archives  split over multiple files) require the .zip
+       extension on the last split.
+
+       Scanning and reading files.  When zip starts, it  scans  for  files  to
+       process  (if  needed).  If this scan takes longer than about 5 seconds,
+       zip will display  a  "Scanning  files"  message  and  start  displaying
+       progress  dots  every  2  seconds  or  every so many entries processed,
+       whichever takes longer.  If there is more than 2 seconds  between  dots
+       it  could indicate that finding each file is taking time and could mean
+       a slow network connection for example.  (Actually the initial file scan
+       is  a  two-step  process where the directory scan is followed by a sort
+       and these two steps are separated with a space in the dots.  If  updat-
+       ing an existing archive, a space also appears between the existing file
+       scan and the new file scan.)  The scanning  files  dots  are  not  con-
+       trolled  by the -ds dot size option, but the dots are turned off by the
+       -q quiet option.  The -sf show files option can be  used  to  scan  for
+       files  and  get  the  list of files scanned without actually processing
+       them.
+
+       If zip is not able to read a file, it issues a warning  but  continues.
+       See  the -MM option below for more on how zip handles patterns that are
+       not matched and files that  are  not  readable.   If  some  files  were
+       skipped, a warning is issued at the end of the zip operation noting how
+       many files were read and how many skipped.
+
+       Command modes.  zip now supports two distinct types of  command  modes,
+       external  and  internal.  The external modes (add, update, and freshen)
+       read files from the file system (as well as from an  existing  archive)
+       while  the  internal  modes  (delete  and  copy) operate exclusively on
+       entries in an existing archive.
+
+       add
+              Update existing entries and add new files.  If the archive  does
+              not exist create it.  This is the default mode.
+
+       update (-u)
+              Update  existing entries if newer on the file system and add new
+              files.  If the archive does not exist issue warning then  create
+              a new archive.
+
+       freshen (-f)
+              Update  existing entries of an archive if newer on the file sys-
+              tem.  Does not add new files to the archive.
+
+       delete (-d)
+              Select entries in an existing archive and delete them.
+
+       copy (-U)
+              Select entries in an existing archive and copy  them  to  a  new
+              archive.   This  new  mode is similar to update but command line
+              patterns select entries in  the  existing  archive  rather  than
+              files from the file system and it uses the --out option to write
+              the resulting archive to a  new  file  rather  than  update  the
+              existing archive, leaving the original archive unchanged.
+
+       The new File Sync option (-FS) is also considered a new mode, though it
+       is similar to update.  This mode  synchronizes  the  archive  with  the
+       files  on  the OS, only replacing files in the archive if the file time
+       or size of the OS file is different, adding  new  files,  and  deleting
+       entries from the archive where there is no matching file.  As this mode
+       can delete entries from the archive, consider making a backup  copy  of
+       the archive.
+
+       Also see -DF for creating difference archives.
+
+       See  each option description below for details and the EXAMPLES section
+       below for examples.
+
+       Split archives.  zip version 3.0 and later can create  split  archives.
+       A  split  archive  is a standard zip archive split over multiple files.
+       (Note that split archives are not just archives split in to pieces,  as
+       the  offsets of entries are now based on the start of each split.  Con-
+       catenating the pieces together will invalidate these offsets, but unzip
+       can  usually  deal  with it.  zip will usually refuse to process such a
+       spliced archive unless the -FF fix option is used to fix the  offsets.)
+
+       One use of split archives is storing a large archive on multiple remov-
+       able media.  For a split archive with 20 split files the files are typ-
+       ically   named   (replace  ARCHIVE  with  the  name  of  your  archive)
+       ARCHIVE.z01, ARCHIVE.z02, ..., ARCHIVE.z19, ARCHIVE.zip.  Note that the
+       last  file  is  the  .zip  file.  In contrast, spanned archives are the
+       original multi-disk archive generally requiring floppy disks and  using
+       volume  labels  to store disk numbers.  zip supports split archives but
+       not spanned archives, though a procedure exists  for  converting  split
+       archives  of  the  right size to spanned archives.  The reverse is also
+       true, where each file of a spanned archive can be copied  in  order  to
+       files with the above names to create a split archive.
+
+       Use  -s  to set the split size and create a split archive.  The size is
+       given as a number followed optionally by one of k (kB), m (MB), g (GB),
+       or  t (TB) (the default is m).  The -sp option can be used to pause zip
+       between splits to allow changing removable media, for example, but read
+       the descriptions and warnings for both -s and -sp below.
+
+       Though  zip does not update split archives, zip provides the new option
+       -O (--output-file or --out) to allow split archives to be  updated  and
+       saved in a new archive.  For example,
+
+              zip inarchive.zip foo.c bar.c --out outarchive.zip
+
+       reads  archive  inarchive.zip,  even if split, adds the files foo.c and
+       bar.c, and writes the resulting archive to  outarchive.zip.   If  inar-
+       chive.zip is split then outarchive.zip defaults to the same split size.
+       Be aware that if outarchive.zip and any split files  that  are  created
+       with  it  already exist, these are always overwritten as needed without
+       warning.  This may be changed in the future.
+
+       Unicode.  Though the zip standard requires storing paths in an  archive
+       using  a  specific character set, in practice zips have stored paths in
+       archives in whatever the local character set is.  This creates problems
+       when  an  archive is created or updated on a system using one character
+       set and then extracted on another system using  a  different  character
+       set.  When compiled with Unicode support enabled on platforms that sup-
+       port wide characters, zip now stores, in addition to the standard local
+       path  for  backward  compatibility,  the UTF-8 translation of the path.
+       This provides a common universal character set for storing  paths  that
+       allows  these paths to be fully extracted on other systems that support
+       Unicode and to match as close as possible on systems that don't.
+
+       On Win32 systems where paths are internally stored as Unicode but  rep-
+       resented in the local character set, it's possible that some paths will
+       be skipped during a local character set directory scan.  zip with  Uni-
+       code support now can read and store these paths.  Note that Win 9x sys-
+       tems and FAT file systems don't fully support Unicode.
+
+       Be aware that console windows on Win32 and Unix, for example, sometimes
+       don't  accurately  show all characters due to how each operating system
+       switches in character sets for display.  However, directory  navigation
+       tools should show the correct paths if the needed fonts are loaded.
+
+       Command line format.  This version of zip has updated command line pro-
+       cessing and support for long options.
+
+       Short options take the form
+
+              -s[-][s[-]...][value][=value][ value]
+
+       where s is a one or two character short option.  A  short  option  that
+       takes  a value is last in an argument and anything after it is taken as
+       the value.  If the option can be negated and  "-"  immediately  follows
+       the  option, the option is negated.  Short options can also be given as
+       separate arguments
+
+              -s[-][value][=value][ value] -s[-][value][=value][ value] ...
+
+       Short options in general take values either as part of the  same  argu-
+       ment  or  as  the following argument.  An optional = is also supported.
+       So
+
+              -ttmmddyyyy
+
+       and
+
+              -tt=mmddyyyy
+
+       and
+
+              -tt mmddyyyy
+
+       all work.  The -x and -i options accept  lists  of  values  and  use  a
+       slightly  different format described below.  See the -x and -i options.
+
+       Long options take the form
+
+              --longoption[-][=value][ value]
+
+       where the option starts with --, has a multicharacter name, can include
+       a  trailing  dash to negate the option (if the option supports it), and
+       can have a value (option argument) specified by preceeding  it  with  =
+       (no spaces).  Values can also follow the argument.  So
+
+              --before-date=mmddyyyy
+
+       and
+
+              --before-date mmddyyyy
+
+       both work.
+
+       Long option names can be shortened to the shortest unique abbreviation.
+       See the option descriptions below for which support long  options.   To
+       avoid confusion, avoid abbreviating a negatable option with an embedded
+       dash ("-") at the dash if you plan to negate it (the parser would  con-
+       sider  a  trailing  dash,  such  as  for the option --some-option using
+       --some- as the option, as part of  the  name  rather  than  a  negating
+       dash).   This  may  be  changed to force the last dash in --some- to be
+       negating in the future.
+
+OPTIONS
+       -a
+       --ascii
+              [Systems using EBCDIC] Translate file to ASCII format.
+
+       -A
+       --adjust-sfx
+              Adjust self-extracting executable  archive.   A  self-extracting
+              executable  archive  is created by prepending the SFX stub to an
+              existing archive. The -A option tells zip to  adjust  the  entry
+              offsets  stored in the archive to take into account this "pream-
+              ble" data.
+
+       Note: self-extracting archives for the Amiga are a  special  case.   At
+       present, only the Amiga port of zip is capable of adjusting or updating
+       these without corrupting them. -J can be used to remove the SFX stub if
+       other updates need to be made.
+
+       -AC
+       --archive-clear
+              [WIN32]   Once  archive  is  created  (and tested if -T is used,
+              which is recommended), clear the  archive  bits  of  files  pro-
+              cessed.   WARNING:  Once  the bits are cleared they are cleared.
+              You may want to use the -sf show files option to store the  list
+              of  files  processed  in  case  the  archive  operation  must be
+              repeated.  Also consider using the -MM must  match  option.   Be
+              sure to check out -DF as a possibly better way to do incremental
+              backups.
+
+       -AS
+       --archive-set
+              [WIN32]  Only include files  that  have  the  archive  bit  set.
+              Directories  are  not stored when -AS is used, though by default
+              the paths of entries, including directories, are stored as usual
+              and can be used by most unzips to recreate directories.
+
+              The  archive  bit  is set by the operating system when a file is
+              modified and, if used with -AC, -AS can provide  an  incremental
+              backup  capability.   However, other applications can modify the
+              archive bit and it may not be  a  reliable  indicator  of  which
+              files  have  changed since the last archive operation.  Alterna-
+              tive ways to create incremental backups are using -t to use file
+              dates,  though  this won't catch old files copied to directories
+              being archived, and -DF to create a differential archive.
+
+       -B
+       --binary
+              [VM/CMS and MVS] force file to be read binary (default is text).
+
+       -Bn    [TANDEM] set Edit/Enscribe formatting options with n defined as
+              bit  0: Don't add delimiter (Edit/Enscribe)
+              bit  1: Use LF rather than CR/LF as delimiter (Edit/Enscribe)
+              bit  2: Space fill record to maximum record length (Enscribe)
+              bit  3: Trim trailing space (Enscribe)
+              bit  8: Force 30K (Expand) large read for unstructured files
+
+       -b path
+       --temp-path path
+              Use  the specified path for the temporary zip archive. For exam-
+              ple:
+
+                     zip -b /tmp stuff *
+
+              will put the temporary zip archive in the directory /tmp,  copy-
+              ing  over  stuff.zip  to  the  current directory when done. This
+              option is useful when updating an existing archive and the  file
+              system containing this old archive does not have enough space to
+              hold both old and new archives at the same time.  It may also be
+              useful  when  streaming in some cases to avoid the need for data
+              descriptors.  Note that using this option may require  zip  take
+              additional time to copy the archive file when done to the desti-
+              nation file system.
+
+       -c
+       --entry-comments
+              Add one-line comments for each file.  File  operations  (adding,
+              updating)  are  done  first, and the user is then prompted for a
+              one-line comment for each file.  Enter the comment  followed  by
+              return, or just return for no comment.
+
+       -C
+       --preserve-case
+              [VMS]   Preserve  case  all  on VMS.  Negating this option (-C-)
+              downcases.
+
+       -C2
+       --preserve-case-2
+              [VMS]  Preserve case ODS2 on VMS.  Negating this  option  (-C2-)
+              downcases.
+
+       -C5
+       --preserve-case-5
+              [VMS]   Preserve  case ODS5 on VMS.  Negating this option (-C5-)
+              downcases.
+
+       -d
+       --delete
+              Remove (delete) entries from a zip archive.  For example:
+
+                     zip -d foo foo/tom/junk foo/harry/\* \*.o
+
+              will remove the entry foo/tom/junk, all of the files that  start
+              with  foo/harry/,  and all of the files that end with .o (in any
+              path).  Note that shell pathname expansion  has  been  inhibited
+              with  backslashes,  so  that zip can see the asterisks, enabling
+              zip to match on the contents of the zip archive instead  of  the
+              contents  of  the  current  directory.  (The backslashes are not
+              used on MSDOS-based platforms.)  Can also use quotes  to  escape
+              the asterisks as in
+
+                     zip -d foo foo/tom/junk "foo/harry/*" "*.o"
+
+              Not  escaping  the asterisks on a system where the shell expands
+              wildcards could result in the asterisks  being  converted  to  a
+              list  of  files  in  the current directory and that list used to
+              delete entries from the archive.
+
+              Under MSDOS, -d is case sensitive when it matches names  in  the
+              zip  archive.  This requires that file names be entered in upper
+              case if they were zipped by PKZIP on an MSDOS system.  (We  con-
+              sidered making this case insensitive on systems where paths were
+              case insensitive, but it is possible the  archive  came  from  a
+              system where case does matter and the archive could include both
+              Bar and bar as separate files in the archive.)  But see the  new
+              option -ic to ignore case in the archive.
+
+       -db
+       --display-bytes
+              Display  running  byte  counts  showing the bytes zipped and the
+              bytes to go.
+
+       -dc
+       --display-counts
+              Display running count of entries zipped and entries to go.
+
+       -dd
+       --display-dots
+              Display dots while each entry is zipped (except  on  ports  that
+              have  their  own progress indicator).  See -ds below for setting
+              dot size.  The default is a dot every 10 MB of input  file  pro-
+              cessed.   The -v option also displays dots (previously at a much
+              higher rate than this but now -v also defaults  to  10  MB)  and
+              this rate is also controlled by -ds.
+
+       -df
+       --datafork
+              [MacOS] Include only data-fork of files zipped into the archive.
+              Good  for  exporting   files   to   foreign   operating-systems.
+              Resource-forks will be ignored at all.
+
+       -dg
+       --display-globaldots
+              Display  progress dots for the archive instead of for each file.
+              The command
+
+                         zip -qdgds 10m
+
+              will turn off most output except dots every 10 MB.
+
+       -ds size
+       --dot-size size
+              Set amount of input file processed for each dot displayed.   See
+              -dd to enable displaying dots.  Setting this option implies -dd.
+              Size is in the format nm where n is a number and m is  a  multi-
+              plier.  Currently m can be k (KB), m (MB), g (GB), or t (TB), so
+              if n is 100 and m is k, size would be 100k which is 100 KB.  The
+              default is 10 MB.
+
+              The -v option also displays dots and now defaults to 10 MB also.
+              This rate is also controlled by this option.  A size of 0  turns
+              dots off.
+
+              This  option does not control the dots from the "Scanning files"
+              message as zip scans for input files.  The dot size for that  is
+              fixed  at  2  seconds or a fixed number of entries, whichever is
+              longer.
+
+       -du
+       --display-usize
+              Display the uncompressed size of each entry.
+
+       -dv
+       --display-volume
+              Display the volume (disk) number each entry is being read  from,
+              if reading an existing archive, and being written to.
+
+       -D
+       --no-dir-entries
+              Do  not  create  entries  in  the  zip  archive for directories.
+              Directory  entries  are  created  by  default  so   that   their
+              attributes  can  be  saved  in the zip archive.  The environment
+              variable ZIPOPT can be used to change the default  options.  For
+              example under Unix with sh:
+
+                     ZIPOPT="-D"; export ZIPOPT
+
+              (The  variable  ZIPOPT  can be used for any option, including -i
+              and -x using a new option format detailed below, and can include
+              several  options.)  The option -D is a shorthand for -x "*/" but
+              the latter previously could not be set as default in the  ZIPOPT
+              environment  variable  as  the  contents of ZIPOPT gets inserted
+              near the beginning of the command line and the file list had  to
+              end at the end of the line.
+
+              This  version  of  zip does allow -x and -i options in ZIPOPT if
+              the form
+
+              -x file file ... @
+
+              is used, where the @ (an argument that is just @) terminates the
+              list.
+
+       -DF
+       --difference-archive
+              Create  an archive that contains all new and changed files since
+              the original archive was created.  For this to work,  the  input
+              file  list  and current directory must be the same as during the
+              original zip operation.
+
+              For example, if the existing archive was created using
+
+                     zip -r foofull .
+
+              from the bar directory, then the command
+
+                     zip -r foofull . -DF --out foonew
+
+              also from the bar directory creates the archive foonew with just
+              the  files  not  in foofull and the files where the size or file
+              time of the files do not match those in foofull.
+
+              Note that the timezone environment variable  TZ  should  be  set
+              according to the local timezone in order for this option to work
+              correctly.  A change in timezone since the original archive  was
+              created  could  result  in no times matching and all files being
+              included.
+
+              A possible approach to backing up a directory might be to create
+              a  normal  archive  of  the  contents of the directory as a full
+              backup, then use this option to create incremental backups.
+
+       -e
+       --encrypt
+              Encrypt the contents of the zip archive using a  password  which
+              is  entered  on  the terminal in response to a prompt (this will
+              not be echoed; if standard error is not a  tty,  zip  will  exit
+              with  an  error).   The  password prompt is repeated to save the
+              user from typing errors.
+
+       -E
+       --longnames
+              [OS/2] Use the .LONGNAME Extended Attribute (if found) as  file-
+              name.
+
+       -f
+       --freshen
+              Replace  (freshen)  an existing entry in the zip archive only if
+              it has been modified more recently than the version  already  in
+              the zip archive; unlike the update option (-u) this will not add
+              files that are not already in the zip archive.  For example:
+
+                     zip -f foo
+
+              This command should be run from the same  directory  from  which
+              the  original  zip  command  was  run, since paths stored in zip
+              archives are always relative.
+
+              Note that the timezone environment variable  TZ  should  be  set
+              according  to  the local timezone in order for the -f, -u and -o
+              options to work correctly.
+
+              The reasons behind this are somewhat subtle but have to do  with
+              the  differences  between  the Unix-format file times (always in
+              GMT) and most of the other operating systems (always local time)
+              and  the  necessity  to  compare the two.  A typical TZ value is
+              ``MET-1MEST'' (Middle European time  with  automatic  adjustment
+              for ``summertime'' or Daylight Savings Time).
+
+              The  format is TTThhDDD, where TTT is the time zone such as MET,
+              hh is the difference between GMT  and  local  time  such  as  -1
+              above, and DDD is the time zone when daylight savings time is in
+              effect.  Leave off the DDD if there is no daylight savings time.
+              For the US Eastern time zone EST5EDT.
+
+       -F
+       --fix
+       -FF
+       --fixfix
+              Fix  the zip archive. The -F option can be used if some portions
+              of the archive are missing, but  requires  a  reasonably  intact
+              central  directory.   The input archive is scanned as usual, but
+              zip will ignore some problems.  The resulting archive should  be
+              valid, but any inconsistent entries will be left out.
+
+              When  doubled  as in -FF, the archive is scanned from the begin-
+              ning and zip scans for special signatures to identify the limits
+              between  the  archive members. The single -F is more reliable if
+              the archive is not too much damaged, so try this option first.
+
+              If the archive is too damaged or the end has been truncated, you
+              must  use  -FF.   This  is  a change from zip 2.32, where the -F
+              option is able to read a truncated archive.  The -F  option  now
+              more  reliably  fixes  archives  with  minor  damage and the -FF
+              option is needed to fix archives where -F might have been suffi-
+              cient before.
+
+              Neither  option will recover archives that have been incorrectly
+              transferred in ascii mode instead of binary. After  the  repair,
+              the  -t option of unzip may show that some files have a bad CRC.
+              Such files cannot be recovered; you can  remove  them  from  the
+              archive using the -d option of zip.
+
+              Note  that  -FF may have trouble fixing archives that include an
+              embedded zip archive that was stored  (without  compression)  in
+              the  archive  and,  depending  on  the  damage,  it may find the
+              entries in the embedded archive rather than the archive  itself.
+              Try -F first as it does not have this problem.
+
+              The  format  of  the fix commands have changed.  For example, to
+              fix the damaged archive foo.zip,
+
+                     zip -F foo --out foofix
+
+              tries to read the entries normally, copying good entries to  the
+              new  archive  foofix.zip.   If  this  doesn't  work, as when the
+              archive is truncated, or if some entries you  know  are  in  the
+              archive are missed, then try
+
+                     zip -FF foo --out foofixfix
+
+              and  compare the resulting archive to the archive created by -F.
+              The -FF option may create an inconsistent archive.  Depending on
+              what  is  damaged,  you  can  then use the -F option to fix that
+              archive.
+
+              A split archive with missing split files can be fixed  using  -F
+              if  you  have the last split of the archive (the .zip file).  If
+              this file is missing, you must use -FF to fix the archive, which
+              will prompt you for the splits you have.
+
+              Currently  the fix options can't recover entries that have a bad
+              checksum or are otherwise damaged.
+
+       -FI
+       --fifo [Unix]  Normally zip  skips  reading  any  FIFOs  (named  pipes)
+              encountered, as zip can hang if the FIFO is not being fed.  This
+              option tells zip to read the contents of any FIFO it finds.
+
+       -FS
+       --filesync
+              Synchronize the contents of an archive with the files on the OS.
+              Normally  when  an  archive  is updated, new files are added and
+              changed files are updated but files that no longer exist on  the
+              OS  are not deleted from the archive.  This option enables a new
+              mode that checks entries in the archive against the file system.
+              If  the file time and file size of the entry matches that of the
+              OS file, the entry is copied from the  old  archive  instead  of
+              being  read from the file system and compressed.  If the OS file
+              has changed, the entry is read and compressed as usual.  If  the
+              entry  in the archive does not match a file on the OS, the entry
+              is deleted.  Enabling this option should  create  archives  that
+              are  the  same  as  new archives, but since existing entries are
+              copied instead of compressed, updating an existing archive  with
+              -FS  can  be much faster than creating a new archive.  Also con-
+              sider using -u for updating an archive.
+
+              For this option to work, the archive should be updated from  the
+              same  directory  it  was created in so the relative paths match.
+              If few files are being copied from the old archive,  it  may  be
+              faster to create a new archive instead.
+
+              Note  that  the  timezone  environment variable TZ should be set
+              according to the local timezone in order for this option to work
+              correctly.   A change in timezone since the original archive was
+              created could result in no times matching and  recompression  of
+              all files.
+
+              This option deletes files from the archive.  If you need to pre-
+              serve the original archive, make a copy of the archive first  or
+              use  the  --out  option  to  output the updated archive to a new
+              file.  Even though it may be slower, creating a new archive with
+              a  new  archive name is safer, avoids mismatches between archive
+              and OS paths, and is preferred.
+
+       -g
+       --grow
+              Grow (append to) the specified zip archive, instead of  creating
+              a  new one. If this operation fails, zip attempts to restore the
+              archive to its original state. If  the  restoration  fails,  the
+              archive  might  become  corrupted.  This  option is ignored when
+              there's no existing archive or when at least one archive  member
+              must be updated or deleted.
+
+       -h
+       -?
+       --help
+              Display  the  zip  help information (this also appears if zip is
+              run with no arguments).
+
+       -h2
+       --more-help
+              Display extended help including more  on  command  line  format,
+              pattern matching, and more obscure options.
+
+       -i files
+       --include files
+              Include only the specified files, as in:
+
+                     zip -r foo . -i \*.c
+
+              which  will include only the files that end in .c in the current
+              directory and its subdirectories. (Note  for  PKZIP  users:  the
+              equivalent command is
+
+                     pkzip -rP foo *.c
+
+              PKZIP  does  not  allow  recursion in directories other than the
+              current one.)  The backslash avoids the shell filename substitu-
+              tion,  so  that  the  name  matching  is performed by zip at all
+              directory levels.  [This is for Unix and other systems  where  \
+              escapes  the  next character.  For other systems where the shell
+              does not process * do not use \ and the above is
+
+                     zip -r foo . -i *.c
+
+              Examples are  for  Unix  unless  otherwise  specified.]   So  to
+              include  dir,  a directory directly under the current directory,
+              use
+
+                     zip -r foo . -i dir/\*
+
+              or
+
+                     zip -r foo . -i "dir/*"
+
+              to match paths such as dir/a and dir/b/file.c [on ports  without
+              wildcard expansion in the shell such as MSDOS and Windows
+
+                     zip -r foo . -i dir/*
+
+              is  used.]   Note  that  currently  the trailing / is needed for
+              directories (as in
+
+                     zip -r foo . -i dir/
+
+              to include directory dir).
+
+              The long option form of the first example is
+
+                     zip -r foo . --include \*.c
+
+              and does the same thing as the short option form.
+
+              Though the command syntax used to require -i at the end  of  the
+              command  line,  this  version  actually allows -i (or --include)
+              anywhere.  The list of files terminates  at  the  next  argument
+              starting with -, the end of the command line, or the list termi-
+              nator @ (an argument that is just @).  So the above can be given
+              as
+
+                     zip -i \*.c @ -r foo .
+
+              for  example.   There must be a space between the option and the
+              first file of a list.  For just one file you can use the  single
+              value form
+
+                     zip -i\*.c -r foo .
+
+              (no space between option and value) or
+
+                     zip --include=\*.c -r foo .
+
+              as  additional  examples.  The single value forms are not recom-
+              mended because they can be confusing  and,  in  particular,  the
+              -ifile  format  can  cause  problems if the first letter of file
+              combines with i to form a two-letter  option  starting  with  i.
+              Use -sc to see how your command line will be parsed.
+
+              Also possible:
+
+                     zip -r foo  . -i@include.lst
+
+              which  will  only include the files in the current directory and
+              its  subdirectories  that  match  the  patterns  in   the   file
+              include.lst.
+
+              Files to -i and -x are patterns matching internal archive paths.
+              See -R for more on patterns.
+
+       -I
+       --no-image
+              [Acorn RISC OS] Don't scan through Image files.  When used,  zip
+              will  not  consider  Image  files  (eg.  DOS partitions or Spark
+              archives when SparkFS is loaded) as directories but  will  store
+              them as single files.
+
+              For example, if you have SparkFS loaded, zipping a Spark archive
+              will result in a zipfile containing a directory  (and  its  con-
+              tent)  while  using the 'I' option will result in a zipfile con-
+              taining a Spark archive. Obviously this second case will also be
+              obtained (without the 'I' option) if SparkFS isn't loaded.
+
+       -ic
+       --ignore-case
+              [VMS,  WIN32]  Ignore  case when matching archive entries.  This
+              option is only available on systems where the case of  files  is
+              ignored.  On systems with case-insensitive file systems, case is
+              normally ignored when matching files on the file system  but  is
+              not  ignored for -f (freshen), -d (delete), -U (copy), and simi-
+              lar modes when matching against archive  entries  (currently  -f
+              ignores case on VMS) because archive entries can be from systems
+              where case does matter and names that are the  same  except  for
+              case can exist in an archive.  The -ic option makes all matching
+              case insensitive.  This can result in multiple  archive  entries
+              matching a command line pattern.
+
+       -j
+       --junk-paths
+              Store  just the name of a saved file (junk the path), and do not
+              store directory names. By default, zip will store the full  path
+              (relative to the current directory).
+
+       -jj
+       --absolute-path
+              [MacOS] record Fullpath (+ Volname). The complete path including
+              volume will be stored. By default  the  relative  path  will  be
+              stored.
+
+       -J
+       --junk-sfx
+              Strip any prepended data (e.g. a SFX stub) from the archive.
+
+       -k
+       --DOS-names
+              Attempt  to  convert  the  names  and paths to conform to MSDOS,
+              store only the MSDOS attribute (just the  user  write  attribute
+              from  Unix), and mark the entry as made under MSDOS (even though
+              it was not); for compatibility with PKUNZIP  under  MSDOS  which
+              cannot handle certain names such as those with two dots.
+
+       -l
+       --to-crlf
+              Translate  the Unix end-of-line character LF into the MSDOS con-
+              vention CR LF. This option should not be used on  binary  files.
+              This  option can be used on Unix if the zip file is intended for
+              PKUNZIP under MSDOS. If the input files already contain  CR  LF,
+              this option adds an extra CR. This is to ensure that unzip -a on
+              Unix will get back an exact copy of the original file,  to  undo
+              the effect of zip -l.  See -ll for how binary files are handled.
+
+       -la
+       --log-append
+              Append to existing logfile.  Default is to overwrite.
+
+       -lf logfilepath
+       --logfile-path logfilepath
+              Open a logfile at the given path.  By default any existing  file
+              at  that location is overwritten, but the -la option will result
+              in an existing file being opened and  the  new  log  information
+              appended  to any existing information.  Only warnings and errors
+              are written to the log unless the -li option is also given, then
+              all information messages are also written to the log.
+
+       -li
+       --log-info
+              Include  information  messages, such as file names being zipped,
+              in the log.  The default is to only include  the  command  line,
+              any warnings and errors, and the final status.
+
+       -ll
+       --from-crlf
+              Translate the MSDOS end-of-line CR LF into Unix LF.  This option
+              should not be used on binary files.  This option can be used  on
+              MSDOS  if the zip file is intended for unzip under Unix.  If the
+              file is converted and the file is later determined to be  binary
+              a warning is issued and the file is probably corrupted.  In this
+              release if -ll detects binary in the first buffer  read  from  a
+              file,  zip now issues a warning and skips line end conversion on
+              the file.  This check seems to catch all  binary  files  tested,
+              but  the original check remains and if a converted file is later
+              determined to be binary that warning is  still  issued.   A  new
+              algorithm  is  now  being  used for binary detection that should
+              allow line end conversion of text files  in  UTF-8  and  similar
+              encodings.
+
+       -L
+       --license
+              Display the zip license.
+
+       -m
+       --move
+              Move  the  specified  files into the zip archive; actually, this
+              deletes the target directories/files after making the  specified
+              zip  archive.  If a directory becomes empty after removal of the
+              files, the directory is also  removed.  No  deletions  are  done
+              until zip has created the archive without error.  This is useful
+              for conserving disk space, but is potentially dangerous so it is
+              recommended to use it in combination with -T to test the archive
+              before removing all input files.
+
+       -MM
+       --must-match
+              All input patterns must match at least one file  and  all  input
+              files  found  must  be readable.  Normally when an input pattern
+              does not match a file the "name not matched" warning  is  issued
+              and  when  an  input file has been found but later is missing or
+              not readable a missing or not readable warning  is  issued.   In
+              either  case zip continues creating the archive, with missing or
+              unreadable new files being skipped  and  files  already  in  the
+              archive  remaining  unchanged.  After the archive is created, if
+              any files were not readable zip returns the OPEN error code  (18
+              on most systems) instead of the normal success return (0 on most
+              systems).  With -MM set, zip exits as soon as an  input  pattern
+              is not matched (whenever the "name not matched" warning would be
+              issued) or when an input file is not readable.  In  either  case
+              zip exits with an OPEN error and no archive is created.
+
+              This option is useful when a known list of files is to be zipped
+              so any missing or unreadable files will result in an error.   It
+              is less useful when used with wildcards, but zip will still exit
+              with an error if any input pattern doesn't match  at  least  one
+              file  and  if  any matched files are unreadable.  If you want to
+              create the archive anyway and only need to know  if  files  were
+              skipped, don't use -MM and just check the return code.  Also -lf
+              could be useful.
+
+       -n suffixes
+       --suffixes suffixes
+              Do not attempt to compress files named with the given  suffixes.
+              Such  files are simply stored (0% compression) in the output zip
+              file, so that zip doesn't waste  its  time  trying  to  compress
+              them.   The  suffixes  are  separated  by either colons or semi-
+              colons.  For example:
+
+                     zip -rn .Z:.zip:.tiff:.gif:.snd  foo foo
+
+              will copy everything from foo into foo.zip, but will  store  any
+              files  that end in .Z, .zip, .tiff, .gif, or .snd without trying
+              to compress them (image and sound files  often  have  their  own
+              specialized compression methods).  By default, zip does not com-
+              press     files     with     extensions     in     the      list
+              .Z:.zip:.zoo:.arc:.lzh:.arj.   Such files are stored directly in
+              the output archive.  The environment variable ZIPOPT can be used
+              to change the default options. For example under Unix with csh:
+
+                     setenv ZIPOPT "-n .gif:.zip"
+
+              To attempt compression on all files, use:
+
+                     zip -n : foo
+
+              The  maximum  compression option -9 also attempts compression on
+              all files regardless of extension.
+
+              On Acorn RISC OS systems the suffixes are actually filetypes  (3
+              hex  digit format). By default, zip does not compress files with
+              filetypes in the list DDC:D96:68E (i.e. Archives, CFS files  and
+              PackDir files).
+
+       -nw
+       --no-wild
+              Do not perform internal wildcard processing (shell processing of
+              wildcards is still done by the shell unless  the  arguments  are
+              escaped).   Useful if a list of paths is being read and no wild-
+              card substitution is desired.
+
+       -N
+       --notes
+              [Amiga, MacOS] Save Amiga or MacOS  filenotes  as  zipfile  com-
+              ments.  They can be restored by using the -N option of unzip. If
+              -c is used also, you are prompted for comments  only  for  those
+              files that do not have filenotes.
+
+       -o
+       --latest-time
+              Set  the  "last  modified" time of the zip archive to the latest
+              (oldest) "last modified" time found among the entries in the zip
+              archive.   This  can  be  used  without any other operations, if
+              desired.  For example:
+
+              zip -o foo
+
+              will change the last modified time of foo.zip to the latest time
+              of the entries in foo.zip.
+
+       -O output-file
+       --output-file output-file
+              Process  the  archive  changes as usual, but instead of updating
+              the existing archive, output the  new  archive  to  output-file.
+              Useful  for  updating  an  archive without changing the existing
+              archive and the input archive must be a different file than  the
+              output archive.
+
+              This  option  can  be used to create updated split archives.  It
+              can also be used with  -U  to  copy  entries  from  an  existing
+              archive to a new archive.  See the EXAMPLES section below.
+
+              Another  use  is  converting  zip  files  from one split size to
+              another.  For instance, to convert an archive  with  700  MB  CD
+              splits to one with 2 GB DVD splits, can use:
+
+                     zip -s 2g cd-split.zip --out dvd-split.zip
+
+              which uses copy mode.  See -U below.  Also:
+
+                     zip -s 0 split.zip --out unsplit.zip
+
+              will convert a split archive to a single-file archive.
+
+              Copy  mode  will  convert stream entries (using data descriptors
+              and which should be  compatible  with  most  unzips)  to  normal
+              entries  (which should be compatible with all unzips), except if
+              standard encryption  was  used.   For  archives  with  encrypted
+              entries,  zipcloak  will decrypt the entries and convert them to
+              normal entries.
+
+       -p
+       --paths
+              Include relative file paths as part of the names of files stored
+              in  the  archive.  This is the default.  The -j option junks the
+              paths and just stores the names of the files.
+
+       -P password
+       --password password
+              Use password to encrypt zipfile entries (if any).  THIS IS INSE-
+              CURE!   Many  multi-user  operating systems provide ways for any
+              user to see the current command line of any other user; even  on
+              stand-alone  systems  there  is  always  the threat of over-the-
+              shoulder peeking.  Storing the plaintext password as part  of  a
+              command  line  in  an  automated script is even worse.  Whenever
+              possible, use the non-echoing, interactive prompt to enter pass-
+              words.   (And  where  security  is  truly  important, use strong
+              encryption such as Pretty Good Privacy instead of the relatively
+              weak standard encryption provided by zipfile utilities.)
+
+       -q
+       --quiet
+              Quiet   mode;   eliminate  informational  messages  and  comment
+              prompts.  (Useful, for example, in shell scripts and  background
+              tasks).
+
+       -Qn
+       --Q-flag n
+              [QDOS]  store information about the file in the file header with
+              n defined as
+              bit  0: Don't add headers for any file
+              bit  1: Add headers for all files
+              bit  2: Don't wait for interactive key press on exit
+
+       -r
+       --recurse-paths
+              Travel the directory structure recursively; for example:
+
+                     zip -r foo.zip foo
+
+              or more concisely
+
+                     zip -r foo foo
+
+              In this case, all the files and directories in foo are saved  in
+              a zip archive named foo.zip, including files with names starting
+              with ".", since the recursion does not use the shell's file-name
+              substitution  mechanism.  If you wish to include only a specific
+              subset of the files in directory foo and its subdirectories, use
+              the  -i  option  to specify the pattern of files to be included.
+              You should not use -r with the name  ".*",  since  that  matches
+              ".."   which will attempt to zip up the parent directory (proba-
+              bly not what was intended).
+
+              Multiple source directories are allowed as in
+
+                     zip -r foo foo1 foo2
+
+              which first zips up foo1 and then foo2, going down  each  direc-
+              tory.
+
+              Note  that  while  wildcards  to -r are typically resolved while
+              recursing down directories in the file system, any -R,  -x,  and
+              -i  wildcards are applied to internal archive pathnames once the
+              directories are scanned.  To have wildcards apply  to  files  in
+              subdirectories  when recursing on Unix and similar systems where
+              the shell does wildcard substitution, either  escape  all  wild-
+              cards  or put all arguments with wildcards in quotes.  This lets
+              zip see the wildcards and match files  in  subdirectories  using
+              them as it recurses.
+
+       -R
+       --recurse-patterns
+              Travel  the directory structure recursively starting at the cur-
+              rent directory; for example:
+
+                     zip -R foo "*.c"
+
+              In this case, all the files matching *.c in the tree starting at
+              the  current  directory  are  stored  into  a  zip archive named
+              foo.zip.  Note that *.c will match file.c, a/file.c and  a/b/.c.
+              More than one pattern can be listed as separate arguments.  Note
+              for PKZIP users: the equivalent command is
+
+                     pkzip -rP foo *.c
+
+              Patterns are relative file paths as they appear in the  archive,
+              or  will after zipping, and can have optional wildcards in them.
+              For example, given the current directory is foo and under it are
+              directories foo1 and foo2 and in foo1 is the file bar.c,
+
+                     zip -R foo/*
+
+              will zip up foo, foo/foo1, foo/foo1/bar.c, and foo/foo2.
+
+                     zip -R */bar.c
+
+              will  zip  up  foo/foo1/bar.c.   See the note for -r on escaping
+              wildcards.
+
+       -RE
+       --regex
+              [WIN32]  Before zip 3.0, regular expression  list  matching  was
+              enabled  by  default on Windows platforms.  Because of confusion
+              resulting from the need to escape "[" and "]" in  names,  it  is
+              now  off  by  default for Windows so "[" and "]" are just normal
+              characters in names.  This option enables [] matching again.
+
+       -s splitsize
+       --split-size splitsize
+              Enable creating a split archive and set the split size.  A split
+              archive  is  an archive that could be split over many files.  As
+              the archive is created, if the size of the archive  reaches  the
+              specified  split  size,  that split is closed and the next split
+              opened.  In general all splits but the last will  be  the  split
+              size  and  the  last  will  be  whatever is left.  If the entire
+              archive is smaller than the split size a single-file archive  is
+              created.
+
+              Split  archives  are  stored in numbered files.  For example, if
+              the output  archive  is  named  archive  and  three  splits  are
+              required,  the  resulting  archive  will  be  in the three files
+              archive.z01, archive.z02, and archive.zip.  Do  not  change  the
+              numbering  of these files or the archive will not be readable as
+              these are used to determine the order the splits are read.
+
+              Split size is a number  optionally  followed  by  a  multiplier.
+              Currently  the  number  must  be an integer.  The multiplier can
+              currently be one of k (kilobytes), m (megabytes), g (gigabytes),
+              or  t  (terabytes).   As  64k is the minimum split size, numbers
+              without multipliers default to megabytes.  For example, to  cre-
+              ate  a  split  archive  called  foo with the contents of the bar
+              directory with splits of 670 MB that might be useful for burning
+              on CDs, the command:
+
+                     zip -s 670m -r foo bar
+
+              could be used.
+
+              Currently  the  old  splits  of a split archive are not excluded
+              from a new archive, but they can be specifically  excluded.   If
+              possible,  keep  the  input  and output archives out of the path
+              being zipped when creating split archives.
+
+              Using -s without -sp as above creates all the splits  where  foo
+              is  being  written,  in  this  case the current directory.  This
+              split mode updates the splits as the archive is  being  created,
+              requiring  all  splits  to  remain  writable,  but creates split
+              archives that are readable by  any  unzip  that  supports  split
+              archives.   See  -sp  below  for enabling split pause mode which
+              allows splits to be written directly to removable media.
+
+              The option -sv can be used to enable verbose splitting and  pro-
+              vide details of how the splitting is being done.  The -sb option
+              can be used to ring the bell when zip pauses for the next  split
+              destination.
+
+              Split  archives cannot be updated, but see the -O (--out) option
+              for how a split archive can be updated as it is copied to a  new
+              archive.   A  split archive can also be converted into a single-
+              file archive using a split size of 0 or negating the -s option:
+
+                     zip -s 0 split.zip --out single.zip
+
+              Also see -U (--copy) for more on using copy mode.
+
+       -sb
+       --split-bell
+              If splitting and using split pause mode, ring the bell when  zip
+              pauses for each split destination.
+
+       -sc
+       --show-command
+              Show  the  command line starting zip as processed and exit.  The
+              new command parser permutes the arguments, putting  all  options
+              and  any values associated with them before any non-option argu-
+              ments.  This allows an option to appear anywhere in the  command
+              line  as  long as any values that go with the option go with it.
+              This option displays the command line as zip sees it,  including
+              any arguments from the environment such as from the ZIPOPT vari-
+              able.  Where allowed, options later  in  the  command  line  can
+              override options earlier in the command line.
+
+       -sf
+       --show-files
+              Show  the  files  that  would  be  operated  on, then exit.  For
+              instance, if creating a new archive, this will  list  the  files
+              that  would  be  added.   If the option is negated, -sf-, output
+              only to an open log file.  Screen display is not recommended for
+              large lists.
+
+       -so
+       --show-options
+              Show  all  available options supported by zip as compiled on the
+              current system.  As this command  reads  the  option  table,  it
+              should include all options.  Each line includes the short option
+              (if defined), the long option (if defined), the  format  of  any
+              value  that  goes with the option, if the option can be negated,
+              and a small description.  The value  format  can  be  no  value,
+              required  value,  optional value, single character value, number
+              value, or a list of values.  The output of this  option  is  not
+              intended  to  show  how  to  use  any  option but only show what
+              options are available.
+
+       -sp
+       --split-pause
+              If splitting is enabled with -s, enable split pause mode.   This
+              creates split archives as -s does, but stream writing is used so
+              each split can be closed as soon as it is written and  zip  will
+              pause  between each split to allow changing split destination or
+              media.
+
+              Though this split mode allows writing splits directly to  remov-
+              able  media, it uses stream archive format that may not be read-
+              able by some unzips.  Before relying on splits created with -sp,
+              test a split archive with the unzip you will be using.
+
+              To  convert a stream split archive (created with -sp) to a stan-
+              dard archive see the --out option.
+
+       -su
+       --show-unicode
+              As -sf, but also show Unicode version of the path if exists.
+
+       -sU
+       --show-just-unicode
+              As -sf, but only show Unicode version of  the  path  if  exists,
+              otherwise show the standard version of the path.
+
+       -sv
+       --split-verbose
+              Enable various verbose messages while splitting, showing how the
+              splitting is being done.
+
+       -S
+       --system-hidden
+              [MSDOS, OS/2, WIN32 and ATARI] Include system and hidden  files.
+              [MacOS]  Includes finder invisible files, which are ignored oth-
+              erwise.
+
+       -t mmddyyyy
+       --from-date mmddyyyy
+              Do not operate on files modified prior to  the  specified  date,
+              where  mm  is  the  month  (00-12),  dd  is the day of the month
+              (01-31), and  yyyy  is  the  year.   The  ISO 8601  date  format
+              yyyy-mm-dd is also accepted.  For example:
+
+                     zip -rt 12071991 infamy foo
+
+                     zip -rt 1991-12-07 infamy foo
+
+              will  add  all the files in foo and its subdirectories that were
+              last modified on or after 7 December 1991, to  the  zip  archive
+              infamy.zip.
+
+       -tt mmddyyyy
+       --before-date mmddyyyy
+              Do not operate on files modified after or at the specified date,
+              where mm is the month (00-12),  dd  is  the  day  of  the  month
+              (01-31),  and  yyyy  is  the  year.   The  ISO 8601  date format
+              yyyy-mm-dd is also accepted.  For example:
+
+                     zip -rtt 11301995 infamy foo
+
+                     zip -rtt 1995-11-30 infamy foo
+
+              will add all the files in foo and its subdirectories  that  were
+              last  modified  before  30  November  1995,  to  the zip archive
+              infamy.zip.
+
+       -T
+       --test
+              Test the integrity of the new zip file. If the check fails,  the
+              old  zip  file  is  unchanged  and (with the -m option) no input
+              files are removed.
+
+       -TT cmd
+       --unzip-command cmd
+              Use command cmd instead of 'unzip -tqq' to test an archive  when
+              the  -T  option is used.  On Unix, to use a copy of unzip in the
+              current directory instead of the standard  system  unzip,  could
+              use:
+
+               zip archive file1 file2 -T -TT "./unzip -tqq"
+
+              In  cmd,  {}  is  replaced by the name of the temporary archive,
+              otherwise the name of the archive is appended to the end of  the
+              command.  The return code is checked for success (0 on Unix).
+
+       -u
+       --update
+              Replace (update) an existing entry in the zip archive only if it
+              has been modified more recently than the version already in  the
+              zip archive.  For example:
+
+                     zip -u stuff *
+
+              will  add any new files in the current directory, and update any
+              files which have been modified since the zip  archive  stuff.zip
+              was  last  created/modified  (note that zip will not try to pack
+              stuff.zip into itself when you do this).
+
+              Note that the -u option with no input file arguments  acts  like
+              the -f (freshen) option.
+
+       -U
+       --copy-entries
+              Copy  entries  from  one archive to another.  Requires the --out
+              option to  specify  a  different  output  file  than  the  input
+              archive.  Copy mode is the reverse of -d delete.  When delete is
+              being used with --out, the selected entries are deleted from the
+              archive  and  all  other  entries are copied to the new archive,
+              while copy mode selects the files to include in the new archive.
+              Unlike -u update, input patterns on the command line are matched
+              against archive entries only and not the file system files.  For
+              instance,
+
+                     zip inarchive "*.c" --copy --out outarchive
+
+              copies  entries  with  names ending in .c from inarchive to out-
+              archive.  The wildcard must be escaped on some systems  to  pre-
+              vent  the  shell  from substituting names of files from the file
+              system which may  have  no  relevance  to  the  entries  in  the
+              archive.
+
+              If  no input files appear on the command line and --out is used,
+              copy mode is assumed:
+
+                     zip inarchive --out outarchive
+
+              This is useful for changing split size for instance.  Encrypting
+              and  decrypting  entries  is  not yet supported using copy mode.
+              Use zipcloak for that.
+
+       -UN v
+       --unicode v
+              Determine what zip should do with Unicode file names.   zip 3.0,
+              in  addition  to  the standard file path, now includes the UTF-8
+              translation of the path if the entry path is not entirely  7-bit
+              ASCII.   When  an entry is missing the Unicode path, zip reverts
+              back to the standard file path.   The  problem  with  using  the
+              standard  path is this path is in the local character set of the
+              zip that created the entry, which may  contain  characters  that
+              are  not  valid  in  the  character set being used by the unzip.
+              When zip is reading an archive, if an entry also has  a  Unicode
+              path, zip now defaults to using the Unicode path to recreate the
+              standard path using the current local character set.
+
+              This option can be used to determine what  zip  should  do  with
+              this  path  if  there  is a mismatch between the stored standard
+              path and the stored UTF-8 path (which can happen if the standard
+              path  was  updated).  In all cases, if there is a mismatch it is
+              assumed that the standard path is  more  current  and  zip  uses
+              that.  Values for v are
+
+                     q - quit if paths do not match
+
+                     w - warn, continue with standard path
+
+                     i - ignore, continue with standard path
+
+                     n - no Unicode, do not use Unicode paths
+
+              The default is to warn and continue.
+
+              Characters  that  are not valid in the current character set are
+              escaped as #Uxxxx and #Lxxxxxx, where x is  an  ASCII  character
+              for a hex digit.  The first is used if a 16-bit character number
+              is sufficient to represent the Unicode character and the  second
+              if  the character needs more than 16 bits to represent it's Uni-
+              code character code.  Setting -UN to
+
+                     e - escape
+
+              as in
+
+                     zip archive -sU -UN=e
+
+              forces zip to escape all characters that are not printable 7-bit
+              ASCII.
+
+              Normally zip stores UTF-8 directly in the standard path field on
+              systems where UTF-8 is the current character set and stores  the
+              UTF-8 in the new extra fields otherwise.  The option
+
+                     u - UTF-8
+
+              as in
+
+                     zip archive dir -r -UN=UTF8
+
+              forces  zip  to store UTF-8 as native in the archive.  Note that
+              storing UTF-8 directly is the default on Unix systems that  sup-
+              port  it.   This option could be useful on Windows systems where
+              the escaped path is too large to be a valid path and  the  UTF-8
+              version of the path is smaller, but native UTF-8 is not backward
+              compatible on Windows systems.
+
+       -v
+       --verbose
+              Verbose mode or print diagnostic version info.
+
+              Normally, when applied to real operations, this  option  enables
+              the  display of a progress indicator during compression (see -dd
+              for more on dots) and requests  verbose  diagnostic  info  about
+              zipfile structure oddities.
+
+              However,  when -v is the only command line argument a diagnostic
+              screen is printed instead.  This should now work even if  stdout
+              is redirected to a file, allowing easy saving of the information
+              for sending with bug reports to Info-ZIP.   The  version  screen
+              provides  the help screen header with program name, version, and
+              release date, some pointers to the Info-ZIP home  and  distribu-
+              tion  sites,  and shows information about the target environment
+              (compiler type and version, OS version, compilation date and the
+              enabled optional features used to create the zip executable).
+
+       -V
+       --VMS-portable
+              [VMS]  Save VMS file attributes.  (Files are  truncated at EOF.)
+              When a -V archive is unpacked on a non-VMS  system,   some  file
+              types  (notably  Stream_LF  text  files   and  pure binary files
+              like fixed-512) should be extracted intact.  Indexed  files  and
+              file  types  with embedded record sizes (notably variable-length
+              record types) will probably be seen as corrupt elsewhere.
+
+       -VV
+       --VMS-specific
+              [VMS] Save VMS file attributes, and  all allocated blocks  in  a
+              file,   including  any  data beyond EOF.  Useful for moving ill-
+              formed files  among   VMS  systems.    When  a  -VV  archive  is
+              unpacked  on a non-VMS system, almost all files will appear cor-
+              rupt.
+
+       -w
+       --VMS-versions
+              [VMS] Append the version  number  of  the  files  to  the  name,
+              including  multiple  versions  of files.  Default is to use only
+              the most recent version of a specified file.
+
+       -ww
+       --VMS-dot-versions
+              [VMS] Append the version  number  of  the  files  to  the  name,
+              including  multiple  versions  of  files, using the .nnn format.
+              Default is to use only the most recent version  of  a  specified
+              file.
+
+       -ws
+       --wild-stop-dirs
+              Wildcards match only at a directory level.  Normally zip handles
+              paths as strings and given the paths
+
+                     /foo/bar/dir/file1.c
+
+                     /foo/bar/file2.c
+
+              an input pattern such as
+
+                     /foo/bar/*
+
+              normally would match both paths, the * matching dir/file1.c  and
+              file2.c.   Note  that in the first case a directory boundary (/)
+              was crossed in the match.  With -ws no directory bounds will  be
+              included  in  the  match,  making  wildcards local to a specific
+              directory level.  So, with -ws enabled,  only  the  second  path
+              would be matched.
+
+              When using -ws, use ** to match across directory boundaries as *
+              does normally.
+
+       -x files
+       --exclude files
+              Explicitly exclude the specified files, as in:
+
+                     zip -r foo foo -x \*.o
+
+              which will include the contents of foo in foo.zip while  exclud-
+              ing  all  the  files  that  end in .o.  The backslash avoids the
+              shell filename substitution, so that the name matching  is  per-
+              formed by zip at all directory levels.
+
+              Also possible:
+
+                     zip -r foo foo -x@exclude.lst
+
+              which  will include the contents of foo in foo.zip while exclud-
+              ing  all  the  files  that  match  the  patterns  in  the   file
+              exclude.lst.
+
+              The long option forms of the above are
+
+                     zip -r foo foo --exclude \*.o
+
+              and
+
+                     zip -r foo foo --exclude @exclude.lst
+
+              Multiple patterns can be specified, as in:
+
+                     zip -r foo foo -x \*.o \*.c
+
+              If  there is no space between -x and the pattern, just one value
+              is assumed (no list):
+
+                     zip -r foo foo -x\*.o
+
+              See -i for more on include and exclude.
+
+       -X
+       --no-extra
+              Do not save extra file attributes (Extended Attributes on  OS/2,
+              uid/gid  and  file  times  on  Unix).  The zip format uses extra
+              fields to include additional information for each  entry.   Some
+              extra fields are specific to particular systems while others are
+              applicable to all systems.  Normally when zip reads entries from
+              an  existing archive, it reads the extra fields it knows, strips
+              the rest, and adds the extra fields applicable to  that  system.
+              With -X, zip strips all old fields and only includes the Unicode
+              and Zip64 extra fields (currently these two extra fields  cannot
+              be disabled).
+
+              Negating  this  option,  -X-,  includes  all  the  default extra
+              fields, but also copies over any unrecognized extra fields.
+
+       -y
+       --symlinks
+              For UNIX and VMS (V8.3 and later), store symbolic links as  such
+              in  the zip archive, instead of compressing and storing the file
+              referred to by the link.  This  can  avoid  multiple  copies  of
+              files  being  included in the archive as zip recurses the direc-
+              tory trees and accesses files directly and by links.
+
+       -z
+       --archive-comment
+              Prompt for a multi-line comment for the entire zip archive.  The
+              comment  is  ended by a line containing just a period, or an end
+              of file condition (^D on Unix, ^Z on MSDOS, OS/2, and VMS).  The
+              comment can be taken from a file:
+
+                     zip -z foo < foowhat
+
+       -Z cm
+       --compression-method cm
+              Set  the default compression method.  Currently the main methods
+              supported by zip are store and deflate.  Compression method  can
+              be set to:
+
+              store  -  Setting  the compression method to store forces zip to
+              store entries with no compression.   This  is  generally  faster
+              than compressing entries, but results in no space savings.  This
+              is the same as using -0 (compression level zero).
+
+              deflate - This is the default method for zip.  If zip determines
+              that  storing is better than deflation, the entry will be stored
+              instead.
+
+              bzip2 - If bzip2 support is compiled in, this compression method
+              also  becomes available.  Only some modern unzips currently sup-
+              port the bzip2 compression method, so test the unzip you will be
+              using  before relying on archives using this method (compression
+              method 12).
+
+              For example, to add bar.c to archive foo  using  bzip2  compres-
+              sion:
+
+                     zip -Z bzip2 foo bar.c
+
+              The compression method can be abbreviated:
+
+                     zip -Zb foo bar.c
+
+       -#
+       (-0, -1, -2, -3, -4, -5, -6, -7, -8, -9)
+              Regulate  the  speed of compression using the specified digit #,
+              where -0 indicates no compression (store all  files),  -1  indi-
+              cates  the  fastest  compression speed (less compression) and -9
+              indicates the slowest compression  speed  (optimal  compression,
+              ignores the suffix list). The default compression level is -6.
+
+              Though  still  being  worked, the intention is this setting will
+              control compression speed for  all  compression  methods.   Cur-
+              rently only deflation is controlled.
+
+       -!
+       --use-privileges
+              [WIN32]  Use  priviliges  (if  granted) to obtain all aspects of
+              WinNT security.
+
+       -@
+       --names-stdin
+              Take the list of input files from standard input. Only one file-
+              name per line.
+
+       -$
+       --volume-label
+              [MSDOS,  OS/2,  WIN32]  Include  the  volume label for the drive
+              holding the first file to be compressed.  If you want to include
+              only  the  volume  label  or  to force a specific drive, use the
+              drive name as first file name, as in:
+
+                     zip -$ foo a: c:bar
+
+EXAMPLES
+       The simplest example:
+
+              zip stuff *
+
+       creates the archive stuff.zip (assuming it does not exist) and puts all
+       the  files in the current directory in it, in compressed form (the .zip
+       suffix is added automatically, unless the archive name contains  a  dot
+       already; this allows the explicit specification of other suffixes).
+
+       Because  of the way the shell on Unix does filename substitution, files
+       starting with "." are not included; to include these as well:
+
+              zip stuff .* *
+
+       Even this will not include any subdirectories from the  current  direc-
+       tory.
+
+       To zip up an entire directory, the command:
+
+              zip -r foo foo
+
+       creates  the  archive foo.zip, containing all the files and directories
+       in the directory foo that is contained within the current directory.
+
+       You may want to make a zip archive that  contains  the  files  in  foo,
+       without  recording  the directory name, foo.  You can use the -j option
+       to leave off the paths, as in:
+
+              zip -j foo foo/*
+
+       If you are short on disk space, you might not have enough room to  hold
+       both  the  original  directory  and  the  corresponding  compressed zip
+       archive.  In this case, you can create the archive in steps  using  the
+       -m  option.   If  foo contains the subdirectories tom, dick, and harry,
+       you can:
+
+              zip -rm foo foo/tom
+              zip -rm foo foo/dick
+              zip -rm foo foo/harry
+
+       where the first command creates foo.zip, and the next two  add  to  it.
+       At  the  completion  of  each  zip command, the last created archive is
+       deleted, making room for the next zip command to function.
+
+       Use -s to set the split size and create a split archive.  The  size  is
+       given as a number followed optionally by one of k (kB), m (MB), g (GB),
+       or t (TB).  The command
+
+              zip -s 2g -r split.zip foo
+
+       creates a split archive of the directory foo with splits no bigger than
+       2 GB  each.   If  foo  contained 5 GB of contents and the contents were
+       stored in the split archive without compression (to make  this  example
+       simple),  this  would create three splits, split.z01 at 2 GB, split.z02
+       at 2 GB, and split.zip at a little over 1 GB.
+
+       The -sp option can be used to pause zip between splits to allow  chang-
+       ing  removable  media, for example, but read the descriptions and warn-
+       ings for both -s and -sp below.
+
+       Though zip does not update split archives, zip provides the new  option
+       -O (--output-file) to allow split archives to be updated and saved in a
+       new archive.  For example,
+
+              zip inarchive.zip foo.c bar.c --out outarchive.zip
+
+       reads archive inarchive.zip, even if split, adds the  files  foo.c  and
+       bar.c,  and  writes  the resulting archive to outarchive.zip.  If inar-
+       chive.zip is split then outarchive.zip defaults to the same split size.
+       Be  aware that outarchive.zip and any split files that are created with
+       it are always overwritten without warning.  This may be changed in  the
+       future.
+
+PATTERN MATCHING
+       This  section  applies  only  to Unix.  Watch this space for details on
+       MSDOS and VMS operation.  However, the special  wildcard  characters  *
+       and [] below apply to at least MSDOS also.
+
+       The  Unix  shells (sh, csh, bash, and others) normally do filename sub-
+       stitution (also called "globbing") on command arguments.  Generally the
+       special characters are:
+
+       ?      match any single character
+
+       *      match any number of characters (including none)
+
+       []     match  any  character in the range indicated within the brackets
+              (example: [a-f], [0-9]).  This form of wildcard matching  allows
+              a  user  to specify a list of characters between square brackets
+              and if any of the characters match the expression matches.   For
+              example:
+
+                     zip archive "*.[hc]"
+
+              would  archive all files in the current directory that end in .h
+              or .c.
+
+              Ranges of characters are supported:
+
+                     zip archive "[a-f]*"
+
+              would add to the archive all files  starting  with  "a"  through
+              "f".
+
+              Negation is also supported, where any character in that position
+              not in the list matches.  Negation is supported by adding ! or ^
+              to the beginning of the list:
+
+                     zip archive "*.[!o]"
+
+              matches files that don't end in ".o".
+
+              On  WIN32, [] matching needs to be turned on with the -RE option
+              to avoid the confusion that names with [ or ] have caused.
+
+       When these characters are encountered (without  being  escaped  with  a
+       backslash  or  quotes),  the  shell will look for files relative to the
+       current path that match the pattern, and replace the  argument  with  a
+       list of the names that matched.
+
+       The  zip  program can do the same matching on names that are in the zip
+       archive being modified or, in the  case  of  the  -x  (exclude)  or  -i
+       (include)  options,  on  the  list of files to be operated on, by using
+       backslashes or quotes to tell the shell not to do the  name  expansion.
+       In  general,  when zip encounters a name in the list of files to do, it
+       first looks for the name in the file system.  If it finds it,  it  then
+       adds  it  to the list of files to do.  If it does not find it, it looks
+       for the name in the zip archive being modified (if  it  exists),  using
+       the  pattern matching characters described above, if present.  For each
+       match, it will add that name to the list  of  files  to  be  processed,
+       unless  this  name  matches  one  given with the -x option, or does not
+       match any name given with the -i option.
+
+       The pattern matching includes the path, and so patterns like \*.o match
+       names  that  end in ".o", no matter what the path prefix is.  Note that
+       the backslash must precede every special character (i.e. ?*[]), or  the
+       entire argument must be enclosed in double quotes ("").
+
+       In  general, use backslashes or double quotes for paths that have wild-
+       cards to make zip do the pattern matching for file  paths,  and  always
+       for paths and strings that have spaces or wildcards for -i, -x, -R, -d,
+       and -U and anywhere zip needs to process the wildcards.
+
+ENVIRONMENT
+       The following environment  variables  are  read  and  used  by  zip  as
+       described.
+
+       ZIPOPT
+              contains  default  options  that  will be used when running zip.
+              The contents of this environment variable will get added to  the
+              command line just after the zip command.
+
+       ZIP
+              [Not on RISC OS and VMS] see ZIPOPT
+
+       Zip$Options
+              [RISC OS] see ZIPOPT
+
+       Zip$Exts
+              [RISC  OS]  contains extensions separated by a : that will cause
+              native filenames with one of  the  specified  extensions  to  be
+              added to the zip file with basename and extension swapped.
+
+       ZIP_OPTS
+              [VMS] see ZIPOPT
+
+SEE ALSO
+       compress(1), shar(1L), tar(1), unzip(1L), gzip(1L)
+
+DIAGNOSTICS
+       The exit status (or error level) approximates the exit codes defined by
+       PKWARE and takes on the following values, except under VMS:
+
+              0      normal; no errors or warnings detected.
+
+              2      unexpected end of zip file.
+
+              3      a generic error in the zipfile format was detected.  Pro-
+                     cessing may have completed successfully anyway; some bro-
+                     ken zipfiles created by other archivers have simple work-
+                     arounds.
+
+              4      zip was unable to allocate memory for one or more buffers
+                     during program initialization.
+
+              5      a severe error in the zipfile format was detected.   Pro-
+                     cessing probably failed immediately.
+
+              6      entry  too  large  to  be  processed (such as input files
+                     larger than 2 GB when not using Zip64 or trying  to  read
+                     an existing archive that is too large) or entry too large
+                     to be split with zipsplit
+
+              7      invalid comment format
+
+              8      zip -T failed or out of memory
+
+              9      the user aborted zip prematurely with control-C (or simi-
+                     lar)
+
+              10     zip encountered an error while using a temp file
+
+              11     read or seek error
+
+              12     zip has nothing to do
+
+              13     missing or empty zip file
+
+              14     error writing to a file
+
+              15     zip was unable to create a file to write to
+
+              16     bad command line parameters
+
+              18     zip could not open a specified file to read
+
+              19     zip  was compiled with options not supported on this sys-
+                     tem
+
+       VMS interprets standard Unix (or PC) return values as  other,  scarier-
+       looking  things,  so zip instead maps them into VMS-style status codes.
+       In general, zip sets VMS Facility = 1955 (0x07A3), Code = 2*  Unix_sta-
+       tus,  and  an  appropriate  Severity  (as specified in ziperr.h).  More
+       details  are  included  in   the   VMS-specific   documentation.    See
+       [.vms]NOTES.TXT and [.vms]vms_msg_gen.c.
+
+BUGS
+       zip 3.0 is not compatible with PKUNZIP 1.10. Use zip 1.1 to produce zip
+       files which can be extracted by PKUNZIP 1.10.
+
+       zip files produced by zip 3.0 must not be updated by zip 1.1  or  PKZIP
+       1.10,  if  they contain encrypted members or if they have been produced
+       in a pipe or on a non-seekable device. The old versions of zip or PKZIP
+       would create an archive with an incorrect format.  The old versions can
+       list the contents of the zip file but cannot extract it anyway (because
+       of  the  new  compression algorithm).  If you do not use encryption and
+       use regular disk files, you do not have to care about this problem.
+
+       Under VMS, not all of the odd file formats are treated properly.   Only
+       stream-LF  format  zip files are expected to work with zip.  Others can
+       be converted using Rahul Dhesi's BILF program.   This  version  of  zip
+       handles some of the conversion internally.  When using Kermit to trans-
+       fer zip files from VMS to MSDOS, type "set file  type  block"  on  VMS.
+       When  transfering from MSDOS to VMS, type "set file type fixed" on VMS.
+       In both cases, type "set file type binary" on MSDOS.
+
+       Under some older VMS versions, zip may  hang  for  file  specifications
+       that use DECnet syntax foo::*.*.
+
+       On OS/2, zip cannot match some names, such as those including an excla-
+       mation mark or a hash sign.  This is a bug in OS/2 itself:  the  32-bit
+       DosFindFirst/Next  don't  find  such names.  Other programs such as GNU
+       tar are also affected by this bug.
+
+       Under OS/2, the amount of Extended Attributes displayed by DIR is  (for
+       compatibility)  the  amount returned by the 16-bit version of DosQuery-
+       PathInfo(). Otherwise OS/2 1.3 and 2.0 would report different EA  sizes
+       when  DIRing  a  file.   However,  the structure layout returned by the
+       32-bit DosQueryPathInfo() is a bit different,  it  uses  extra  padding
+       bytes  and  link  pointers  (it's  a linked list) to have all fields on
+       4-byte boundaries for portability to future RISC OS/2 versions.  There-
+       fore  the value reported by zip (which uses this 32-bit-mode size) dif-
+       fers from that reported by DIR.   zip  stores  the  32-bit  format  for
+       portability, even the 16-bit MS-C-compiled version running on OS/2 1.3,
+       so even this one shows the 32-bit-mode size.
+
+AUTHORS
+       Copyright (C) 1997-2008 Info-ZIP.
+
+       Currently distributed under the Info-ZIP license.
+
+       Copyright (C) 1990-1997 Mark Adler, Richard B. Wales, Jean-loup Gailly,
+       Onno  van  der Linden, Kai Uwe Rommel, Igor Mandrichenko, John Bush and
+       Paul Kienitz.
+
+       Original copyright:
+
+       Permission is granted to any individual or institution to use, copy, or
+       redistribute  this  software  so  long as all of the original files are
+       included, that it is not sold  for  profit,  and  that  this  copyright
+       notice is retained.
+
+       LIKE  ANYTHING  ELSE  THAT'S FREE, ZIP AND ITS ASSOCIATED UTILITIES ARE
+       PROVIDED AS IS AND COME WITH NO WARRANTY OF ANY KIND, EITHER  EXPRESSED
+       OR  IMPLIED.  IN  NO EVENT WILL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+       DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE.
+
+       Please send bug reports and comments using the web page  at:  www.info-
+       zip.org.   For  bug  reports,  please  include  the version of zip (see
+       zip -h), the make options used to compile it (see zip -v), the  machine
+       and operating system in use, and as much additional information as pos-
+       sible.
+
+ACKNOWLEDGEMENTS
+       Thanks to R. P. Byrne for his Shrink.Pas program, which  inspired  this
+       project,  and  from which the shrink algorithm was stolen; to Phil Katz
+       for placing in the public domain the zip file format, compression  for-
+       mat,  and  .ZIP  filename extension, and for accepting minor changes to
+       the file format; to Steve Burg for clarifications on the  deflate  for-
+       mat;  to Haruhiko Okumura and Leonid Broukhis for providing some useful
+       ideas for the compression algorithm; to  Keith  Petersen,  Rich  Wales,
+       Hunter Goatley and Mark Adler for providing a mailing list and ftp site
+       for the Info-ZIP group to use; and most importantly,  to  the  Info-ZIP
+       group  itself  (listed  in the file infozip.who) without whose tireless
+       testing and bug-fixing efforts a portable zip would not have been  pos-
+       sible.   Finally  we should thank (blame) the first Info-ZIP moderator,
+       David Kirschbaum, for getting us into this mess  in  the  first  place.
+       The  manual page was rewritten for Unix by R. P. C. Rodgers and updated
+       by E. Gordon for zip 3.0.
+
+Info-ZIP                      16 June 2008 (v3.0)                      ZIP(1L)
diff --git a/zip30.ann b/zip30.ann
new file mode 100644 (file)
index 0000000..2e8cfce
--- /dev/null
+++ b/zip30.ann
@@ -0,0 +1,95 @@
+Zip 3.0
+
+We have posted Zip 3.0, July 5th 2008.  This is a major upgrade
+from Zip 2.32, the current Zip 2.x release.  A quick summary of
+features is below, but see the file WhatsNew for the detailed list
+of major features and upgrades as well as what's on the list for
+Zip 3.1.  Send in your feature suggestions and bug reports.
+
+Quick list of major changes in Zip 3.0:
+
+- Large files.  Support for files and archives greater than 2 GB using
+  large file I/O and the Zip64 extensions.  Also can now have more
+  than 64K entries in an archive.
+
+- Split archives.  Zip now supports split archives, zip archives
+  split into a set of files that can then be stored on removable media
+  for instance.
+
+- Unicode.  If Unicode support is enabled and supported on the system
+  Zip is run on, Zip now can read paths not in the current character
+  set and store those paths in portable UTF-8 format.  These Unicode
+  paths can then be used to partially or fully recreate the paths on
+  other systems depending on the character set support provided by
+  the unzip on the receiving system.  In particular, this allows
+  portability of paths between Windows and Unix.  Unicode comments
+  are also supported on systems where UTF-8 is the current character
+  set.  Unicode comment support for other systems is expected in
+  Zip 3.1.
+
+- New command line parser.  This new parser allows for command line
+  permuting, where options can appear almost anywhere on the command
+  line.  This allows adding options to the end of the command line,
+  for instance.  It also supports long options, allowing for
+  more readable command lines, and also allows lists for the -x
+  exclude and -i include options to appear not just at the end of
+  the command line.  And some bugs in command line processing in
+  Zip 2.32 have been fixed.
+
+- Unix 32-bit UIDs/GIDs.  Now UIDs/GIDs larger than 16 bits are
+  supported, but UnZip 6.0 is needed to restore these larger
+  UIDs/GIDs.  If Zip detects that the current system does not use
+  16-bit UIDs/GIDs, the old 16-bit UID/GID storage is not used
+  as putting 32-bit UIDs/GIDs into 16-bit fields can cause
+  problems.
+
+- New modes.  Additional archive modes have been added, including a
+  difference mode for supporting incremental backups, a file sync
+  mode for synchronizing an existing archive with the current file
+  system (which can be much faster than creating a new archive), and
+  a copy mode that allows copying entries from one archive to another.
+
+- Compression using bzip2.  Now can add bzip2 compression as a
+  compression option in Zip.  bzip2 compression can result in much
+  more compact entries in some cases, but the user should verify
+  that bzip2 is supported on the target unzip before using this new
+  compression choice.
+
+- New Windows dll.  The Windows dll has been updated to support the
+  new Zip64 large file and larger number of entries limits.  This
+  new dll is not backward compatible with the Zip 2.32 dll, as the
+  arguments to the dll have been updated to support the added
+  capabilities, but modifying existing programs to use the new dll
+  should be simple.  See the included Visual Basic example project
+  for details.
+
+- Better streaming and piping.  Zip now has better support of
+  streaming and piping and handles Unix FIFOs (named pipes) better.
+
+- Gobs of new progress information.  Zip can now output progress
+  information, such as how many entries processed and to go, how
+  many bytes processed and to go, and adjustable size progress
+  dots.  If the initial file scan takes longer than about 5
+  seconds, Zip now outputs dots during the scan to avoid a long
+  period of quiet.  Zip can also now generate log files.
+
+- Updated archive fixing.  The archive fixing capability is
+  slightly improved, and now can fix split archives.
+
+- Windows Archive bit support.  The Windows archive bit is now
+  supported, though the new difference mode is probably more
+  reliable than relying on the Windows archive bit for creating
+  incremental backups.
+
+- File lists.  Zip can list the files that would be added to an
+  archive as well as the files in an existing archive.
+
+- Extended help.  A new extended help option lists a very terse
+  summary of the major features of Zip and how to use them.
+
+- Many bug fixes.
+
+As always, see the Zip manual page for details on what Zip has and
+how to use all features.
+
+Enjoy!
diff --git a/zip30f.ann b/zip30f.ann
new file mode 100644 (file)
index 0000000..79285e0
--- /dev/null
@@ -0,0 +1,61 @@
+Zip 3.0f
+
+We have posted Zip Beta 3.0f, September 24th 2007.  This is a beta
+release, but is more or less complete.  See the file WhatsNew for
+a list of major features implemented and what's left.
+
+The archive reading and writing code in this beta has been redone to
+support split archives.  We've extensively tested the code over the
+last year, but you should thoroughly test it yourself before relying
+on it.  Also note that Unicode support is preliminary and may change
+before release, but currently there seems agreement between Info-ZIP
+and others on how to handle storing UTF-8 paths and that approach is
+implemented in Zip 3.0.
+
+Please test this beta and let us know if we're ready to officially
+release Zip 3.0.
+
+New things in Zip 3.0f
+- Split archives - Zip now can create and indirectly update split
+  archives
+- Unicode support - Zip now stores Unicode paths that should be more
+  portable across character sets and languages and Zip now can
+  read Windows file names in most all character sets using Unicode,
+  but this support is preliminary and may change by release
+- bzip2 - bzip2 compression is now supported
+- Console writing - Messages to the console are more consistently
+  formatted
+- Streaming - Directories are now handled better when streaming
+- Date range - Can now use -t and -tt to set a date range
+- UnZip Check - Check if UnZip 6.00 or later is available for
+  testing a Zip64 archive
+- License - minor updates to the license
+- Difference mode - A new option -DF (--dif) creates an output archive that
+  includes only files changed or added since the input archive was created,
+  and might be useful for incremental backups
+- File Sync - New option -FS synchronizes the entries in an archive with the
+  files on the file system, adding, updating, and deleting entries as needed,
+  creating an updated archive that should be the same as a new archive, but
+  since existing entries are copied and not recompressed it can be faster
+- Fix options - Options -F and -FF now fix split archives
+- Copy Mode - This new mode allows selecting archive entries to copy
+  to a new archive
+- Case matching - On Windows and VMS, option -ic (ignore case) turns off
+  case-sensitive matching of command line input patterns when matching
+  entries in an archive
+- Windows OEM - With this compile option, file names are saved on
+  Windows in the local OEM character set, as some other zips do
+- Windows Archive Bit support - On Windows can now select files
+  using the Windows archive bit
+- Global dots - Can now set quiet mode, but output progress dots every
+  so many bytes read, settable from KB to TB, allowing progress to be
+  displayed for large archives without the screen scrolling
+- Empty archives - Options -i or -i@ can now output empty archives,
+  which is useful in some scripts
+- Keep extra fields option - Option -X- allows passing through extra
+  fields that Zip does not process
+- Large file encryption bug fixed - Fix for bug that very rarely
+  results in bad data being stored when deflating and encrypting
+  uncompressable large amounts of data and resulting in CRC errors
+- Show Files option - Can list the files that would be operated on
+- Delete date bug fixed - Bug when using -d with -t or -tt is fixed
diff --git a/zip30g.ann b/zip30g.ann
new file mode 100644 (file)
index 0000000..8ec2e38
--- /dev/null
@@ -0,0 +1,33 @@
+Zip 3.0g
+
+We have posted Zip Beta 3.0g, January 30th 2008.  This is a beta
+release, but is more or less complete and is considered a release
+candidate.  See the file WhatsNew for a list of major features
+implemented and what's left.
+
+The archive reading and writing code in Zip 3.0 has been redone to
+support split archives.  We've extensively tested the code over the
+last year, but you should thoroughly test it yourself before relying
+on it.  Also note that Unicode support has been added and should comply
+with the latest AppNote, but is still new and so may need refining.
+
+Please test this beta and let us know if we're ready to officially
+release Zip 3.0.
+
+New things in Zip 3.0g
+- Add split support to VB project for Zip64.
+
+- Disable reading of Unix FIFOs unless new -FI option used to avoid an
+  archiving operation stopping when it hits an active unfed FIFO.
+
+- The [list] wildcard expression (regular expression matching of any
+  character or range of characters in list) is now disabled on DOS and
+  Windows as it has caused confusion when filenames have [ and ] in
+  them.  The new -RE option reenables it.
+
+- Add negation to many display options such as -dc and -db.
+
+- Allow -FF to read and fix archives having local entries that appear
+  after central directory entries.
+
+- Many small bug fixes.
diff --git a/zip30h.ann b/zip30h.ann
new file mode 100644 (file)
index 0000000..48bda34
--- /dev/null
@@ -0,0 +1,47 @@
+Zip 3.0h
+
+We have posted Zip Beta 3.0h, May 31st 2008.  This is a beta
+release, but is more or less complete and is considered a release
+candidate.  See the file WhatsNew for a list of major features
+implemented and what's left.
+
+The archive reading and writing code in Zip 3.0 has been redone to
+support split archives.  We've extensively tested the code over the
+last year, but you should thoroughly test it yourself before relying
+on it.  Also note that Unicode support has been added and should comply
+with the latest AppNote, but is still new and so may need refining.
+
+Please test this beta and let us know if we're ready to officially
+release Zip 3.0.
+
+New things in Zip 3.0h
+- Allow -@ and -x to work together.
+
+- Change long Unicode escapes from #Lxxxxxxxx to #Lxxxxxx.
+
+- Unicode code cleanup to support additional compilers and also
+  some memory leak fixes.
+
+- Update symbolic link checks.
+
+- Add support for 32-bit UIDs/GIDs.
+
+- Update VMS notes.
+
+- Fix bug where directory scan using -AS (include only files
+  with Windows archive bit set) would skip files in directories
+  with bit not set.
+
+- Add Unix IBM support.
+
+- Change -W to -ws to free -W for later use.
+
+- Fix large file support for MinGW.
+
+- Fix large file support for bzip2.
+
+- Fix compile error in ZipCloak when UNICODE_SUPPORT is not enabled.
+
+- Fix Unicode bug in ZipCloak involving Unicode paths.
+
+- Additional small bug fixes.
diff --git a/zipcloak.c b/zipcloak.c
new file mode 100644 (file)
index 0000000..37bd414
--- /dev/null
@@ -0,0 +1,771 @@
+/*
+  zipcloak.c - Zip 3
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+   This code was originally written in Europe and could be freely distributed
+   from any country except the U.S.A. If this code was imported into the U.S.A,
+   it could not be re-exported from the U.S.A to another country. (This
+   restriction might seem curious but this is what US law required.)
+
+   Now this code can be freely exported and imported.  See README.CR.
+ */
+#define __ZIPCLOAK_C
+
+#ifndef UTIL
+# define UTIL
+#endif
+#include "zip.h"
+#define DEFCPYRT        /* main module: enable copyright string defines! */
+#include "revision.h"
+#include "crc32.h"
+#include "crypt.h"
+#include "ttyio.h"
+#include <signal.h>
+#ifndef NO_STDLIB_H
+#  include <stdlib.h>
+#endif
+
+#if CRYPT       /* defined (as TRUE or FALSE) in crypt.h */
+
+int main OF((int argc, char **argv));
+
+local void handler OF((int sig));
+local void license OF((void));
+local void help OF((void));
+local void version_info OF((void));
+
+/* Temporary zip file pointer */
+local FILE *tempzf;
+
+/* Pointer to CRC-32 table (used for decryption/encryption) */
+#if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB))
+ZCONST ulg near *crc_32_tab;
+#else
+ZCONST uLongf *crc_32_tab;
+#endif
+
+int set_filetype(out_path)
+  char *out_path;
+{
+#ifdef __BEOS__
+  /* Set the filetype of the zipfile to "application/zip" */
+  setfiletype( out_path, "application/zip" );
+#endif
+
+#ifdef __ATHEOS__
+  /* Set the filetype of the zipfile to "application/x-zip" */
+  setfiletype(out_path, "application/x-zip");
+#endif
+
+#ifdef MACOS
+  /* Set the Creator/Type of the zipfile to 'IZip' and 'ZIP ' */
+  setfiletype(out_path, 'IZip', 'ZIP ');
+#endif
+
+#ifdef RISCOS
+  /* Set the filetype of the zipfile to &DDC */
+  setfiletype(out_path, 0xDDC);
+#endif
+  return ZE_OK;
+}
+
+/* rename a split
+ * A split has a tempfile name until it is closed, then
+ * here rename it as out_path the final name for the split.
+ */
+int rename_split(temp_name, out_path)
+  char *temp_name;
+  char *out_path;
+{
+  int r;
+  /* Replace old zip file with new zip file, leaving only the new one */
+  if ((r = replace(out_path, temp_name)) != ZE_OK)
+  {
+    zipwarn("new zip file left as: ", temp_name);
+    free((zvoid *)tempzip);
+    tempzip = NULL;
+    ZIPERR(r, "was replacing split file");
+  }
+  if (zip_attributes) {
+    setfileattr(out_path, zip_attributes);
+  }
+  return ZE_OK;
+}
+
+void zipmessage_nl(a, nl)
+ZCONST char *a;     /* message string to output */
+int nl;             /* 1 = add nl to end */
+/* If nl false, print a message to mesg without new line.
+   If nl true, print and add new line. */
+{
+  if (noisy) {
+    fprintf(mesg, "%s", a);
+    if (nl) {
+      fprintf(mesg, "\n");
+      mesg_line_started = 0;
+    } else {
+      mesg_line_started = 1;
+    }
+    fflush(mesg);
+  }
+}
+
+void zipmessage(a, b)
+ZCONST char *a, *b;     /* message strings juxtaposed in output */
+/* Print a message to mesg and flush.  Write new line first
+   if current line has output already. */
+{
+  if (noisy) {
+    if (mesg_line_started)
+      fprintf(mesg, "\n");
+    fprintf(mesg, "%s%s\n", a, b);
+    mesg_line_started = 0;
+    fflush(mesg);
+  }
+}
+
+/***********************************************************************
+ * Issue a message for the error, clean up files and memory, and exit.
+ */
+void ziperr(code, msg)
+    int code;               /* error code from the ZE_ class */
+    ZCONST char *msg;       /* message about how it happened */
+{
+    if (PERR(code)) perror("zipcloak error");
+    fprintf(mesg, "zipcloak error: %s (%s)\n", ZIPERRORS(code), msg);
+    if (tempzf != NULL) fclose(tempzf);
+    if (tempzip != NULL) {
+        destroy(tempzip);
+        free((zvoid *)tempzip);
+    }
+    if (zipfile != NULL) free((zvoid *)zipfile);
+    EXIT(code);
+}
+
+/***********************************************************************
+ * Print a warning message to mesg (usually stderr) and return.
+ */
+void zipwarn(msg1, msg2)
+    ZCONST char *msg1, *msg2;   /* message strings juxtaposed in output */
+{
+    fprintf(mesg, "zipcloak warning: %s%s\n", msg1, msg2);
+}
+
+
+/***********************************************************************
+ * Upon getting a user interrupt, turn echo back on for tty and abort
+ * cleanly using ziperr().
+ */
+local void handler(sig)
+    int sig;                  /* signal number (ignored) */
+{
+#if (!defined(MSDOS) && !defined(__human68k__) && !defined(RISCOS))
+    echon();
+    putc('\n', mesg);
+#endif
+    ziperr(ZE_ABORT +sig-sig, "aborting");
+    /* dummy usage of sig to avoid compiler warnings */
+}
+
+
+static ZCONST char *public[] = {
+"The encryption code of this program is not copyrighted and is",
+"put in the public domain. It was originally written in Europe",
+"and can be freely distributed in both source and object forms",
+"from any country, including the USA under License Exception",
+"TSU of the U.S. Export Administration Regulations (section",
+"740.13(e)) of 6 June 2002.  (Prior to January 2000, re-export",
+"from the US was a violation of US law.)"
+};
+
+/***********************************************************************
+ * Print license information to stdout.
+ */
+local void license()
+{
+    extent i;             /* counter for copyright array */
+
+    for (i = 0; i < sizeof(swlicense)/sizeof(char *); i++) {
+        puts(swlicense[i]);
+    }
+    putchar('\n');
+    printf("Export notice:\n");
+    for (i = 0; i < sizeof(public)/sizeof(char *); i++) {
+        puts(public[i]);
+    }
+}
+
+
+static ZCONST char *help_info[] = {
+"",
+"ZipCloak %s (%s)",
+#ifdef VM_CMS
+"Usage:  zipcloak [-dq] [-b fm] zipfile",
+#else
+"Usage:  zipcloak [-dq] [-b path] zipfile",
+#endif
+"  the default action is to encrypt all unencrypted entries in the zip file",
+"",
+"  -d  --decrypt      decrypt encrypted entries (copy if given wrong password)",
+#ifdef VM_CMS
+"  -b  --temp-mode    use \"fm\" as the filemode for the temporary zip file",
+#else
+"  -b  --temp-path    use \"path\" for the temporary zip file",
+#endif
+"  -O  --output-file  write output to new zip file",
+"  -q  --quiet        quiet operation, suppress some informational messages",
+"  -h  --help         show this help",
+"  -v  --version      show version info",
+"  -L  --license      show software license"
+  };
+
+/***********************************************************************
+ * Print help (along with license info) to stdout.
+ */
+local void help()
+{
+    extent i;             /* counter for help array */
+
+    for (i = 0; i < sizeof(help_info)/sizeof(char *); i++) {
+        printf(help_info[i], VERSION, REVDATE);
+        putchar('\n');
+    }
+}
+
+
+local void version_info()
+/* Print verbose info about program version and compile time options
+   to stdout. */
+{
+  extent i;             /* counter in text arrays */
+
+  /* Options info array */
+  static ZCONST char *comp_opts[] = {
+#ifdef DEBUG
+    "DEBUG",
+#endif
+#if CRYPT && defined(PASSWD_FROM_STDIN)
+    "PASSWD_FROM_STDIN",
+#endif /* CRYPT && PASSWD_FROM_STDIN */
+    NULL
+  };
+
+  for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
+  {
+    printf(copyright[i], "zipcloak");
+    putchar('\n');
+  }
+  putchar('\n');
+
+  for (i = 0; i < sizeof(versinfolines)/sizeof(char *); i++)
+  {
+    printf(versinfolines[i], "ZipCloak", VERSION, REVDATE);
+    putchar('\n');
+  }
+
+  version_local();
+
+  puts("ZipCloak special compilation options:");
+  for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++)
+  {
+    printf("\t%s\n",comp_opts[i]);
+  }
+  printf("\t[encryption, version %d.%d%s of %s]\n",
+            CR_MAJORVER, CR_MINORVER, CR_BETA_VER, CR_VERSION_DATE);
+}
+
+/* options for zipcloak - 3/5/2004 EG */
+struct option_struct far options[] = {
+  /* short longopt        value_type        negatable        ID    name */
+#ifdef VM_CMS
+    {"b",  "temp-mode",   o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'b',  "temp file mode"},
+#else
+    {"b",  "temp-path",   o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'b',  "path for temp file"},
+#endif
+    {"d",  "decrypt",     o_NO_VALUE,       o_NOT_NEGATABLE, 'd',  "decrypt"},
+    {"h",  "help",        o_NO_VALUE,       o_NOT_NEGATABLE, 'h',  "help"},
+    {"L",  "license",     o_NO_VALUE,       o_NOT_NEGATABLE, 'L',  "license"},
+    {"l",  "",            o_NO_VALUE,       o_NOT_NEGATABLE, 'L',  "license"},
+    {"O",  "output-file", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'O',  "output to new archive"},
+    {"v",  "version",     o_NO_VALUE,       o_NOT_NEGATABLE, 'v',  "version"},
+    /* the end of the list */
+    {NULL, NULL,          o_NO_VALUE,       o_NOT_NEGATABLE, 0,    NULL} /* end has option_ID = 0 */
+  };
+
+
+/***********************************************************************
+ * Encrypt or decrypt all of the entries in a zip file.  See the command
+ * help in help() above.
+ */
+
+int main(argc, argv)
+    int argc;                   /* number of tokens in command line */
+    char **argv;                /* command line tokens */
+{
+    int attr;                   /* attributes of zip file */
+    zoff_t start_offset;        /* start of central directory */
+    int decrypt;                /* decryption flag */
+    int temp_path;              /* 1 if next argument is path for temp files */
+    char passwd[IZ_PWLEN+1];    /* password for encryption or decryption */
+    char verify[IZ_PWLEN+1];    /* password for encryption or decryption */
+#if 0
+    char *q;                    /* steps through option arguments */
+    int r;                      /* arg counter */
+#endif
+    int res;                    /* result code */
+    zoff_t length;              /* length of central directory */
+    FILE *inzip, *outzip;       /* input and output zip files */
+    struct zlist far *z;        /* steps through zfiles linked list */
+    /* used by get_option */
+    unsigned long option; /* option ID returned by get_option */
+    int argcnt = 0;       /* current argcnt in args */
+    int argnum = 0;       /* arg number */
+    int optchar = 0;      /* option state */
+    char *value = NULL;   /* non-option arg, option value or NULL */
+    int negated = 0;      /* 1 = option negated */
+    int fna = 0;          /* current first non-opt arg */
+    int optnum = 0;       /* index in table */
+
+    char **args;               /* copy of argv that can be freed */
+
+#ifdef THEOS
+    setlocale(LC_CTYPE, "I");
+#endif
+
+#ifdef UNICODE_SUPPORT
+# ifdef UNIX
+  /* For Unix, set the locale to UTF-8.  Any UTF-8 locale is
+     OK and they should all be the same.  This allows seeing,
+     writing, and displaying (if the fonts are loaded) all
+     characters in UTF-8. */
+  {
+    char *loc;
+
+    /*
+      loc = setlocale(LC_CTYPE, NULL);
+      printf("  Initial language locale = '%s'\n", loc);
+    */
+
+    loc = setlocale(LC_CTYPE, "en_US.UTF-8");
+
+    /*
+      printf("langinfo %s\n", nl_langinfo(CODESET));
+    */
+
+    if (loc != NULL) {
+      /* using UTF-8 character set so can set UTF-8 GPBF bit 11 */
+      using_utf8 = 1;
+      /*
+        printf("  Locale set to %s\n", loc);
+      */
+    } else {
+      /*
+        printf("  Could not set Unicode UTF-8 locale\n");
+      */
+    }
+  }
+# endif
+#endif
+
+    /* If no args, show help */
+    if (argc == 1) {
+        help();
+        EXIT(ZE_OK);
+    }
+
+    /* Informational messages are written to stdout. */
+    mesg = stdout;
+
+    init_upper();               /* build case map table */
+
+    crc_32_tab = get_crc_table();
+                                /* initialize crc table for crypt */
+
+    /* Go through args */
+    zipfile = tempzip = NULL;
+    tempzf = NULL;
+#ifdef SIGINT
+    signal(SIGINT, handler);
+#endif
+#ifdef SIGTERM                  /* Some don't have SIGTERM */
+    signal(SIGTERM, handler);
+#endif
+#ifdef SIGABRT
+    signal(SIGABRT, handler);
+#endif
+#ifdef SIGBREAK
+    signal(SIGBREAK, handler);
+#endif
+#ifdef SIGBUS
+    signal(SIGBUS, handler);
+#endif
+#ifdef SIGILL
+    signal(SIGILL, handler);
+#endif
+#ifdef SIGSEGV
+    signal(SIGSEGV, handler);
+#endif
+    temp_path = decrypt = 0;
+#if 0
+    /* old command line */
+    for (r = 1; r < argc; r++) {
+        if (*argv[r] == '-') {
+            if (!argv[r][1]) ziperr(ZE_PARMS, "zip file cannot be stdin");
+            for (q = argv[r]+1; *q; q++) {
+                switch (*q) {
+                case 'b':   /* Specify path for temporary file */
+                    if (temp_path) {
+                        ziperr(ZE_PARMS, "use -b before zip file name");
+                    }
+                    temp_path = 1;          /* Next non-option is path */
+                    break;
+                case 'd':
+                    decrypt = 1;  break;
+                case 'h':   /* Show help */
+                    help();
+                    EXIT(ZE_OK);
+                case 'l': case 'L':  /* Show copyright and disclaimer */
+                    license();
+                    EXIT(ZE_OK);
+                case 'q':   /* Quiet operation, suppress info messages */
+                    noisy = 0;  break;
+                case 'v':   /* Show version info */
+                    version_info();
+                    EXIT(ZE_OK);
+                default:
+                    ziperr(ZE_PARMS, "unknown option");
+                } /* switch */
+            } /* for */
+
+        } else if (temp_path == 0) {
+            if (zipfile != NULL) {
+                ziperr(ZE_PARMS, "can only specify one zip file");
+
+            } else if ((zipfile = ziptyp(argv[r])) == NULL) {
+                ziperr(ZE_MEM, "was processing arguments");
+            }
+        } else {
+            tempath = argv[r];
+            temp_path = 0;
+        } /* if */
+    } /* for */
+
+#else
+
+    /* new command line */
+
+    zipfile = NULL;
+    out_path = NULL;
+
+    /* make copy of args that can use with insert_arg() */
+    args = copy_args(argv, 0);
+
+    /*
+    -------------------------------------------
+    Process command line using get_option
+    -------------------------------------------
+
+    Each call to get_option() returns either a command
+    line option and possible value or a non-option argument.
+    Arguments are permuted so that all options (-r, -b temp)
+    are returned before non-option arguments (zipfile).
+    Returns 0 when nothing left to read.
+    */
+
+    /* set argnum = 0 on first call to init get_option */
+    argnum = 0;
+
+    /* get_option returns the option ID and updates parameters:
+           args    - usually same as argv if no argument file support
+           argcnt  - current argc for args
+           value   - char* to value (free() when done with it) or NULL if no value
+           negated - option was negated with trailing -
+    */
+
+    while ((option = get_option(&args, &argcnt, &argnum,
+                                &optchar, &value, &negated,
+                                &fna, &optnum, 0)))
+    {
+      switch (option)
+      {
+        case 'b':   /* Specify path for temporary file */
+          if (temp_path) {
+            ziperr(ZE_PARMS, "more than one temp_path");
+          }
+          temp_path = 1;
+          tempath = value;
+          break;
+        case 'd':
+          decrypt = 1;  break;
+        case 'h':   /* Show help */
+          help();
+          EXIT(ZE_OK);
+        case 'l': case 'L':  /* Show copyright and disclaimer */
+          license();
+          EXIT(ZE_OK);
+        case 'O':   /* Output to new zip file instead of updating original zip file */
+          if ((out_path = ziptyp(value)) == NULL) {
+            ziperr(ZE_MEM, "was processing arguments");
+          }
+          free(value);
+          break;
+        case 'q':   /* Quiet operation, suppress info messages */
+          noisy = 0;  break;
+        case 'v':   /* Show version info */
+          version_info();
+          EXIT(ZE_OK);
+        case o_NON_OPTION_ARG:
+          /* not an option */
+          /* no more options as permuting */
+          /* just dash also ends up here */
+
+          if (strcmp(value, "-") == 0) {
+            ziperr(ZE_PARMS, "zip file cannot be stdin");
+          } else if (zipfile != NULL) {
+            ziperr(ZE_PARMS, "can only specify one zip file");
+          }
+
+          if ((zipfile = ziptyp(value)) == NULL) {
+            ziperr(ZE_MEM, "was processing arguments");
+          }
+          free(value);
+          break;
+
+        default:
+          ziperr(ZE_PARMS, "unknown option");
+      }
+    }
+
+    free_args(args);
+
+#endif
+
+    if (zipfile == NULL) ziperr(ZE_PARMS, "need to specify zip file");
+
+    /* in_path is the input zip file */
+    if ((in_path = malloc(strlen(zipfile) + 1)) == NULL) {
+      ziperr(ZE_MEM, "input");
+    }
+    strcpy(in_path, zipfile);
+
+    /* out_path defaults to in_path */
+    if (out_path == NULL) {
+      if ((out_path = malloc(strlen(zipfile) + 1)) == NULL) {
+        ziperr(ZE_MEM, "output");
+      }
+      strcpy(out_path, zipfile);
+    }
+
+    /* Read zip file */
+    if ((res = readzipfile()) != ZE_OK) ziperr(res, zipfile);
+    if (zfiles == NULL) ziperr(ZE_NAME, zipfile);
+
+    /* Check for something to do */
+    for (z = zfiles; z != NULL; z = z->nxt) {
+        if (decrypt ? z->flg & 1 : !(z->flg & 1)) break;
+    }
+    if (z == NULL) {
+        ziperr(ZE_NONE, decrypt ? "no encrypted files"
+                       : "all files encrypted already");
+    }
+
+    /* Before we get carried away, make sure zip file is writeable */
+    if ((inzip = fopen(zipfile, "a")) == NULL) ziperr(ZE_CREAT, zipfile);
+    fclose(inzip);
+    attr = getfileattr(zipfile);
+
+    /* Open output zip file for writing */
+#if defined(UNIX) && !defined(NO_MKSTEMP)
+    {
+      int yd;
+      int i;
+
+      /* use mkstemp to avoid race condition and compiler warning */
+
+      if (tempath != NULL)
+      {
+        /* if -b used to set temp file dir use that for split temp */
+        if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
+          ZIPERR(ZE_MEM, "allocating temp filename");
+        }
+        strcpy(tempzip, tempath);
+        if (lastchar(tempzip) != '/')
+          strcat(tempzip, "/");
+      }
+      else
+      {
+        /* create path by stripping name and appending template */
+        if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
+        ZIPERR(ZE_MEM, "allocating temp filename");
+        }
+        strcpy(tempzip, zipfile);
+        for(i = strlen(tempzip); i > 0; i--) {
+          if (tempzip[i - 1] == '/')
+            break;
+        }
+        tempzip[i] = '\0';
+      }
+      strcat(tempzip, "ziXXXXXX");
+
+      if ((yd = mkstemp(tempzip)) == EOF) {
+        ZIPERR(ZE_TEMP, tempzip);
+      }
+      if ((y = tempzf = outzip = fdopen(yd, FOPW_TMP)) == NULL) {
+        ZIPERR(ZE_TEMP, tempzip);
+      }
+    }
+#else
+    if ((y = tempzf = outzip = fopen(tempzip = tempname(zipfile), FOPW)) == NULL) {
+        ziperr(ZE_TEMP, tempzip);
+    }
+#endif
+
+    /* Get password */
+    if (getp("Enter password: ", passwd, IZ_PWLEN+1) == NULL)
+        ziperr(ZE_PARMS,
+               "stderr is not a tty (you may never see this message!)");
+
+    if (decrypt == 0) {
+        if (getp("Verify password: ", verify, IZ_PWLEN+1) == NULL)
+               ziperr(ZE_PARMS,
+                      "stderr is not a tty (you may never see this message!)");
+
+        if (strcmp(passwd, verify))
+               ziperr(ZE_PARMS, "password verification failed");
+
+        if (*passwd == '\0')
+               ziperr(ZE_PARMS, "zero length password not allowed");
+    }
+
+    /* Open input zip file again, copy preamble if any */
+    if ((in_file = fopen(zipfile, FOPR)) == NULL) ziperr(ZE_NAME, zipfile);
+
+    if (zipbeg && (res = bfcopy(zipbeg)) != ZE_OK)
+    {
+        ziperr(res, res == ZE_TEMP ? tempzip : zipfile);
+    }
+    tempzn = zipbeg;
+
+    /* Go through local entries, copying, encrypting, or decrypting */
+    for (z = zfiles; z != NULL; z = z->nxt) {
+        if (decrypt && (z->flg & 1)) {
+            printf("decrypting: %s", z->zname);
+            fflush(stdout);
+            if ((res = zipbare(z, passwd)) != ZE_OK)
+            {
+                if (res != ZE_MISS) ziperr(res, "was decrypting an entry");
+                printf(" (wrong password--just copying)");
+                fflush(stdout);
+            }
+            putchar('\n');
+
+        } else if ((!decrypt) && !(z->flg & 1)) {
+            printf("encrypting: %s\n", z->zname);
+            fflush(stdout);
+            if ((res = zipcloak(z, passwd)) != ZE_OK)
+            {
+                ziperr(res, "was encrypting an entry");
+            }
+        } else {
+            printf("   copying: %s\n", z->zname);
+            fflush(stdout);
+            if ((res = zipcopy(z)) != ZE_OK)
+            {
+                ziperr(res, "was copying an entry");
+            }
+        } /* if */
+    } /* for */
+
+    fclose(in_file);
+
+
+    /* Write central directory and end of central directory */
+
+    /* get start of central */
+    if ((start_offset = zftello(outzip)) == (zoff_t)-1)
+        ziperr(ZE_TEMP, tempzip);
+
+    for (z = zfiles; z != NULL; z = z->nxt) {
+        if ((res = putcentral(z)) != ZE_OK) ziperr(res, tempzip);
+    }
+
+    /* get end of central */
+    if ((length = zftello(outzip)) == (zoff_t)-1)
+        ziperr(ZE_TEMP, tempzip);
+
+    length -= start_offset;               /* compute length of central */
+    if ((res = putend((zoff_t)zcount, length, start_offset, zcomlen,
+                      zcomment)) != ZE_OK) {
+        ziperr(res, tempzip);
+    }
+    tempzf = NULL;
+    if (fclose(outzip)) ziperr(ZE_TEMP, tempzip);
+    if ((res = replace(out_path, tempzip)) != ZE_OK) {
+        zipwarn("new zip file left as: ", tempzip);
+        free((zvoid *)tempzip);
+        tempzip = NULL;
+        ziperr(res, "was replacing the original zip file");
+    }
+    free((zvoid *)tempzip);
+    tempzip = NULL;
+    setfileattr(zipfile, attr);
+#ifdef RISCOS
+    /* Set the filetype of the zipfile to &DDC */
+    setfiletype(zipfile, 0xDDC);
+#endif
+    free((zvoid *)in_path);
+    free((zvoid *)out_path);
+
+    free((zvoid *)zipfile);
+    zipfile = NULL;
+
+    /* Done! */
+    RETURN(0);
+}
+#else /* !CRYPT */
+
+
+/* below is only used if crypt is not enabled */
+
+struct option_struct far options[] = {
+  /* short longopt        value_type        negatable        ID    name */
+    {"h",  "help",        o_NO_VALUE,       o_NOT_NEGATABLE, 'h',  "help"},
+    /* the end of the list */
+    {NULL, NULL,          o_NO_VALUE,       o_NOT_NEGATABLE, 0,    NULL} /* end has option_ID = 0 */
+  };
+
+
+int main OF((void));
+
+void zipwarn(msg1, msg2)
+ZCONST char  *msg1, *msg2;
+{
+    /* Tell picky compilers to shut up about unused variables */
+    msg1 = msg1; msg2 = msg2;
+}
+
+void ziperr(c, h)
+int  c;
+ZCONST char *h;
+{
+    /* Tell picky compilers to shut up about unused variables */
+    c = c; h = h;
+}
+
+int main()
+{
+    fprintf(mesg, "\
+This version of ZipCloak does not support encryption.  Get the current Zip\n\
+source distribution and recompile ZipCloak after you have added an option to\n\
+define the symbol USE_CRYPT to the C compiler's command arguments.\n");
+    RETURN(1);
+}
+
+#endif /* ?CRYPT */
diff --git a/zipcloak.txt b/zipcloak.txt
new file mode 100644 (file)
index 0000000..0f24dc0
--- /dev/null
@@ -0,0 +1,75 @@
+zipcloak(1)                                                        zipcloak(1)
+
+NAME
+       zipcloak - encrypt entries in a zipfile
+
+SYNOPSIS
+       zipcloak [-d] [-b path] [-h] [-v] [-L] zipfile
+
+ARGUMENTS
+       zipfile  Zipfile to encrypt entries in
+
+OPTIONS
+       -b path
+       --temp-path path
+              Use the directory given by path for the temporary zip file.
+
+       -d
+       --decrypt
+              Decrypt encrypted entries (copy if given wrong password).
+
+       -h
+       --help
+              Show a short help.
+
+       -L
+       --license
+              Show software license.
+
+       -O path
+       --output-file zipfile
+              Write output to new archive zipfile, leaving original archive as
+              is.
+
+       -q
+       --quiet
+              Quiet operation.  Suppresses some informational messages.
+
+       -v
+       --version
+              Show version information.
+
+DESCRIPTION
+       zipcloak encrypts all unencrypted entries in the zipfile.  This is  the
+       default action.
+
+       The -d option is used to decrypt encrypted entries in the zipfile.
+
+       zipcloak uses original zip encryption which is considered weak.
+
+       Note:  The  encryption  code  of this program is not copyrighted and is
+              put in the public domain.  It was originally written  in  Europe
+              and  can  be  freely  distributed from any country including the
+              U.S.A.  (Previously if this program was imported into the U.S.A,
+              it  could not be re-exported from the U.S.A to another country.)
+              See the file README.CR included in the source  distribution  for
+              more on this.  Otherwise, the Info-ZIP license applies.
+
+EXAMPLES
+       To be added.
+
+BUGS
+       Large files (> 2 GB) and large archives not yet supported.
+
+       Split  archives  not  yet  supported.   A work around is to convert the
+       split archive to a single-file archive using zip and then use  zipcloak
+       on  the single-file archive.  If needed, the resulting archive can then
+       be split again using zip.
+
+SEE ALSO
+       zip(1), unzip(1)
+
+AUTHOR
+       Info-ZIP
+
+                              v3.0 of 8 May 2008                   zipcloak(1)
diff --git a/ziperr.h b/ziperr.h
new file mode 100644 (file)
index 0000000..19c7655
--- /dev/null
+++ b/ziperr.h
@@ -0,0 +1,115 @@
+/*
+  ziperr.h - Zip 3
+
+  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  ziperr.h by Mark Adler
+ */
+
+
+/*
+ * VMS message file ident string.  (The "-xxx" suffix should be
+ * incremented when messages are changed for a particular program
+ * version.)  Used only when generating the VMS message source file, but
+ * that can be done on a non-VMS system.
+ */
+#define VMS_MSG_IDENT "V3.0-000"
+
+/* VMS-compatible "severity" values (bits 2:0): */
+#define ZE_S_WARNING 0x00
+#define ZE_S_SUCCESS 0x01
+#define ZE_S_ERROR   0x02
+#define ZE_S_INFO    0x03
+#define ZE_S_SEVERE  0x04
+#define ZE_S_UNUSED  0x07
+
+/* Flags: */
+#define ZE_S_PERR    0x10
+
+
+ /* Error return values.  The values 0..4 and 12..18 follow the conventions
+   of PKZIP.   The values 4..10 are all assigned to "insufficient memory"
+   by PKZIP, so the codes 5..10 are used here for other purposes. */
+#define ZE_MISS         -1      /* used by procname(), zipbare() */
+#define ZE_OK           0       /* success */
+#define ZE_EOF          2       /* unexpected end of zip file */
+#define ZE_FORM         3       /* zip file structure error */
+#define ZE_MEM          4       /* out of memory */
+#define ZE_LOGIC        5       /* internal logic error */
+#define ZE_BIG          6       /* entry too large to split, read, or write */
+#define ZE_NOTE         7       /* invalid comment format */
+#define ZE_TEST         8       /* zip test (-T) failed or out of memory */
+#define ZE_ABORT        9       /* user interrupt or termination */
+#define ZE_TEMP         10      /* error using a temp file */
+#define ZE_READ         11      /* read or seek error */
+#define ZE_NONE         12      /* nothing to do */
+#define ZE_NAME         13      /* missing or empty zip file */
+#define ZE_WRITE        14      /* error writing to a file */
+#define ZE_CREAT        15      /* couldn't open to write */
+#define ZE_PARMS        16      /* bad command line */
+#define ZE_OPEN         18      /* could not open a specified file to read */
+#define ZE_COMPERR      19      /* error in compilation options */
+#define ZE_ZIP64        20      /* Zip64 not supported */
+
+#define ZE_MAXERR       20      /* the highest error number */
+
+
+/* Error messages for the ziperr() function in the zip programs. */
+
+#ifdef GLOBALS
+struct
+{
+    char *name;
+    char *string;
+    int severity;
+} ziperrors[ZE_MAXERR + 1] = {
+/*  0 */ { "OK",      "Normal successful completion", ZE_S_SUCCESS },
+/*  1 */ { "",        "",                             ZE_S_UNUSED },
+/*  2 */ { "EOF",     "Unexpected end of zip file",   ZE_S_SEVERE },
+/*  3 */ { "FORM",    "Zip file structure invalid",   ZE_S_ERROR },
+/*  4 */ { "MEM",     "Out of memory",                ZE_S_SEVERE },
+/*  5 */ { "LOGIC",   "Internal logic error",         ZE_S_SEVERE },
+/*  6 */ { "BIG",     "Entry too big to split, read, or write",
+                                                      ZE_S_ERROR },
+/*  7 */ { "NOTE",    "Invalid comment format",       ZE_S_ERROR },
+/*  8 */ { "TEST",    "Zip file invalid, could not spawn unzip, or wrong unzip",
+                                                      ZE_S_SEVERE },
+/*  9 */ { "ABORT",   "Interrupted",                  ZE_S_ERROR },
+/* 10 */ { "TEMP",    "Temporary file failure",       ZE_S_SEVERE | ZE_S_PERR },
+/* 11 */ { "READ",    "Input file read failure",      ZE_S_SEVERE | ZE_S_PERR },
+/* 12 */ { "NONE",    "Nothing to do!",               ZE_S_WARNING },
+/* 13 */ { "NAME",    "Missing or empty zip file",    ZE_S_ERROR },
+/* 14 */ { "WRITE",   "Output file write failure",    ZE_S_SEVERE | ZE_S_PERR },
+/* 15 */ { "CREAT",   "Could not create output file", ZE_S_SEVERE | ZE_S_PERR },
+/* 16 */ { "PARMS",   "Invalid command arguments",    ZE_S_ERROR },
+/* 17 */ { "",        "",                             ZE_S_UNUSED },
+/* 18 */ { "OPEN",    "File not found or no read permission",
+                                                      ZE_S_ERROR | ZE_S_PERR },
+/* 19 */ { "COMPERR", "Not supported",                ZE_S_SEVERE },
+/* 20 */ { "ZIP64",   "Attempt to read unsupported Zip64 archive",
+                                                      ZE_S_SEVERE }
+#  ifdef AZTEC_C
+          ,     /* extremely lame compiler bug workaround */
+#  endif
+};
+#else /* !GLOBALS */
+/* Error messages for ziperr() */
+extern struct
+{
+    char *name;
+    char *string;
+    int severity;
+} ziperrors[ZE_MAXERR + 1];
+#endif /* ?GLOBALS */
+
+/* Macro to determine whether to call perror() or not. */
+#define PERR(e) (ziperrors[e].severity & ZE_S_PERR)
+
+/* Macro for easy access to the message string. */
+#define ZIPERRORS(e) ziperrors[e].string
diff --git a/zipfile.c b/zipfile.c
new file mode 100644 (file)
index 0000000..1990cde
--- /dev/null
+++ b/zipfile.c
@@ -0,0 +1,6820 @@
+/*
+  zipfile.c - Zip 3
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  zipfile.c by Mark Adler.
+ */
+#define __ZIPFILE_C
+
+#include "zip.h"
+#include "revision.h"
+#ifdef UNICODE_SUPPORT
+# include "crc32.h"
+#endif
+
+/* for realloc 2/6/2005 EG */
+#include <stdlib.h>
+
+#include <errno.h>
+
+/* for toupper() */
+#include <ctype.h>
+
+#ifdef VMS
+#  include "vms/vms.h"
+#  include "vms/vmsmunch.h"
+#  include "vms/vmsdefs.h"
+#endif
+
+#ifdef WIN32
+#  define WIN32_LEAN_AND_MEAN
+#  include <windows.h>
+#endif
+
+/*
+ * XXX start of zipfile.h
+ */
+#ifdef THEOS
+ /* Macros cause stack overflow in compiler */
+ ush SH(uch* p) { return ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)); }
+ ulg LG(uch* p) { return ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)); }
+#else /* !THEOS */
+ /* Macros for converting integers in little-endian to machine format */
+# define SH(a) ((ush)(((ush)(uch)(a)[0]) | (((ush)(uch)(a)[1]) << 8)))
+# define LG(a) ((ulg)SH(a) | ((ulg)SH((a)+2) << 16))
+# ifdef ZIP64_SUPPORT           /* zip64 support 08/31/2003 R.Nausedat */
+#  define LLG(a) ((zoff_t)LG(a) | ((zoff_t)LG((a)+4) << 32))
+# endif
+#endif /* ?THEOS */
+
+/* Macros for writing machine integers to little-endian format */
+#define PUTSH(a,f) {putc((char)((a) & 0xff),(f)); putc((char)((a) >> 8),(f));}
+#define PUTLG(a,f) {PUTSH((a) & 0xffff,(f)) PUTSH((a) >> 16,(f))}
+
+#ifdef ZIP64_SUPPORT           /* zip64 support 08/31/2003 R.Nausedat */
+# define PUTLLG(a,f) {PUTLG((a) & 0xffffffff,(f)) PUTLG((a) >> 32,(f))}
+#endif
+
+
+/* -- Structure of a ZIP file -- */
+
+/* Signatures for zip file information headers */
+#define LOCSIG     0x04034b50L
+#define CENSIG     0x02014b50L
+#define ENDSIG     0x06054b50L
+#define EXTLOCSIG  0x08074b50L
+
+/* Offsets of values in headers */
+/* local header */
+#define LOCVER  0               /* version needed to extract */
+#define LOCFLG  2               /* encrypt, deflate flags */
+#define LOCHOW  4               /* compression method */
+#define LOCTIM  6               /* last modified file time, DOS format */
+#define LOCDAT  8               /* last modified file date, DOS format */
+#define LOCCRC  10              /* uncompressed crc-32 for file */
+#define LOCSIZ  14              /* compressed size in zip file */
+#define LOCLEN  18              /* uncompressed size */
+#define LOCNAM  22              /* length of filename */
+#define LOCEXT  24              /* length of extra field */
+
+/* extended local header (data descriptor) following file data (if bit 3 set) */
+/* if Zip64 then all are 8 byte and not below - 11/1/03 EG */
+#define EXTCRC  0               /* uncompressed crc-32 for file */
+#define EXTSIZ  4               /* compressed size in zip file */
+#define EXTLEN  8               /* uncompressed size */
+
+/* central directory header */
+#define CENVEM  0               /* version made by */
+#define CENVER  2               /* version needed to extract */
+#define CENFLG  4               /* encrypt, deflate flags */
+#define CENHOW  6               /* compression method */
+#define CENTIM  8               /* last modified file time, DOS format */
+#define CENDAT  10              /* last modified file date, DOS format */
+#define CENCRC  12              /* uncompressed crc-32 for file */
+#define CENSIZ  16              /* compressed size in zip file */
+#define CENLEN  20              /* uncompressed size */
+#define CENNAM  24              /* length of filename */
+#define CENEXT  26              /* length of extra field */
+#define CENCOM  28              /* file comment length */
+#define CENDSK  30              /* disk number start */
+#define CENATT  32              /* internal file attributes */
+#define CENATX  34              /* external file attributes */
+#define CENOFF  38              /* relative offset of local header */
+
+/* end of central directory record */
+#define ENDDSK  0               /* number of this disk */
+#define ENDBEG  2               /* number of the starting disk */
+#define ENDSUB  4               /* entries on this disk */
+#define ENDTOT  6               /* total number of entries */
+#define ENDSIZ  8               /* size of entire central directory */
+#define ENDOFF  12              /* offset of central on starting disk */
+#define ENDCOM  16              /* length of zip file comment */
+
+/* zip64 support 08/31/2003 R.Nausedat */
+
+/* EOCDL_SIG used to detect Zip64 archive */
+#define ZIP64_EOCDL_SIG                  0x07064b50
+/* EOCDL size is used in the empty archive check */
+#define ZIP64_EOCDL_OFS_SIZE                20
+
+#define ZIP_UWORD16_MAX                  0xFFFF                        /* border value */
+#define ZIP_UWORD32_MAX                  0xFFFFFFFF                    /* border value */
+#define ZIP_EF_HEADER_SIZE               4                             /* size of pre-header of extra fields */
+
+#ifdef ZIP64_SUPPORT
+# define ZIP64_EXTCRC                    0                             /* uncompressed crc-32 for file */
+# define ZIP64_EXTSIZ                    4                             /* compressed size in zip file */
+# define ZIP64_EXTLEN                    12                            /* uncompressed size */
+# define ZIP64_EOCD_SIG                  0x06064b50
+# define ZIP64_EOCD_OFS_SIZE             40
+# define ZIP64_EOCD_OFS_CD_START         48
+# define ZIP64_EOCDL_OFS_SIZE                20
+# define ZIP64_EOCDL_OFS_EOCD_START      8
+# define ZIP64_EOCDL_OFS_TOTALDISKS      16
+# define ZIP64_MIN_VER                   45                            /* min version to set in the CD extra records */
+# define ZIP64_CENTRAL_DIR_TAIL_SIZE     (56 - 8 - 4)                  /* size of zip64 central dir tail, minus sig and size field bytes */
+# define ZIP64_CENTRAL_DIR_TAIL_SIG      0x06064B50L                   /* zip64 central dir tail signature */
+# define ZIP64_CENTRAL_DIR_TAIL_END_SIG  0x07064B50L                   /* zip64 end of cen dir locator signature */
+# define ZIP64_LARGE_FILE_HEAD_SIZE      32                            /* total size of zip64 extra field */
+# define ZIP64_EF_TAG                    0x0001                        /* ID for zip64 extra field */
+# define ZIP64_EFIELD_OFS_OSIZE          ZIP_EF_HEADER_SIZE            /* zip64 extra field: offset to original file size */
+# define ZIP64_EFIELD_OFS_CSIZE          (ZIP64_EFIELD_OFS_OSIZE + 8)  /* zip64 extra field: offset to compressed file size */
+# define ZIP64_EFIELD_OFS_OFS            (ZIP64_EFIELD_OFS_CSIZE + 8)  /* zip64 extra field: offset to offset in archive */
+# define ZIP64_EFIELD_OFS_DISK           (ZIP64_EFIELD_OFS_OFS + 8)    /* zip64 extra field: offset to start disk # */
+/* -------------------------------------------------------------------------------------------------------------------------- */
+ local int adjust_zip_local_entry OF((struct zlist far *));
+ local void adjust_zip_central_entry OF((struct zlist far *));
+#if 0
+ local int remove_local_extra_field OF((struct zlist far *, ulg));
+ local int remove_central_extra_field OF((struct zlist far *, ulg));
+#endif
+ local int add_central_zip64_extra_field OF((struct zlist far *));
+ local int add_local_zip64_extra_field OF((struct zlist far *));
+#endif /* ZIP64_SUPPORT */
+#ifdef UNICODE_SUPPORT
+# define UTF8_PATH_EF_TAG                0x7075                        /* ID for Unicode path (up) extra field */
+ local int add_Unicode_Path_local_extra_field OF((struct zlist far *));
+ local int add_Unicode_Path_cen_extra_field OF((struct zlist far *));
+#endif
+
+/* New General Purpose Bit Flag bit 11 flags when entry path and
+   comment are in UTF-8 */
+#define UTF8_BIT (1 << 11)
+
+/* moved out of ZIP64_SUPPORT - 2/6/2005 EG */
+local void write_ushort_to_mem OF((ush, char *));                      /* little endian conversions */
+local void write_ulong_to_mem OF((ulg, char *));
+#ifdef ZIP64_SUPPORT
+ local void write_int64_to_mem OF((uzoff_t, char *));
+#endif /* def ZIP64_SUPPORT */
+#ifdef UNICODE_SUPPORT
+ local void write_string_to_mem OF((char *, char *));
+#endif
+#if 0
+local char *get_extra_field OF((ush, char *, unsigned));           /* zip64 */
+#endif
+#ifdef UNICODE_SUPPORT
+local void read_Unicode_Path_entry OF((struct zlist far *));
+local void read_Unicode_Path_local_entry OF((struct zlist far *));
+#endif
+
+/* added these self allocators - 2/6/2005 EG */
+local void append_ushort_to_mem OF((ush, char **, extent *, extent *));
+local void append_ulong_to_mem OF((ulg, char **, extent *, extent *));
+#ifdef ZIP64_SUPPORT
+ local void append_int64_to_mem OF((uzoff_t, char **, extent *, extent *));
+#endif /* def ZIP64_SUPPORT */
+local void append_string_to_mem OF((char *, int, char**, extent *, extent *));
+
+
+/* Local functions */
+
+local int find_next_signature OF((FILE *f));
+local int find_signature OF((FILE *, ZCONST char *));
+local int is_signature OF((ZCONST char *, ZCONST char *));
+local int at_signature OF((FILE *, ZCONST char *));
+
+local int zqcmp OF((ZCONST zvoid *, ZCONST zvoid *));
+#ifdef UNICODE_SUPPORT
+local int zuqcmp OF((ZCONST zvoid *, ZCONST zvoid *));
+#endif
+#if 0
+ local int scanzipf_reg OF((FILE *f));
+#endif
+local int scanzipf_regnew OF((void));
+#ifndef UTIL
+ local int rqcmp OF((ZCONST zvoid *, ZCONST zvoid *));
+ local int zbcmp OF((ZCONST zvoid *, ZCONST zvoid far *));
+# ifdef UNICODE_SUPPORT
+ local int zubcmp OF((ZCONST zvoid *, ZCONST zvoid far *));
+#  if 0
+ local int zuebcmp OF((ZCONST zvoid *, ZCONST zvoid far *));
+#  endif
+# endif /* UNICODE_SUPPORT */
+ local void zipoddities OF((struct zlist far *));
+# if 0
+  local int scanzipf_fix OF((FILE *f));
+# endif
+ local int scanzipf_fixnew OF((void));
+# ifdef USE_EF_UT_TIME
+   local int ef_scan_ut_time OF((char *ef_buf, extent ef_len, int ef_is_cent,
+                                   iztimes *z_utim));
+# endif /* USE_EF_UT_TIME */
+ local void cutpath OF((char *p, int delim));
+#endif /* !UTIL */
+
+/*
+ * XXX end of zipfile.h
+ */
+
+/* Local data */
+
+#ifdef HANDLE_AMIGA_SFX
+   ulg amiga_sfx_offset;        /* place where size field needs updating */
+#endif
+
+local int zqcmp(a, b)
+ZCONST zvoid *a, *b;          /* pointers to pointers to zip entries */
+/* Used by qsort() to compare entries in the zfile list.
+ * Compares the internal names z->iname */
+{
+  char *aname = (*(struct zlist far **)a)->iname;
+  char *bname = (*(struct zlist far **)b)->iname;
+
+  return namecmp(aname, bname);
+}
+
+#ifdef UNICODE_SUPPORT
+local int zuqcmp(a, b)
+ZCONST zvoid *a, *b;          /* pointers to pointers to zip entries */
+/* Used by qsort() to compare entries in the zfile list.
+ * Compares the internal names z->zuname */
+{
+  char *aname = (*(struct zlist far **)a)->iname;
+  char *bname = (*(struct zlist far **)b)->iname;
+
+  /* zuname could be NULL */
+  if ((*(struct zlist far **)a)->zuname)
+    aname = (*(struct zlist far **)a)->zuname;
+  if ((*(struct zlist far **)b)->zuname)
+    bname = (*(struct zlist far **)b)->zuname;
+  return namecmp(aname, bname);
+}
+#endif
+
+
+#ifndef UTIL
+
+local int rqcmp(a, b)
+ZCONST zvoid *a, *b;          /* pointers to pointers to zip entries */
+/* Used by qsort() to compare entries in the zfile list.
+ * Compare the internal names z->iname, but in reverse order. */
+{
+  return namecmp((*(struct zlist far **)b)->iname,
+                 (*(struct zlist far **)a)->iname);
+}
+
+
+local int zbcmp(n, z)
+ZCONST zvoid *n;        /* string to search for */
+ZCONST zvoid far *z;    /* pointer to a pointer to a zip entry */
+/* Used by search() to compare a target to an entry in the zfile list. */
+{
+  return namecmp((char *)n, ((struct zlist far *)z)->zname);
+}
+
+#ifdef UNICODE_SUPPORT
+/* search unicode paths */
+local int zubcmp(n, z)
+ZCONST zvoid *n;        /* string to search for */
+ZCONST zvoid far *z;    /* pointer to a pointer to a zip entry */
+/* Used by search() to compare a target to an entry in the zfile list. */
+{
+  char *zuname = ((struct zlist far *)z)->zuname;
+
+  /* zuname is NULL if no UTF-8 name */
+  if (zuname == NULL)
+    zuname = ((struct zlist far *)z)->zname;
+
+  return namecmp((char *)n, zuname);
+}
+
+#if 0
+/* search escaped unicode paths */
+local int zuebcmp(n, z)
+ZCONST zvoid *n;        /* string to search for */
+ZCONST zvoid far *z;    /* pointer to a pointer to a zip entry */
+/* Used by search() to compare a target to an entry in the zfile list. */
+{
+  char *zuname = ((struct zlist far *)z)->zuname;
+  char *zuename;
+  int k;
+
+  /* zuname is NULL if no UTF-8 name */
+  if (zuname == NULL)
+    zuname = ((struct zlist far *)z)->zname;
+  zuename = local_to_escape_string(zuname);
+  k = namecmp((char *)n, zuename);
+  free(zuename);
+
+  return k;
+}
+#endif
+#endif
+
+
+struct zlist far *zsearch(n)
+  ZCONST char *n;      /* name to find */
+/* Return a pointer to the entry in zfile with the name n, or NULL if
+   not found. */
+{
+  zvoid far **p;        /* result of search() */
+
+  if (zcount) {
+    if ((p = search(n, (ZCONST zvoid far **)zsort, zcount, zbcmp)) != NULL)
+      return *(struct zlist far **)p;
+#ifdef UNICODE_SUPPORT
+    else if (unicode_mismatch != 3 && fix != 2 &&
+        (p = search(n, (ZCONST zvoid far **)zusort, zcount, zubcmp)) != NULL)
+      return *(struct zlist far **)p;
+#endif
+    else
+      return NULL;
+  }
+  return NULL;
+}
+
+#endif /* !UTIL */
+
+#ifndef VMS     /* See [.VMS]VMS.C for VMS-specific ziptyp(). */
+#  ifndef PATHCUT
+#    define PATHCUT '/'
+#  endif
+
+char *ziptyp(s)
+  char *s;             /* file name to force to zip */
+/* If the file name *s has a dot (other than the first char), or if
+   the -A option is used (adjust self-extracting file) then return
+   the name, otherwise append .zip to the name.  Allocate the space for
+   the name in either case.  Return a pointer to the new name, or NULL
+   if malloc() fails. */
+{
+  char *q;              /* temporary pointer */
+  char *t;              /* pointer to malloc'ed string */
+#  ifdef THEOS
+  char *r;              /* temporary pointer */
+  char *disk;
+#  endif
+
+  if ((t = malloc(strlen(s) + 5)) == NULL)
+    return NULL;
+  strcpy(t, s);
+#  ifdef __human68k__
+  _toslash(t);
+#  endif
+#  ifdef MSDOS
+  for (q = t; *q; INCSTR(q))
+    if (*q == '\\')
+      *q = '/';
+#  endif /* MSDOS */
+#  if defined(__RSXNT__) || defined(WIN32_CRT_OEM)
+   /* RSXNT/EMX C rtl uses OEM charset */
+  AnsiToOem(t, t);
+#  endif
+  if (adjust) return t;
+#  ifndef RISCOS
+#    ifndef QDOS
+#      ifdef AMIGA
+  if ((q = MBSRCHR(t, '/')) == NULL)
+    q = MBSRCHR(t, ':');
+  if (MBSRCHR((q ? q + 1 : t), '.') == NULL)
+#      else /* !AMIGA */
+#        ifdef THEOS
+  /* the argument expansion add a dot to the end of file names when
+   * there is no extension and at least one of a argument has wild cards.
+   * So check for at least one character in the extension if there is a dot
+   * in file name */
+  if ((q = MBSRCHR((q = MBSRCHR(t, PATHCUT)) == NULL ? t : q + 1, '.')) == NULL
+    || q[1] == '\0') {
+#        else /* !THEOS */
+#          ifdef TANDEM
+  if (MBSRCHR((q = MBSRCHR(t, '.')) == NULL ? t : q + 1, ' ') == NULL)
+#          else /* !TANDEM */
+  if (MBSRCHR((q = MBSRCHR(t, PATHCUT)) == NULL ? t : q + 1, '.') == NULL)
+#          endif /* ?TANDEM */
+#        endif /* ?THEOS */
+#      endif /* ?AMIGA */
+#      ifdef CMS_MVS
+    if (strncmp(t,"dd:",3) != 0 && strncmp(t,"DD:",3) != 0)
+#      endif /* CMS_MVS */
+#      ifdef THEOS
+    /* insert .zip extension before disk name */
+    if ((r = MBSRCHR(t, ':')) != NULL) {
+        /* save disk name */
+        if ((disk = strdup(r)) == NULL)
+            return NULL;
+        strcpy(r[-1] == '.' ? r - 1 : r, ".zip");
+        strcat(t, disk);
+        free(disk);
+    } else {
+        if (q != NULL && *q == '.')
+          strcpy(q, ".zip");
+        else
+          strcat(t, ".zip");
+    }
+  }
+#      else /* !THEOS */
+#        ifdef TANDEM     /*  Tandem can't cope with extensions */
+    strcat(t, " ZIP");
+#        else /* !TANDEM */
+    strcat(t, ".zip");
+#        endif /* ?TANDEM */
+#      endif /* ?THEOS */
+#    else /* QDOS */
+  q = LastDir(t);
+  if(MBSRCHR(q, '_') == NULL && MBSRCHR(q, '.') == NULL)
+  {
+      strcat(t, "_zip");
+  }
+#    endif /* QDOS */
+#  endif /* !RISCOS */
+  return t;
+}
+#endif  /* ndef VMS */
+
+/* ---------------------------------------------------- */
+
+/* moved out of ZIP64_SUPPORT - 2/6/2005 EG */
+
+/* 08/31/2003 R.Nausedat */
+
+local void write_ushort_to_mem( OFT( ush) usValue,
+                                OFT( char *)pPtr)
+#ifdef NO_PROTO
+  ush usValue;
+  char *pPtr;
+#endif /* def NO_PROTO */
+{
+  *pPtr++ = ((char)(usValue) & 0xff);
+  *pPtr = ((char)(usValue >> 8) & 0xff);
+}
+
+local void write_ulong_to_mem(uValue, pPtr)
+ulg uValue;
+char *pPtr;
+{
+  write_ushort_to_mem((ush)(uValue & 0xffff), pPtr);
+  write_ushort_to_mem((ush)((uValue >> 16) & 0xffff), pPtr + 2);
+}
+
+#ifdef ZIP64_SUPPORT
+
+local void write_int64_to_mem(l64Value,pPtr)
+  uzoff_t l64Value;
+  char *pPtr;
+{
+  write_ulong_to_mem((ulg)(l64Value & 0xffffffff),pPtr);
+  write_ulong_to_mem((ulg)((l64Value >> 32) & 0xffffffff),pPtr + 4);
+}
+
+#endif /* def ZIP64_SUPPORT */
+
+#ifdef UNICODE_SUPPORT
+
+/* Write a string to memory */
+local void write_string_to_mem(strValue, pPtr)
+  char *strValue;
+  char *pPtr;
+{
+  if (strValue != NULL) {
+    int ssize = strlen(strValue);
+    int i;
+
+    for (i = 0; i < ssize; i++) {
+      *(pPtr + i) = *(strValue + i);
+    }
+  }
+}
+
+#endif /* def UNICODE_SUPPORT */
+
+
+
+/* same as above but allocate memory as needed and keep track of current end
+   using offset - 2/6/05 EG */
+
+#if 0 /* ubyte version not used */
+local void append_ubyte_to_mem( OFT( unsigned char) ubValue,
+                                OFT( char **) pPtr,
+                                OFT( extent *) offset,
+                                OFT( extent *) blocksize)
+#ifdef NO_PROTO
+  unsigned char ubValue;  /* byte to append */
+  char **pPtr;            /* start of block */
+  extent *offset;         /* next byte to write */
+  extent *blocksize;      /* current size of block */
+#endif /* def NO_PROTO */
+{
+  if (*pPtr == NULL) {
+    /* malloc a 1K block */
+    (*blocksize) = 1024;
+    *pPtr = (char *) malloc(*blocksize);
+    if (*pPtr == NULL) {
+      ziperr(ZE_MEM, "append_ubyte_to_mem");
+    }
+  }
+  /* if (*offset) + 1 > (*blocksize) - 1 */
+  else if ((*offset) > (*blocksize) - (1 + 1)) {
+    /* realloc a bigger block in 1 K increments */
+    (*blocksize) += 1024;
+    *pPtr = realloc(*pPtr, *blocksize);
+    if (*pPtr == NULL) {
+      ziperr(ZE_MEM, "append_ubyte_to_mem");
+    }
+  }
+  *(*pPtr + *offset) = ubValue;
+  (*offset)++;
+}
+#endif
+
+local void append_ushort_to_mem( OFT( ush) usValue,
+                                 OFT( char **) pPtr,
+                                 OFT( extent *) offset,
+                                 OFT( extent *) blocksize)
+#ifdef NO_PROTO
+  ush usValue;
+  char **pPtr;
+  extent *offset;
+  extent *blocksize;
+#endif /* def NO_PROTO */
+{
+  if (*pPtr == NULL) {
+    /* malloc a 1K block */
+    (*blocksize) = 1024;
+    *pPtr = (char *) malloc(*blocksize);
+    if (*pPtr == NULL) {
+      ziperr(ZE_MEM, "append_ushort_to_mem");
+    }
+  }
+  /* if (*offset) + 2 > (*blocksize) - 1 */
+  else if ((*offset) > (*blocksize) - (1 + 2)) {
+    /* realloc a bigger block in 1 K increments */
+    (*blocksize) += 1024;
+    *pPtr = realloc(*pPtr, (extent)*blocksize);
+    if (*pPtr == NULL) {
+      ziperr(ZE_MEM, "append_ushort_to_mem");
+    }
+  }
+  write_ushort_to_mem(usValue, (*pPtr) + (*offset));
+  (*offset) += 2;
+}
+
+local void append_ulong_to_mem(uValue, pPtr, offset, blocksize)
+  ulg uValue;
+  char **pPtr;
+  extent *offset;
+  extent *blocksize;
+{
+  if (*pPtr == NULL) {
+    /* malloc a 1K block */
+    (*blocksize) = 1024;
+    *pPtr = (char *) malloc(*blocksize);
+    if (*pPtr == NULL) {
+      ziperr(ZE_MEM, "append_ulong_to_mem");
+    }
+  }
+  else if ((*offset) > (*blocksize) - (1 + 4)) {
+    /* realloc a bigger block in 1 K increments */
+    (*blocksize) += 1024;
+    *pPtr = realloc(*pPtr, *blocksize);
+    if (*pPtr == NULL) {
+      ziperr(ZE_MEM, "append_ulong_to_mem");
+    }
+  }
+  write_ulong_to_mem(uValue, (*pPtr) + (*offset));
+  (*offset) += 4;
+}
+
+#ifdef ZIP64_SUPPORT
+
+local void append_int64_to_mem(l64Value, pPtr, offset, blocksize)
+  uzoff_t l64Value;
+  char **pPtr;
+  extent *offset;
+  extent *blocksize;
+{
+  if (*pPtr == NULL) {
+    /* malloc a 1K block */
+    (*blocksize) = 1024;
+    *pPtr = (char *) malloc(*blocksize);
+    if (*pPtr == NULL) {
+      ziperr(ZE_MEM, "append_int64_to_mem");
+    }
+  }
+  else if ((*offset) > (*blocksize) - (1 + 8)) {
+    /* realloc a bigger block in 1 K increments */
+    (*blocksize) += 1024;
+    *pPtr = realloc(*pPtr, *blocksize);
+    if (*pPtr == NULL) {
+      ziperr(ZE_MEM, "append_int64_to_mem");
+    }
+  }
+  write_int64_to_mem(l64Value, (*pPtr) + (*offset));
+  (*offset) += 8;
+}
+
+#endif /* def ZIP64_SUPPORT */
+
+/* Append a string to the memory block. */
+local void append_string_to_mem(strValue, strLength, pPtr, offset, blocksize)
+  char *strValue;
+  int  strLength;
+  char **pPtr;
+  extent *offset;
+  extent *blocksize;
+{
+  if (strValue != NULL) {
+    unsigned bsize = 1024;
+    unsigned ssize = strLength;
+    unsigned i;
+
+    if (ssize > bsize) {
+      bsize = ssize;
+    }
+    if (*pPtr == NULL) {
+      /* malloc a 1K block */
+      (*blocksize) = bsize;
+      *pPtr = (char *) malloc(*blocksize);
+      if (*pPtr == NULL) {
+        ziperr(ZE_MEM, "append_string_to_mem");
+      }
+    }
+    else if ((*offset) + ssize > (*blocksize) - 1) {
+      /* realloc a bigger block in 1 K increments */
+      (*blocksize) += bsize;
+      *pPtr = realloc(*pPtr, *blocksize);
+      if (*pPtr == NULL) {
+        ziperr(ZE_MEM, "append_string_to_mem");
+      }
+    }
+    for (i = 0; i < ssize; i++) {
+      *(*pPtr + *offset + i) = *(strValue + i);
+    }
+    (*offset) += ssize;
+  }
+}
+
+/* ---------------------------------------------------- */
+
+/* zip64 support 08/31/2003 R.Nausedat */
+/* moved out of zip64 support 10/22/05 */
+
+/* Searches pExtra for extra field with specified tag.
+ * If it finds one it returns a pointer to it, else NULL.
+ * Renamed and made generic.  10/3/03
+ */
+char *get_extra_field( OFT( ush) tag,
+                       OFT( char *) pExtra,
+                       OFT( unsigned) iExtraLen)
+#ifdef NO_PROTO
+  ush tag;              /* tag to look for */
+  char *pExtra;         /* pointer to extra field in memory */
+  unsigned iExtraLen;   /* length of extra field */
+#endif /* def NO_PROTO */
+{
+  char  *pTemp;
+  ush   usBlockTag;
+  ush   usBlockSize;
+
+  if( pExtra == NULL )
+    return NULL;
+
+  for (pTemp = pExtra; pTemp < pExtra  + iExtraLen - ZIP_EF_HEADER_SIZE;)
+  {
+    usBlockTag = SH(pTemp);       /* get tag */
+    usBlockSize = SH(pTemp + 2);  /* get field data size */
+    if (usBlockTag == tag)
+      return pTemp;
+    pTemp += (usBlockSize + ZIP_EF_HEADER_SIZE);
+  }
+  return NULL;
+}
+
+/* copy_nondup_extra_fields
+ *
+ * Copy any extra fields in old that are not in new to new.
+ * Returns the new extra fields block and newLen is new length.
+ */
+char *copy_nondup_extra_fields(oldExtra, oldExtraLen, newExtra, newExtraLen, newLen)
+  char *oldExtra;       /* pointer to old extra fields */
+  unsigned oldExtraLen; /* length of old extra fields */
+  char *newExtra;       /* pointer to new extra fields */
+  unsigned newExtraLen; /* length of new extra fields */
+  unsigned *newLen;     /* length of new extra fields after copy */
+{
+  char *returnExtra = NULL;
+  ush   returnExtraLen = 0;
+  char *tempExtra;
+  char *pTemp;
+  ush   tag;
+  ush   blocksize;
+
+  if( oldExtra == NULL ) {
+    /* no old extra fields so return copy of newExtra */
+    if (newExtra == NULL || newExtraLen == 0) {
+      *newLen = 0;
+      return NULL;
+    } else {
+      if ((returnExtra = malloc(newExtraLen)) == NULL)
+        ZIPERR(ZE_MEM, "extra field copy");
+      memcpy(returnExtra, newExtra, newExtraLen);
+      returnExtraLen = newExtraLen;
+      *newLen = returnExtraLen;
+      return returnExtra;
+    }
+  }
+
+  /* allocate block large enough for all extra fields */
+  if ((tempExtra = malloc(0xFFFF)) == NULL)
+    ZIPERR(ZE_MEM, "extra field copy");
+
+  /* look for each old extra field in new block */
+  for (pTemp = oldExtra; pTemp < oldExtra  + oldExtraLen;)
+  {
+    tag = SH(pTemp);            /* get tag */
+    blocksize = SH(pTemp + 2);  /* get field data size */
+    if (get_extra_field(tag, newExtra, newExtraLen) == NULL) {
+      /* tag not in new block so add it */
+      memcpy(tempExtra + returnExtraLen, pTemp, blocksize + 4);
+      returnExtraLen += blocksize + 4;
+    }
+    pTemp += blocksize + 4;
+  }
+
+  /* copy all extra fields from new block */
+  memcpy(tempExtra + returnExtraLen, newExtra, newExtraLen);
+  returnExtraLen += newExtraLen;
+
+  /* copy tempExtra to returnExtra */
+  if ((returnExtra = malloc(returnExtraLen)) == NULL)
+    ZIPERR(ZE_MEM, "extra field copy");
+  memcpy(returnExtra, tempExtra, returnExtraLen);
+  free(tempExtra);
+
+  *newLen = returnExtraLen;
+  return returnExtra;
+}
+
+#ifdef UNICODE_SUPPORT
+
+/* The latest format is
+     1 byte     Version of Unicode Path Extra Field
+     4 bytes    Name Field CRC32 Checksum
+     variable   UTF-8 Version Of Name
+ */
+
+local void read_Unicode_Path_entry(pZipListEntry)
+  struct zlist far *pZipListEntry;
+{
+  char *pTemp;
+  char *UPath;
+  char *iname;
+  ush ELen;
+  uch Version;
+  ush ULen;
+  ulg chksum = CRCVAL_INITIAL;
+  ulg iname_chksum;
+
+  /* check if we have a Unicode Path extra field ... */
+  pTemp = get_extra_field( UTF8_PATH_EF_TAG, pZipListEntry->cextra, pZipListEntry->cext );
+  pZipListEntry->uname = NULL;
+  if( pTemp == NULL ) {
+    return;
+  }
+
+  /* ... if so, update corresponding entries in struct zlist */
+
+  pTemp += 2;
+
+  /* length of this extra field */
+  ELen = SH(pTemp);
+  pTemp += 2;
+
+  /* version */
+  Version = (uch) *pTemp;
+  pTemp += 1;
+  if (Version > 1) {
+    zipwarn("Unicode Path Extra Field version > 1 - skipping", pZipListEntry->oname);
+    return;
+  }
+
+  /* iname CRC */
+  iname_chksum = LG(pTemp);
+  pTemp += 4;
+
+  /*
+   * Compute the CRC-32 checksum of iname
+   */
+/*
+  crc_16 = crc16f((uch *)(pZipListEntry->iname), strlen(pZipListEntry->iname));
+ */
+
+  if ((iname = malloc(strlen(pZipListEntry->iname) + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "write Unicode");
+  }
+  strcpy(iname, pZipListEntry->iname);
+
+  chksum = crc32(chksum, (uch *)(iname), strlen(iname));
+
+  free(iname);
+
+/*  chksum = adler16(ADLERVAL_INITIAL,
+    (uch *)(pZipListEntry->iname), strlen(pZipListEntry->iname));
+*/
+
+  /* If the checksums's don't match then likely iname has been modified and
+   * the Unicode Path is no longer valid
+   */
+  if (chksum != iname_chksum) {
+    printf("unicode_mismatch = %d\n", unicode_mismatch);
+    if (unicode_mismatch == 1) {
+      /* warn and continue */
+      zipwarn("Unicode does not match path - ignoring Unicode: ", pZipListEntry->oname);
+    } else if (unicode_mismatch == 2) {
+      /* ignore and continue */
+    } else if (unicode_mismatch == 0) {
+      /* error */
+      sprintf(errbuf, "Unicode does not match path:  %s\n", pZipListEntry->oname);
+      strcat(errbuf,
+        "                     Likely entry name changed but Unicode not updated\n");
+      strcat(errbuf,
+        "                     Use -UN=i to ignore errors or n for no Unicode paths");
+      zipwarn(errbuf, "");
+      ZIPERR(ZE_FORM, "Unicode path error");
+    }
+    return;
+  }
+
+  ULen = ELen - 5;
+
+  /* UTF-8 Path */
+  if (ULen == 0) {
+    /* standard path is UTF-8 so use that */
+    ULen = pZipListEntry->nam;
+    if ((UPath = malloc(ULen + 1)) == NULL) {
+      return;
+    }
+    strcpy(UPath, pZipListEntry->name);
+  } else {
+    /* use Unicode path */
+    if ((UPath = malloc(ULen + 1)) == NULL) {
+      return;
+    }
+    strncpy(UPath, pTemp, ULen);
+    UPath[ULen] = '\0';
+  }
+  pZipListEntry->uname = UPath;
+  return;
+}
+
+local void read_Unicode_Path_local_entry(pZipListEntry)
+  struct zlist far *pZipListEntry;
+{
+  char *pTemp;
+  char *UPath;
+  char *iname;
+  ush ELen;
+  uch Version;
+  ush ULen;
+  ulg chksum = CRCVAL_INITIAL;
+  ulg iname_chksum;
+
+  /* check if we have a Unicode Path extra field ... */
+  pTemp = get_extra_field( UTF8_PATH_EF_TAG, pZipListEntry->extra, pZipListEntry->ext );
+  pZipListEntry->uname = NULL;
+  if( pTemp == NULL ) {
+    return;
+  }
+
+  /* ... if so, update corresponding entries in struct zlist */
+
+  pTemp += 2;
+
+  /* length of this extra field */
+  ELen = SH(pTemp);
+  pTemp += 2;
+
+  /* version */
+  Version = (uch) *pTemp;
+  pTemp += 1;
+  if (Version > 1) {
+    zipwarn("Unicode Path Extra Field version > 1 - skipping", pZipListEntry->oname);
+    return;
+  }
+
+  /* iname CRC */
+  iname_chksum = LG(pTemp);
+  pTemp += 4;
+
+  /*
+   * Compute 32-bit crc of iname and AND halves to make 16-bit version
+   */
+  /*
+  chksum = adler16(ADLERVAL_INITIAL,
+    (uch *)(pZipListEntry->iname), strlen(pZipListEntry->iname));
+  */
+
+  if ((iname = malloc(strlen(pZipListEntry->iname) + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "write Unicode");
+  }
+  strcpy(iname, pZipListEntry->iname);
+
+  chksum = crc32(chksum, (uch *)(iname), strlen(iname));
+
+  free(iname);
+
+  /* If the checksums's don't match then likely iname has been modified and
+   * the Unicode Path is no longer valid
+   */
+  if (chksum != iname_chksum) {
+    if (unicode_mismatch == 1) {
+      /* warn and continue */
+      zipwarn("Unicode does not match path - ignoring Unicode: ", pZipListEntry->oname);
+    } else if (unicode_mismatch == 2) {
+      /* ignore and continue */
+    } else if (unicode_mismatch == 0) {
+      /* error */
+      sprintf(errbuf, "Unicode does not match path:  %s\n", pZipListEntry->oname);
+      strcat(errbuf,
+        "                     Likely entry name changed but Unicode not updated\n");
+      strcat(errbuf,
+        "                     Use -UN=i to ignore errors or n for no Unicode paths");
+      zipwarn(errbuf, "");
+      ZIPERR(ZE_FORM, "Unicode path error");
+    }
+    return;
+  }
+
+  ULen = ELen - 5;
+
+  /* UTF-8 Path */
+  if (ULen == 0) {
+    /* standard path is UTF-8 so use that */
+    ULen = pZipListEntry->nam;
+    if ((UPath = malloc(ULen + 1)) == NULL) {
+      return;
+    }
+    strcpy(UPath, pZipListEntry->name);
+  } else {
+    /* use Unicode path */
+    if ((UPath = malloc(ULen + 1)) == NULL) {
+      return;
+    }
+    strncpy(UPath, pTemp, ULen);
+    UPath[ULen] = '\0';
+  }
+  pZipListEntry->uname = UPath;
+  return;
+}
+
+#endif /* def UNICODE_SUPPORT */
+
+#ifdef ZIP64_SUPPORT           /* zip64 support 08/31/2003 R.Nausedat */
+
+/* searches the cextra member of zlist for a zip64 extra field. if it finds one it  */
+/* updates the len, siz and off members of zlist with the corresponding values of   */
+/* the zip64 extra field, that is if either the len, siz or off member of zlist is  */
+/* set to its max value we have to use the corresponding value from the zip64 extra */
+/* field. as of now the dsk member of zlist is not much of interest since we should */
+/* not modify multi volume archives at all.                                         */
+local void adjust_zip_central_entry(pZipListEntry)
+  struct zlist far *pZipListEntry;
+{
+  char  *pTemp;
+
+  /* assume not using zip64 fields */
+  zip64_entry = 0;
+
+  /* check if we have a "large file" Zip64 extra field ... */
+  pTemp = get_extra_field( ZIP64_EF_TAG, pZipListEntry->cextra, pZipListEntry->cext );
+  if( pTemp == NULL )
+    return;
+
+  /* using zip64 field */
+  zip64_entry = 1;
+  pTemp += ZIP_EF_HEADER_SIZE;
+
+  /* ... if so, update corresponding entries in struct zlist */
+  if (pZipListEntry->len == ZIP_UWORD32_MAX)
+  {
+    pZipListEntry->len = LLG(pTemp);
+    pTemp += 8;
+  }
+
+  if (pZipListEntry->siz == ZIP_UWORD32_MAX)
+  {
+    pZipListEntry->siz = LLG(pTemp);
+    pTemp += 8;
+  }
+
+  if (pZipListEntry->off == ZIP_UWORD32_MAX)
+  {
+    pZipListEntry->off = LLG(pTemp);
+    pTemp += 8;
+  }
+
+  if (pZipListEntry->dsk == ZIP_UWORD16_MAX)
+  {
+    pZipListEntry->dsk = LG(pTemp);
+  }
+
+}
+
+
+/* adjust_zip_local_entry
+ *
+ * Return 1 if there is a Zip64 extra field and 0 if not
+ */
+local int adjust_zip_local_entry(pZipListEntry)
+  struct zlist far *pZipListEntry;
+{
+  char  *pTemp;
+
+  /* assume not using zip64 fields */
+  zip64_entry = 0;
+
+  /* check if we have a "large file" Zip64 extra field ... */
+  pTemp = get_extra_field(ZIP64_EF_TAG, pZipListEntry->extra, pZipListEntry->ext );
+  if( pTemp == NULL )
+    return zip64_entry;
+
+  /* using zip64 field */
+  zip64_entry = 1;
+  pTemp += ZIP_EF_HEADER_SIZE;
+
+  /* ... if so, update corresponding entries in struct zlist */
+  if (pZipListEntry->len == ZIP_UWORD32_MAX)
+  {
+    pZipListEntry->len = LLG(pTemp);
+    pTemp += 8;
+  }
+
+  if (pZipListEntry->siz == ZIP_UWORD32_MAX)
+  {
+    pZipListEntry->siz = LLG(pTemp);
+    pTemp += 8;
+  }
+  return zip64_entry;
+}
+
+/* adds a zip64 extra field to the data the cextra member of zlist points to. If
+ * there is already a zip64 extra field present delete it first.
+ */
+local int add_central_zip64_extra_field(pZipListEntry)
+  struct zlist far *pZipListEntry;
+{
+  char   *pExtraFieldPtr;
+  char   *pTemp;
+  ush    usTemp;
+  ush    efsize = 0;
+  ush    esize;
+  ush    oldefsize;
+  extent len;
+  int    used_zip64 = 0;
+
+  /* get length of ef based on which fields exceed limits */
+  /* AppNote says:
+   *      The order of the fields in the ZIP64 extended
+   *      information record is fixed, but the fields will
+   *      only appear if the corresponding Local or Central
+   *      directory record field is set to 0xFFFF or 0xFFFFFFFF.
+   */
+  efsize = ZIP_EF_HEADER_SIZE;             /* type + size */
+  if (pZipListEntry->len > ZIP_UWORD32_MAX || force_zip64 == 1) {
+    /* compressed size */
+    efsize += 8;
+    used_zip64 = 1;
+  }
+  if (pZipListEntry->siz > ZIP_UWORD32_MAX) {
+    /* uncompressed size */
+    efsize += 8;
+    used_zip64 = 1;
+  }
+  if (pZipListEntry->off > ZIP_UWORD32_MAX) {
+    /* offset */
+    efsize += 8;
+    used_zip64 = 1;
+  }
+  if (pZipListEntry->dsk > ZIP_UWORD16_MAX) {
+    /* disk number */
+    efsize += 4;
+    used_zip64 = 1;
+  }
+
+  if (used_zip64 && force_zip64 == 0) {
+    zipwarn("Large entry support disabled using -fz- but needed", "");
+    return ZE_BIG;
+  }
+
+  /* malloc zip64 extra field? */
+  if( pZipListEntry->cextra == NULL )
+  {
+    if (efsize == ZIP_EF_HEADER_SIZE) {
+      return ZE_OK;
+    }
+    if ((pExtraFieldPtr = pZipListEntry->cextra = (char *) malloc(efsize)) == NULL) {
+      return ZE_MEM;
+    }
+    pZipListEntry->cext = efsize;
+  }
+  else
+  {
+    /* check if we have a "large file" extra field ... */
+    pExtraFieldPtr = get_extra_field(ZIP64_EF_TAG, pZipListEntry->cextra, pZipListEntry->cext);
+    if( pExtraFieldPtr == NULL )
+    {
+      /* ... we don't, so re-malloc enough memory for the old extra data plus
+       * the size of the zip64 extra field
+       */
+      if ((pExtraFieldPtr = (char *) malloc(efsize + pZipListEntry->cext)) == NULL) {
+        return ZE_MEM;
+      }
+      /* move the old extra field */
+      memmove(pExtraFieldPtr, pZipListEntry->cextra, pZipListEntry->cext);
+      free(pZipListEntry->cextra);
+      pZipListEntry->cextra = pExtraFieldPtr;
+      pExtraFieldPtr += pZipListEntry->cext;
+      pZipListEntry->cext += efsize;
+    }
+    else
+    {
+      /* ... we have. sort out the existing zip64 extra field and remove it from
+       * pZipListEntry->cextra, re-malloc enough memory for the old extra data
+       * left plus the size of the zip64 extra field
+       */
+      usTemp = SH(pExtraFieldPtr + 2);
+      /* if pZipListEntry->cextra == pExtraFieldPtr and pZipListEntry->cext == usTemp + efsize
+       * we should have only one extra field, and this is a zip64 extra field. as some
+       * zip tools seem to require fixed zip64 extra fields we have to check if
+       * usTemp + ZIP_EF_HEADER_SIZE is equal to ZIP64_LARGE_FILE_HEAD_SIZE. if it
+       * isn't, we free the old extra field and allocate memory for a new one
+       */
+      if( pZipListEntry->cext == (extent)(usTemp + ZIP_EF_HEADER_SIZE) )
+      {
+        /* just Zip64 extra field in extra field */
+        if( pZipListEntry->cext != efsize )
+        {
+          /* wrong size */
+          if ((pExtraFieldPtr = (char *) malloc(efsize)) == NULL) {
+            return ZE_MEM;
+          }
+          free(pZipListEntry->cextra);
+          pZipListEntry->cextra = pExtraFieldPtr;
+          pZipListEntry->cext = efsize;
+        }
+      }
+      else
+      {
+        /* get the old Zip64 extra field out and add new */
+        oldefsize = usTemp + ZIP_EF_HEADER_SIZE;
+        if ((pTemp = (char *) malloc(pZipListEntry->cext - oldefsize + efsize)) == NULL) {
+          return ZE_MEM;
+        }
+        len = (extent)(pExtraFieldPtr - pZipListEntry->cextra);
+        memcpy(pTemp, pZipListEntry->cextra, len);
+        memcpy(pTemp + len, pExtraFieldPtr + oldefsize,
+          pZipListEntry->cext - oldefsize - len);
+        pZipListEntry->cext -= oldefsize;
+        pExtraFieldPtr = pTemp + pZipListEntry->cext;
+        pZipListEntry->cext += efsize;
+        free(pZipListEntry->cextra);
+        pZipListEntry->cextra = pTemp;
+      }
+    }
+  }
+
+  /* set zip64 extra field members */
+  write_ushort_to_mem(ZIP64_EF_TAG, pExtraFieldPtr);
+  write_ushort_to_mem((ush) (efsize - ZIP_EF_HEADER_SIZE), pExtraFieldPtr + 2);
+  esize = ZIP_EF_HEADER_SIZE;
+  if (pZipListEntry->len > ZIP_UWORD32_MAX || force_zip64 == 1) {
+    write_int64_to_mem(pZipListEntry->len, pExtraFieldPtr + esize);
+    esize += 8;
+  }
+  if (pZipListEntry->siz > ZIP_UWORD32_MAX) {
+    write_int64_to_mem(pZipListEntry->siz, pExtraFieldPtr + esize);
+    esize += 8;
+  }
+  if (pZipListEntry->off > ZIP_UWORD32_MAX) {
+    write_int64_to_mem(pZipListEntry->off, pExtraFieldPtr + esize);
+    esize += 8;
+  }
+  if (pZipListEntry->dsk > ZIP_UWORD16_MAX) {
+    write_ulong_to_mem(pZipListEntry->dsk, pExtraFieldPtr + esize);
+  }
+
+  /* un' wech */
+  return ZE_OK;
+}
+
+#if 0
+/* Remove extra field in local extra field
+ * Return 1 if found, else 0
+ * 12/28/05
+ */
+local int remove_local_extra_field(pZEntry, tag)
+  struct zlist far *pZEntry;
+  ulg tag;
+{
+  char  *pExtra;
+  char  *pOldExtra;
+  char  *pOldTemp;
+  char  *pTemp;
+  ush   newEFSize;
+  ush   usTemp;
+  ush   blocksize;
+
+  /* check if we have the extra field ... */
+  pOldExtra = get_extra_field( (ush)tag, pZEntry->extra, pZEntry->ext );
+  if (pOldExtra)
+  {
+    /* We have. Get rid of it. */
+    blocksize = SH( pOldExtra + 2 );
+    newEFSize = pZEntry->ext - blocksize;
+    pExtra = (char *) malloc( newEFSize );
+    if( pExtra == NULL )
+      ziperr(ZE_MEM, "Remove Local Extra Field");
+    /* move all before EF */
+    usTemp = (extent) (pOldExtra - pZEntry->extra);
+    pTemp = pExtra;
+    memcpy( pTemp, pZEntry->extra, usTemp );
+    /* move all after old Zip64 EF */
+    pTemp = pExtra + usTemp;
+    pOldTemp = pOldExtra + blocksize;
+    usTemp = pZEntry->ext - usTemp - blocksize;
+    memcpy( pTemp, pOldTemp, usTemp);
+    /* replace extra fields */
+    pZEntry->ext = newEFSize;
+    free(pZEntry->extra);
+    pZEntry->extra = pExtra;
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+/* Remove extra field in central extra field
+ * Return 1 if found, else 0
+ * 12/28/05
+ */
+local int remove_central_extra_field(pZEntry, tag)
+  struct zlist far *pZEntry;
+  ulg tag;
+{
+  char  *pExtra;
+  char  *pOldExtra;
+  char  *pOldTemp;
+  char  *pTemp;
+  ush   newEFSize;
+  ush   usTemp;
+  ush   blocksize;
+
+  /* check if we have the extra field ... */
+  pOldExtra = get_extra_field( (ush)tag, pZEntry->cextra, pZEntry->cext );
+  if (pOldExtra)
+  {
+    /* We have. Get rid of it. */
+    blocksize = SH( pOldExtra + 2 );
+    newEFSize = pZEntry->cext - blocksize;
+    pExtra = (char *) malloc( newEFSize );
+    if( pExtra == NULL )
+      ziperr(ZE_MEM, "Remove Local Extra Field");
+    /* move all before EF */
+    usTemp = (extent) (pOldExtra - pZEntry->cextra);
+    pTemp = pExtra;
+    memcpy( pTemp, pZEntry->cextra, usTemp );
+    /* move all after old Zip64 EF */
+    pTemp = pExtra + usTemp;
+    pOldTemp = pOldExtra + blocksize;
+    usTemp = pZEntry->cext - usTemp - blocksize;
+    memcpy( pTemp, pOldTemp, usTemp);
+    /* replace extra fields */
+    pZEntry->cext = newEFSize;
+    free(pZEntry->cextra);
+    pZEntry->cextra = pExtra;
+    return 1;
+  } else {
+    return 0;
+  }
+}
+#endif
+
+/* Add Zip64 extra field to local header
+ * 10/5/03 EG
+ */
+local int add_local_zip64_extra_field(pZEntry)
+  struct zlist far *pZEntry;
+{
+  char  *pZ64Extra;
+  char  *pOldZ64Extra;
+  char  *pOldTemp;
+  char  *pTemp;
+  ush   newEFSize;
+  ush   usTemp;
+  ush   blocksize;
+  ush   Z64LocalLen = ZIP_EF_HEADER_SIZE +  /* tag + EF Data Len */
+                      8 +                   /* original uncompressed length of file */
+                      8;                    /* compressed size of file */
+
+  /* malloc zip64 extra field? */
+  /* after the below pZ64Extra should point to start of Zip64 extra field */
+  if (pZEntry->ext == 0 || pZEntry->extra == NULL)
+  {
+    /* get new extra field */
+    pZ64Extra = pZEntry->extra = (char *) malloc(Z64LocalLen);
+    if (pZEntry->extra == NULL) {
+      ziperr( ZE_MEM, "Zip64 local extra field" );
+    }
+    pZEntry->ext = Z64LocalLen;
+  }
+  else
+  {
+    /* check if we have a Zip64 extra field ... */
+    pOldZ64Extra = get_extra_field( ZIP64_EF_TAG, pZEntry->extra, pZEntry->ext );
+    if (pOldZ64Extra == NULL)
+    {
+      /* ... we don't, so re-malloc enough memory for the old extra data plus */
+      /* the size of the zip64 extra field */
+      pZ64Extra = (char *) malloc( Z64LocalLen + pZEntry->ext );
+      if (pZ64Extra == NULL)
+        ziperr( ZE_MEM, "Zip64 Extra Field" );
+      /* move old extra field and update pointer and length */
+      memmove( pZ64Extra, pZEntry->extra, pZEntry->ext);
+      free( pZEntry->extra );
+      pZEntry->extra = pZ64Extra;
+      pZ64Extra += pZEntry->ext;
+      pZEntry->ext += Z64LocalLen;
+    }
+    else
+    {
+      /* ... we have. Sort out the existing zip64 extra field and remove it
+       * from pZEntry->extra, re-malloc enough memory for the old extra data
+       * left plus the size of the zip64 extra field */
+      blocksize = SH( pOldZ64Extra + 2 );
+      /* If the right length then go with it, else get rid of it and add a new extra field
+       * to existing block. */
+      if (blocksize == Z64LocalLen - ZIP_EF_HEADER_SIZE)
+      {
+        /* looks good */
+        pZ64Extra = pOldZ64Extra;
+      }
+      else
+      {
+        newEFSize = pZEntry->ext - (blocksize + ZIP_EF_HEADER_SIZE) + Z64LocalLen;
+        pZ64Extra = (char *) malloc( newEFSize );
+        if( pZ64Extra == NULL )
+          ziperr(ZE_MEM, "Zip64 Extra Field");
+        /* move all before Zip64 EF */
+        usTemp = (extent) (pOldZ64Extra - pZEntry->extra);
+        pTemp = pZ64Extra;
+        memcpy( pTemp, pZEntry->extra, usTemp );
+        /* move all after old Zip64 EF */
+        pTemp = pZ64Extra + usTemp;
+        pOldTemp = pOldZ64Extra + ZIP_EF_HEADER_SIZE + blocksize;
+        usTemp = pZEntry->ext - usTemp - blocksize;
+        memcpy( pTemp, pOldTemp, usTemp);
+        /* replace extra fields */
+        pZEntry->ext = newEFSize;
+        free(pZEntry->extra);
+        pZEntry->extra = pZ64Extra;
+        pZ64Extra = pTemp + usTemp;
+      }
+    }
+  }
+  /* set/update zip64 extra field members */
+  write_ushort_to_mem(ZIP64_EF_TAG, pZ64Extra);
+  write_ushort_to_mem((ush) (Z64LocalLen - ZIP_EF_HEADER_SIZE), pZ64Extra + 2);
+  write_int64_to_mem(pZEntry->len, pZ64Extra + 2 + 2);
+  write_int64_to_mem(pZEntry->siz, pZ64Extra + 2 + 2 + 8);
+
+  return ZE_OK;
+}
+
+# endif /* ZIP64_SUPPORT */
+
+#ifdef UNICODE_SUPPORT
+/* Add UTF-8 path extra field
+ * 10/11/05
+ */
+local int add_Unicode_Path_local_extra_field(pZEntry)
+  struct zlist far *pZEntry;
+{
+  char  *pUExtra;
+  char  *pOldUExtra;
+  char  *pOldTemp;
+  char  *pTemp;
+#ifdef WIN32_OEM
+  char  *inameLocal;
+#endif
+  ush   newEFSize;
+  ush   usTemp;
+  ush   ULen = strlen(pZEntry->uname);
+  ush   blocksize;
+  ulg   chksum = CRCVAL_INITIAL;
+  ush   ULocalLen = ZIP_EF_HEADER_SIZE +  /* tag + EF Data Len */
+                    1 +                   /* version */
+                    4 +                   /* iname chksum */
+                    ULen;                 /* UTF-8 path */
+
+  /* malloc Unicode Path extra field? */
+  /* after the below pUExtra should point to start of Unicode Path extra field */
+  if (pZEntry->ext == 0 || pZEntry->extra == NULL)
+  {
+    /* get new extra field */
+    pUExtra = pZEntry->extra = (char *) malloc(ULocalLen);
+    if (pZEntry->extra == NULL) {
+      ziperr( ZE_MEM, "UTF-8 Path local extra field" );
+    }
+    pZEntry->ext = ULocalLen;
+  }
+  else
+  {
+    /* check if we have a Unicode Path extra field ... */
+    pOldUExtra = get_extra_field( UTF8_PATH_EF_TAG, pZEntry->extra, pZEntry->ext );
+    if (pOldUExtra == NULL)
+    {
+      /* ... we don't, so re-malloc enough memory for the old extra data plus */
+      /* the size of the UTF-8 Path extra field */
+      pUExtra = (char *) malloc( ULocalLen + pZEntry->ext );
+      if (pUExtra == NULL)
+        ziperr( ZE_MEM, "UTF-8 Path Extra Field" );
+      /* move old extra field and update pointer and length */
+      memmove( pUExtra, pZEntry->extra, pZEntry->ext);
+      free( pZEntry->extra );
+      pZEntry->extra = pUExtra;
+      pUExtra += pZEntry->ext;
+      pZEntry->ext += ULocalLen;
+    }
+    else
+    {
+      /* ... we have. Sort out the existing UTF-8 Path extra field and remove it
+       * from pZEntry->extra, re-malloc enough memory for the old extra data
+       * left plus the size of the UTF-8 Path extra field */
+      blocksize = SH( pOldUExtra + 2 );
+      /* If the right length then go with it, else get rid of it and add a new extra field
+       * to existing block. */
+      if (blocksize == ULocalLen - ZIP_EF_HEADER_SIZE)
+      {
+        /* looks good */
+        pUExtra = pOldUExtra;
+      }
+      else
+      {
+        newEFSize = pZEntry->ext - (blocksize + ZIP_EF_HEADER_SIZE) + ULocalLen;
+        pUExtra = (char *) malloc( newEFSize );
+        if( pUExtra == NULL )
+          ziperr(ZE_MEM, "UTF-8 Path Extra Field");
+        /* move all before UTF-8 Path EF */
+        usTemp = (extent) (pOldUExtra - pZEntry->extra);
+        pTemp = pUExtra;
+        memcpy( pTemp, pZEntry->extra, usTemp );
+        /* move all after old UTF-8 Path EF */
+        pTemp = pUExtra + usTemp;
+        pOldTemp = pOldUExtra + ZIP_EF_HEADER_SIZE + blocksize;
+        usTemp = pZEntry->ext - usTemp - blocksize;
+        memcpy( pTemp, pOldTemp, usTemp);
+        /* replace extra fields */
+        pZEntry->ext = newEFSize;
+        free(pZEntry->extra);
+        pZEntry->extra = pUExtra;
+        pUExtra = pTemp + usTemp;
+      }
+    }
+  }
+
+  /*
+   * Compute the Adler-16 checksum of iname
+   */
+/*
+  chksum = adler16(ADLERVAL_INITIAL,
+                   (uch *)(pZEntry->iname), strlen(pZEntry->iname));
+*/
+
+#ifdef WIN32_OEM
+  if ((inameLocal = malloc(strlen(pZEntry->iname) + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "write Unicode");
+  }
+  /* if oem translation done convert back for checksum */
+  if ((pZEntry->vem & 0xff00) == 0) {
+    /* get original */
+    INTERN_TO_OEM(pZEntry->iname, inameLocal);
+  } else {
+    strcpy(inameLocal, pZEntry->iname);
+  }
+#else
+# define inameLocal (pZEntry->iname)
+#endif
+
+  chksum = crc32(chksum, (uch *)(inameLocal), strlen(inameLocal));
+
+#ifdef WIN32_OEM
+  free(inameLocal);
+#else
+# undef inameLocal
+#endif
+
+  /* set/update UTF-8 Path extra field members */
+  /* tag header */
+  write_ushort_to_mem(UTF8_PATH_EF_TAG, pUExtra);
+  /* data size */
+  write_ushort_to_mem((ush) (ULocalLen - ZIP_EF_HEADER_SIZE), pUExtra + 2);
+  /* version */
+  *(pUExtra + 2 + 2) = 1;
+  /* iname chksum */
+  write_ulong_to_mem(chksum, pUExtra + 2 + 2 + 1);
+  /* UTF-8 path */
+  write_string_to_mem(pZEntry->uname, pUExtra + 2 + 2 + 1 + 4);
+
+  return ZE_OK;
+}
+
+local int add_Unicode_Path_cen_extra_field(pZEntry)
+  struct zlist far *pZEntry;
+{
+  char  *pUExtra;
+  char  *pOldUExtra;
+  char  *pOldTemp;
+  char  *pTemp;
+#ifdef WIN32_OEM
+  char  *inameLocal;
+#endif
+  ush   newEFSize;
+  ush   usTemp;
+  ush   ULen = strlen(pZEntry->uname);
+  ush   blocksize;
+  ulg   chksum = CRCVAL_INITIAL;
+  ush   UCenLen = ZIP_EF_HEADER_SIZE +  /* tag + EF Data Len */
+                  1 +                   /* version */
+                  4 +                   /* checksum */
+                  ULen;                 /* UTF-8 path */
+
+  /* malloc Unicode Path extra field? */
+  /* after the below pUExtra should point to start of Unicode Path extra field */
+  if (pZEntry->cext == 0 || pZEntry->cextra == NULL)
+  {
+    /* get new extra field */
+    pUExtra = pZEntry->cextra = (char *) malloc(UCenLen);
+    if (pZEntry->cextra == NULL) {
+      ziperr( ZE_MEM, "UTF-8 Path cen extra field" );
+    }
+    pZEntry->cext = UCenLen;
+  }
+  else
+  {
+    /* check if we have a Unicode Path extra field ... */
+    pOldUExtra = get_extra_field( UTF8_PATH_EF_TAG, pZEntry->cextra, pZEntry->cext );
+    if (pOldUExtra == NULL)
+    {
+      /* ... we don't, so re-malloc enough memory for the old extra data plus */
+      /* the size of the UTF-8 Path extra field */
+      pUExtra = (char *) malloc( UCenLen + pZEntry->cext );
+      if (pUExtra == NULL)
+        ziperr( ZE_MEM, "UTF-8 Path Extra Field" );
+      /* move old extra field and update pointer and length */
+      memmove( pUExtra, pZEntry->cextra, pZEntry->cext);
+      free( pZEntry->cextra );
+      pZEntry->cextra = pUExtra;
+      pUExtra += pZEntry->cext;
+      pZEntry->cext += UCenLen;
+    }
+    else
+    {
+      /* ... we have. Sort out the existing UTF-8 Path extra field and remove it
+       * from pZEntry->extra, re-malloc enough memory for the old extra data
+       * left plus the size of the UTF-8 Path extra field */
+      blocksize = SH( pOldUExtra + 2 );
+      /* If the right length then go with it, else get rid of it and add a new extra field
+       * to existing block. */
+      if (blocksize == UCenLen - ZIP_EF_HEADER_SIZE)
+      {
+        /* looks good */
+        pUExtra = pOldUExtra;
+      }
+      else
+      {
+        newEFSize = pZEntry->cext - (blocksize + ZIP_EF_HEADER_SIZE) + UCenLen;
+        pUExtra = (char *) malloc( newEFSize );
+        if( pUExtra == NULL )
+          ziperr(ZE_MEM, "UTF-8 Path Extra Field");
+        /* move all before UTF-8 Path EF */
+        usTemp = (extent) (pOldUExtra - pZEntry->cextra);
+        pTemp = pUExtra;
+        memcpy( pTemp, pZEntry->cextra, usTemp );
+        /* move all after old UTF-8 Path EF */
+        pTemp = pUExtra + usTemp;
+        pOldTemp = pOldUExtra + ZIP_EF_HEADER_SIZE + blocksize;
+        usTemp = pZEntry->cext - usTemp - blocksize;
+        memcpy( pTemp, pOldTemp, usTemp);
+        /* replace extra fields */
+        pZEntry->cext = newEFSize;
+        free(pZEntry->cextra);
+        pZEntry->cextra = pUExtra;
+        pUExtra = pTemp + usTemp;
+      }
+    }
+  }
+
+  /*
+   * Compute the CRC-32 checksum of iname
+   */
+#ifdef WIN32_OEM
+  if ((inameLocal = malloc(strlen(pZEntry->iname) + 1)) == NULL) {
+    ZIPERR(ZE_MEM, "write Unicode");
+  }
+  /* if oem translation done convert back for checksum */
+  if ((pZEntry->vem & 0xff00) == 0) {
+    /* get original */
+    INTERN_TO_OEM(pZEntry->iname, inameLocal);
+  } else {
+    strcpy(inameLocal, pZEntry->iname);
+  }
+#else
+# define inameLocal (pZEntry->iname)
+#endif
+
+  chksum = crc32(chksum, (uch *)(inameLocal), strlen(inameLocal));
+
+#ifdef WIN32_OEM
+  free(inameLocal);
+#else
+# undef inameLocal
+#endif
+
+  /*
+   * Compute the Adler-16 checksum of iname
+   */
+/*
+  chksum = adler16(ADLERVAL_INITIAL,
+                   (uch *)(pZEntry->iname), strlen(pZEntry->iname));
+*/
+
+  /* set/update UTF-8 Path extra field members */
+  /* tag header */
+  write_ushort_to_mem(UTF8_PATH_EF_TAG, pUExtra);
+  /* data size */
+  write_ushort_to_mem((ush) (UCenLen - ZIP_EF_HEADER_SIZE), pUExtra + 2);
+  /* version */
+  *(pUExtra + 2 + 2) = 1;
+  /* iname checksum */
+  write_ulong_to_mem(chksum, pUExtra + 2 + 2 + 1);
+  /* UTF-8 path */
+  write_string_to_mem(pZEntry->uname, pUExtra + 2 + 2 + 1 + 4);
+
+  return ZE_OK;
+}
+#endif /* def UNICODE_SUPPORT */
+
+
+zoff_t ffile_size OF((FILE *));
+
+
+/* 2004-12-06 SMS.
+ * ffile_size() returns reliable file size or EOF.
+ * May be used to detect large files in a small-file program.
+ */
+zoff_t ffile_size( file)
+FILE *file;
+{
+  int sts;
+  size_t siz;
+  zoff_t ofs;
+  char waste[ 4];
+
+  /* Seek to actual EOF. */
+  sts = zfseeko( file, 0, SEEK_END);
+  if (sts != 0)
+  {
+    /* fseeko() failed.  (Unlikely.) */
+    ofs = EOF;
+  }
+  else
+  {
+    /* Get apparent offset at EOF. */
+    ofs = zftello( file);
+    if (ofs < 0)
+    {
+      /* Offset negative (overflow).  File too big. */
+      ofs = EOF;
+    }
+    else
+    {
+      /* Seek to apparent EOF offset.
+         Won't be at actual EOF if offset was truncated.
+      */
+      sts = zfseeko( file, ofs, SEEK_SET);
+      if (sts != 0)
+      {
+        /* fseeko() failed.  (Unlikely.) */
+        ofs = EOF;
+      }
+      else
+      {
+        /* Read a byte at apparent EOF.  Should set EOF flag. */
+        siz = fread( waste, 1, 1, file);
+        if (feof( file) == 0)
+        {
+          /* Not at EOF, but should be.  File too big. */
+          ofs = EOF;
+        }
+      }
+    }
+  }
+  /* Seek to BOF.
+   *
+   * 2007-05-23 SMS.
+   * Note that a problem in a prehistoric VAX C run-time library
+   * requires that rewind() be used instead of fseek(), or else
+   * the EOF flag is not cleared properly.
+   */
+  /* As WIN32 has this same problem (EOF not being cleared) when
+   * NO_ZIP64_SUPPORT is set but LARGE_FILE_SUPPORT is set on a
+   * small file, seems no reason not to always use rewind().
+   * 8/5/07 EG
+   */
+#if 0
+#ifdef VAXC
+  sts = rewind( file);
+#else /* def VAXC */
+  sts = zfseeko( file, 0, SEEK_SET);
+#endif /* def VAXC [else] */
+#endif
+  rewind(file);
+
+  return ofs;
+}
+
+
+#ifndef UTIL
+
+local void zipoddities(z)
+struct zlist far *z;
+{
+    if ((z->vem >> 8) >= NUM_HOSTS)
+    {
+        sprintf(errbuf, "made by version %d.%d on system type %d: ",
+                (ush)(z->vem & 0xff) / (ush)10, (ush)(z->vem & 0xff) % (ush)10,
+                z->vem >> 8);
+        zipwarn(errbuf, z->oname);
+    }
+    if (z->ver != 10 && z->ver != 11 && z->ver != 20)
+    {
+        sprintf(errbuf, "needs unzip %d.%d on system type %d: ",
+                (ush)(z->ver & 0xff) / (ush)10,
+                (ush)(z->ver & 0xff) % (ush)10, z->ver >> 8);
+        zipwarn(errbuf, z->oname);
+    }
+
+    if ((fix == 2) && (z->flg != z->lflg))
+    /* The comparision between central and local version of the
+       "general purpose bit flag" cannot be used from scanzipf_regnew(),
+       because in the "regular" zipfile processing, the local header reads
+       have been postponed until the actual entry processing takes place.
+       They have not yet been read when "zipoddities()" is called.
+       This change was neccessary to support multivolume archives.
+     */
+    {
+        sprintf(errbuf, "local flags = 0x%04x, central = 0x%04x: ",
+                z->lflg, z->flg);
+        zipwarn(errbuf, z->oname);
+    }
+    else if (z->flg & ~0xf && (z->flg & ~0xf0) != UTF8_BIT)
+    /* Only bit in high byte we support is the new UTF-8 bit */
+    {
+        sprintf(errbuf, "undefined bits used in flags = 0x%04x: ", z->flg);
+        zipwarn(errbuf, z->oname);
+    }
+    if (z->how > LAST_KNOWN_COMPMETHOD)    {
+        sprintf(errbuf, "unknown compression method %u: ", z->how);
+        zipwarn(errbuf, z->oname);
+    }
+    if (z->dsk)
+    {
+        sprintf(errbuf, "starts on disk %lu: ", z->dsk);
+        zipwarn(errbuf, z->oname);
+    }
+    if (z->att!=ASCII && z->att!=BINARY && z->att!=__EBCDIC)
+    {
+        sprintf(errbuf, "unknown internal attributes = 0x%04x: ", z->att);
+        zipwarn(errbuf, z->oname);
+    }
+# if 0
+/* This test is ridiculous, it produces an error message for almost every */
+/* platform of origin other than MS-DOS, Unix, VMS, and Acorn!  Perhaps   */
+/* we could test "if (z->dosflag && z->atx & ~0xffL)", but what for?      */
+    if (((n = z->vem >> 8) != 3) && n != 2 && n != 13 && z->atx & ~0xffL)
+    {
+        sprintf(errbuf, "unknown external attributes = 0x%08lx: ", z->atx);
+        zipwarn(errbuf, z->oname);
+    }
+# endif
+
+    /* This test is just annoying, as Zip itself does not write the same
+       extra fields to both the local and central headers.  It's much more
+       complicated than this test implies.  3/17/05 */
+#if 0
+    if (z->ext || z->cext)
+    {
+# if 0
+        if (z->ext && z->cext && z->extra != z->cextra)
+        {
+          sprintf(errbuf,
+                  "local extra (%ld bytes) != central extra (%ld bytes): ",
+                  (ulg)z->ext, (ulg)z->cext);
+          if (noisy) fprintf(mesg, "\tzip info: %s%s\n", errbuf, z->oname);
+        }
+#   if (!defined(RISCOS) && !defined(CMS_MVS))
+        /* in noisy mode, extra field sizes are always reported */
+        else if (noisy)
+#   else /* RISCOS || CMS_MVS */
+/* avoid warnings for zipfiles created on the same type of OS system! */
+/* or, was this warning really intended (eg. OS/2)? */
+        /* Only give info if extra bytes were added by another system */
+        else if (noisy && ((z->vem >> 8) != (OS_CODE >> 8)))
+#   endif /* ?(RISCOS || CMS_MVS) */
+# endif /* 0 */
+        {
+            fprintf(mesg, "zip info: %s has %ld bytes of %sextra data\n",
+                    z->oname, z->ext ? (ulg)z->ext : (ulg)z->cext,
+                    z->ext ? (z->cext ? "" : "local ") : "central ");
+        }
+    }
+#endif
+}
+
+
+#if 0 /* scanzipf_fix() no longer used */
+/*
+ * scanzipf_fix is called with zip -F or zip -FF
+ * read the file from front to back and pick up the pieces
+ * NOTE: there are still checks missing to see if the header
+ *       that was found is *VALID*
+ *
+ * Still much work to do so can handle more cases.  1/18/04 EG
+ */
+local int scanzipf_fix(f)
+  FILE *f;                      /* zip file */
+/*
+   The name of the zip file is pointed to by the global "zipfile".  The globals
+   zipbeg, cenbeg, zfiles, zcount, zcomlen, zcomment, and zsort are filled in.
+   Return an error code in the ZE_ class.
+*/
+{
+    ulg a = 0L;                 /* attributes returned by filetime() */
+    char b[CENHEAD];            /* buffer for central headers */
+    ush flg;                    /* general purpose bit flag */
+    int m;                      /* mismatch flag */
+    extent n;                   /* length of name */
+    uzoff_t p;                  /* current file offset */
+    uzoff_t s;                  /* size of data, start of central */
+    struct zlist far * far *x;  /* pointer last entry's link */
+    struct zlist far *z;        /* current zip entry structure */
+
+#ifndef ZIP64_SUPPORT
+
+/* 2004-12-06 SMS.
+ * Check for too-big file before doing any serious work.
+ */
+    if (ffile_size( f) == EOF)
+      return ZE_ZIP64;
+
+#endif /* ndef ZIP64_SUPPORT */
+
+
+    /* Get any file attribute valid for this OS, to set in the central
+     * directory when fixing the archive:
+     */
+# ifndef UTIL
+    filetime(zipfile, &a, (zoff_t*)&s, NULL);
+# endif
+    x = &zfiles;                        /* first link */
+    p = 0;                              /* starting file offset */
+# ifdef HANDLE_AMIGA_SFX
+    amiga_sfx_offset = 0L;
+# endif
+
+    /* Find start of zip structures */
+    for (;;) {
+      /* look for signature */
+      while ((m = getc(f)) != EOF && m != 0x50)    /* 0x50 == 'P' */
+      {
+# ifdef HANDLE_AMIGA_SFX
+        if (p == 0 && m == 0)
+          amiga_sfx_offset = 1L;
+        else if (amiga_sfx_offset) {
+          if ((p == 1 && m != 0) || (p == 2 && m != 3)
+                                 || (p == 3 && (uch) m != 0xF3))
+            amiga_sfx_offset = 0L;
+        }
+# endif /* HANDLE_AMIGA_SFX */
+        p++;
+      }
+      /* found a P */
+      b[0] = (char) m;
+      /* local - 11/2/03 EG */
+      if (fread(b+1, 3, 1, f) != 1 || (s = LG(b)) == LOCSIG)
+        break;
+      /* why search for ENDSIG if doing only local - 11/2/03 EG
+      if (fread(b+1, 3, 1, f) != 1 || (s = LG(b)) == LOCSIG || s == ENDSIG)
+        break;
+      */
+      /* back up */
+      if (zfseeko(f, -3L, SEEK_CUR))
+        return ferror(f) ? ZE_READ : ZE_EOF;
+      /* move 1 byte forward */
+      p++;
+    }
+    zipbeg = p;
+# ifdef HANDLE_AMIGA_SFX
+    if (amiga_sfx_offset && zipbeg >= 12 && (zipbeg & 3) == 0
+        && fseek(f, -12L, SEEK_CUR) == 0 && fread(b, 12, 1, f) == 1
+        && LG(b + 4) == 0xF1030000 /* 1009 in Motorola byte order */)
+      amiga_sfx_offset = zipbeg - 4;
+    else
+      amiga_sfx_offset = 0L;
+# endif /* HANDLE_AMIGA_SFX */
+
+    /* Read local headers */
+    while (LG(b) == LOCSIG)
+    {
+      if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL ||
+          zcount + 1 < zcount)
+        return ZE_MEM;
+      if (fread(b, LOCHEAD, 1, f) != 1) {
+          farfree((zvoid far *)z);
+          break;
+      }
+
+      z->ver = SH(LOCVER + b);
+      z->vem = (ush)(dosify ? 20 : OS_CODE + Z_MAJORVER * 10 + Z_MINORVER);
+      z->dosflag = dosify;
+      flg = z->flg = z->lflg = SH(LOCFLG + b);
+      z->how = SH(LOCHOW + b);
+      z->tim = LG(LOCTIM + b);          /* time and date into one long */
+      z->crc = LG(LOCCRC + b);
+      z->siz = LG(LOCSIZ + b);
+      z->len = LG(LOCLEN + b);
+      n = z->nam = SH(LOCNAM + b);
+      z->cext = z->ext = SH(LOCEXT + b);
+
+      z->com = 0;
+      z->dsk = 0;
+      z->att = 0;
+      z->atx = dosify ? a & 0xff : a;     /* Attributes from filetime() */
+      z->mark = 0;
+      z->trash = 0;
+
+      /* attention: this one breaks the VC optimizer (Release Build) */
+      /* may be fixed - 11/1/03 EG */
+      s = fix > 1 ? 0L : z->siz; /* discard compressed size with -FF */
+
+      /* Initialize all fields pointing to malloced data to NULL */
+      z->zname = z->name = z->iname = z->extra = z->cextra = z->comment = NULL;
+      z->oname = NULL;
+#ifdef UNICODE_SUPPORT
+      z->uname = z->zuname = z->ouname = NULL;
+#endif
+
+      /* Link into list */
+      *x = z;
+      z->nxt = NULL;
+      x = &z->nxt;
+
+      /* Read file name and extra field and skip data */
+      if (n == 0)
+      {
+        sprintf(errbuf, "%lu", (ulg)zcount + 1);
+        zipwarn("zero-length name for entry #", errbuf);
+# ifndef DEBUG
+        return ZE_FORM;
+# endif
+      }
+      if ((z->iname = malloc(n+1)) ==  NULL ||
+          (z->ext && (z->extra = malloc(z->ext)) == NULL))
+        return ZE_MEM;
+      if (fread(z->iname, n, 1, f) != 1 ||
+          (z->ext && fread(z->extra, z->ext, 1, f) != 1))
+        return ferror(f) ? ZE_READ : ZE_EOF;
+
+#  ifdef ZIP64_SUPPORT
+      /* adjust/update siz,len and off (to come: dsk) entries */
+      /* PKZIP does not care of the version set in a CDH: if  */
+      /* there is a zip64 extra field assigned to a CDH PKZIP */
+      /* uses it, we should do so, too.                       */
+      zip64_entry = adjust_zip_local_entry(z);
+      /* z->siz may be updated */
+      s = fix > 1 ? 0L : z->siz; /* discard compressed size with -FF */
+#  endif
+
+      if (s && zfseeko(f, (zoff_t)s, SEEK_CUR))
+        return ferror(f) ? ZE_READ : ZE_EOF;
+      /* If there is an extended local header, s is either 0 or
+       * the correct compressed size.
+       */
+      z->iname[n] = '\0';               /* terminate name */
+      z->zname = in2ex(z->iname);       /* convert to external name */
+      if (z->zname == NULL)
+        return ZE_MEM;
+      z->name = z->zname;
+      z->cextra = z->extra;
+      if (noisy) fprintf(mesg, "zip: reading %s\n", z->zname);
+
+      /* Save offset, update for next header */
+      z->off = p;
+      p += 4 + LOCHEAD + n + z->ext + s;
+      zcount++;
+
+      /* Skip extended local header if there is one */
+      if ((flg & 8) != 0) {
+        /* Skip the compressed data if compressed size is unknown.
+         * For safety, we should use the central directory.
+         */
+        if (s == 0) {
+          for (;;) {
+            while ((m = getc(f)) != EOF && m != 0x50) ;  /* 0x50 == 'P' */
+            b[0] = (char) m;
+            if (fread(b+1, 15, 1, f) != 1 || LG(b) == EXTLOCSIG)
+              break;
+            if (zfseeko(f, -15L, SEEK_CUR))
+              return ferror(f) ? ZE_READ : ZE_EOF;
+          }
+# ifdef ZIP64_SUPPORT
+          if (zip64_entry) {        /* from extra field */
+            /* all are 8 bytes */
+            s = LG(4 + ZIP64_EXTSIZ + b);
+          } else {
+            s = LG(4 + EXTSIZ + b);
+          }
+# else
+          s = LG(4 + EXTSIZ + b);
+# endif
+          p += s;
+          if ((uzoff_t) zftello(f) != p+16L) {
+            zipwarn("bad extended local header for ", z->zname);
+            return ZE_FORM;
+          }
+        } else {
+          /* compressed size non-zero, assume that it is valid: */
+          Assert(p == zftello(f), "bad compressed size with extended header");
+
+          if (zfseeko(f, p, SEEK_SET) || fread(b, 16, 1, f) != 1)
+            return ferror(f) ? ZE_READ : ZE_EOF;
+          if (LG(b) != EXTLOCSIG) {
+            zipwarn("extended local header not found for ", z->zname);
+            return ZE_FORM;
+          }
+        }
+        /* overwrite the unknown values of the local header: */
+
+        /* already in host format */
+# ifdef ZIP64_SUPPORT
+        z->crc = LG(4 + ZIP64_EXTCRC + b);
+        z->siz = s;
+        z->len = LG(4 + ZIP64_EXTLEN + b);
+# else
+        z->crc = LG(4 + EXTCRC + b);
+        z->siz = s;
+        z->len = LG(4 + EXTLEN + b);
+# endif
+
+        p += 16L;
+      }
+      else if (fix > 1) {
+        /* Don't trust the compressed size */
+        for (;;) {
+          while ((m = getc(f)) != EOF && m != 0x50) p++; /* 0x50 == 'P' */
+          b[0] = (char) m;
+          if (fread(b+1, 3, 1, f) != 1 || (s = LG(b)) == LOCSIG || s == CENSIG)
+            break;
+          if (zfseeko(f, -3L, SEEK_CUR))
+            return ferror(f) ? ZE_READ : ZE_EOF;
+          p++;
+        }
+        s = p - (z->off + 4 + LOCHEAD + n + z->ext);
+        if (s != z->siz) {
+          fprintf(mesg, " compressed size %s, actual size %s for %s\n",
+                  zip_fzofft(z->siz, NULL, "u"), zip_fzofft(s, NULL, "u"),
+                  z->zname);
+          z->siz = s;
+        }
+        /* next LOCSIG already read at this point, don't read it again: */
+        continue;
+      }
+
+      /* Read next signature */
+      if (fread(b, 4, 1, f) != 1)
+          break;
+    }
+
+    s = p;                              /* save start of central */
+
+    if (LG(b) != CENSIG && noisy) {
+      fprintf(mesg, "zip warning: %s %s truncated.\n", zipfile,
+              fix > 1 ? "has been" : "would be");
+
+      if (fix == 1) {
+        fprintf(mesg,
+   "Retry with option -qF to truncate, with -FF to attempt full recovery\n");
+        ZIPERR(ZE_FORM, NULL);
+      }
+    }
+
+    cenbeg = s;
+
+    if (zipbeg && noisy)
+      fprintf(mesg, "%s: adjusting offsets for a preamble of %s bytes\n",
+              zipfile, zip_fzofft(zipbeg, NULL, "u"));
+    return ZE_OK;
+} /* end of function scanzipf_fix() */
+#endif /* never, scanzipf_fix() no longer used */
+
+#endif /* !UTIL */
+
+/*
+ * read_local
+ *
+ * Read the local header assumed at in_file file pointer.
+ * localz is the returned local header, z is the central directory entry.
+ *
+ * This is used by crypt.c.
+ *
+ * Return ZE code
+ */
+int readlocal(localz, z)
+  struct zlist far **localz;
+  struct zlist far *z;
+{
+  char buf[LOCHEAD + 1];
+  struct zlist far *locz;
+
+#ifndef UTIL
+  ulg start_disk = 0;
+  uzoff_t start_offset = 0;
+  char *split_path;
+
+  start_disk = z->dsk;
+  start_offset = z->off;
+
+  /* don't assume reading the right disk */
+
+  if (start_disk != current_in_disk) {
+    if (in_file) {
+      fclose(in_file);
+      in_file = NULL;
+    }
+  }
+
+  current_in_disk = start_disk;
+
+  /* disks are archive.z01, archive.z02, ..., archive.zip */
+  split_path = get_in_split_path(in_path, current_in_disk);
+
+  if (in_file == NULL) {
+    while ((in_file = zfopen(split_path, FOPR)) == NULL) {
+      /* could not open split */
+
+      /* Ask for directory with split.  Updates in_path */
+      if (ask_for_split_read_path(start_disk) != ZE_OK) {
+        return ZE_ABORT;
+      }
+      free(split_path);
+      split_path = get_in_split_path(in_path, start_disk);
+    }
+  }
+#endif
+
+  /* For utilities assume archive is on one disk for now */
+
+  if (zfseeko(in_file, z->off, SEEK_SET) != 0) {
+    fclose(in_file);
+    in_file = NULL;
+    zipwarn("reading archive fseek: ", strerror(errno));
+    return ZE_READ;
+  }
+  if (!at_signature(in_file, "PK\03\04")) {
+    fclose(in_file);
+    in_file = NULL;
+    zipwarn("Did not find entry for ", z->iname);
+    return ZE_FORM;
+  }
+
+  /* read local header */
+  if (fread(buf, LOCHEAD, 1, in_file) != 1) {
+    int f = ferror(in_file);
+    zipwarn("reading local entry: ", strerror(errno));
+    fclose(in_file);
+    return f ? ZE_READ : ZE_EOF;
+  }
+
+  /* Local Header
+       local file header signature     4 bytes  (0x04034b50)
+       version needed to extract       2 bytes
+       general purpose bit flag        2 bytes
+       compression method              2 bytes
+       last mod file time              2 bytes
+       last mod file date              2 bytes
+       crc-32                          4 bytes
+       compressed size                 4 bytes
+       uncompressed size               4 bytes
+       file name length                2 bytes
+       extra field length              2 bytes
+
+       file name (variable size)
+       extra field (variable size)
+   */
+
+  if ((locz = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) {
+    zipwarn("reading entry", "");
+    fclose(in_file);
+    return ZE_MEM;
+  }
+
+  locz->ver = SH(LOCVER + buf);
+  locz->lflg = SH(LOCFLG + buf);
+  locz->how = SH(LOCHOW + buf);
+  locz->tim = LG(LOCTIM + buf);          /* time and date into one long */
+  locz->crc = LG(LOCCRC + buf);
+  locz->nam = SH(LOCNAM + buf);
+  locz->ext = SH(LOCEXT + buf);
+
+  /* Initialize all fields pointing to malloced data to NULL */
+  locz->zname = locz->name = locz->iname = locz->extra = NULL;
+  locz->oname = NULL;
+#ifdef UNICODE_SUPPORT
+  locz->uname = NULL;
+  locz->zuname = NULL;
+  locz->ouname = NULL;
+#endif
+
+  /* Read file name, extra field and comment field */
+  if ((locz->iname = malloc(locz->nam+1)) ==  NULL ||
+      (locz->ext && (locz->extra = malloc(locz->ext)) == NULL))
+    return ZE_MEM;
+  if (fread(locz->iname, locz->nam, 1, in_file) != 1 ||
+      (locz->ext && fread(locz->extra, locz->ext, 1, in_file) != 1))
+    return ferror(in_file) ? ZE_READ : ZE_EOF;
+  locz->iname[z->nam] = '\0';                  /* terminate name */
+#ifdef UNICODE_SUPPORT
+  if (unicode_mismatch != 3)
+    read_Unicode_Path_local_entry(locz);
+#endif
+#ifdef WIN32
+  {
+    /* translate archive name from OEM if came from OEM-charset environment */
+    unsigned hostver = (z->vem & 0xff);
+    Ext_ASCII_TO_Native(locz->iname, (z->vem >> 8), hostver,
+                        ((z->atx & 0xffff0000L) != 0), TRUE);
+  }
+#endif
+  if ((locz->name = malloc(locz->nam+1)) ==  NULL)
+    return ZE_MEM;
+  strcpy(locz->name, locz->iname);
+
+#ifdef ZIP64_SUPPORT
+  zip64_entry = adjust_zip_local_entry(locz);
+#endif
+
+  /* Compare localz to z */
+  if (locz->ver != z->ver) {
+    sprintf(errbuf, "Local Version Needed (%d) does not match CD (%d): ", locz->ver, z->ver);
+    zipwarn(errbuf, z->iname);
+  }
+  if (locz->lflg != z->flg) {
+    zipwarn("Local Entry Flag does not match CD: ", z->iname);
+  }
+  if (locz->crc != z->crc) {
+    zipwarn("Local Entry CRC does not match CD: ", z->iname);
+  }
+
+  /* as copying get uncompressed and compressed sizes from central directory */
+  locz->len = z->len;
+  locz->siz = z->siz;
+
+  *localz = locz;
+
+  return ZE_OK;
+} /* end function readlocal() */
+
+#if 0 /* following functions are not (no longer) used. */
+/*
+ * scanzipf_reg starts searching for the End Signature at the end of the file
+ * The End Signature points to the Central Directory Signature which points
+ * to the Local Directory Signature
+ * XXX probably some more consistency checks are needed
+ */
+local int scanzipf_reg(f)
+  FILE *f;                      /* zip file */
+/*
+   The name of the zip file is pointed to by the global "zipfile".  The globals
+   zipbeg, cenbeg, zfiles, zcount, zcomlen, zcomment, and zsort are filled in.
+   Return an error code in the ZE_ class.
+*/
+{
+    char b[CENHEAD];            /* buffer for central headers */
+    extent n;                   /* length of name */
+    struct zlist far * far *x;  /* pointer last entry's link */
+    struct zlist far *z;        /* current zip entry structure */
+    char *t;                    /* temporary pointer */
+    char far *u;                /* temporary variable */
+    int found;
+    char *buf;                  /* temp buffer for reading zipfile */
+# ifdef ZIP64_SUPPORT
+    ulg u4;                     /* unsigned 4 byte variable */
+    char bf[8];
+    uzoff_t u8;                 /* unsigned 8 byte variable */
+    uzoff_t censiz;             /* size of central directory */
+    uzoff_t z64eocd;            /* Zip64 End Of Central Directory record byte offset */
+# else
+    ush flg;                    /* general purpose bit flag */
+    int m;                      /* mismatch flag */
+# endif
+    zoff_t deltaoff = 0;
+
+
+#ifndef ZIP64_SUPPORT
+
+    /* 2004-12-06 SMS.
+     * Check for too-big file before doing any serious work.
+     */
+    if (ffile_size( f) == EOF)
+      return ZE_ZIP64;
+
+#endif /* ndef ZIP64_SUPPORT */
+
+
+    buf = malloc(4096 + 4);
+    if (buf == NULL)
+      return ZE_MEM;
+
+#ifdef HANDLE_AMIGA_SFX
+    amiga_sfx_offset = (fread(buf, 1, 4, f) == 4 && LG(buf) == 0xF3030000);
+    /* == 1 if this file is an Amiga executable (presumably UnZipSFX) */
+#endif
+    /* detect spanning signature */
+    zfseeko(f, 0, SEEK_SET);
+    read_split_archive = (fread(buf, 1, 4, f) == 4 && LG(buf) == 0x08074b50L);
+    found = 0;
+    t = &buf[4096];
+    t[1] = '\0';
+    t[2] = '\0';
+    t[3] = '\0';
+    /* back up as much as 4k from end */
+    /* zip64 support 08/31/2003 R.Nausedat */
+    if (zfseeko(f, -4096L, SEEK_END) == 0) {
+      zipbeg = (uzoff_t) (zftello(f) + 4096L);
+      /* back up 4k blocks and look for End Of CD signature */
+      while (!found && zipbeg >= 4096) {
+        zipbeg -= 4096L;
+        buf[4096] = t[1];
+        buf[4097] = t[2];
+        buf[4098] = t[3];
+/*
+ * XXX error check ??
+ */
+        fread(buf, 1, 4096, f);
+        zfseeko(f, -8192L, SEEK_CUR);
+        t = &buf[4095];
+/*
+ * XXX far pointer arithmetic in DOS
+ */
+        while (t >= buf) {
+          /* Check for ENDSIG ("PK\5\6" in ASCII) */
+          if (LG(t) == ENDSIG) {
+            found = 1;
+/*
+ * XXX error check ??
+ * XXX far pointer arithmetic in DOS
+ */
+            zipbeg += (uzoff_t) (t - buf);
+            zfseeko(f, (zoff_t) zipbeg + 4L, SEEK_SET);
+            break;
+          }
+          --t;
+        }
+      }
+    }
+    else
+      /* file less than 4k bytes */
+      zipbeg = 4096L;
+/*
+ * XXX warn: garbage at the end of the file ignored
+ */
+    if (!found && zipbeg > 0) {
+      size_t s;
+
+      zfseeko(f, 0L, SEEK_SET);
+      clearerr(f);
+      s = fread(buf, 1, (size_t) zipbeg, f);
+      /* add 0 bytes at end */
+      buf[s] = t[1];
+      buf[s + 1] = t[2];
+      buf[s + 2] = t[3];
+      t = &buf[s - 1];
+/*
+ * XXX far pointer comparison in DOS
+ */
+      while (t >= buf) {
+        /* Check for ENDSIG ("PK\5\6" in ASCII) */
+        if (LG(t) == ENDSIG) {
+          found = 1;
+/*
+ * XXX far pointer arithmetic in DOS
+ */
+          zipbeg = (ulg) (t - buf);
+          zfseeko(f, (zoff_t) zipbeg + 4L, SEEK_SET);
+          break;
+        }
+        --t;
+      }
+    }
+    free(buf);
+    if (!found) {
+      zipwarn("missing end signature--probably not a zip file (did you", "");
+      zipwarn("remember to use binary mode when you transferred it?)", "");
+      return ZE_FORM;
+    }
+
+/*
+ * Check for a Zip64 EOCD Locator signature - 12/10/04 EG
+ */
+#ifndef ZIP64_SUPPORT
+    /* If Zip64 not enabled check if archive being read is Zip64 */
+    /* back up 24 bytes (size of Z64 EOCDL and ENDSIG) */
+    if (zfseeko(f, -24, SEEK_CUR) != 0) {
+        perror("fseek");
+        return ZE_FORM; /* XXX */
+    }
+    /* read Z64 EOCDL if there */
+    if (fread(b, 20, 1, f) != 1) {
+      return ZE_READ;
+    }
+    /* first 4 bytes are the signature if there */
+    if (LG(b) == ZIP64_EOCDL_SIG) {
+      zipwarn("found Zip64 signature - this may be a Zip64 archive", "");
+      zipwarn("PKZIP 4.5 or later needed - set ZIP64_SUPPORT in Zip 3", "");
+      return ZE_ZIP64;
+    }
+
+    /* now should be back at the EOCD signature */
+    if (fread(b, 4, 1, f) != 1) {
+      zipwarn("unable to read after relative seek", "");
+      return ZE_READ;
+    }
+    if (LG(b) != ENDSIG) {
+      zipwarn("unable to relative seek in archive", "");
+      return ZE_FORM;
+    }
+#if 0
+    if (fseek(f, -4, SEEK_CUR) != 0) {
+        perror("fseek");
+        return ZE_FORM; /* XXX */
+    }
+#endif
+#endif
+
+    /* Read end header */
+    if (fread(b, ENDHEAD, 1, f) != 1)
+      return ferror(f) ? ZE_READ : ZE_EOF;
+    if (SH(ENDDSK + b) || SH(ENDBEG + b) ||
+        SH(ENDSUB + b) != SH(ENDTOT + b))
+      zipwarn("multiple disk information ignored", "");
+    zcomlen = SH(ENDCOM + b);
+    if (zcomlen)
+    {
+      if ((zcomment = malloc(zcomlen)) == NULL)
+        return ZE_MEM;
+      if (fread(zcomment, zcomlen, 1, f) != 1)
+      {
+        free((zvoid *)zcomment);
+        zcomment = NULL;
+        return ferror(f) ? ZE_READ : ZE_EOF;
+      }
+#ifdef EBCDIC
+      if (zcomment)
+         memtoebc(zcomment, zcomment, zcomlen);
+#endif /* EBCDIC */
+    }
+#ifdef ZIP64_SUPPORT
+    /* account for Zip64 EOCD Record and Zip64 EOCD Locator */
+
+    /* Z64 EOCDL should be just before EOCD (unless this is an empty archive) */
+    cenbeg = zipbeg - ZIP64_EOCDL_OFS_SIZE;
+    /* check for empty archive */
+    /* changed cenbeg to uzoff_t so instead of cenbeg >= 0 use new check - 5/23/05 EG */
+    if (zipbeg >= ZIP64_EOCDL_OFS_SIZE) {
+      /* look for signature */
+      if (zfseeko(f, cenbeg, SEEK_SET)) {
+        zipwarn("end of file seeking Z64EOCDL", "");
+        return ZE_FORM;
+      }
+      if (fread(bf, 4, 1, f) != 1) {
+        ziperr(ZE_FORM, "read error");
+      }
+      u4 = LG(bf);
+      if (u4 == ZIP64_EOCDL_SIG) {
+        /* found Zip64 EOCD Locator */
+        /* check for disk information */
+        zfseeko(f, cenbeg + ZIP64_EOCDL_OFS_TOTALDISKS, SEEK_SET);
+        if (fread(bf, 4, 1, f) != 1) {
+          ziperr(ZE_FORM, "read error");
+        }
+        u4 = LG(bf);
+        if (u4 != 1) {
+          ziperr(ZE_FORM, "multiple disk archives not yet supported");
+        }
+
+        /* look for Zip64 EOCD Record */
+        zfseeko(f, cenbeg + ZIP64_EOCDL_OFS_EOCD_START, SEEK_SET);
+        if (fread(bf, 8, 1, f) != 1) {
+         ziperr(ZE_FORM, "read error");
+        }
+        z64eocd = LLG(bf);
+        if (zfseeko(f, z64eocd, SEEK_SET)) {
+          ziperr(ZE_FORM, "error searching for Z64 EOCD Record");
+        }
+        if (fread(bf, 4, 1, f) != 1) {
+         ziperr(ZE_FORM, "read error");
+        }
+        u4 = LG(bf);
+        if (u4 != ZIP64_EOCD_SIG) {
+          ziperr(ZE_FORM, "Z64 EOCD not found but Z64 EOCD Locator exists");
+        }
+        /* get size of CD */
+        zfseeko(f, z64eocd + ZIP64_EOCD_OFS_SIZE, SEEK_SET);
+        if (fread(bf, 8, 1, f) != 1) {
+         ziperr(ZE_FORM, "read error");
+        }
+        censiz = LLG(bf);
+        /* get start of CD */
+        zfseeko(f, z64eocd + ZIP64_EOCD_OFS_CD_START, SEEK_SET);
+        if (fread(bf, 8, 1, f) == (size_t) -1) {
+         ziperr(ZE_FORM, "read error");
+        }
+        cenbeg = LLG(bf);
+        u8 = z64eocd - cenbeg;
+        deltaoff = adjust ? u8 - censiz : 0L;
+      } else {
+        /* assume no Locator and no Zip64 EOCD Record */
+        censiz = LG(ENDSIZ + b);
+        cenbeg = LG(b + ENDOFF);
+        u8 = zipbeg - censiz;
+        deltaoff = adjust ? u8 - censiz : 0L;
+      }
+    }
+#else /* !ZIP64_SUPPORT */
+/*
+ * XXX assumes central header immediately precedes end header
+ */
+    /* start of central directory */
+    cenbeg = zipbeg - LG(ENDSIZ + b);
+/*
+printf("start of central directory cenbeg %ld\n", cenbeg);
+*/
+
+    /* offset to first entry of archive */
+    deltaoff = adjust ? cenbeg - LG(b + ENDOFF) : 0L;
+#endif /* ?ZIP64_SUPPORT */
+
+    if (zipbeg < ZIP64_EOCDL_OFS_SIZE) {
+      /* zip file seems empty */
+      return ZE_OK;
+    }
+
+    if (zfseeko(f, cenbeg, SEEK_SET) != 0) {
+        perror("fseek");
+        return ZE_FORM; /* XXX */
+    }
+
+    x = &zfiles;                        /* first link */
+
+    if (fread(b, 4, 1, f) != 1)
+      return ferror(f) ? ZE_READ : ZE_EOF;
+
+    while (LG(b) == CENSIG) {
+      /* Read central header. The portion of the central header that should
+         be in common with local header is read raw, for later comparison.
+         (this requires that the offset of ext in the zlist structure
+         be greater than or equal to LOCHEAD) */
+      if (fread(b, CENHEAD, 1, f) != 1)
+        return ferror(f) ? ZE_READ : ZE_EOF;
+      if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL)
+        return ZE_MEM;
+      z->vem = SH(CENVEM + b);
+      for (u = (char far *)(&(z->ver)), n = 0; n < (CENNAM-CENVER); n++)
+        u[n] = b[CENVER + n];
+      z->nam = SH(CENNAM + b);          /* used before comparing cen vs. loc */
+      z->cext = SH(CENEXT + b);         /* may be different from z->ext */
+      z->com = SH(CENCOM + b);
+      z->dsk = SH(CENDSK + b);
+      z->att = SH(CENATT + b);
+      z->atx = LG(CENATX + b);
+      z->off = LG(CENOFF + b) + deltaoff;
+      z->dosflag = (z->vem & 0xff00) == 0;
+
+      /* Initialize all fields pointing to malloced data to NULL */
+      z->zname = z->name = z->iname = z->extra = z->cextra = z->comment = NULL;
+      z->oname = NULL;
+#ifdef UNICODE_SUPPORT
+      z->uname = NULL;      /* UTF-8 path */
+      z->zuname = NULL;     /* Escaped local version of uname */
+      z->ouname = NULL;     /* Display version of zuname */
+#endif
+
+      /* Link into list */
+      *x = z;
+      z->nxt = NULL;
+      x = &z->nxt;
+
+      /* Read file name, extra field and comment field */
+      if (z->nam == 0)
+      {
+        sprintf(errbuf, "%lu", (ulg)zcount + 1);
+        zipwarn("zero-length name for entry #", errbuf);
+#ifndef DEBUG
+        farfree((zvoid far *)z);
+        return ZE_FORM;
+#endif
+      }
+      if ((z->iname = malloc(z->nam+1)) ==  NULL ||
+          (z->cext && (z->cextra = malloc(z->cext)) == NULL) ||
+          (z->com && (z->comment = malloc(z->com)) == NULL))
+        return ZE_MEM;
+      if (fread(z->iname, z->nam, 1, f) != 1 ||
+          (z->cext && fread(z->cextra, z->cext, 1, f) != 1) ||
+          (z->com && fread(z->comment, z->com, 1, f) != 1))
+        return ferror(f) ? ZE_READ : ZE_EOF;
+      z->iname[z->nam] = '\0';                  /* terminate name */
+
+#ifdef EBCDIC
+      if (z->com)
+         memtoebc(z->comment, z->comment, z->com);
+#endif /* EBCDIC */
+
+#ifdef ZIP64_SUPPORT
+      /* zip64 support 08/31/2003 R.Nausedat                          */
+      /* here, we have to read the len, siz etc values from the CD    */
+      /* entry as we might have to adjust them regarding their        */
+      /* correspronding zip64 extra fields.                           */
+      /* also, we cannot compare the values from the CD entries with  */
+      /* the values from the LH as they might be different.           */
+      z->len = LG(CENLEN + b);
+      z->siz = LG(CENSIZ + b);
+      z->crc = LG(CENCRC + b);
+      z->tim = LG(CENTIM + b);   /* time and date into one long */
+      z->how = SH(CENHOW + b);
+      z->flg = SH(CENFLG + b);
+      z->ver = SH(CENVER + b);
+      /* adjust/update siz,len and off (to come: dsk) entries */
+      /* PKZIP does not care of the version set in a CDH: if  */
+      /* there is a zip64 extra field assigned to a CDH PKZIP */
+      /* uses it, we should do so, too.                       */
+      adjust_zip_central_entry(z);
+#endif /* ZIP64_SUPPORT */
+
+      /* Update zipbeg offset, prepare for next header */
+      if (z->off < zipbeg)
+         zipbeg = z->off;
+      zcount++;
+      /* Read next signature */
+      if (fread(b, 4, 1, f) != 1)
+          return ferror(f) ? ZE_READ : ZE_EOF;
+    }
+
+    /* Point to start of header list and read local headers */
+    z = zfiles;
+    while (z != NULL) {
+      /* Read next signature */
+      if (zfseeko(f, z->off, SEEK_SET) != 0 || fread(b, 4, 1, f) != 1)
+        return ferror(f) ? ZE_READ : ZE_EOF;
+      if (LG(b) == LOCSIG) {
+        if (fread(b, LOCHEAD, 1, f) != 1)
+            return ferror(f) ? ZE_READ : ZE_EOF;
+
+        z->lflg = SH(LOCFLG + b);
+        n = SH(LOCNAM + b);
+        z->ext = SH(LOCEXT + b);
+
+        /* Compare name and extra fields */
+        if (n != z->nam)
+        {
+#ifdef EBCDIC
+          strtoebc(z->iname, z->iname);
+#endif
+          zipwarn("name lengths in local and central differ for ", z->iname);
+          return ZE_FORM;
+        }
+        if ((t = malloc(z->nam)) == NULL)
+          return ZE_MEM;
+        if (fread(t, z->nam, 1, f) != 1)
+        {
+          free((zvoid *)t);
+          return ferror(f) ? ZE_READ : ZE_EOF;
+        }
+        if (memcmp(t, z->iname, z->nam))
+        {
+          free((zvoid *)t);
+#ifdef EBCDIC
+          strtoebc(z->iname, z->iname);
+#endif
+          zipwarn("names in local and central differ for ", z->iname);
+          return ZE_FORM;
+        }
+        free((zvoid *)t);
+        if (z->ext)
+        {
+          if ((z->extra = malloc(z->ext)) == NULL)
+            return ZE_MEM;
+          if (fread(z->extra, z->ext, 1, f) != 1)
+          {
+            free((zvoid *)(z->extra));
+            return ferror(f) ? ZE_READ : ZE_EOF;
+          }
+          if (z->ext == z->cext && memcmp(z->extra, z->cextra, z->ext) == 0)
+          {
+            free((zvoid *)(z->extra));
+            z->extra = z->cextra;
+          }
+        }
+
+#ifdef ZIP64_SUPPORT       /* zip64 support 09/02/2003 R.Nausedat */
+        /*
+        for now the below is left out if ZIP64_SUPPORT is defined as the fields
+        len, siz and off in struct zlist are type of int64 if ZIP64_SUPPORT
+        is defined. In either way, the values read from the central directory
+        should be valid. comments are welcome
+        */
+#else /* !ZIP64_SUPPORT */
+        /* Check extended local header if there is one */
+        /* bit 3 */
+        if ((z->lflg & 8) != 0)
+        {
+          char buf2[16];
+          ulg s;                        /* size of compressed data */
+
+          s = LG(LOCSIZ + b);
+          if (s == 0)
+            s = LG((CENSIZ-CENVER) + (char far *)(&(z->ver)));
+          if (zfseeko(f, (z->off + (4+LOCHEAD) + z->nam + z->ext + s), SEEK_SET)
+              || (fread(buf2, 16, 1, f) != 1))
+            return ferror(f) ? ZE_READ : ZE_EOF;
+          if (LG(buf2) != EXTLOCSIG)
+          {
+# ifdef EBCDIC
+            strtoebc(z->iname, z->iname);
+# endif
+            zipwarn("extended local header not found for ", z->iname);
+            return ZE_FORM;
+          }
+          /* overwrite the unknown values of the local header: */
+          for (n = 0; n < 12; n++)
+            b[LOCCRC+n] = buf2[4+n];
+        }
+
+        /* Compare local header with that part of central header (except
+           for the reserved bits in the general purpose flags and except
+           for the already checked entry name length */
+        /* If I have read this right we are stepping through the z struct
+           here as a byte array.  Need to fix this.  5/25/2005 EG */
+        u = (char far *)(&(z->ver));
+        flg = SH((CENFLG-CENVER) + u);          /* Save central flags word */
+        u[CENFLG-CENVER+1] &= 0x1f;             /* Mask reserved flag bits */
+        b[LOCFLG+1] &= 0x1f;
+        for (m = 0, n = 0; n < LOCNAM; n++) {
+          if (b[n] != u[n])
+          {
+            if (!m)
+            {
+              zipwarn("local and central headers differ for ", z->iname);
+              m = 1;
+            }
+            if (noisy)
+            {
+              sprintf(errbuf, " offset %u--local = %02x, central = %02x",
+                      (unsigned)n, (uch)b[n], (uch)u[n]);
+              zipwarn(errbuf, "");
+            }
+          }
+        }
+        if (m && !adjust)
+          return ZE_FORM;
+
+        /* Complete the setup of the zlist entry by translating the remaining
+         * central header fields in memory, starting with the fields with
+         * highest offset. This order of the conversion commands takes into
+         * account potential buffer overlaps caused by structure padding.
+         */
+        z->len = LG((CENLEN-CENVER) + u);
+        z->siz = LG((CENSIZ-CENVER) + u);
+        z->crc = LG((CENCRC-CENVER) + u);
+        z->tim = LG((CENTIM-CENVER) + u);   /* time and date into one long */
+        z->how = SH((CENHOW-CENVER) + u);
+        z->flg = flg;                       /* may be different from z->lflg */
+        z->ver = SH((CENVER-CENVER) + u);
+#endif /* ?ZIP64_SUPPORT */
+
+        /* Clear actions */
+        z->mark = 0;
+        z->trash = 0;
+#ifdef UNICODE_SUPPORT
+        if (unicode_mismatch != 3) {
+          read_Unicode_Path_entry(z);
+          if (z->uname) {
+            /* match based on converted Unicode name */
+            z->name = utf8_to_local_string(z->uname);
+# ifdef EBCDIC
+            /* z->zname is used for printing and must be coded in native charset */
+            strtoebc(z->zname, z->name);
+# else
+            if ((z->zname = malloc(strlen(z->name) + 1)) == NULL) {
+              ZIPERR(ZE_MEM, "scanzipf_reg");
+            }
+            strcpy(z->zname, z->name);
+# endif
+            z->oname = local_to_display_string(z->zname);
+          } else {
+            /* no UTF-8 path */
+            if ((z->name = malloc(strlen(z->iname) + 1)) == NULL) {
+              ZIPERR(ZE_MEM, "scanzipf_reg");
+            }
+            strcpy(z->name, z->iname);
+            if ((z->zname = malloc(strlen(z->iname) + 1)) == NULL) {
+              ZIPERR(ZE_MEM, "scanzipf_reg");
+            }
+            strcpy(z->zname, z->iname);
+            z->oname = local_to_display_string(z->iname);
+          }
+        }
+#else /* !UNICODE_SUPPORT */
+# ifdef UTIL
+/* We only need z->iname in the utils */
+        z->name = z->iname;
+#  ifdef EBCDIC
+/* z->zname is used for printing and must be coded in native charset */
+        if ((z->zname = malloc(z->nam+1)) ==  NULL)
+          return ZE_MEM;
+        strtoebc(z->zname, z->iname);
+#  else
+        z->zname = z->iname;
+#  endif
+# else /* !UTIL */
+        z->zname = in2ex(z->iname);       /* convert to external name */
+        if (z->zname == NULL)
+          return ZE_MEM;
+        z->name = z->zname;
+# endif /* ?UTIL */
+        if ((z->oname = malloc(strlen(z->zname) + 1)) == NULL) {
+          ZIPERR(ZE_MEM, "scanzipf_reg");
+        }
+        strcpy(z->oname, z->zname);
+#endif /* ?UNICODE_SUPPORT */
+      }
+      else {
+#ifdef EBCDIC
+        strtoebc(z->iname, z->iname);
+#endif
+        zipwarn("local header not found for ", z->iname);
+        return ZE_FORM;
+      }
+#ifndef UTIL
+      if (verbose && fix == 0)
+        zipoddities(z);
+#endif
+      z = z->nxt;
+    }
+
+    if (zipbeg && noisy)
+      fprintf(mesg, "%s: %s a preamble of %s bytes\n",
+              zipfile, adjust ? "adjusting offsets for" : "found",
+              zip_fzofft(zipbeg, NULL, "u"));
+#ifdef HANDLE_AMIGA_SFX
+    if (zipbeg < 12 || (zipbeg & 3) != 0 /* must be longword aligned */)
+      amiga_sfx_offset = 0;
+    else if (amiga_sfx_offset) {
+      char buf2[16];
+      if (!fseek(f, zipbeg - 12, SEEK_SET) && fread(buf2, 12, 1, f) == 1) {
+        if (LG(buf2 + 4) == 0xF1030000 /* 1009 in Motorola byte order */)
+          /* could also check if LG(buf2) == 0xF2030000... no for now */
+          amiga_sfx_offset = zipbeg - 4;
+        else
+          amiga_sfx_offset = 0L;
+      }
+    }
+#endif /* HANDLE_AMIGA_SFX */
+    return ZE_OK;
+} /* end of function scanzipf_reg() */
+#endif /* never */
+
+
+
+
+/* find_next_signature
+ *
+ * Scan the file forward and look for the next PK signature.
+ *
+ * Return 1 if find one and leave file pointer pointing to next char
+ * after signature and set sigbuf to signature.
+ *
+ * Return 0 if not.  Will be at EOF on return unless error.
+ *
+ */
+
+local char sigbuf[4];   /* signature found */
+
+#if 0 /* currently unused */
+/* copy signature */
+char *copy_sig(copyto, copyfrom)
+  char *copyto;
+  char *copyfrom;
+{
+  int i;
+
+  for (i = 0; i < 4; i++) {
+    copyto[i] = copyfrom[i];
+  }
+  return copyto;
+}
+#endif /* currently unused */
+
+
+local int find_next_signature(f)
+  FILE *f;
+{
+  int m;
+  /*
+  zoff_t here;
+  */
+
+  /* look for P K ? ? signature */
+
+  m = getc(f);
+
+  /*
+  here = zftello(f);
+  */
+
+  while (m != EOF)
+  {
+    if (m == 0x50 /*'P' except EBCDIC*/) {
+      /* found a P */
+      sigbuf[0] = (char) m;
+
+      if ((m = getc(f)) == EOF)
+        break;
+      if (m != 0x4b /*'K' except EBCDIC*/) {
+        /* not a signature */
+        ungetc(m, f);
+      } else {
+        /* found P K */
+        sigbuf[1] = (char) m;
+
+        if ((m = getc(f)) == EOF)
+          break;
+        if (m == 0x50 /*'P' except EBCDIC*/) {
+          /* not a signature but maybe start of new one */
+          ungetc(m, f);
+          continue;
+        } else if (m >= 16) {
+          /* last 2 chars expect < 16 for signature */
+          continue;
+        }
+        sigbuf[2] = (char) m;
+
+        if ((m = getc(f)) == EOF)
+          break;
+        if (m == 0x50 /*'P' except EBCDIC*/) {
+          /* not a signature but maybe start of new one */
+          ungetc(m, f);
+          continue;
+        } else if (m >= 16) {
+          /* last 2 chars expect < 16 */
+          continue;
+        }
+        sigbuf[3] = (char) m;
+
+        /* found possible signature */
+        return 1;
+      }
+    }
+    m = getc(f);
+  }
+  if (ferror(f)) {
+    return 0;
+  }
+
+  /* found nothing */
+  return 0;
+}
+
+/* find_signature
+ *
+ * Find signature.
+ *
+ * Return 1 if found and leave file pointing to next character
+ * after signature.  Set sigbuf with signature.
+ *
+ * Return 0 if not found.
+ */
+
+local int find_signature(f, signature)
+  FILE *f;
+  ZCONST char *signature;
+{
+  int i;
+  char sig[4];
+  /*
+  zoff_t here = zftello(f);
+  */
+
+  for (i = 0; i < 4; i++)
+    sig[i] = signature[i];
+
+  /* for EBCDIC */
+  if (sig[0] == 'P')
+    sig[0] = 0x50;
+  if (sig[1] == 'K')
+    sig[1] = 0x4b;
+
+  while (!feof(f)) {
+    if (!find_next_signature(f)) {
+      return 0;
+    } else {
+      for (i = 0; i < 4; i++) {
+        if (sig[i] != sigbuf[i]) {
+          /* not a match */
+          break;
+        }
+      }
+      if (i == 4) {
+        /* found it */
+        return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+
+/* is_signature
+ *
+ * Compare signatures
+ *
+ * Return 1 if the signatures match.
+ */
+
+local int is_signature(sig1, sig2)
+  ZCONST char *sig1;
+  ZCONST char *sig2;
+{
+  int i;
+  char tsig1[4];
+  char tsig2[4];
+
+  for (i = 0; i < 4; i++) {
+    tsig1[i] = sig1[i];
+    tsig2[i] = sig2[i];
+  }
+
+  /* for EBCDIC */
+  if (tsig1[0] == 'P')
+    tsig1[0] = 0x50;
+  if (tsig1[1] == 'K')
+    tsig1[1] = 0x4b;
+
+  if (tsig2[0] == 'P')
+    tsig2[0] = 0x50;
+  if (tsig2[1] == 'K')
+    tsig2[1] = 0x4b;
+
+  for (i = 0; i < 4; i++) {
+    if (tsig1[i] != tsig2[i]) {
+      /* not a match */
+      break;
+    }
+  }
+  if (i == 4) {
+    /* found it */
+    return 1;
+  }
+  return 0;
+}
+
+
+/* at_signature
+ *
+ * Is at signature in file
+ *
+ * Return 1 if at the signature and leave file pointing to next character
+ * after signature.
+ *
+ * Return 0 if not.
+ */
+
+local int at_signature(f, signature)
+  FILE *f;
+  ZCONST char *signature;
+{
+  int i;
+  extent m;
+  char sig[4];
+  char b[4];
+
+  for (i = 0; i < 4; i++)
+    sig[i] = signature[i];
+
+  /* for EBCDIC */
+  if (sig[0] == 'P')
+    sig[0] = 0x50;
+  if (sig[1] == 'K')
+    sig[1] = 0x4b;
+
+  m = fread(b, 1, 4, f);
+  if (m != 4) {
+    return 0;
+  } else {
+    for (i = 0; i < 4; i++) {
+      if (sig[i] != b[i]) {
+        /* not a match */
+        break;
+      }
+    }
+    if (i == 4) {
+      /* found it */
+      return 1;
+    }
+  }
+  return 0;
+}
+
+
+#ifndef UTIL
+
+local int scanzipf_fixnew()
+/*
+   Scan an assumed broke archive from the beginning, salvaging what can.
+
+   Generally scanzipf_regnew() is used for reading archives normally and
+   for fixing archives with a readable central directory using -F.  This
+   scan is used by -FF and is for an archive that is unreadable by
+   scanzipf_regnew().
+
+   Start with the first file of the archive, either .z01 or .zip, and
+   look for local entries.  Read local entries found and create zlist
+   entries for them.  If we find central directory entries, read them
+   and update the zlist created while reading local entries.
+
+   The input path for the .zip file is in in_path.  If this is a multiple disk
+   archive get the paths for splits from in_path as we go.  If a split is not in
+   the same directory as the last split we ask the user where it is and update
+   in_path.
+ */
+/*
+   This is old:
+
+   The name of the zip file is pointed to by the global "zipfile".  The globals
+   zipbeg, cenbeg, zfiles, zcount, zcomlen, zcomment, and zsort are filled in.
+   Return an error code in the ZE_ class.
+*/
+{
+  /* This function only reads the standard End-of-CentralDir record and the
+     standard CentralDir-Entry records directly.  To conserve stack space,
+     only a buffer of minimal size is declared.
+   */
+# if CENHEAD > ENDHEAD
+#   define FIXSCAN_BUFSIZE  CENHEAD
+# else
+#   define FIXSCAN_BUFSIZE  ENDHEAD
+# endif
+
+  char    scbuf[FIXSCAN_BUFSIZE];  /* buffer big enough for headers */
+  char   *split_path;
+  ulg     eocdr_disk;
+  uzoff_t eocdr_offset;
+
+  uzoff_t current_offset = 0; /* offset before */
+  uzoff_t offset = 0;         /* location after return from seek */
+
+  int skip_disk = 0;          /* 1 if user asks to skip current disk */
+  int skipped_disk = 0;       /* 1 if skipped start disk and start offset is useless */
+
+  int r = 0;                  /* zipcopy return */
+  uzoff_t s;                  /* size of data, start of central */
+  struct zlist far * far *x;  /* pointer last entry's link */
+  struct zlist far *z;        /* current zip entry structure */
+  int plen;
+  char *in_path_ext;
+  int in_central_directory = 0; /* found a central directory record */
+  struct zlist far *cz;
+  uzoff_t cd_total_entries = 0; /* number of entries according to EOCDR */
+  ulg     in_cd_start_disk;     /* central directory start disk */
+  uzoff_t in_cd_start_offset;   /* offset of start of cd on cd start disk */
+
+
+  total_disks = 1000000;
+
+  /* open the zipfile */
+  /* This must be .zip file, even if it doesn't exist */
+
+  /* see if zipfile name ends in .zip */
+  plen = strlen(in_path);
+
+#ifdef VMS
+  /* On VMS, adjust plen (and in_path_ext) to avoid the file version. */
+  plen -= strlen(vms_file_version(in_path));
+#endif /* def VMS */
+  in_path_ext = zipfile + plen - 4;
+
+  if (plen >= 4 &&
+      in_path_ext[0] == '.' &&
+      toupper(in_path_ext[1]) == 'Z' &&
+      in_path_ext[2] >= '0' && in_path_ext[2] <= '9' &&
+      in_path_ext[3] >= '0' && in_path_ext[3] <= '9' &&
+      (plen == 4 || (in_path_ext[4] >= '0' && in_path_ext[4] <= '9'))) {
+    /* This may be a split but not the end split */
+    strcpy(errbuf, "if archive to fix is split archive, need to provide\n");
+    strcat(errbuf, "      path of the last split with .zip extension,\n");
+    strcat(errbuf, "      even if it doesn't exist (zip will ask for splits)");
+    zipwarn(errbuf, "");
+    return ZE_FORM;
+  }
+
+  if ((in_file = zfopen(in_path, FOPR)) == NULL) {
+    zipwarn("could not open input archive: ", in_path);
+  }
+  else
+  {
+
+#ifndef ZIP64_SUPPORT
+    /* 2004-12-06 SMS.
+     * Check for too-big file before doing any serious work.
+     */
+    if (ffile_size( in_file) == EOF) {
+      fclose(in_file);
+      in_file = NULL;
+      zipwarn("input file requires Zip64 support: ", in_path);
+      return ZE_ZIP64;
+    }
+#endif /* ndef ZIP64_SUPPORT */
+
+    /* look for End Of Central Directory Record */
+
+    /* back up 64k (the max size of the EOCDR) from end */
+    if (zfseeko(in_file, -0x40000L, SEEK_END) != 0) {
+      /* assume file is less than 64 KB so backup to beginning */
+      if (zfseeko(in_file, 0L, SEEK_SET) != 0) {
+        fclose(in_file);
+        in_file = NULL;
+        zipwarn("unable to seek in input file ", in_path);
+        return ZE_READ;
+      }
+    }
+
+
+    /* find EOCD Record signature */
+    if (!find_signature(in_file, "PK\05\06")) {
+      /* No End Of Central Directory Record */
+      strcpy(errbuf, "Missing end (EOCDR) signature - either this archive\n");
+      strcat(errbuf, "                     is not readable or the end is damaged");
+      zipwarn(errbuf, "");
+    }
+    else
+    {
+      /* at start of data after EOCDR signature */
+      eocdr_offset = (uzoff_t) zftello(in_file);
+
+      /* OK, it is possible this is not the last EOCDR signature (might be
+         EOCDR signature from a stored archive in the last 64 KB) and so not
+         the one we want.
+
+         The below assumes the signature does not appear in the assumed
+         ASCII text .ZIP file comment.  Even if something like UTF-8
+         is stored in the comment, it's unlikely the binary \05 and \06
+         will be in the comment text.
+      */
+      while (find_signature(in_file, "PK\05\06")) {
+        eocdr_offset = (uzoff_t) zftello(in_file);
+      }
+
+      /* found EOCDR */
+      /* format is
+           end of central dir signature     4 bytes  (0x06054b50)
+           number of this disk              2 bytes
+           number of the disk with the
+            start of the central directory  2 bytes
+           total number of entries in the
+            central directory on this disk  2 bytes
+           total number of entries in
+            the central directory           2 bytes
+           size of the central directory    4 bytes
+           offset of start of central
+            directory with respect to
+            the starting disk number        4 bytes
+           .ZIP file comment length         2 bytes
+           .ZIP file comment        (variable size)
+       */
+
+      if (zfseeko(in_file, eocdr_offset, SEEK_SET) != 0) {
+        fclose(in_file);
+        in_file = NULL;
+        zipwarn("unable to seek in input file ", in_path);
+        return ZE_READ;
+      }
+
+      /* read the EOCDR */
+      s = fread(scbuf, 1, ENDHEAD, in_file);
+
+      /* make sure we read enough bytes */
+      if (s < ENDHEAD) {
+        sprintf(errbuf, "End record (EOCDR) only %s bytes - assume truncated",
+                  zip_fzofft(s, NULL, "u"));
+        zipwarn(errbuf, "");
+      }
+      else
+      {
+        /* the first field should be number of this (the last) disk */
+        eocdr_disk = (ulg)SH(scbuf);
+        total_disks = eocdr_disk + 1;
+
+        /* assume this is this disk - if Zip64 it may not be as the
+           disk number may be bigger than this field can hold
+        */
+        current_in_disk = total_disks - 1;
+
+        /* Central Directory disk, offset, and total entries */
+        in_cd_start_disk = (ulg)SH(scbuf + 2);
+        in_cd_start_offset = (uzoff_t)LG(scbuf + 12);
+        cd_total_entries = (uzoff_t)SH(scbuf + 6);
+
+        /* the in_cd_start_disk should always be less than the total_disks,
+           unless the -1 flags are being used */
+        if (total_disks < 0x10000 && in_cd_start_disk > total_disks) {
+          zipwarn("End record (EOCDR) has bad disk numbers - ignoring EOCDR", "");
+          total_disks = 0;
+        }
+        else
+        {
+          /* length of zipfile comment */
+          zcomlen = SH(scbuf + ENDCOM);
+          if (zcomlen)
+          {
+            if ((zcomment = malloc(zcomlen + 1)) == NULL)
+              return ZE_MEM;
+            if (fread(zcomment, zcomlen, 1, in_file) != 1)
+            {
+              free((zvoid *)zcomment);
+              zcomment = NULL;
+              zipwarn("zipfile comment truncated - ignoring", "");
+            } else {
+              zcomment[zcomlen] = '\0';
+            }
+#ifdef EBCDIC
+            if (zcomment)
+               memtoebc(zcomment, zcomment, zcomlen);
+#endif /* EBCDIC */
+          }
+        }
+        if (total_disks != 1)
+          sprintf(errbuf, " Found end record (EOCDR) - says expect %lu splits", total_disks);
+        else
+          sprintf(errbuf, " Found end record (EOCDR) - says expect single disk archive");
+        zipmessage(errbuf, "");
+        if (zcomment)
+          zipmessage("  Found archive comment", "");
+      } /* good EOCDR */
+
+    } /* found EOCDR */
+
+    /* if total disks is other than 1 then this is not start disk */
+    /* if the EOCDR is bad, total_disks is 0 */
+
+    /* if total_disks = 0, then guess if this is a single-disk archive
+       by seeing if starts with local header */
+
+    if (total_disks == 0) {
+      int issig;
+      /* seek to top */
+      if (zfseeko(in_file, 0, SEEK_SET) != 0) {
+        fclose(in_file);
+        in_file = NULL;
+        zipwarn("unable to seek in input file ", in_path);
+        return ZE_READ;
+      }
+      /* get next signature */
+      issig = find_next_signature(in_file);
+      if (issig) {
+        current_in_offset = zftello(in_file);
+        if (current_in_offset == 4 && is_signature(sigbuf, "PK\03\03")) {
+          /* could be multi-disk aborted signature at top */
+          /* skip */
+          issig = find_next_signature(in_file);
+        } else if (current_in_offset <= 4 && is_signature(sigbuf, "PK\03\03")) {
+          /* multi-disk spanning signature */
+          total_disks = 99999;
+        }
+      }
+      if (issig && total_disks == 0) {
+        current_in_offset = zftello(in_file);
+
+        if (current_in_offset == 8 && is_signature(sigbuf, "PK\03\04")) {
+
+          /* Local Header Record at top */
+
+          printf("Is this a single-disk archive?  (y/n): ");
+          fflush(stdout);
+
+          if (fgets(errbuf, 100, stdin) != NULL) {
+            if (errbuf[0] == 'y' || errbuf[0] == 'Y') {
+              total_disks = 1;
+              zipmessage("  Assuming single-disk archive", "");
+            }
+          }
+        }
+      }
+    }
+    if (!noisy)
+      /* if quiet assume single-disk archive */
+      total_disks = 1;
+
+    if (total_disks == 1000000) {
+      /* still don't know, so ask */
+      printf("Is this a single-disk archive?  (y/n): ");
+      fflush(stdout);
+
+      if (fgets(errbuf, 100, stdin) != NULL) {
+        if (errbuf[0] == 'y' || errbuf[0] == 'Y') {
+          total_disks = 1;
+          zipmessage("  Assuming single-disk archive", "");
+        }
+      }
+    }
+    if (total_disks == 1000000) {
+      /* assume max */
+      total_disks = 100000;
+    }
+
+  } /* .zip file exists */
+
+  /* Skip reading the Zip64 EOCDL, Zip64 EOCDR, or central directory */
+
+  /* Now read the archive starting with first disk.  Find local headers,
+     create entry in zlist, then copy entry to new archive */
+
+  /* Multi-volume file names end in .z01, .z02, ..., .z10, .zip for 11 disk archive */
+
+  /* Unless quiet, always close the in_path disk and ask user for first disk,
+     unless there is an End Of Central Directory record and that says there is
+     only one disk.
+     If quiet, assume the file pointed to is a single file archive to fix. */
+  if (noisy && in_file) {
+    fclose(in_file);
+    in_file = NULL;
+  }
+
+  /* Read the archive disks - no idea how many disks there are
+     since we can't trust the EOCDR and other end records
+   */
+  zipmessage("Scanning for entries...", "");
+
+  for (current_in_disk = 0; current_in_disk < total_disks; current_in_disk++) {
+    /* get the path for this disk */
+    split_path = get_in_split_path(in_path, current_in_disk);
+
+    /* if in_file is not NULL then in_file is already open */
+    if (in_file == NULL) {
+      /* open the split */
+      while ((in_file = zfopen(split_path, FOPR)) == NULL) {
+        int result;
+        /* could not open split */
+
+        /* Ask for directory with split.  Updates global variable in_path */
+        result = ask_for_split_read_path(current_in_disk);
+        if (result == ZE_ABORT) {
+          zipwarn("could not find split: ", split_path);
+          return ZE_ABORT;
+        } else if (result == ZE_EOF) {
+          zipmessage_nl("", 1);
+          zipwarn("user ended reading - closing archive", "");
+          return ZE_EOF;
+        } else if (result == ZE_FORM) {
+          /* user asked to skip this disk */
+          zipmessage_nl("", 1);
+          sprintf(errbuf, "skipping disk %lu ...\n", current_in_disk);
+          zipwarn(errbuf, "");
+          skip_disk = 1;
+          break;
+        }
+
+        split_path = get_in_split_path(in_path, current_in_disk);
+      }
+      if (skip_disk) {
+        /* skip this current disk - this works because central directory entries
+           can't be split across splits */
+        skip_disk = 0;
+        skipped_disk = 1;
+        continue;
+      }
+    }
+
+    if (skipped_disk) {
+      /* Not much to do here as between entries.  Entries are copied
+         in zipcopy() and that has to handle missing disks while
+         reading data for an entry.
+       */
+    }
+
+    /* Main loop */
+    /* Look for next signature and process it */
+    while (find_next_signature(in_file)) {
+      current_in_offset = zftello(in_file);
+
+      if (is_signature(sigbuf, "PK\05\06")) {
+
+        /* End Of Central Directory Record */
+
+        sprintf(errbuf, "EOCDR found (%2lu %6s)...",
+                current_in_disk + 1, zip_fzofft(current_in_offset - 4, NULL, "u"));
+        zipmessage_nl(errbuf, 1);
+
+
+      } else if (is_signature(sigbuf, "PK\06\06")) {
+
+        /* Zip64 End Of Central Directory Record */
+
+        sprintf(errbuf, "Zip64 EOCDR found (%2lu %6s)...",
+                current_in_disk + 1, zip_fzofft(current_in_offset - 4, NULL, "u"));
+        zipmessage_nl(errbuf, 1);
+
+
+      } else if (is_signature(sigbuf, "PK\06\07")) {
+
+        /* Zip64 End Of Central Directory Locator */
+
+        sprintf(errbuf, "Zip64 EOCDL found (%2lu %6s)...",
+                current_in_disk + 1, zip_fzofft(current_in_offset - 4, NULL, "u"));
+        zipmessage_nl(errbuf, 1);
+
+
+      } else if (is_signature(sigbuf, "PK\03\04")) {
+
+        /* Local Header Record */
+
+
+        if (verbose) {
+          sprintf(errbuf, " Local (%2lu %6s):",
+                  current_in_disk + 1, zip_fzofft(current_in_offset - 4, NULL, "u"));
+          zipmessage_nl(errbuf, 0);
+        }
+
+        /* Create zlist entry.  Most will be filled in by zipcopy(). */
+
+        if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) {
+          zipwarn("reading central directory", "");
+          return ZE_MEM;
+        }
+
+        z->vem = 0;
+        z->ver = 0;
+        z->flg = 0;
+        z->how = 0;
+        z->tim = 0;          /* time and date into one long */
+        z->crc = 0;
+        z->siz = 0;
+        z->len = 0;
+        z->nam = 0;          /* used before comparing cen vs. loc */
+        z->cext = 0;         /* may be different from z->ext */
+        z->com = 0;
+        z->dsk = 0;
+        z->att = 0;
+        z->atx = 0;
+        z->off = 0;
+        z->dosflag = 0;
+
+        /* Initialize all fields pointing to malloced data to NULL */
+        z->zname = z->name = z->iname = z->extra = z->cextra = z->comment = NULL;
+        z->oname = NULL;
+#ifdef UNICODE_SUPPORT
+        z->uname = z->zuname = z->ouname = NULL;
+#endif
+
+        /* Attempt to copy entry */
+
+        r = zipcopy(z);
+
+        if (in_central_directory) {
+          sprintf(errbuf, "Entry after central directory found (%2lu %6s)...",
+                  current_in_disk + 1, zip_fzofft(current_in_offset - 4, NULL, "u"));
+          zipmessage_nl(errbuf, 1);
+          in_central_directory = 0;
+        }
+
+        if (r == ZE_EOF)
+          /* user said no more splits */
+          break;
+        else if (r == ZE_OK) {
+          zcount++;
+          files_total++;
+          bytes_total += z->siz;
+
+          /* Link into list */
+          if (zfiles == NULL)
+            /* first link */
+            x = &zfiles;
+          /* Link into list */
+          *x = z;
+          z->nxt = NULL;
+          x = &z->nxt;
+        }
+
+      } else if (is_signature(sigbuf, "PK\01\02")) {
+
+        /* Central directory header */
+
+
+        /* sort the zlist */
+        if (in_central_directory == 0) {
+          zipmessage("Central Directory found...", "");
+          /* If one or more files, sort by name */
+          if (zcount)
+          {
+            struct zlist far * far *x;    /* pointer into zsort array */
+            struct zlist far *z;          /* pointer into zfiles linked list */
+            int i = 0;
+            extent zl_size = zcount * sizeof(struct zlist far *);
+
+            if (zl_size / sizeof(struct zlist far *) != zcount ||
+                (x = zsort = (struct zlist far **)malloc(zl_size)) == NULL)
+              return ZE_MEM;
+            for (z = zfiles; z != NULL; z = z->nxt)
+              x[i++] = z;
+            qsort((char *)zsort, zcount, sizeof(struct zlist far *), zqcmp);
+
+            /* Skip Unicode searching */
+          }
+        }
+
+        if (verbose) {
+          sprintf(errbuf, " Cen   (%2lu %6s): ",
+                  current_in_disk + 1, zip_fzofft(current_in_offset - 4, NULL, "u"));
+          zipmessage_nl(errbuf, 0);
+        }
+
+        in_central_directory = 1;
+
+        /* Read central directory entry */
+
+        /* central directory signature */
+
+        /* The format of a central directory record
+          central file header signature   4 bytes  (0x02014b50)
+          version made by                 2 bytes
+          version needed to extract       2 bytes
+          general purpose bit flag        2 bytes
+          compression method              2 bytes
+          last mod file time              2 bytes
+          last mod file date              2 bytes
+          crc-32                          4 bytes
+          compressed size                 4 bytes
+          uncompressed size               4 bytes
+          file name length                2 bytes
+          extra field length              2 bytes
+          file comment length             2 bytes
+          disk number start               2 bytes
+          internal file attributes        2 bytes
+          external file attributes        4 bytes
+          relative offset of local header 4 bytes
+
+          file name (variable size)
+          extra field (variable size)
+          file comment (variable size)
+         */
+
+        if (fread(scbuf, CENHEAD, 1, in_file) != 1) {
+          zipwarn("reading central directory: ", strerror(errno));
+          zipwarn("bad archive - error reading central directory", "");
+          zipwarn("skipping this entry...", "");
+          continue;
+        }
+
+        if ((cz = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) {
+          zipwarn("reading central directory", "");
+          return ZE_MEM;
+        }
+
+        cz->vem = SH(CENVEM + scbuf);
+        cz->ver = SH(CENVER + scbuf);
+        cz->flg = SH(CENFLG + scbuf);
+        cz->how = SH(CENHOW + scbuf);
+        cz->tim = LG(CENTIM + scbuf);   /* time and date into one long */
+        cz->crc = LG(CENCRC + scbuf);
+        cz->siz = LG(CENSIZ + scbuf);
+        cz->len = LG(CENLEN + scbuf);
+        cz->nam = SH(CENNAM + scbuf);   /* used before comparing cen vs. loc */
+        cz->cext = SH(CENEXT + scbuf);  /* may be different from z->ext */
+        cz->com = SH(CENCOM + scbuf);
+        cz->dsk = SH(CENDSK + scbuf);
+        cz->att = SH(CENATT + scbuf);
+        cz->atx = LG(CENATX + scbuf);
+        cz->off = LG(CENOFF + scbuf);
+        cz->dosflag = (cz->vem & 0xff00) == 0;
+
+        /* Initialize all fields pointing to malloced data to NULL */
+        cz->zname = cz->name = cz->iname = cz->extra = cz->cextra = NULL;
+        cz->comment = cz->oname = NULL;
+#ifdef UNICODE_SUPPORT
+        cz->uname = cz->zuname = cz->ouname = NULL;
+#endif
+
+        /* Read file name, extra field and comment field */
+        if (cz->nam == 0)
+        {
+          sprintf(errbuf, "%lu", (ulg)zcount + 1);
+          zipwarn("zero-length name for entry #", errbuf);
+          zipwarn("skipping this entry...", "");
+          continue;
+        }
+        if ((cz->iname = malloc(cz->nam+1)) ==  NULL ||
+            (cz->cext && (cz->cextra = malloc(cz->cext + 1)) == NULL) ||
+            (cz->com && (cz->comment = malloc(cz->com + 1)) == NULL))
+          return ZE_MEM;
+        if (fread(cz->iname, cz->nam, 1, in_file) != 1 ||
+            (cz->cext && fread(cz->cextra, cz->cext, 1, in_file) != 1) ||
+            (cz->com && fread(cz->comment, cz->com, 1, in_file) != 1)) {
+          zipwarn("error reading entry:  ", strerror(errno));
+          zipwarn("skipping this entry...", "");
+          continue;
+        }
+        cz->iname[cz->nam] = '\0';                  /* terminate name */
+
+        /* Look up this name in zlist from local entries */
+        z = zsearch(cz->iname);
+
+
+        if (z && z->tim == cz->tim) {
+
+          /* Apparently as iname and date and time match this central
+             directory entry goes with this zlist entry */
+
+          if (verbose) {
+            /* cen dir name matches a local name */
+            sprintf(errbuf, "updating: %s", cz->iname);
+            zipmessage_nl(errbuf, 0);
+          }
+
+          if (z->crc != cz->crc) {
+            sprintf(errbuf, "local (%lu) and cen (%lu) crc mismatch", z->crc, cz->crc);
+            zipwarn(errbuf, "");
+          }
+
+          z->vem = cz->vem;
+         /* z->ver = cz->ver; */
+         /* z->flg = cz->flg; */
+         /* z->how = cz->how; */
+         /* z->tim = cz->tim; */          /* time and date into one long */
+         /* z->crc = cz->crc; */
+         /* z->siz = cz->siz; */
+         /* z->len = cz->len; */
+         /* z->nam = cz->nam; */          /* used before comparing cen vs. loc */
+          z->cext = cz->cext;             /* may be different from z->ext */
+          z->com = cz->com;
+          z->cextra = cz->cextra;
+          z->comment = cz->comment;
+         /* z->dsk = cz->dsk; */
+          z->att = cz->att;
+          z->atx = cz->atx;
+         /* z->off = cz->off; */
+          z->dosflag = cz->dosflag;
+
+#ifdef UNICODE_SUPPORT
+          if (unicode_mismatch != 3 && z->uname == NULL) {
+            if (z->flg & UTF8_BIT) {
+              /* path is UTF-8 */
+              if ((z->uname = malloc(strlen(z->iname) + 1)) == NULL) {
+                ZIPERR(ZE_MEM, "reading archive");
+              }
+              strcpy(z->uname, z->iname);
+            } else {
+              /* check for UTF-8 path extra field */
+              read_Unicode_Path_entry(z);
+            }
+          }
+#endif
+
+#ifdef WIN32
+          /* Input path may be OEM */
+          {
+            unsigned hostver = (z->vem & 0xff);
+            Ext_ASCII_TO_Native(z->iname, (z->vem >> 8), hostver,
+                                ((z->atx & 0xffff0000L) != 0), FALSE);
+          }
+#endif
+
+#ifdef EBCDIC
+          if (z->com)
+             memtoebc(z->comment, z->comment, z->com);
+#endif /* EBCDIC */
+#ifdef WIN32
+          /* Comment may be OEM */
+          {
+            unsigned hostver = (z->vem & 0xff);
+            Ext_ASCII_TO_Native(z->comment, (z->vem >> 8), hostver,
+                                ((z->atx & 0xffff0000L) != 0), FALSE);
+          }
+#endif
+
+#ifdef ZIP64_SUPPORT
+          /* zip64 support 08/31/2003 R.Nausedat                          */
+          /* here, we have to read the len, siz etc values from the CD    */
+          /* entry as we might have to adjust them regarding their        */
+          /* correspronding zip64 extra fields.                           */
+          /* also, we cannot compare the values from the CD entries with  */
+          /* the values from the LH as they might be different.           */
+
+          /* adjust/update siz,len and off (to come: dsk) entries */
+          /* PKZIP does not care of the version set in a CDH: if  */
+          /* there is a zip64 extra field assigned to a CDH PKZIP */
+          /* uses it, we should do so, too.                       */
+  /*
+          adjust_zip_central_entry(z);
+   */
+#endif
+
+        /* Update zipbeg beginning of archive offset, prepare for next header */
+/*
+          if (z->dsk == 0 && (!zipbegset || z->off < zipbeg)) {
+            zipbeg = z->off;
+            zipbegset = 1;
+          }
+          zcount++;
+ */
+
+#ifndef UTIL
+          if (verbose)
+            zipoddities(z);
+#endif
+
+          current_offset = zftello(y);
+
+          if (zfseeko(y, z->off, SEEK_SET) != 0) {
+            fclose(in_file);
+            in_file = NULL;
+            zipwarn("writing archive seek: ", strerror(errno));
+            return ZE_WRITE;
+          }
+
+          if (putlocal(z, PUTLOCAL_REWRITE) != ZE_OK)
+            zipwarn("Error rewriting local header", "");
+
+          if (zfseeko(y, current_offset, SEEK_SET) != 0) {
+            fclose(in_file);
+            in_file = NULL;
+            zipwarn("write archive seek: ", strerror(errno));
+            return ZE_WRITE;
+          }
+          offset = zftello(y);
+          if (current_offset != offset) {
+            fclose(in_file);
+            in_file = NULL;
+            zipwarn("seek after local: ", strerror(errno));
+            return ZE_WRITE;
+          }
+
+          if (verbose)
+            zipmessage_nl("", 1);
+
+        } else {
+          /* cen dir name does not match local name */
+          sprintf(errbuf, "no local entry: %s", cz->iname);
+          zipmessage_nl(errbuf, 1);
+        }
+
+      } else if (zfiles == NULL && is_signature(sigbuf, "PK\07\010")) {
+
+        /* assume spanning signature at top of archive */
+        if (total_disks == 1) {
+          zipmessage("  Found spanning marker, but did not expect split (multi-disk) archive...", "");
+
+        } else if (total_disks > 1) {
+          zipmessage("  Found spanning marker - expected as this is split (multi-disk) archive...", "");
+
+        } else {
+          zipmessage("  Found spanning marker - could be split archive...", "");
+
+        }
+
+      } else {
+
+        /* this signature shouldn't be here */
+        int c;
+        char errbuftemp[40];
+
+        strcpy(errbuf, "unexpected signature ");
+        for (c = 0; c < 4; c++) {
+          sprintf(errbuftemp, "%02x ", sigbuf[c]);
+          strcat(errbuf, errbuftemp);
+        }
+        sprintf(errbuftemp, "on disk %lu at %s\n", current_in_disk,
+                                 zip_fzofft(current_in_offset - 4, NULL, "u"));
+        strcat(errbuf, errbuftemp);
+        zipwarn(errbuf, "");
+        zipwarn("skipping this signature...", "");
+      }
+
+
+    } /* while reading file */
+
+    /* close disk and do next disk */
+    if (in_file)
+      fclose(in_file);
+    in_file = NULL;
+    free(split_path);
+
+    if (r == ZE_EOF)
+      /* user says no more splits */
+      break;
+
+  } /* for each disk */
+
+  return ZE_OK;
+
+} /* end of function scanzipf_fixnew() */
+
+#endif /* !UTIL */
+
+
+
+
+
+
+/* ---------------------- */
+/* New regular scan       */
+
+/*
+ * scanzipf_regnew is similar to the orignal scanzipf_reg in that it
+ * reads the end of the archive and goes from there.  Unlike that
+ * scan this one stops after reading the central directory and does
+ * not read the local headers.  After the directory scan for new
+ * files is done in zip.c the zlist created here is used to read
+ * the old archive entries there.  The local headers are read using
+ * readlocal() in zipcopy().
+ *
+ * This scan assumes the zip file is well structured.  If not it may
+ * fail and the new scanzipf_fixnew should be used.
+ *
+ * 2006-2-4, 2007-12-10 EG
+ */
+
+local int scanzipf_regnew()
+/*
+   The input path for the .zip file is in in_path.  If a split archive,
+   the path for each split is created from the current disk number
+   and in_path.  If a split is not in the same directory as the last
+   split we ask the user where it is and update in_path.
+ */
+/*
+   This is old but more or less still applies:
+
+   The name of the zip file is pointed to by the global "zipfile".  The globals
+   zipbeg, cenbeg, zfiles, zcount, zcomlen, zcomment, and zsort are filled in.
+   Return an error code in the ZE_ class.
+*/
+{
+  /* In this function, a local buffer is used to read in the following Zip
+     structures:
+      End-of-CentralDir record (EOCDR) (ENDHEAD)
+      Zip64-End-of-CentralDir-Record locator (Zip64 EOCDL) (EC64LOC)
+      Zip64-End-of-CentralDir record (Zip64 EOCDR) (EC64REC)
+      CentralDir-Entry record (CENHEAD)
+     To conserve valuable stack space, this buffer is sized to the largest
+     of these structures.
+   */
+# if CENHEAD > ENDHEAD
+#   define SCAN_BUFSIZE CENHEAD   /* CENHEAD should be the larger struct */
+# else
+#   define SCAN_BUFSIZE ENDHEAD
+# endif
+
+#ifdef ZIP64_SUPPORT
+# if EC64REC > SCAN_BUFSIZE
+#   undef SCAN_BUFSIZE
+#   define SCAN_BUFSIZE EC64REC   /* EC64 record should be largest struct */
+# endif
+# if EC64LOC > SCAN_BUFSIZE
+#   undef SCAN_BUFSIZE
+#   define SCAN_BUFSIZE EC64LOC
+# endif
+#endif
+
+  char    scbuf[SCAN_BUFSIZE];  /* buffer just enough for all header types */
+  char   *split_path;
+  ulg     eocdr_disk;
+  uzoff_t eocdr_offset;
+# ifdef ZIP64_SUPPORT
+  ulg     z64eocdr_disk;
+  uzoff_t z64eocdr_offset;
+  uzoff_t z64eocdr_size;
+  ush     version_made;
+  ush     version_needed = 0;
+  zoff_t zip64_eocdr_start;
+  zoff_t z64eocdl_offset;
+# endif /* def ZIP64_SUPPORT */
+  uzoff_t cd_total_entries;        /* num of entries as read from (Zip64) EOCDR */
+  ulg     in_cd_start_disk;        /* central directory start disk */
+  uzoff_t in_cd_start_offset;      /* offset of start of cd on cd start disk */
+  uzoff_t adjust_offset = 0;       /* bytes before first entry (size of sfx prefix) */
+  uzoff_t cd_total_size = 0;       /* total size of cd */
+
+
+  int first_CD = 1;           /* looking for first CD entry */
+  int zipbegset = 0;
+
+  int skip_disk = 0;          /* 1 if user asks to skip current disk */
+  int skipped_disk = 0;       /* 1 if skipped start disk and start offset is useless */
+
+  uzoff_t s;                  /* size of data, start of central */
+  struct zlist far * far *x;  /* pointer last entry's link */
+  struct zlist far *z;        /* current zip entry structure */
+
+
+  /* open the zipfile */
+  if ((in_file = zfopen(in_path, FOPR)) == NULL) {
+    zipwarn("could not open input archive", in_path);
+    return ZE_OPEN;
+  }
+
+#ifndef ZIP64_SUPPORT
+  /* 2004-12-06 SMS.
+   * Check for too-big file before doing any serious work.
+   */
+  if (ffile_size( in_file) == EOF) {
+    fclose(in_file);
+    in_file = NULL;
+    zipwarn("input file requires Zip64 support: ", in_path);
+    return ZE_ZIP64;
+  }
+#endif /* ndef ZIP64_SUPPORT */
+
+  /* look for End Of Central Directory Record */
+
+  /* In a valid Zip archive, the EOCDR can be at most (64k-1 + ENDHEAD + 4)
+     bytes (=65557 bytes) from the end of the file.
+     We back up 128k, to allow some junk being appended to a Zip file.
+   */
+  if ((zfseeko(in_file, -0x20000L, SEEK_END) != 0) ||
+      /* Some fseek() implementations (e.g. MSC 8.0 16-bit) fail to signal
+         an error when seeking before the beginning of the file.
+         As work-around, we check the position returned by zftello()
+         for the error value -1.
+       */
+      (zftello(in_file) == (zoff_t)-1L)) {
+    /* file is less than 128 KB so back up to beginning */
+    if (zfseeko(in_file, 0L, SEEK_SET) != 0) {
+      fclose(in_file);
+      in_file = NULL;
+      zipwarn("unable to seek in input file ", in_path);
+      return ZE_READ;
+    }
+  }
+
+  /* find EOCD Record signature */
+  if (!find_signature(in_file, "PK\05\06")) {
+    /* No End Of Central Directory Record */
+    fclose(in_file);
+    in_file = NULL;
+    if (fix == 1) {
+      zipwarn("bad archive - missing end signature", "");
+      zipwarn("(If downloaded, was binary mode used?  If not, the", "");
+      zipwarn(" archive may be scrambled and not recoverable)", "");
+      zipwarn("Can't use -F to fix (try -FF)", "");
+    } else{
+      zipwarn("missing end signature--probably not a zip file (did you", "");
+      zipwarn("remember to use binary mode when you transferred it?)", "");
+      zipwarn("(if you are trying to read a damaged archive try -F)", "");
+    }
+    return ZE_FORM;
+  }
+
+  /* at start of data after EOCDR signature */
+  eocdr_offset = (uzoff_t) zftello(in_file);
+
+  /* OK, it is possible this is not the last EOCDR signature (might be
+     EOCDR signature from a stored archive in the last 128 KB) and so not
+     the one we want.
+
+     The below assumes the signature does not appear in the assumed ASCII text
+     .ZIP file comment.
+  */
+  while (find_signature(in_file, "PK\05\06")) {
+    /* previous one was not the one */
+    eocdr_offset = (uzoff_t) zftello(in_file);
+  }
+
+  /* found EOCDR */
+  /* format is
+       end of central dir signature     4 bytes  (0x06054b50)
+       number of this disk              2 bytes
+       number of the disk with the
+        start of the central directory  2 bytes
+       total number of entries in the
+        central directory on this disk  2 bytes
+       total number of entries in
+        the central directory           2 bytes
+       size of the central directory    4 bytes
+       offset of start of central
+        directory with respect to
+        the starting disk number        4 bytes
+       .ZIP file comment length         2 bytes
+       .ZIP file comment        (variable size)
+   */
+
+  if (zfseeko(in_file, eocdr_offset, SEEK_SET) != 0) {
+    fclose(in_file);
+    in_file = NULL;
+    zipwarn("unable to seek in input file ", in_path);
+    return ZE_READ;
+  }
+
+  /* read the EOCDR */
+  s = fread(scbuf, 1, ENDHEAD, in_file);
+
+  /* the first field should be number of this (the last) disk */
+  eocdr_disk = (ulg)SH(scbuf);
+  total_disks = eocdr_disk + 1;
+
+  /* Assume EOCDR disk is this disk.  If a lot of disks, the Zip64 field
+     may be needed and this EOCDR field could be set to the Zip64 flag
+     value as the disk number may be bigger than this field can hold.
+  */
+  current_in_disk = total_disks - 1;
+
+  /* Central Directory disk, offset, and total entries */
+  in_cd_start_disk = (ulg)SH(scbuf + ENDBEG);
+  in_cd_start_offset = (uzoff_t)LG(scbuf + ENDOFF);
+  cd_total_entries = (uzoff_t)SH(scbuf + ENDTOT);
+  cd_total_size = (uzoff_t)LG(scbuf + ENDSIZ);
+
+  /* length of zipfile comment */
+  zcomlen = SH(scbuf + ENDCOM);
+  if (zcomlen)
+  {
+    if ((zcomment = malloc(zcomlen + 1)) == NULL)
+      return ZE_MEM;
+    if (fread(zcomment, zcomlen, 1, in_file) != 1)
+    {
+      free((zvoid *)zcomment);
+      zcomment = NULL;
+      return ferror(in_file) ? ZE_READ : ZE_EOF;
+    }
+    zcomment[zcomlen] = '\0';
+#ifdef EBCDIC
+    if (zcomment)
+       memtoebc(zcomment, zcomment, zcomlen);
+#endif /* EBCDIC */
+  }
+
+  if (cd_total_entries == 0) {
+    /* empty archive */
+
+    fclose(in_file);
+    in_file = NULL;
+    return ZE_OK;
+  }
+
+  /* if total disks is other than 1 then multi-disk archive */
+  if (total_disks != 1) {
+    /* zipfile name must end in .zip for split archives */
+    int plen = strlen(in_path);
+    char *in_path_ext;
+
+    if (adjust) {
+      zipwarn("Adjusting split archives not yet supported", "");
+      return ZE_FORM;
+    }
+
+#ifdef VMS
+    /* On VMS, adjust plen (and in_path_ext) to avoid the file version. */
+    plen -= strlen(vms_file_version(in_path));
+#endif /* def VMS */
+    in_path_ext = zipfile + plen - 4;
+
+    if (plen < 4 ||
+        in_path_ext[0] != '.' ||
+        toupper(in_path_ext[1]) != 'Z' ||
+        toupper(in_path_ext[2]) != 'I' ||
+        toupper(in_path_ext[3]) != 'P') {
+      zipwarn("archive name must end in .zip for splits", "");
+      fclose(in_file);
+      in_file = NULL;
+      return ZE_PARMS;
+    }
+  }
+
+  /* if input or output are split archives, must be different archives */
+  if ((total_disks != 1 || split_method) && !show_files &&
+      strcmp(in_path, out_path) == 0) {
+    fclose(in_file);
+    in_file = NULL;
+    zipwarn("cannot update a split archive (use --out option)", "");
+    return ZE_PARMS;
+  }
+
+  /* if fixing archive, input and output must be different archives */
+  if (fix == 1 && strcmp(in_path, out_path) == 0) {
+    fclose(in_file);
+    in_file = NULL;
+    zipwarn("must use --out when fixing an archive", "");
+    return ZE_PARMS;
+  }
+
+
+  /* Get sfx offset if adjusting. Above we made sure not split archive. */
+  /* Also check for an offset if fix and single disk archive. */
+  if ((fix == 1 && total_disks == 1) || adjust) {
+    zoff_t cd_start;
+# ifdef ZIP64_SUPPORT
+    zoff_t zip64_eocdr_start;
+# endif
+
+    /* First attempt.  If the CD start offset and size are valid in the EOCDR
+       (meaning they are not the Zip64 flag values that say the actual values
+       are in the Zip64 EOCDR), we can use them to get the offset */
+    if (in_cd_start_offset != 0xFFFFFFFF && cd_total_size != 0xFFFFFFFF) {
+      /* Search for start of central directory */
+      /* There still might be a Zip64 EOCDR.  This assumes if there is
+         a Zip64 EOCDR, it's version 1 and 52 bytes */
+      cd_start = eocdr_offset - cd_total_size - 24 - 56;
+      if (zfseeko(in_file, cd_start, SEEK_SET) != 0) {
+        fclose(in_file);
+        in_file = NULL;
+        if (fix == 1) {
+          zipwarn("could not seek back to start of central directory: ", strerror(errno));
+          zipwarn("(try -FF)", "");
+        } else {
+          zipwarn("reading archive fseek: ", strerror(errno));
+        }
+        return ZE_FORM;
+      }
+      if (find_signature(in_file, "PK\01\02")) {
+        /* Should now be after first central directory header signature in archive */
+        adjust_offset = zftello(in_file) - 4 - in_cd_start_offset;
+      } else {
+        zipwarn("central dir not where expected - could not adjust offsets", "");
+        zipwarn("(try -FF)", "");
+        return ZE_FORM;
+      }
+    } else {
+
+      /* Second attempt.  We need the Zip64 EOCDL to get the offset */
+
+      /*
+       * Check for a Zip64 EOCD Locator signature
+       */
+
+      /* Format of Z64EOCD Locator is
+           zip64 end of central dir locator
+            signature                       4 bytes  (0x07064b50)
+           number of the disk with the
+            start of the zip64 end of
+            central directory               4 bytes
+           relative offset of the zip64
+            end of central directory record 8 bytes
+           total number of disks            4 bytes
+       */
+
+      /* back up 20 bytes from EOCDR to Z64 EOCDL */
+      if (zfseeko(in_file, eocdr_offset - 24, SEEK_SET) != 0) {
+        fclose(in_file);
+        in_file = NULL;
+        if (fix == 1) {
+          zipwarn("could not seek back to Zip64 EOCDL: ", strerror(errno));
+          zipwarn("(try -FF)", "");
+        } else {
+          zipwarn("reading archive fseek: ", strerror(errno));
+        }
+        return ZE_FORM;
+      }
+      if (at_signature(in_file, "PK\06\07"))
+#ifndef ZIP64_SUPPORT
+      {
+        fclose(in_file);
+        in_file = NULL;
+        zipwarn("found Zip64 signature - this may be a Zip64 archive", "");
+        zipwarn("Need PKZIP 4.5 or later compatible zip", "");
+        zipwarn("Set ZIP64_SUPPORT in Zip 3", "");
+        return ZE_ZIP64;
+      }
+#else /* ZIP64_SUPPORT */
+      {
+        z64eocdl_offset = zftello(in_file) - 4;
+
+        /* read Z64 EOCDL */
+        if (fread(scbuf, EC64LOC, 1, in_file) != 1) {
+          fclose(in_file);
+          in_file = NULL;
+          zipwarn("reading archive: ", strerror(errno));
+          return ZE_READ;
+        }
+        /* now should be back at the EOCD signature */
+        if (!at_signature(in_file, "PK\05\06")) {
+          fclose(in_file);
+          in_file = NULL;
+          zipwarn("unable to read EOCD after seek: ", in_path);
+          return ZE_READ;
+        }
+
+        /* read disk and offset to Zip64 EOCDR and total disks */
+        z64eocdr_disk = LG(scbuf);
+        z64eocdr_offset = LLG(scbuf + 4);
+        total_disks = LG(scbuf + 12);
+
+        /* For now no split archives */
+        if (total_disks != 1) {
+          zipwarn("Adjusting split archives not supported:  ", in_path);
+          zipwarn("(try -FF)", "");
+          return ZE_FORM;
+        }
+
+        /* go to the Zip64 EOCDR */
+        if (zfseeko(in_file, z64eocdr_offset, SEEK_SET) != 0) {
+          fclose(in_file);
+          in_file = NULL;
+          zipwarn("reading archive fseek: ", strerror(errno));
+          return ZE_FORM;
+        }
+        /* Should be at Zip64 EOCDR signature */
+        if (at_signature(in_file, "PK\06\06")) {
+          /* apparently no offset */
+
+        } else {
+          /* Wasn't there, so calculate based on Zip64 EOCDL offset */
+
+          zip64_eocdr_start = z64eocdl_offset - 24 - 56;
+          if (zfseeko(in_file, zip64_eocdr_start, SEEK_SET) != 0) {
+            fclose(in_file);
+            in_file = NULL;
+            if (fix == 1) {
+              zipwarn("could not seek back to Zip64 EOCDR: ", strerror(errno));
+              zipwarn("(try -FF)", "");
+            } else {
+              zipwarn("reading archive fseek: ", strerror(errno));
+            }
+            return ZE_FORM;
+          }
+          if (find_next_signature(in_file) && is_signature(sigbuf, "PK\06\06")) {
+            /* Should now be after Zip64 EOCDR signature in archive */
+            adjust_offset = zftello(in_file) - 4 - z64eocdr_offset;
+          } else {
+            zipwarn("Could not determine offset of entries", "");
+            zipwarn("(try -FF)", "");
+            return ZE_FORM;
+          }
+        }
+      }
+#endif
+    }
+    if (noisy) {
+      if (adjust_offset) {
+        sprintf(errbuf, "Zip entry offsets appear off by %s bytes - correcting...",
+                        zip_fzofft(adjust_offset, NULL, NULL));
+      } else {
+        sprintf(errbuf, "Zip entry offsets do not need adjusting");
+      }
+      zipmessage(errbuf, "");
+    }
+  }
+
+
+  /*
+   * Check for a Zip64 EOCD Locator signature
+   */
+
+  /* Format of Z64EOCD Locator is
+       zip64 end of central dir locator
+        signature                       4 bytes  (0x07064b50)
+       number of the disk with the
+        start of the zip64 end of
+        central directory               4 bytes
+       relative offset of the zip64
+        end of central directory record 8 bytes
+       total number of disks            4 bytes
+   */
+
+  /* back up 20 bytes from EOCDR to Z64 EOCDL */
+  if (zfseeko(in_file, eocdr_offset - 24, SEEK_SET) != 0) {
+    fclose(in_file);
+    in_file = NULL;
+    if (fix == 1) {
+      zipwarn("bad archive - could not seek back to Zip64 EOCDL: ", strerror(errno));
+      zipwarn("(try -FF)", "");
+    } else {
+      zipwarn("reading archive fseek: ", strerror(errno));
+    }
+    return ZE_FORM;
+  }
+  if (at_signature(in_file, "PK\06\07"))
+#ifndef ZIP64_SUPPORT
+  {
+    fclose(in_file);
+    in_file = NULL;
+    zipwarn("found Zip64 signature - this may be a Zip64 archive", "");
+    zipwarn("Need PKZIP 4.5 or later compatible zip", "");
+    zipwarn("Set ZIP64_SUPPORT in Zip 3", "");
+    return ZE_ZIP64;
+  }
+#else /* ZIP64_SUPPORT */
+  {
+    z64eocdl_offset = zftello(in_file) - 4;
+    /* read Z64 EOCDL */
+    if (fread(scbuf, EC64LOC, 1, in_file) != 1) {
+      fclose(in_file);
+      in_file = NULL;
+      zipwarn("reading archive: ", strerror(errno));
+      return ZE_READ;
+    }
+    /* now should be back at the EOCD signature */
+    if (!at_signature(in_file, "PK\05\06")) {
+      fclose(in_file);
+      in_file = NULL;
+      zipwarn("unable to read EOCD after seek: ", in_path);
+      return ZE_READ;
+    }
+
+    /* read disk and offset to Zip64 EOCDR and total disks */
+    z64eocdr_disk = LG(scbuf);
+    z64eocdr_offset = LLG(scbuf + 4) + adjust_offset;
+    total_disks = LG(scbuf + 12);
+
+    /* set the current disk */
+    current_in_disk = total_disks - 1;
+
+    /* Now need to read the Zip64 EOCD Record to get version needed
+       to extract */
+
+    if (z64eocdr_disk != total_disks - 1) {
+      /* Zip64 EOCDR not on this disk */
+
+      /* done with this disk (since apparently there are no CD entries
+         on it) */
+      fclose(in_file);
+      in_file = NULL;
+
+      /* get the path for the disk with the Zip64 EOCDR */
+      split_path = get_in_split_path(in_path, z64eocdr_disk);
+
+      while ((in_file = zfopen(split_path, FOPR)) == NULL) {
+        /* could not open split */
+
+        /* Ask where this split is.  This call also updates global in_path. */
+        if (ask_for_split_read_path(z64eocdr_disk) != ZE_OK) {
+          return ZE_ABORT;
+        }
+        free(split_path);
+        split_path = get_in_split_path(in_path, z64eocdr_disk);
+      }
+      free(split_path);
+    }
+
+    current_in_disk = z64eocdr_disk;
+
+    /* go to the Zip64 EOCDR */
+    if (zfseeko(in_file, z64eocdr_offset, SEEK_SET) != 0) {
+      fclose(in_file);
+      in_file = NULL;
+      zipwarn("reading archive fseek: ", strerror(errno));
+      return ZE_FORM;
+    }
+    /* Should be at Zip64 EOCDR signature */
+    if (!at_signature(in_file, "PK\06\06")) {
+      /* Wasn't there, so calculate based on Zip64 EOCDL offset */
+      zip64_eocdr_start = z64eocdl_offset - 24 - 56;
+      if (zfseeko(in_file, zip64_eocdr_start, SEEK_SET) != 0) {
+        fclose(in_file);
+        in_file = NULL;
+        if (fix == 1) {
+          zipwarn("bad archive - could not seek back to Zip64 EOCDR: ", strerror(errno));
+          zipwarn("(try -FF)", "");
+        } else {
+          zipwarn("reading archive fseek: ", strerror(errno));
+        }
+        return ZE_FORM;
+      }
+      if (find_next_signature(in_file) && is_signature(sigbuf, "PK\06\06")) {
+        /* Should now be after Zip64 EOCDR signature in archive */
+        adjust_offset = zftello(in_file) - 4 - z64eocdr_offset;
+        zipwarn("Zip64 EOCDR not found where expected - compensating", "");
+        zipwarn("(try -A to adjust offsets)", "");
+      } else {
+        fclose(in_file);
+        in_file = NULL;
+        if (fix == 1) {
+          zipwarn("bad archive - Zip64 EOCDR not found in split:  ", in_path);
+          zipwarn("(try -FF)", "");
+        } else {
+          zipwarn("Zip64 End Of Central Directory Record not found:  ", in_path);
+        }
+        return ZE_FORM;
+      }
+    }
+
+    /*
+     * Read the Z64 End Of Central Directory Record
+     */
+
+    /* The format of the Z64 EOCDR is
+        zip64 end of central dir
+         signature                       4 bytes  (0x06064b50)
+        size of zip64 end of central
+         directory record                8 bytes
+        version made by                  2 bytes
+        version needed to extract        2 bytes
+        number of this disk              4 bytes
+        number of the disk with the
+         start of the central directory  4 bytes
+        total number of entries in the
+         central directory on this disk  8 bytes
+        total number of entries in the
+         central directory               8 bytes
+        size of the central directory    8 bytes
+        offset of start of central
+         directory with respect to
+         the starting disk number        8 bytes
+        (version 2 of the Zip64 EOCDR has more after this)
+        zip64 extensible data sector    (variable size)
+     */
+
+    /* read the first 52 bytes of the Zip64 EOCDR (we don't support
+       version 2, which supports PKZip licensed features)
+    */
+    s = fread(scbuf, 1, EC64REC, in_file);
+    if (s < EC64REC) {
+      if (fix == 1) {
+        zipwarn("bad archive - Zip64 EOCDR bad or truncated", "");
+        zipwarn("(try -FF)", "");
+      } else {
+        zipwarn("Zip64 EOCD Record bad or truncated", "");
+      }
+      fclose(in_file);
+      in_file = NULL;
+      return ZE_FORM;
+    }
+    z64eocdr_size = LLG(scbuf);
+    version_made = SH(scbuf + 8);
+    version_needed = SH(scbuf + 10);
+    in_cd_start_disk = LG(scbuf + 16);
+    cd_total_entries = LLG(scbuf + 28);
+    in_cd_start_offset = LLG(scbuf + 44) + adjust_offset;
+
+    if (version_needed > 46) {
+      int major = version_needed / 10;
+      int minor = version_needed - (major * 10);
+      sprintf(errbuf, "This archive requires version %d.%d", major, minor);
+      zipwarn(errbuf, "");
+      zipwarn("Zip currently only supports up to version 4.6 archives", "");
+      zipwarn("(up to 4.5 if bzip2 is not compiled in)", "");
+      if (fix == 1)
+        zipwarn("If -F fails try -FF to try to salvage something", "");
+      else if (fix == 2)
+        zipwarn("Attempting to salvage what can", "");
+      else {
+        zipwarn("Try -F to attempt to read anyway", "");
+        fclose(in_file);
+        in_file = NULL;
+        return ZE_FORM;
+      }
+    }
+  }
+#endif /* ?ZIP64_SUPPORT */
+
+  /* Now read the central directory and create the zlist */
+
+  /* Multi-volume file names end in .z01, .z02, ..., .z10, .zip for 11 disk archive */
+
+  in_cd_start_offset += adjust_offset;
+  cenbeg = in_cd_start_offset;
+  zipbegset = 0;
+  zipbeg = 0;
+  first_CD = 1;
+
+  /* if the central directory starts on other than this disk, close this disk */
+  if (current_in_disk != in_cd_start_disk) {
+    /* close current disk */
+    fclose(in_file);
+    in_file = NULL;
+  }
+
+  /* Read the disks with the central directory in order - usually the
+     central directory fits on the last disk, but it doesn't have to.
+   */
+  for (current_in_disk = in_cd_start_disk;
+       current_in_disk < total_disks;
+       current_in_disk++) {
+    /* get the path for this disk */
+    if (current_in_disk == total_disks - 1) {
+      /* last disk is archive.zip */
+      if ((split_path = malloc(strlen(in_path) + 1)) == NULL) {
+        zipwarn("reading archive: ", in_path);
+        return ZE_MEM;
+      }
+      strcpy(split_path, in_path);
+    } else {
+      /* other disks are archive.z01, archive.z02, ... */
+      split_path = get_in_split_path(in_path, current_in_disk);
+    }
+
+    /* if in_file is not NULL then in_file is already open */
+    if (in_file == NULL) {
+      /* open the split */
+      while ((in_file = zfopen(split_path, FOPR)) == NULL) {
+        int result;
+        /* could not open split */
+
+        /* Ask for directory with split.  Updates global variable in_path */
+        result = ask_for_split_read_path(current_in_disk);
+        if (result == ZE_ABORT) {
+          zipwarn("could not find split: ", split_path);
+          return ZE_ABORT;
+        } else if (result == ZE_FORM) {
+          /* user asked to skip this disk */
+          sprintf(errbuf, "skipping disk %lu ...\n", current_in_disk);
+          zipwarn(errbuf, "");
+          skip_disk = 1;
+          break;
+        }
+
+        if (current_in_disk == total_disks - 1) {
+          /* last disk is archive.zip */
+          if ((split_path = malloc(strlen(in_path) + 1)) == NULL) {
+            zipwarn("reading archive: ", in_path);
+            return ZE_MEM;
+          }
+          strcpy(split_path, in_path);
+        } else {
+          /* other disks are archive.z01, archive.z02, ... */
+          split_path = get_in_split_path(zipfile, current_in_disk);
+        }
+      }
+      if (skip_disk) {
+        /* skip this current disk - this works because central directory entries
+           can't be split across splits */
+        skip_disk = 0;
+        skipped_disk = 1;
+        continue;
+      }
+    }
+
+    if (skipped_disk) {
+      /* skipped start CD disk so start searching for CD signature at start of disk */
+      first_CD = 0;
+    } else {
+      /* seek to the first CD entry */
+      if (first_CD) {
+        if (zfseeko(in_file, in_cd_start_offset, SEEK_SET) != 0) {
+          fclose(in_file);
+          in_file = NULL;
+          zipwarn("unable to seek in input file ", split_path);
+          return ZE_READ;
+        }
+        first_CD = 0;
+        x = &zfiles;                        /* first link */
+      }
+    }
+
+    /* Main loop */
+    /* Look for next signature and process it */
+    while (find_next_signature(in_file)) {
+      current_in_offset = zftello(in_file);
+
+      if (is_signature(sigbuf, "PK\05\06")) {
+        /* End Of Central Directory Record */
+        /*
+          fprintf(mesg, "EOCDR signature at %d / %I64d\n",
+                  current_in_disk, current_in_offset - 4);
+        */
+        break;
+
+      } else if (is_signature(sigbuf, "PK\06\06")) {
+        /* Zip64 End Of Central Directory Record */
+        /*
+          fprintf(mesg, "Zip64 EOCDR signature at %d / %I64d\n",
+                  current_in_disk, current_in_offset - 4);
+        */
+        break;
+
+      } else if (!is_signature(sigbuf, "PK\01\02")) {
+        /* Not Central Directory Record */
+
+        /* this signature shouldn't be here */
+        if (fix == 1) {
+          int c;
+          char errbuftemp[40];
+
+          strcpy(errbuf, "bad archive - unexpected signature ");
+          for (c = 0; c < 4; c++) {
+            sprintf(errbuftemp, "%02x ", sigbuf[c]);
+            strcat(errbuf, errbuftemp);
+          }
+          sprintf(errbuftemp, "on disk %lu at %s\n", current_in_disk,
+                                   zip_fzofft(current_in_offset - 4, NULL, "u"));
+          strcat(errbuf, errbuftemp);
+          zipwarn(errbuf, "");
+          zipwarn("skipping this signature...", "");
+          continue;
+        } else {
+          sprintf(errbuf, "unexpected signature on disk %lu at %s\n",
+                  current_in_disk, zip_fzofft(current_in_offset - 4, NULL, "u"));
+          zipwarn(errbuf, "");
+          zipwarn("archive not in correct format: ", split_path);
+          zipwarn("(try -F to attempt recovery)", "");
+          fclose(in_file);
+          in_file = NULL;
+          return ZE_FORM;
+        }
+      }
+
+      /* central directory signature */
+      if (verbose && fix == 1) {
+        fprintf(mesg, "central directory header signature on disk %lu at %s\n",
+                current_in_disk, zip_fzofft(current_in_offset - 4, NULL, "u"));
+      }
+
+      /* The format of a central directory record
+        central file header signature   4 bytes  (0x02014b50)
+        version made by                 2 bytes
+        version needed to extract       2 bytes
+        general purpose bit flag        2 bytes
+        compression method              2 bytes
+        last mod file time              2 bytes
+        last mod file date              2 bytes
+        crc-32                          4 bytes
+        compressed size                 4 bytes
+        uncompressed size               4 bytes
+        file name length                2 bytes
+        extra field length              2 bytes
+        file comment length             2 bytes
+        disk number start               2 bytes
+        internal file attributes        2 bytes
+        external file attributes        4 bytes
+        relative offset of local header 4 bytes
+
+        file name (variable size)
+        extra field (variable size)
+        file comment (variable size)
+       */
+
+      if (fread(scbuf, CENHEAD, 1, in_file) != 1) {
+        zipwarn("reading central directory: ", strerror(errno));
+        if (fix == 1) {
+          zipwarn("bad archive - error reading central directory", "");
+          zipwarn("skipping this entry...", "");
+          continue;
+        } else {
+          return ferror(in_file) ? ZE_READ : ZE_EOF;
+        }
+      }
+
+      if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) {
+        zipwarn("reading central directory", "");
+        return ZE_MEM;
+      }
+
+      z->vem = SH(CENVEM + scbuf);
+      z->ver = SH(CENVER + scbuf);
+      z->flg = SH(CENFLG + scbuf);
+      z->how = SH(CENHOW + scbuf);
+      z->tim = LG(CENTIM + scbuf);      /* time and date into one long */
+      z->crc = LG(CENCRC + scbuf);
+      z->siz = LG(CENSIZ + scbuf);
+      z->len = LG(CENLEN + scbuf);
+      z->nam = SH(CENNAM + scbuf);      /* used before comparing cen vs. loc */
+      z->cext = SH(CENEXT + scbuf);     /* may be different from z->ext */
+      z->com = SH(CENCOM + scbuf);
+      z->dsk = SH(CENDSK + scbuf);
+      z->att = SH(CENATT + scbuf);
+      z->atx = LG(CENATX + scbuf);
+      z->off = LG(CENOFF + scbuf);      /* adjust_offset is added below */
+      z->dosflag = (z->vem & 0xff00) == 0;
+
+      /* Initialize all fields pointing to malloced data to NULL */
+      z->zname = z->name = z->iname = z->extra = z->cextra = z->comment = NULL;
+      z->oname = NULL;
+#ifdef UNICODE_SUPPORT
+      z->uname = z->zuname = z->ouname = NULL;
+#endif
+
+      /* Read file name, extra field and comment field */
+      if (z->nam == 0)
+      {
+        sprintf(errbuf, "%lu", (ulg)zcount + 1);
+        zipwarn("zero-length name for entry #", errbuf);
+        if (fix == 1) {
+          zipwarn("skipping this entry...", "");
+          continue;
+        }
+#ifndef DEBUG
+        return ZE_FORM;
+#endif
+      }
+      if ((z->iname = malloc(z->nam+1)) ==  NULL ||
+          (z->cext && (z->cextra = malloc(z->cext)) == NULL) ||
+          (z->com && (z->comment = malloc(z->com)) == NULL))
+        return ZE_MEM;
+      if (fread(z->iname, z->nam, 1, in_file) != 1 ||
+          (z->cext && fread(z->cextra, z->cext, 1, in_file) != 1) ||
+          (z->com && fread(z->comment, z->com, 1, in_file) != 1)) {
+        if (fix == 1) {
+          zipwarn("error reading entry:  ", strerror(errno));
+          zipwarn("skipping this entry...", "");
+          continue;
+        }
+        return ferror(in_file) ? ZE_READ : ZE_EOF;
+      }
+      z->iname[z->nam] = '\0';                  /* terminate name */
+#ifdef UNICODE_SUPPORT
+      if (unicode_mismatch != 3) {
+        if (z->flg & UTF8_BIT) {
+          char *iname;
+          /* path is UTF-8 */
+          if ((z->uname = malloc(strlen(z->iname) + 1)) == NULL) {
+            zipwarn("could not allocate memory: scanzipf_reg", "");
+            return ZE_MEM;
+          }
+          strcpy(z->uname, z->iname);
+          /* Create a local name.  If UTF-8 system this should also be UTF-8 */
+          iname = utf8_to_local_string(z->uname);
+          if (iname) {
+            free(z->iname);
+            z->iname = iname;
+          }
+          else
+            zipwarn("illegal UTF-8 name: ", z->uname);
+        } else {
+          /* check for UTF-8 path extra field */
+          read_Unicode_Path_entry(z);
+        }
+      }
+#endif
+
+#ifdef WIN32
+      /* Input path may be OEM */
+      {
+        unsigned hostver = (z->vem & 0xff);
+        Ext_ASCII_TO_Native(z->iname, (z->vem >> 8), hostver,
+                            ((z->atx & 0xffff0000L) != 0), FALSE);
+      }
+#endif
+
+#ifdef EBCDIC
+      if (z->com)
+         memtoebc(z->comment, z->comment, z->com);
+#endif /* EBCDIC */
+#ifdef WIN32
+      /* Comment may be OEM */
+      {
+        unsigned hostver = (z->vem & 0xff);
+        Ext_ASCII_TO_Native(z->comment, (z->vem >> 8), hostver,
+                            ((z->atx & 0xffff0000L) != 0), FALSE);
+      }
+#endif
+
+#ifdef ZIP64_SUPPORT
+      /* zip64 support 08/31/2003 R.Nausedat                          */
+      /* here, we have to read the len, siz etc values from the CD    */
+      /* entry as we might have to adjust them regarding their        */
+      /* correspronding zip64 extra fields.                           */
+      /* also, we cannot compare the values from the CD entries with  */
+      /* the values from the LH as they might be different.           */
+
+      /* adjust/update siz,len and off (to come: dsk) entries */
+      /* PKZIP does not care of the version set in a CDH: if  */
+      /* there is a zip64 extra field assigned to a CDH PKZIP */
+      /* uses it, we should do so, too.                       */
+      adjust_zip_central_entry(z);
+#endif
+      /* if adjusting for sfx prefix, add the offset */
+      if ((fix ==1 && total_disks == 1) || adjust) z->off += adjust_offset;
+
+      /* Update zipbeg beginning of archive offset, prepare for next header */
+      if (z->dsk == 0 && (!zipbegset || z->off < zipbeg)) {
+        zipbeg = z->off;
+        zipbegset = 1;
+      }
+      zcount++;
+
+      /* Clear actions */
+      z->mark = 0;
+      z->trash = 0;
+#if defined(UNICODE_SUPPORT) && !defined(UTIL)
+      z->zname = in2ex(z->iname);       /* convert to external name */
+      if (z->zname == NULL)
+        return ZE_MEM;
+      if ((z->name = malloc(strlen(z->zname) + 1)) == NULL) {
+        zipwarn("could not allocate memory: scanzipf_reg", "");
+        return ZE_MEM;
+      }
+      strcpy(z->name, z->zname);
+      z->oname = local_to_display_string(z->iname);
+
+# ifdef WIN32
+      z->namew = NULL;
+      z->inamew = NULL;
+      z->znamew = NULL;
+# endif
+
+      if (unicode_mismatch != 3) {
+        if (z->uname) {
+          /* create zuname which is alternate zname for matching based on
+             converted Unicode name */
+          char *name;
+
+          /* Convert UTF-8 to current local character set */
+          name = utf8_to_local_string(z->uname);
+
+          if (name == NULL) {
+            /*
+            zipwarn("illegal UTF-8 name: ", z->uname);
+            */
+            /* not able to convert name, so use iname */
+            if ((name = malloc(strlen(z->iname) + 1)) == NULL) {
+              zipwarn("could not allocate memory: scanzipf_reg", "");
+              return ZE_MEM;
+            }
+            strcpy(name, z->iname);
+          }
+
+# ifdef EBCDIC
+          /* z->zname is used for printing and must be coded in native charset */
+          strtoebc(z->zuname, name);
+# else /* !EBCDIC */
+          if ((z->zuname = malloc(strlen(name) + 1)) == NULL) {
+            zipwarn("could not allocate memory: scanzipf_reg", "");
+            return ZE_MEM;
+          }
+          strcpy(z->zuname, name);
+          /* For output to terminal */
+          if (unicode_escape_all) {
+            char *ouname;
+            /* Escape anything not 7-bit ASCII */
+            ouname = utf8_to_escape_string(z->uname);
+            if (ouname)
+              z->ouname = ouname;
+            else {
+              if ((z->ouname = malloc(strlen(name) + 1)) == NULL) {
+                zipwarn("could not allocate memory: scanzipf_reg", "");
+                return ZE_MEM;
+              }
+              strcpy(z->ouname, name);
+            }
+          } else {
+            if ((z->ouname = malloc(strlen(name) + 1)) == NULL) {
+              zipwarn("could not allocate memory: scanzipf_reg", "");
+              return ZE_MEM;
+            }
+            strcpy(z->ouname, name);
+          }
+#  ifdef WIN32
+
+          if (!no_win32_wide) {
+            z->inamew = utf8_to_wchar_string(z->uname);
+            z->znamew = in2exw(z->inamew); /* convert to external name */
+            if (z->znamew == NULL)
+              return ZE_MEM;
+          }
+
+          local_to_oem_string(z->ouname, z->ouname);
+          /* For matching.  There seems to be something lost
+             in the translation from displaying a name in a
+             console window using zip -su on Win32 and using
+             that name in a command line to match what's in
+             the archive.  This is klugy though.
+          */
+          if ((z->wuname = malloc(strlen(z->ouname) + 1)) == NULL) {
+            zipwarn("could not allocate memory: scanzipf_reg", "");
+            return ZE_MEM;
+          }
+          strcpy(z->wuname, z->ouname);
+          oem_to_local_string(z->wuname, z->wuname);
+#  endif /* WIN32 */
+# endif /* ?EBCDIC */
+        } else {
+          /* no uname */
+# ifdef WIN32
+          if (!no_win32_wide) {
+            z->inamew = local_to_wchar_string(z->iname);
+            z->znamew = in2exw(z->inamew); /* convert to external name */
+            if (z->znamew == NULL)
+              return ZE_MEM;
+          }
+# endif
+        }
+      }
+#else /* !(UNICODE_SUPPORT && !UTIL) */
+# ifdef UTIL
+/* We only need z->iname in the utils */
+      z->name = z->iname;
+#  ifdef EBCDIC
+/* z->zname is used for printing and must be coded in native charset */
+      if ((z->zname = malloc(z->nam+1)) ==  NULL) {
+        zipwarn("could not allocate memory: scanzipf_reg", "");
+        return ZE_MEM;
+      }
+      strtoebc(z->zname, z->iname);
+#  else
+      z->zname = z->iname;
+#  endif
+# else /* !UTIL */
+      z->zname = in2ex(z->iname);       /* convert to external name */
+      if (z->zname == NULL)
+        return ZE_MEM;
+      z->name = z->zname;
+# endif /* ?UTIL */
+      if ((z->oname = malloc(strlen(z->zname) + 1)) == NULL) {
+        zipwarn("could not allocate memory: scanzipf_reg", "");
+        return ZE_MEM;
+      }
+      strcpy(z->oname, z->zname);
+#endif /* ?(UNICODE_SUPPORT && !UTIL) */
+
+#ifndef UTIL
+      if (verbose && fix == 0)
+        zipoddities(z);
+#endif
+
+      /* Link into list */
+      *x = z;
+      z->nxt = NULL;
+      x = &z->nxt;
+
+    } /* while reading file */
+
+    /* close disk and do next disk */
+    fclose(in_file);
+    in_file = NULL;
+    free(split_path);
+
+    if (!is_signature(sigbuf, "PK\01\02")) {
+      /* if the last signature is not a CD signature and we get here then
+         hit either the  Zip64 EOCDR or the EOCDR and done */
+      break;
+    }
+
+  } /* for each disk */
+
+  if (zcount != cd_total_entries) {
+    sprintf(errbuf, "expected %s entries but found %s",
+      zip_fzofft(cd_total_entries, NULL, "u"),
+      zip_fzofft(zcount, NULL, "u"));
+    zipwarn(errbuf, "");
+    return ZE_FORM;
+  }
+
+  return ZE_OK;
+
+} /* end of function scanzipf_regnew() */
+
+
+
+
+
+
+
+
+/* ---------------------- */
+
+
+
+
+/*
+ * readzipfile initializes the global variables that hold the zipfile
+ * directory info and opens the zipfile. For the actual zipfile scan,
+ * the subroutine scanzipf_reg() or scanzipf_fix() is called,
+ * depending on the mode of operation (regular processing, or zipfix mode).
+ */
+int readzipfile()
+/*
+   The name of the zip file is pointed to by the global "zipfile".
+   The globals zipbeg, zfiles, zcount, and zcomlen are initialized.
+   Return an error code in the ZE_ class.
+*/
+{
+  FILE *f;              /* zip file */
+  int retval;           /* return code */
+  int readable;         /* 1 if zipfile exists and is readable */
+
+  /* Initialize zip file info */
+  zipbeg = 0;
+  zfiles = NULL;                        /* Points to first header */
+  zcount = 0;                           /* number of files */
+  zcomlen = 0;                          /* zip file comment length */
+  retval = ZE_OK;
+  f = NULL;                             /* shut up some compilers */
+  zipfile_exists = 0;
+
+  /* If zip file exists, read headers and check structure */
+#ifdef VMS
+  if (zipfile == NULL || !(*zipfile) || !strcmp(zipfile, "-"))
+    return ZE_OK;
+  {
+    int rtype;
+
+    if ((VMSmunch(zipfile, GET_RTYPE, (char *)&rtype) == RMS$_NORMAL) &&
+        (rtype == FAT$C_VARIABLE)) {
+      fprintf(mesg,
+     "\n     Error:  zipfile is in variable-length record format.  Please\n\
+     run \"bilf b %s\" to convert the zipfile to fixed-length\n\
+     record format.\n\n", zipfile);
+      return ZE_FORM;
+    }
+  }
+  readable = ((f = zfopen(zipfile, FOPR)) != NULL);
+#else /* !VMS */
+  readable = (zipfile != NULL && *zipfile && strcmp(zipfile, "-"));
+  if (readable) {
+    readable = ((f = zfopen(zipfile, FOPR)) != NULL);
+  }
+#endif /* ?VMS */
+
+  /* skip check if streaming */
+  if (!readable) {
+    if (!zip_to_stdout && fix != 2 && strcmp(in_path, out_path)) {
+      /* If -O used then in_path must exist */
+      if (fix == 1)
+        zipwarn("No .zip file found\n        ",
+                "(If all you have are splits (.z01, .z02, ...) and no .zip, try -FF)");
+      ZIPERR(ZE_OPEN, zipfile);
+    }
+  } else {
+    zipfile_exists = 1;
+  }
+
+#ifdef MVS
+  /* Very nasty special case for MVS.  Just because the zipfile has been
+   * opened for reading does not mean that we can actually read the data.
+   * Typical JCL to create a zipfile is
+   *
+   * //ZIPFILE  DD  DISP=(NEW,CATLG),DSN=prefix.ZIP,
+   * //             SPACE=(CYL,(10,10))
+   *
+   * That creates a VTOC entry with an end of file marker (DS1LSTAR) of zero.
+   * Alas the VTOC end of file marker is only used when the file is opened in
+   * append mode.  When a file is opened in read mode, the "other" end of file
+   * marker is used, a zero length data block signals end of file when reading.
+   * With a brand new file which has not been written to yet, it is undefined
+   * what you read off the disk.  In fact you read whatever data was in the same
+   * disk tracks before the zipfile was allocated.  You would be amazed at the
+   * number of application programmers who still do not understand this.  Makes
+   * for interesting and semi-random errors, GIGO.
+   *
+   * Newer versions of SMS will automatically write a zero length block when a
+   * file is allocated.  However not all sites run SMS or they run older levels
+   * so we cannot rely on that.  The only safe thing to do is close the file,
+   * open in append mode (we already know that the file exists), close it again,
+   * reopen in read mode and try to read a data block.  Opening and closing in
+   * append mode will write a zero length block where DS1LSTAR points, making
+   * sure that the VTOC and internal end of file markers are in sync.  Then it
+   * is safe to read data.  If we cannot read one byte of data after all that,
+   * it is a brand new zipfile and must not be read.
+   */
+  if (readable)
+  {
+    char c;
+    fclose(f);
+    /* append mode */
+    if ((f = zfopen(zipfile, "ab")) == NULL) {
+      ZIPERR(ZE_OPEN, zipfile);
+    }
+    fclose(f);
+    /* read mode again */
+    if ((f = zfopen(zipfile, FOPR)) == NULL) {
+      ZIPERR(ZE_OPEN, zipfile);
+    }
+    if (fread(&c, 1, 1, f) != 1) {
+      /* no actual data */
+      readable = 0;
+      fclose(f);
+    }
+    else{
+      fseek(f, 0, SEEK_SET);  /* at least one byte in zipfile, back to the start */
+    }
+  }
+#endif /* MVS */
+
+  /* ------------------------ */
+  /* new file read */
+
+
+
+#ifndef UTIL
+  if (fix == 2) {
+    scanzipf_fixnew();
+  }
+  else
+#endif
+  if (readable)
+  {
+    /* close file as the new scan opens the splits as needed */
+    fclose(f);
+# ifndef UTIL
+    retval = (fix == 2 && !adjust) ? scanzipf_fixnew() : scanzipf_regnew();
+# else
+    retval = scanzipf_regnew();
+# endif
+  }
+
+  if (fix != 2 && readable)
+  {
+    /* If one or more files, sort by name */
+    if (zcount)
+    {
+      struct zlist far * far *x;    /* pointer into zsort array */
+      struct zlist far *z;          /* pointer into zfiles linked list */
+      extent zl_size = zcount * sizeof(struct zlist far *);
+
+      if (zl_size / sizeof(struct zlist far *) != zcount ||
+          (x = zsort = (struct zlist far **)malloc(zl_size)) == NULL)
+        return ZE_MEM;
+      for (z = zfiles; z != NULL; z = z->nxt)
+        *x++ = z;
+      qsort((char *)zsort, zcount, sizeof(struct zlist far *), zqcmp);
+
+#ifdef UNICODE_SUPPORT
+      /* sort by zuname (local conversion of UTF-8 name) */
+      if (zl_size / sizeof(struct zlist far *) != zcount ||
+          (x = zusort = (struct zlist far **)malloc(zl_size)) == NULL)
+        return ZE_MEM;
+      for (z = zfiles; z != NULL; z = z->nxt)
+        *x++ = z;
+      qsort((char *)zusort, zcount, sizeof(struct zlist far *), zuqcmp);
+#endif
+    }
+  }
+
+  /* ------------------------ */
+
+  return retval;
+} /* end of function readzipfile() */
+
+
+int putlocal(z, rewrite)
+  struct zlist far *z;    /* zip entry to write local header for */
+  int rewrite;            /* did seek to rewrite */
+/* Write a local header described by *z to file *f.  Return an error code
+   in the ZE_ class. */
+{
+  /* If any of compressed size (siz), uncompressed size (len), offset(off), or
+     disk number (dsk) is larger than can fit in the below standard fields then a
+     Zip64 flag value is stored and a Zip64 extra field is created.
+     Only siz and len are in the local header while all can be in the central
+     directory header.
+
+     For the local header if the extra field is created must store both
+     uncompressed and compressed sizes.
+
+     This assumes that for large entries the compressed size won't need a
+     Zip64 extra field if the uncompressed size did not.  This assumption should
+     only fail for a large file of nearly totally uncompressable data.
+
+     If streaming stdin in and use_descriptors is set then always create a Zip64
+     extra field flagging the data descriptor as being in Zip64 format.  This is
+     needed as don't know if need Zip64 or not when need to set Zip64 flag in
+     local header.
+
+     If rewrite is set then don't count bytes written for splits
+   */
+  char *block = NULL;   /* mem block to write to */
+  extent offset = 0;    /* offset into block */
+  extent blocksize = 0; /* size of block */
+#ifdef UNICODE_SUPPORT
+  ush nam = z->nam;     /* size of name to write to header */
+  int use_uname = 0;    /* write uname to header */
+#endif
+#ifdef ZIP64_SUPPORT
+  int streaming_in = 0; /* streaming stdin */
+  int was_zip64 = 0;
+
+  /* If input is stdin then streaming stdin.  No problem with that.
+
+     The problem is updating the local header data in the output once the sizes
+     and crc are known.  If the output is not seekable, then need data descriptors
+     and also need to assume Zip64 will be needed as don't know yet.  Even if the
+     output is seekable, if the input is streamed need to write the Zip64 extra field
+     before writing the data or there won't be room for it later if we need it.
+  */
+  streaming_in = (strcmp(z->name, "-") == 0);
+
+  if (!rewrite) {
+    zip64_entry = 0;
+    /* initial local header */
+    if (z->siz > ZIP_UWORD32_MAX || z->len > ZIP_UWORD32_MAX ||
+      force_zip64 == 1 || (force_zip64 != 0 && streaming_in))
+    {
+      /* assume Zip64 */
+      if (force_zip64 == 0) {
+        zipwarn("Entry too big:", z->oname);
+        ZIPERR(ZE_BIG, "Large entry support disabled with -fz- but needed");
+      }
+      zip64_entry = 1;        /* header of this entry has a field needing Zip64 */
+      if (z->ver < ZIP64_MIN_VER)
+        z->ver = ZIP64_MIN_VER;
+      was_zip64 = 1;
+    }
+  } else {
+    /* rewrite */
+    was_zip64 = zip64_entry;
+    zip64_entry = 0;
+    if (z->siz > ZIP_UWORD32_MAX || z->len > ZIP_UWORD32_MAX ||
+      force_zip64 == 1 || (force_zip64 != 0 && streaming_in))
+    {
+      /* Zip64 entry */
+      zip64_entry = 1;
+    }
+    if (force_zip64 == 0 && zip64_entry) {
+      /* tried to force into standard entry but needed Zip64 entry */
+      zipwarn("Entry too big:", z->oname);
+      ZIPERR(ZE_BIG, "Large entry support disabled with -fz- but entry needs");
+    }
+    /* Normally for a large archive if the input file is less than 4 GB then
+       the compressed or stored version should be less than 4 GB.  If this
+       assumption is wrong this catches it.  This is a problem even if not
+       streaming as the Zip64 extra field was not written and now there's no
+       room for it. */
+    if (was_zip64 == 0 && zip64_entry == 1) {
+      /* guessed wrong and need Zip64 */
+      zipwarn("Entry too big:", z->oname);
+      if (force_zip64 == 0) {
+        ZIPERR(ZE_BIG, "Compressed/stored entry unexpectedly large - do not use -fz-");
+      } else {
+        ZIPERR(ZE_BIG, "Poor compression resulted in unexpectedly large entry - try -fz");
+      }
+    }
+    if (zip64_entry) {
+      /* Zip64 entry still */
+      /* this archive needs Zip64 (version 4.5 unzipper) */
+      zip64_archive = 1;
+      if (z->ver < ZIP64_MIN_VER)
+        z->ver = ZIP64_MIN_VER;
+    } else {
+      /* it turns out we do not need Zip64 */
+      zip64_entry = 0;
+    }
+    if (was_zip64 && zip64_entry != 1) {
+      z->ver = 20;
+    }
+  }
+
+
+#endif /* ZIP64_SUPPORT */
+
+  /* Instead of writing to the file as we go, to do splits we have to write it
+     to memory and see if it will fit before writing the entire local header.
+     If the local header doesn't fit we need to save it for the next disk.
+   */
+
+#ifdef ZIP64_SUPPORT
+  if (zip64_entry || was_zip64)
+    /* update extra field */
+    add_local_zip64_extra_field( z );
+#endif /* ZIP64_SUPPORT */
+
+#ifdef UNICODE_SUPPORT
+# if 0
+  /* if UTF-8 bit is set on an existing entry, assume it should be */
+  /* clear the UTF-8 flag */
+  z->flg &= ~UTF8_BIT;
+  z->lflg &= ~UTF8_BIT;
+# endif
+
+  if (z->uname) {
+    /* need UTF-8 name */
+    if (utf8_force || using_utf8) {
+      z->lflg |= UTF8_BIT;
+      z->flg |= UTF8_BIT;
+    }
+    if (z->flg & UTF8_BIT) {
+      /* If this flag is set, then restore UTF-8 as path name */
+      use_uname = 1;
+      nam = strlen(z->uname);
+    } else {
+      /* use extra field */
+      add_Unicode_Path_local_extra_field(z);
+    }
+  } else {
+    /* clear UTF-8 bit as not needed */
+    z->flg &= ~UTF8_BIT;
+    z->lflg &= ~UTF8_BIT;
+  }
+#endif
+
+  append_ulong_to_mem(LOCSIG, &block, &offset, &blocksize);     /* local file header signature */
+  append_ushort_to_mem(z->ver, &block, &offset, &blocksize);    /* version needed to extract */
+  append_ushort_to_mem(z->lflg, &block, &offset, &blocksize);   /* general purpose bit flag */
+  append_ushort_to_mem(z->how, &block, &offset, &blocksize);    /* compression method */
+  append_ulong_to_mem(z->tim, &block, &offset, &blocksize);     /* last mod file date time */
+  append_ulong_to_mem(z->crc, &block, &offset, &blocksize);     /* crc-32 */
+#ifdef ZIP64_SUPPORT        /* zip64 support 09/02/2003 R.Nausedat */
+                            /* changes 10/5/03 EG */
+  if (zip64_entry) {
+    append_ulong_to_mem(0xFFFFFFFF, &block, &offset, &blocksize);      /* compressed size */
+    append_ulong_to_mem(0xFFFFFFFF, &block, &offset, &blocksize);      /* uncompressed size */
+  } else {
+    append_ulong_to_mem((ulg)z->siz, &block, &offset, &blocksize);/* compressed size */
+    append_ulong_to_mem((ulg)z->len, &block, &offset, &blocksize);/* uncompressed size */
+  }
+#else
+  append_ulong_to_mem((ulg)z->siz, &block, &offset, &blocksize);    /* compressed size */
+  append_ulong_to_mem((ulg)z->len, &block, &offset, &blocksize);    /* uncompressed size */
+#endif
+#ifdef UNICODE_SUPPORT
+  append_ushort_to_mem(nam, &block, &offset, &blocksize);   /* file name length */
+#else
+  append_ushort_to_mem(z->nam, &block, &offset, &blocksize);   /* file name length */
+#endif
+
+  append_ushort_to_mem(z->ext, &block, &offset, &blocksize);    /* extra field length */
+
+#ifdef UNICODE_SUPPORT
+  if (use_uname) {
+    /* path is UTF-8 */
+    append_string_to_mem(z->uname, nam, &block, &offset, &blocksize);
+  } else
+#endif
+#ifdef WIN32_OEM
+  /* store name in OEM character set in archive */
+  if ((z->vem & 0xff00) == 0)
+  {
+    char *oem;
+
+    if ((oem = malloc(strlen(z->iname) + 1)) == NULL)
+      ZIPERR(ZE_MEM, "putlocal oem");
+    INTERN_TO_OEM(z->iname, oem);
+    append_string_to_mem(oem, z->nam, &block, &offset, &blocksize); /* file name */
+    free(oem);
+  } else {
+    append_string_to_mem(z->iname, z->nam, &block, &offset, &blocksize); /* file name */
+  }
+#else
+  append_string_to_mem(z->iname, z->nam, &block, &offset, &blocksize); /* file name */
+#endif
+  if (z->ext) {
+    append_string_to_mem(z->extra, z->ext, &block, &offset, &blocksize); /* extra field */
+  }
+
+  /* write the header */
+  if (rewrite == PUTLOCAL_REWRITE) {
+    /* use fwrite as seeked back and not extending the archive */
+    /* also if split_method 1 write to file with local header */
+    if (split_method == 1) {
+      if (fwrite(block, 1, offset, current_local_file) != offset) {
+        free(block);
+        return ZE_TEMP;
+      }
+      /* now can close the split if local header on previous split */
+      if (current_local_disk != current_disk) {
+        close_split(current_local_disk, current_local_file, current_local_tempname);
+        current_local_file = NULL;
+        free(current_local_tempname);
+      }
+    } else {
+      /* not doing splits */
+      if (fwrite(block, 1, offset, y) != offset) {
+        free(block);
+        return ZE_TEMP;
+      }
+    }
+  } else {
+    /* do same if archive not split or split_method 2 with descriptors */
+    /* use bfwrite which counts bytes for splits */
+    if (bfwrite(block, 1, offset, BFWRITE_LOCALHEADER) != offset) {
+      free(block);
+      return ZE_TEMP;
+    }
+  }
+  free(block);
+  return ZE_OK;
+}
+
+int putextended(z)
+  struct zlist far *z;    /* zip entry to write local header for */
+  /* This is the data descriptor.
+   * Write an extended local header described by *z to file *f.
+   * Return an error code in the ZE_ class. */
+{
+  /* write to mem block then write to file 3/10/2005 */
+  char *block = NULL;   /* mem block to write to */
+  extent offset = 0;    /* offset into block */
+  extent blocksize = 0; /* size of block */
+
+  append_ulong_to_mem(EXTLOCSIG, &block, &offset, &blocksize);  /* extended local signature */
+  append_ulong_to_mem(z->crc, &block, &offset, &blocksize);     /* crc-32 */
+#ifdef ZIP64_SUPPORT
+  if (zip64_entry) {
+    /* use Zip64 entries */
+    append_int64_to_mem(z->siz, &block, &offset, &blocksize);   /* compressed size */
+    append_int64_to_mem(z->len, &block, &offset, &blocksize);   /* uncompressed size */
+    /* This is rather klugy as the AppNote handles this poorly.  Typically
+       we don't know at this point if we are writing a Zip64 archive or not,
+       unless a file has needed Zip64.  This is particularly annoying here
+       when deciding the size of the data descriptor (extended local header)
+       fields as the appnote says the uncompressed and compressed sizes
+       should be 8 bytes if the archive is Zip64 and 4 bytes if not.
+
+       One interpretation is the version of the archive is determined from
+       the Version Needed To Extract field in the Zip64 End Of Central Directory
+       record and so either an archive should start as Zip64 and write all data
+       descriptors with 8-byte fields or store everything until all the files
+       are processed and then write everything to the archive as changing the
+       sizes of the data descriptors is messy and just not feasible when
+       streaming to standard output.  This is not easily workable and others
+       use the different interpretation below.
+
+       This was the old thought:
+       We always write a standard data descriptor.  If the file has a large
+       uncompressed or compressed size we set the field to the max field
+       value, which we are defining as flagging the field as having a Zip64
+       value that doesn't fit.  As the CRC happens before the variable size
+       fields the CRC is still valid and can be used to check the file.  We
+       always use deflate if streaming so signatures should not appear in
+       the data and all local header signatures should be valid, allowing a
+       streaming unzip to find entries by local header signatures, if max size
+       values in the data descriptor sizes ignore them, and extract the file and
+       check it using the CRC.  If not streaming the central directory is available
+       so just use those values which are correct.
+
+       After discussions with other groups this is the current thinking:
+
+       Apparent industry interpretation for data descriptors:
+       Data descriptor size is determined for each entry.  If the local header
+       version needed to extract is 45 or higher then the entry can use Zip64
+       data descriptors but more checking is needed.  If Zip64 extra field is
+       present then assume data descriptor is Zip64 and local version needed
+       to extract should be 45 or higher.  If standard data descriptor then
+       local size fields are set to 0 and correct sizes are in standard data descriptor.
+       If Zip64 data descriptor then local sizes are set to -1, Zip64 extra field
+       sizes are set to 0, and the correct sizes are in the Zip64 data descriptor.
+
+       So do this:
+       If an entry is standard and the archive is updatable then seek back and
+       update the local header.  No change.
+
+       If an entry is zip64 and the archive is updatable assume the Zip64 extra
+       field was created and update it.  No change.
+
+       If data descriptors are needed then assume the archive is Zip64.  This is
+       a change and means if ZIP64_SUPPORT is enabled that any non-updatable archive
+       will be in Zip64 format and use Zip64 data descriptors.  This should be
+       compatible with other zippers that depend on the current (though not perfect)
+       AppNote description.
+
+       If anyone has some ideas on this I'd like to hear them.
+
+       3/20/05 EG
+
+       Only assume need Zip64 if the input size is unknown.  If the input size is
+       known we can assume Zip64 if the input is larger than 4 GB and assume not
+       otherwise.  If the output is seekable we still need to create the Zip64
+       extra field if the input size is unknown so we can seek back and update it.
+       12/28/05 EG
+       Updated 5/21/06 EG
+    */
+  } else {
+    /* for encryption */
+    append_ulong_to_mem((ulg)z->siz, &block, &offset, &blocksize);  /* compressed size */
+    append_ulong_to_mem((ulg)z->len, &block, &offset, &blocksize);  /* uncompressed size */
+  }
+#else
+  append_ulong_to_mem((ulg)z->siz, &block, &offset, &blocksize);    /* compressed size */
+  append_ulong_to_mem((ulg)z->len, &block, &offset, &blocksize);    /* uncompressed size */
+#endif
+  /* write the header */
+  if (bfwrite(block, 1, offset, BFWRITE_HEADER) != offset) {
+    free(block);
+    return ZE_TEMP;
+  }
+  free(block);
+  return ZE_OK;
+}
+
+int putcentral(z)
+  struct zlist far *z;    /* zip entry to write central header for */
+/* Write a central header described by *z to file *f.  Return an error code
+   in the ZE_ class. */
+/* output now uses bfwrite which writes global y */
+{
+  /* If any of compressed size (siz), uncompressed size (len), offset(off), or
+     disk number (dsk) is larger than can fit in the below standard fields then a
+     Zip64 flag value is stored and a Zip64 extra field is created.
+     Only siz and len are in the local header while all are in the central directory
+     header.
+
+     For the central directory header just store the fields required.  All previous fields
+     must be stored though.  So can store none (no extra field), just uncompressed size
+     (len), len then siz, len then siz then off, or len then siz then off then dsk, in
+     those orders.  10/6/03 EG
+   */
+
+  /* write to mem block then write to file 3/10/2005 EG */
+  char *block = NULL;   /* mem block to write to */
+  extent offset = 0;    /* offset into block */
+  extent blocksize = 0; /* size of block */
+  uzoff_t off = 0;      /* offset to start of local header */
+  ush nam = z->nam;     /* size of name to write to header */
+#ifdef UNICODE_SUPPORT
+  int use_uname = 0;    /* write uname to header */
+#endif
+
+#ifdef ZIP64_SUPPORT        /* zip64 support 09/02/2003 R.Nausedat */
+  int iRes;
+#endif
+
+#ifdef UNICODE_SUPPORT
+  if (z->uname) {
+    if (utf8_force) {
+      z->flg |= UTF8_BIT;
+    }
+    if (z->flg & UTF8_BIT) {
+      /* If this flag is set, then restore UTF-8 as path name */
+      use_uname = 1;
+      nam = strlen(z->uname);
+    } else {
+      add_Unicode_Path_cen_extra_field(z);
+    }
+  } else {
+    /* clear UTF-8 bit as not needed */
+    z->flg &= ~UTF8_BIT;
+    z->lflg &= ~UTF8_BIT;
+  }
+#endif
+
+  off = z->off;
+
+#ifdef ZIP64_SUPPORT        /* zip64 support 09/02/2003 R.Nausedat */
+  if (z->siz > ZIP_UWORD32_MAX || z->len > ZIP_UWORD32_MAX ||
+      z->off > ZIP_UWORD32_MAX || z->dsk > ZIP_UWORD16_MAX || (force_zip64 == 1))
+  {
+    iRes = add_central_zip64_extra_field(z);
+    if( iRes != ZE_OK )
+      return iRes;
+  }
+
+  append_ulong_to_mem(CENSIG, &block, &offset, &blocksize);     /* central file header signature */
+  append_ushort_to_mem(z->vem, &block, &offset, &blocksize);    /* version made by */
+  append_ushort_to_mem(z->ver, &block, &offset, &blocksize);    /* version needed to extract */
+  append_ushort_to_mem(z->flg, &block, &offset, &blocksize);    /* general purpose bit flag */
+  append_ushort_to_mem(z->how, &block, &offset, &blocksize);    /* compression method */
+  append_ulong_to_mem(z->tim, &block, &offset, &blocksize);     /* last mod file date time */
+  append_ulong_to_mem(z->crc, &block, &offset, &blocksize);     /* crc-32 */
+  if (z->siz > ZIP_UWORD32_MAX)
+  {
+    /* instead of z->siz */
+    append_ulong_to_mem(ZIP_UWORD32_MAX, &block, &offset, &blocksize); /* compressed size */
+  }
+  else
+  {
+    append_ulong_to_mem((ulg)z->siz, &block, &offset, &blocksize); /* compressed size */
+  }
+  /* if forcing Zip64 just force first ef field */
+  if (z->len > ZIP_UWORD32_MAX || (force_zip64 == 1))
+  {
+    /* instead of z->len */
+    append_ulong_to_mem(ZIP_UWORD32_MAX, &block, &offset, &blocksize); /* uncompressed size */
+  }
+  else
+  {
+    append_ulong_to_mem((ulg)z->len, &block, &offset, &blocksize); /* uncompressed size */
+  }
+  append_ushort_to_mem(nam, &block, &offset, &blocksize);       /* file name length */
+  append_ushort_to_mem(z->cext, &block, &offset, &blocksize);   /* extra field length */
+  append_ushort_to_mem(z->com, &block, &offset, &blocksize);    /* file comment length */
+
+  if (z->dsk > ZIP_UWORD16_MAX)
+  {
+    /* instead of z->dsk */
+    append_ushort_to_mem((ush)ZIP_UWORD16_MAX, &block, &offset, &blocksize); /* Zip64 flag */
+  }
+  else
+  {
+    append_ushort_to_mem((ush)z->dsk, &block, &offset, &blocksize);    /* disk number start */
+  }
+  append_ushort_to_mem(z->att, &block, &offset, &blocksize);    /* internal file attributes */
+  append_ulong_to_mem(z->atx, &block, &offset, &blocksize);     /* external file attributes */
+  if (off > ZIP_UWORD32_MAX)
+  {
+    /* instead of z->off */
+    append_ulong_to_mem(ZIP_UWORD32_MAX, &block, &offset, &blocksize); /* Zip64 flag */
+  }
+  else
+  {
+    append_ulong_to_mem((ulg)off, &block, &offset, &blocksize); /* offset of local header */
+  }
+
+#else /* !ZIP64_SUPPORT */
+
+  append_ulong_to_mem(CENSIG, &block, &offset, &blocksize);     /* central file header signature */
+  append_ushort_to_mem(z->vem, &block, &offset, &blocksize);    /* version made by */
+  append_ushort_to_mem(z->ver, &block, &offset, &blocksize);    /* version needed to extract */
+  append_ushort_to_mem(z->flg, &block, &offset, &blocksize);    /* general purpose bit flag */
+  append_ushort_to_mem(z->how, &block, &offset, &blocksize);    /* compression method */
+  append_ulong_to_mem(z->tim, &block, &offset, &blocksize);     /* last mod file date time */
+  append_ulong_to_mem(z->crc, &block, &offset, &blocksize);     /* crc-32 */
+  append_ulong_to_mem((ulg)z->siz, &block, &offset, &blocksize);  /* compressed size */
+  append_ulong_to_mem((ulg)z->len, &block, &offset, &blocksize);  /* uncompressed size */
+  append_ushort_to_mem(nam, &block, &offset, &blocksize);       /* file name length */
+  append_ushort_to_mem(z->cext, &block, &offset, &blocksize);   /* extra field length */
+  append_ushort_to_mem(z->com, &block, &offset, &blocksize);    /* file comment length */
+  append_ushort_to_mem((ush)z->dsk, &block, &offset, &blocksize); /* disk number start */
+  append_ushort_to_mem(z->att, &block, &offset, &blocksize);    /* internal file attributes */
+  append_ulong_to_mem(z->atx, &block, &offset, &blocksize);     /* external file attributes */
+  append_ulong_to_mem((ulg)off, &block, &offset, &blocksize);   /* relative offset of local header */
+
+#endif /* ZIP64_SUPPORT */
+
+#ifdef EBCDIC
+  if (z->com)
+    memtoasc(z->comment, z->comment, z->com);
+#endif /* EBCDIC */
+
+#ifdef UNICODE_SUPPORT
+  if (use_uname) {
+    /* path is UTF-8 */
+    append_string_to_mem(z->uname, nam, &block, &offset, &blocksize);
+  } else
+#endif
+#ifdef WIN32_OEM
+  /* store name in OEM character set in archive */
+  if ((z->vem & 0xff00) == 0)
+  {
+    char *oem;
+
+    if ((oem = malloc(strlen(z->iname) + 1)) == NULL)
+      ZIPERR(ZE_MEM, "putcentral oem");
+    INTERN_TO_OEM(z->iname, oem);
+    append_string_to_mem(oem, z->nam, &block, &offset, &blocksize);
+    free(oem);
+  } else {
+    append_string_to_mem(z->iname, z->nam, &block, &offset, &blocksize);
+  }
+#else
+  append_string_to_mem(z->iname, z->nam, &block, &offset, &blocksize);
+#endif
+
+  if (z->cext) {
+    append_string_to_mem(z->cextra, z->cext, &block, &offset, &blocksize);
+  }
+  if (z->com) {
+#ifdef WIN32_OEM
+    /* store comment in OEM character set in archive */
+    if ((z->vem & 0xff00) == 0)
+    {
+      char *oem;
+
+      if ((oem = malloc(strlen(z->comment) + 1)) == NULL)
+        ZIPERR(ZE_MEM, "putcentral oem comment");
+      INTERN_TO_OEM(z->comment, oem);
+      append_string_to_mem(oem, z->com, &block, &offset, &blocksize);
+      free(oem);
+    } else {
+      append_string_to_mem(z->comment, z->com, &block, &offset, &blocksize);
+    }
+#else
+    append_string_to_mem(z->comment, z->com, &block, &offset, &blocksize);
+#endif
+  }
+
+  /* write the header */
+  if (bfwrite(block, 1, offset, BFWRITE_CENTRALHEADER) != offset) {
+    free(block);
+    return ZE_TEMP;
+  }
+  free(block);
+
+  return ZE_OK;
+}
+
+
+/* Write the end of central directory data to file y.  Return an error code
+   in the ZE_ class. */
+
+int putend( OFT( uzoff_t) n,
+            OFT( uzoff_t) s,
+            OFT( uzoff_t) c,
+            OFT( extent) m,
+            OFT( char *) z
+          )
+#ifdef NO_PROTO
+  uzoff_t n;                /* number of entries in central directory */
+  uzoff_t s;                /* size of central directory */
+  uzoff_t c;                /* offset of central directory */
+  extent m;                 /* length of zip file comment (0 if none) */
+  char *z;                  /* zip file comment if m != 0 */
+#endif /* def NO_PROTO */
+{
+#ifdef ZIP64_SUPPORT        /* zip64 support 09/05/2003 R.Nausedat */
+  ush vem;          /* version made by */
+  int iNeedZip64 = 0;
+
+  char *block = NULL;   /* mem block to write to */
+  extent offset = 0;    /* offset into block */
+  extent blocksize = 0; /* size of block */
+
+  /* we have to create a zip64 archive if we have more than 64k - 1 entries,      */
+  /* if the CD is > 4 GB or if the offset to the CD > 4 GB. even if the CD start  */
+  /* is < 4 GB and CD start + CD size > 4GB we do not need a zip64 archive since  */
+  /* the offset entry in the CD tail is still valid.  [note that there are other  */
+  /* reasons for needing a Zip64 archive though, such as an uncompressed          */
+  /* size > 4 GB for an entry but the entry compresses below 4 GB, so the archive */
+  /* is Zip64 but the CD does not need Zip64.]                                    */
+  /* order of the zip/zip64 records in a zip64 archive:                           */
+  /* central directory                                                            */
+  /* zip64 end of central directory record                                        */
+  /* zip64 end of central directory locator                                       */
+  /* end of central directory record                                              */
+
+  /* check zip64_archive instead of force_zip64 3/19/05 */
+
+  zip64_eocd_disk = current_disk;
+  zip64_eocd_offset = bytes_this_split;
+
+  if( n > ZIP_UWORD16_MAX || s > ZIP_UWORD32_MAX || c > ZIP_UWORD32_MAX ||
+      zip64_archive )
+  {
+    ++iNeedZip64;
+    /* write zip64 central dir tail:  */
+    /*                                    */
+    /* 4 bytes   zip64 end of central dir signature (0x06064b50) */
+    append_ulong_to_mem((ulg)ZIP64_CENTRAL_DIR_TAIL_SIG, &block, &offset, &blocksize);
+    /* 8 bytes   size of zip64 end of central directory record */
+    /* a fixed size unless the end zip64 extensible data sector is used. - 3/19/05 EG */
+    /* also note that AppNote 6.2 creates version 2 of this record for
+       central directory encryption - 3/19/05 EG */
+    append_int64_to_mem((zoff_t)ZIP64_CENTRAL_DIR_TAIL_SIZE, &block, &offset, &blocksize);
+
+    /* 2 bytes   version made by */
+    vem = OS_CODE + Z_MAJORVER * 10 + Z_MINORVER;
+    append_ushort_to_mem(vem, &block, &offset, &blocksize);
+
+    /* APPNOTE says that zip64 archives should have at least version 4.5
+       in the "version needed to extract" field */
+    /* 2 bytes   version needed to extract */
+    append_ushort_to_mem(ZIP64_MIN_VER, &block, &offset, &blocksize);
+
+    /* 4 bytes   number of this disk */
+    append_ulong_to_mem(current_disk, &block, &offset, &blocksize);
+    /* 4 bytes   number of the disk with the start of the central directory */
+    append_ulong_to_mem(cd_start_disk, &block, &offset, &blocksize);
+    /* 8 bytes   total number of entries in the central directory on this disk */
+    append_int64_to_mem(cd_entries_this_disk, &block, &offset, &blocksize);
+    /* 8 bytes   total number of entries in the central directory */
+    append_int64_to_mem(n, &block, &offset, &blocksize);
+    /* 8 bytes   size of the central directory */
+    append_int64_to_mem(s, &block, &offset, &blocksize);
+    /* 8 bytes   offset of start of central directory with respect to the starting disk number */
+    append_int64_to_mem(cd_start_offset, &block, &offset, &blocksize);
+    /* zip64 extensible data sector    (variable size), we don't use it... */
+
+    /* write zip64 end of central directory locator:  */
+    /*                                                    */
+    /* 4 bytes   zip64 end of central dir locator  signature (0x07064b50) */
+    append_ulong_to_mem(ZIP64_CENTRAL_DIR_TAIL_END_SIG, &block, &offset, &blocksize);
+    /* 4 bytes   number of the disk with the start of the zip64 end of central directory */
+    append_ulong_to_mem(zip64_eocd_disk, &block, &offset, &blocksize);
+    /* 8 bytes   relative offset of the zip64 end of central directory record, that is */
+    /* offset of CD + CD size */
+    append_int64_to_mem(zip64_eocd_offset, &block, &offset, &blocksize);
+    /* PUTLLG(l64Temp, f); */
+    /* 4 bytes   total number of disks */
+    append_ulong_to_mem(current_disk + 1, &block, &offset, &blocksize);
+  }
+
+  /* end of central dir signature */
+  append_ulong_to_mem(ENDSIG, &block, &offset, &blocksize);
+    /* mv archives to come :)         */
+    /* for now use n for all          */
+    /* 2 bytes    number of this disk */
+  if (current_disk < 0xFFFF)
+    append_ushort_to_mem((ush)current_disk, &block, &offset, &blocksize);
+  else
+    append_ushort_to_mem((ush)0xFFFF, &block, &offset, &blocksize);
+  /* 2 bytes    number of the disk with the start of the central directory */
+  if (cd_start_disk == (ulg)-1)
+    cd_start_disk = 0;
+  if (cd_start_disk < 0xFFFF)
+    append_ushort_to_mem((ush)cd_start_disk, &block, &offset, &blocksize);
+  else
+    append_ushort_to_mem((ush)0xFFFF, &block, &offset, &blocksize);
+  /* 2 bytes    total number of entries in the central directory on this disk */
+  if (cd_entries_this_disk < 0xFFFF)
+    append_ushort_to_mem((ush)cd_entries_this_disk, &block, &offset, &blocksize);
+  else
+    append_ushort_to_mem((ush)0xFFFF, &block, &offset, &blocksize);
+  /* 2 bytes    total number of entries in the central directory */
+  if (total_cd_entries < 0xFFFF)
+    append_ushort_to_mem((ush)total_cd_entries, &block, &offset, &blocksize);
+  else
+    append_ushort_to_mem((ush)0xFFFF, &block, &offset, &blocksize);
+  if( s > ZIP_UWORD32_MAX )
+    /* instead of s */
+    append_ulong_to_mem(ZIP_UWORD32_MAX, &block, &offset, &blocksize);
+  else
+    /* 4 bytes    size of the central directory */
+    append_ulong_to_mem((ulg)s, &block, &offset, &blocksize);
+  if(force_zip64 == 1 || cd_start_offset > ZIP_UWORD32_MAX)
+    /* instead of cd_start_offset */
+    append_ulong_to_mem(ZIP_UWORD32_MAX, &block, &offset, &blocksize);
+  else
+    /* 4 bytes    offset of start of central directory with respect to the starting disk number */
+    append_ulong_to_mem((ulg)cd_start_offset, &block, &offset, &blocksize);
+
+#else /* !ZIP64_SUPPORT */
+  char *block = NULL;   /* mem block to write to */
+  extent offset = 0;    /* offset into block */
+  extent blocksize = 0; /* size of block */
+
+  /* end of central dir signature */
+  append_ulong_to_mem(ENDSIG, &block, &offset, &blocksize);
+  /* 2 bytes    number of this disk */
+  append_ushort_to_mem((ush)current_disk, &block, &offset, &blocksize);
+  /* 2 bytes    number of the disk with the start of the central directory */
+  append_ushort_to_mem((ush)cd_start_disk, &block, &offset, &blocksize);
+  /* 2 bytes    total number of entries in the central directory on this disk */
+  append_ushort_to_mem((ush)cd_entries_this_disk, &block, &offset, &blocksize);
+  /* 2 bytes    total number of entries in the central directory */
+  append_ushort_to_mem((ush)n, &block, &offset, &blocksize);
+  /* 4 bytes    size of the central directory */
+  append_ulong_to_mem((ulg)s, &block, &offset, &blocksize);
+  /* 4 bytes    offset of start of central directory with respect to the starting disk number */
+  append_ulong_to_mem((ulg)cd_start_offset, &block, &offset, &blocksize);
+#endif /* ZIP64_SUPPORT */
+
+  /* size of comment */
+  append_ushort_to_mem((ush)m, &block, &offset, &blocksize);
+  /* Write the comment, if any */
+#ifdef EBCDIC
+  memtoasc(z, z, m);
+#endif
+  if (m) {
+    /* PKWare defines the archive comment to be ASCII only so no OEM conversion */
+    append_string_to_mem(z, m, &block, &offset, &blocksize);
+  }
+
+  /* write the block */
+  if (bfwrite(block, 1, offset, BFWRITE_HEADER) != offset) {
+    free(block);
+    return ZE_TEMP;
+  }
+  free(block);
+
+#ifdef HANDLE_AMIGA_SFX
+  if (amiga_sfx_offset && zipbeg /* -J zeroes this */) {
+    s = zftello(y);
+    while (s & 3) s++, putc(0, f);   /* final marker must be longword aligned */
+    PUTLG(0xF2030000 /* 1010 in Motorola byte order */, f);
+    c = (s - amiga_sfx_offset - 4) / 4;  /* size of archive part in longwords */
+    if (zfseeko(y, amiga_sfx_offset, SEEK_SET) != 0)
+      return ZE_TEMP;
+    c = ((c >> 24) & 0xFF) | ((c >> 8) & 0xFF00)
+         | ((c & 0xFF00) << 8) | ((c & 0xFF) << 24);     /* invert byte order */
+    PUTLG(c, y);
+    zfseeko(y, 0, SEEK_END);                                  /* just in case */
+  }
+#endif
+
+  return ZE_OK;
+} /* end function putend() */
+
+
+
+/* Note: a zip "entry" includes a local header (which includes the file
+   name), an encryption header if encrypting, the compressed data
+   and possibly an extended local header. */
+
+int zipcopy(z)
+  struct zlist far *z;    /* zip entry to copy */
+/* Copy the zip entry described by *z from in_file to y.  Return an
+   error code in the ZE_ class.  Also update tempzn by the number of bytes
+   copied. */
+/* Now copies to global output file y */
+/* Handle entries that span disks */
+/* If fix == 2, assume in_file is pointing to a local header and fill
+   in z from local header */
+{
+  uzoff_t n;            /* holds local header offset */
+  ulg e = 0;            /* extended local header size */
+  ulg start_disk = 0;
+  uzoff_t start_offset = 0;
+  char *split_path;
+  char buf[LOCHEAD + 1];
+  struct zlist far *localz;
+  int r;
+
+
+  Trace((stderr, "zipcopy %s\n", z->zname));
+
+  /* if fix == 2 assume in_file open and pointing at local header */
+  if (fix != 2) {
+    start_disk = z->dsk;
+    start_offset = z->off;
+
+    /* don't assume reading the right disk */
+
+    /* if start not on current disk then close current disk */
+    if (start_disk != current_in_disk) {
+      if (in_file) {
+        fclose(in_file);
+        in_file = NULL;
+      }
+    }
+
+    current_in_disk = start_disk;
+
+    /* disks are archive.z01, archive.z02, ..., archive.zip */
+    split_path = get_in_split_path(in_path, current_in_disk);
+
+    if (in_file == NULL) {
+      while ((in_file = zfopen(split_path, FOPR)) == NULL) {
+        /* could not open split */
+
+        if (!noisy) {
+          ZIPERR(ZE_OPEN, split_path);
+        }
+
+        /* Ask for directory with split.  Updates global in_path */
+        r = ask_for_split_read_path(start_disk);
+        if (r == ZE_ABORT) {
+          /* user abort */
+          return ZE_ABORT;
+        } else if ((fix == 1 || fix == 2) && r == ZE_FORM) {
+          /* user asks to skip this disk */
+          return ZE_FORM;
+        }
+        free(split_path);
+        split_path = get_in_split_path(in_path, start_disk);
+      }
+    }
+
+    if (zfseeko(in_file, start_offset, SEEK_SET) != 0) {
+      fclose(in_file);
+      in_file = NULL;
+      zipwarn("reading archive fseek: ", strerror(errno));
+      return ZE_READ;
+    }
+  } /* fix != 2 */
+
+  if (fix != 2 && !at_signature(in_file, "PK\03\04")) {
+    fclose(in_file);
+    in_file = NULL;
+    zipwarn("Did not find entry for ", z->iname);
+    return ZE_FORM;
+  }
+
+  /* read local header */
+  if (fread(buf, LOCHEAD, 1, in_file) != 1) {
+    int f = ferror(in_file);
+    zipwarn("reading local entry: ", strerror(errno));
+    if (fix != 2)
+      fclose(in_file);
+    return f ? ZE_READ : ZE_EOF;
+  }
+
+  /* Local Header
+       local file header signature     4 bytes  (0x04034b50)
+       version needed to extract       2 bytes
+       general purpose bit flag        2 bytes
+       compression method              2 bytes
+       last mod file time              2 bytes
+       last mod file date              2 bytes
+       crc-32                          4 bytes
+       compressed size                 4 bytes
+       uncompressed size               4 bytes
+       file name length                2 bytes
+       extra field length              2 bytes
+
+       file name (variable size)
+       extra field (variable size)
+   */
+
+  if ((localz = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) {
+    zipwarn("reading entry", "");
+    if (fix != 2)
+      fclose(in_file);
+    return ZE_MEM;
+  }
+
+  localz->ver = SH(LOCVER + buf);
+  localz->lflg = SH(LOCFLG + buf);
+  localz->how = SH(LOCHOW + buf);
+  localz->tim = LG(LOCTIM + buf);          /* time and date into one long */
+  localz->crc = LG(LOCCRC + buf);
+  localz->nam = SH(LOCNAM + buf);
+  localz->ext = SH(LOCEXT + buf);
+  if (fix == 2) {
+    localz->siz = LG(LOCSIZ + buf);
+    localz->len = LG(LOCLEN + buf);
+  }
+
+  if (fix == 2) {
+    /* Do some sanity checks to make reasonably sure this is a local header */
+    ush os = localz->ver >> 8;
+    ush pkver = localz->ver - os;
+
+    /* OS - currently 0 - 18 (AppNote 6.3) and 30 (ATHEOS) */
+    if (os > 40) {
+      sprintf(errbuf, "Illegal host system mapping in local header:  %d", os);
+      zipwarn(errbuf, "");
+      zipwarn("Skipping:  ", z->iname);
+      return ZE_FORM;
+    }
+    /* PK Version - currently 10 - 62 (AppNote 6.2.2) */
+    /* If PKZip central directory encryption is used (62), the local header
+       values could be masked values.  Specifically, as of AppNote 6.2.2
+       the time, crc-32, and uncompressed file size are masked and the
+       file name is also replaced with a hex entry count.  Should
+       still be able to recover the entries, but they may be unreadable
+       without the 62 support fields. */
+    if (pkver > 100) {
+      sprintf(errbuf, "Illegal PK version mapping in local header:  %d", pkver);
+      zipwarn(errbuf, "");
+      zipwarn("Skipping:  ", z->iname);
+      return ZE_FORM;
+    }
+    /* Currently compression method is defined as 0 - 19 and 98 (AppNote 6.3) */
+    /* We can still copy an entry we can't read, but something over 200 is
+       probably illegal */
+    if (localz->how > 200) {
+      sprintf(errbuf, "Unrecognized compression method in local header:  %d", localz->how);
+      zipwarn(errbuf, "");
+      zipwarn("Skipping:  ", z->iname);
+      return ZE_FORM;
+    }
+
+    /* It's hard to make guesses on the other fields.  Suggestions welcome. */
+  }
+
+  /* Initialize all fields pointing to malloced data to NULL */
+  localz->zname = localz->name = localz->iname = localz->extra = NULL;
+  localz->oname = NULL;
+#ifdef UNICODE_SUPPORT
+  localz->uname = NULL;
+#endif
+
+  /* Read file name, extra field and comment field */
+  if ((localz->iname = malloc(localz->nam+1)) ==  NULL ||
+      (localz->ext && (localz->extra = malloc(localz->ext)) == NULL))
+    return ZE_MEM;
+  if (fread(localz->iname, localz->nam, 1, in_file) != 1 ||
+      (localz->ext && fread(localz->extra, localz->ext, 1, in_file) != 1))
+    return ferror(in_file) ? ZE_READ : ZE_EOF;
+  localz->iname[localz->nam] = '\0';                  /* terminate name */
+  if ((localz->name = malloc(localz->nam+1)) ==  NULL)
+    return ZE_MEM;
+  strcpy(localz->name, localz->iname);
+
+#ifdef ZIP64_SUPPORT
+  zip64_entry = adjust_zip_local_entry(localz);
+#endif
+
+  localz->vem = 0;
+  if (fix != 2) {
+    /* Need vem to determine if iname is Win32 OEM name */
+    localz->vem = z->vem;
+
+#ifdef UNICODE_SUPPORT
+    if (unicode_mismatch != 3) {
+      if (z->flg & UTF8_BIT) {
+        char *iname;
+        /* path is UTF-8 */
+        localz->uname = localz->iname;
+        iname = utf8_to_local_string(localz->uname);
+        if (iname == NULL) {
+          /* a bad UTF-8 character in name likely - go with (probably messed up) uname */
+          if ((localz->iname = malloc(strlen(localz->uname) + 1)) == NULL) {
+            return ZE_MEM;
+          }
+          strcpy(localz->iname, localz->uname);
+        } else {
+          /* go with local character set iname */
+          localz->iname = iname;
+        }
+      } else {
+        /* check for UTF-8 path extra field */
+        read_Unicode_Path_local_entry(localz);
+      }
+    }
+#endif
+
+#ifdef WIN32_OEM
+      /* If fix == 2 and reading local headers first, vem is not in the local
+         header so we don't know when to do OEM translation, as the ver field
+         is set to MSDOS (0) by all unless something specific is needed.
+         However, if local header has a Unicode path extra field, we can get
+         the real file name from there. */
+    if ((z->vem & 0xff00) == 0)
+      /* assume archive name is OEM if from DOS */
+      oem_to_local_string(localz->iname, localz->iname);
+#endif
+  }
+
+  if (fix == 2) {
+# ifdef WIN32
+#  ifdef UNICODE_SUPPORT
+    localz->namew = NULL;
+    localz->inamew = NULL;
+    localz->znamew = NULL;
+    z->namew = NULL;
+    z->inamew = NULL;
+    z->znamew = NULL;
+#  endif
+# endif
+    /* set z from localz */
+    z->flg = localz->lflg;
+    z->len = localz->len;
+    z->siz = localz->siz;
+
+  } else {
+    /* Compare localz to z */
+    if (localz->ver != z->ver) {
+      zipwarn("Local Version Needed To Extract does not match CD: ", z->iname);
+    }
+    if (localz->lflg != z->flg) {
+      zipwarn("Local Entry Flag does not match CD: ", z->iname);
+    }
+    if (!(z->flg & 8)) {
+      if (localz->crc != z->crc) {
+        zipwarn("Local Entry CRC does not match CD: ", z->iname);
+      }
+    }
+    if (fix != 3 && strcmp(localz->iname, z->iname) != 0) {
+      zipwarn("Local Entry name does not match CD: ", z->iname);
+    }
+
+    /* as copying get uncompressed and compressed sizes from central directory */
+    localz->len = z->len;
+    localz->siz = z->siz;
+  }
+
+#if 0
+  if (fix > 1) {
+    if (zfseeko(in_file, z->off + n, SEEK_SET)) /* seek to compressed data */
+      return ferror(in_file) ? ZE_READ : ZE_EOF;
+
+    if (fix > 2) {
+      /* Update length of entry's name, it may have been changed.  This is
+         needed to support the ZipNote ability to rename archive entries. */
+      z->nam = strlen(z->iname);
+      n = (uzoff_t)((LOCHEAD) + (ulg)z->nam + (ulg)z->ext);
+    }
+
+    /* do not trust the old compressed size */
+    if (putlocal(z, PUTLOCAL_WRITE) != ZE_OK)
+      return ZE_TEMP;
+
+    z->off = tempzn;
+    tempzn += n;
+    n = z->siz;
+  } else {
+    if (zfseeko(in_file, z->off, SEEK_SET))     /* seek to local header */
+      return ferror(in_file) ? ZE_READ : ZE_EOF;
+
+    z->off = tempzn;
+    n += z->siz;
+  }
+#endif
+
+  /* from zipnote */
+  if (fix == 3) {
+    /* Update length of entry's name, as it may have been changed.  This is
+       needed to support the ZipNote ability to rename archive entries. */
+    localz->nam = z->nam = strlen(z->iname);
+    /* update local name */
+    free(localz->iname);
+    if ((localz->iname = malloc(strlen(z->iname) + 1)) == NULL) {
+      zipwarn("out of memory in zipcopy", "");
+      return ZE_MEM;
+    }
+    strcpy(localz->iname, z->iname);
+  }
+
+  /* update disk and offset */
+  z->dsk = current_disk;
+  z->off = bytes_this_split;
+
+  /* copy the compressed data and the extended local header if there is one */
+
+  /* copy the compressed data.  We recreate the local header as the local
+     header can't be split and putlocal ensures it won't.  Also, since we
+     use siz and len from the central directory, we don't need the extended
+     local header if there is one, unless the file is encrypted as then the
+     extended header is used to indicate crypt head uses file time instead
+     of crc as the password check.
+
+     If fix = 2 then we don't have the central directory yet so keep
+     any data descriptors. */
+
+  if (fix != 2 && !(z->flg & 1)) {
+    /* Not encrypted */
+    localz->flg = z->flg &= ~8;
+    z->lflg = localz->lflg &= ~8;
+  }
+
+  e = 0;
+  if (z->lflg & 8) {
+#ifdef ZIP64_SUPPORT
+    if (zip64_entry)
+      e = 24;
+    else
+#endif
+      e = 16;
+  }
+  /* 4 is signature */
+  n = 4 + (uzoff_t)((LOCHEAD) + (ulg)(localz->nam) + (ulg)(localz->ext));
+
+  n += e + z->siz;
+  tempzn += n;
+
+  /* Output name */
+  if (fix == 2) {
+    if ((z->oname = malloc(strlen(localz->iname) + 1)) == NULL) {
+      return ZE_MEM;
+    }
+    strcpy(z->oname, localz->iname);
+#ifndef UTIL
+# ifdef WIN32
+    /* Win9x console always uses OEM character coding, and
+       WinNT console is set to OEM charset by default, too */
+    _INTERN_OEM(z->oname);
+# endif
+#endif
+    sprintf(errbuf, " copying: %s ", z->oname);
+    zipmessage_nl(errbuf, 0);
+  }
+
+  if (fix == 2)
+    z->crc = localz->crc;
+  else
+    localz->crc = z->crc;
+
+  if (putlocal(localz, PUTLOCAL_WRITE) != ZE_OK)
+      return ZE_TEMP;
+
+  /*
+  if (zfseeko(in_file, start_offset, SEEK_SET) != 0) {
+    fclose(in_file);
+    in_file = NULL;
+    zipwarn("reading archive fseek: ", strerror(errno));
+    return ZE_READ;
+  }
+  */
+
+  /* copy the data */
+  if (fix == 2 && localz->lflg & 8)
+    /* read to data descriptor */
+    r = bfcopy((uzoff_t) -2);
+  else
+    r = bfcopy(localz->siz);
+
+  if (r == ZE_ABORT) {
+      if (localz->ext) free(localz->extra);
+      if (localz->nam) free(localz->iname);
+      if (localz->nam) free(localz->name);
+#ifdef UNICODE_SUPPORT
+      if (localz->uname) free(localz->uname);
+#endif
+      free(localz);
+      ZIPERR(ZE_ABORT, "Could not find split");
+  }
+
+  if (r == ZE_EOF || skip_this_disk) {
+      /* missing disk */
+      zipwarn("aborting: ", z->oname);
+
+      if (r == ZE_OK)
+        r = ZE_FORM;
+
+      if (fix == 2) {
+#ifdef DEBUG
+        zoff_t here = zftello(y);
+#endif
+
+        /* fix == 2 skips right to next disk */
+        skip_this_disk = 0;
+
+        /* seek back in output to start of this entry so can overwrite */
+        if (zfseeko(y, current_local_offset, SEEK_SET) != 0) {
+          ZIPERR(ZE_WRITE, "seek failed on output file");
+        }
+        bytes_this_split = current_local_offset;
+        tempzn = current_local_offset;
+      }
+
+      /* tell scan to skip this entry */
+      if (localz->ext) free(localz->extra);
+      if (localz->nam) free(localz->iname);
+      if (localz->nam) free(localz->name);
+#ifdef UNICODE_SUPPORT
+      if (localz->uname) free(localz->uname);
+#endif
+      free(localz);
+      return r;
+  }
+
+  if (fix == 2 && z->flg & 8) {
+    /* this entry should have a data descriptor */
+    /* only -FF needs to read the descriptor as other modes
+       rely on the central directory */
+    if (des_good) {
+      /* found an apparently good data descriptor */
+      localz->crc = des_crc;
+      localz->siz = des_csize;
+      localz->len = des_usize;
+    } else {
+      /* no end to this entry found */
+      zipwarn("no end of stream entry found: ", z->oname);
+      zipwarn("rewinding and scanning for later entries", "");
+
+      /* seek back in output to start of this entry so can overwrite */
+      if (zfseeko(y, current_local_offset, SEEK_SET) != 0){
+
+      }
+
+      /* tell scan to skip this entry */
+      if (localz->ext) free(localz->extra);
+      if (localz->nam) free(localz->iname);
+      if (localz->nam) free(localz->name);
+#ifdef UNICODE_SUPPORT
+      if (localz->uname) free(localz->uname);
+#endif
+      free(localz);
+      return ZE_FORM;
+    }
+  }
+
+  if (z->flg & 8) {
+    putextended(localz);
+  }
+
+  /* now can close the split if local header on previous split */
+  if (split_method == 1 && current_local_disk != current_disk) {
+    close_split(current_local_disk, current_local_file, current_local_tempname);
+    current_local_file = NULL;
+    free(current_local_tempname);
+  }
+
+  /* update local header and close start split */
+  /* to use this need to seek back, do this, then come back
+  if (putlocal(localz, PUTLOCAL_REWRITE) != ZE_OK)
+    r = ZE_TEMP;
+  */
+
+  if (fix == 2) {
+    z->ver = localz->ver;
+    z->how = localz->how;
+    z->tim = localz->tim;
+    z->crc = localz->crc;
+    z->lflg = localz->lflg;
+    z->flg = localz->lflg;
+    z->len = localz->len;
+    z->siz = localz->siz;
+    z->nam = localz->nam;
+    z->ext = localz->ext;
+    z->extra = localz->extra;
+    /* copy local extra fields to central directory for now */
+    z->cext = localz->ext;
+    z->cextra = NULL;
+    if (localz->ext) {
+      if ((z->cextra = malloc(localz->ext + 1)) == NULL) {
+      return ZE_MEM;
+      }
+      strcpy(z->cextra, localz->extra);
+    }
+    z->com = 0;
+    z->att = 0;
+    z->atx = 0;
+    z->name = localz->name;
+    z->iname = localz->iname;
+#ifdef UNICODE_SUPPORT
+    z->uname = localz->uname;
+#endif
+    if ((z->zname = malloc(localz->nam + 1)) == NULL) {
+      return ZE_MEM;
+    }
+    strcpy(z->zname, z->iname);
+  } else {
+    if (localz->ext) free(localz->extra);
+    if (localz->nam) free(localz->iname);
+    if (localz->nam) free(localz->name);
+#ifdef UNICODE_SUPPORT
+    if (localz->uname) free(localz->uname);
+#endif
+    free(localz);
+  }
+
+  if (fix == 2) {
+    sprintf(errbuf, " (%s bytes)", zip_fzofft(z->siz, NULL, "u"));
+    zipmessage_nl(errbuf, 1);
+
+    if (r == ZE_READ) {
+      zipwarn("entry truncated: ", z->oname);
+      sprintf(errbuf, "expected compressed/stored size %s, actual %s",
+              zip_fzofft(localz->siz, NULL, "u"), zip_fzofft(bytes_this_entry, NULL, "u"));
+      zipwarn(errbuf, "");
+    }
+  }
+
+  return r;
+}
+
+
+
+#ifndef UTIL
+
+#ifdef USE_EF_UT_TIME
+
+local int ef_scan_ut_time(ef_buf, ef_len, ef_is_cent, z_utim)
+char *ef_buf;                   /* buffer containing extra field */
+extent ef_len;                  /* total length of extra field */
+int ef_is_cent;                 /* flag indicating "is central extra field" */
+iztimes *z_utim;                /* return storage: atime, mtime, ctime */
+/* This function scans the extra field for EF_TIME or EF_IZUNIX blocks
+ * containing Unix style time_t (GMT) values for the entry's access, creation
+ * and modification time.
+ * If a valid block is found, all time stamps are copied to the iztimes
+ * structure.
+ * The presence of an EF_TIME or EF_IZUNIX2 block results in ignoring
+ * all data from probably present obsolete EF_IZUNIX blocks.
+ * If multiple blocks of the same type are found, only the information from
+ * the last block is used.
+ * The return value is the EF_TIME Flags field (simulated in case of an
+ * EF_IZUNIX block) or 0 in case of failure.
+ */
+{
+  int flags = 0;
+  unsigned eb_id;
+  extent eb_len;
+  int have_new_type_eb = FALSE;
+
+  if (ef_len == 0 || ef_buf == NULL)
+    return 0;
+
+  Trace((stderr,"\nef_scan_ut_time: scanning extra field of length %u\n",
+         (unsigned)ef_len));
+  while (ef_len >= EB_HEADSIZE) {
+    eb_id = SH(EB_ID + ef_buf);
+    eb_len = SH(EB_LEN + ef_buf);
+
+    if (eb_len > (ef_len - EB_HEADSIZE)) {
+      /* Discovered some extra field inconsistency! */
+      Trace((stderr,"ef_scan_ut_time: block length %u > rest ef_size %u\n",
+             (unsigned)eb_len, (unsigned)(ef_len - EB_HEADSIZE)));
+      break;
+    }
+
+    switch (eb_id) {
+      case EF_TIME:
+        flags &= ~0x00ff;       /* ignore previous IZUNIX or EF_TIME fields */
+        have_new_type_eb = TRUE;
+        if ( eb_len >= EB_UT_MINLEN && z_utim != NULL) {
+           unsigned eb_idx = EB_UT_TIME1;
+           Trace((stderr,"ef_scan_ut_time: Found TIME extra field\n"));
+           flags |= (ef_buf[EB_HEADSIZE+EB_UT_FLAGS] & 0x00ff);
+           if ((flags & EB_UT_FL_MTIME)) {
+              if ((eb_idx+4) <= eb_len) {
+                 z_utim->mtime = LG((EB_HEADSIZE+eb_idx) + ef_buf);
+                 eb_idx += 4;
+                 Trace((stderr,"  Unix EF modtime = %ld\n", z_utim->mtime));
+              } else {
+                 flags &= ~EB_UT_FL_MTIME;
+                 Trace((stderr,"  Unix EF truncated, no modtime\n"));
+              }
+           }
+           if (ef_is_cent) {
+              break;            /* central version of TIME field ends here */
+           }
+           if (flags & EB_UT_FL_ATIME) {
+              if ((eb_idx+4) <= eb_len) {
+                 z_utim->atime = LG((EB_HEADSIZE+eb_idx) + ef_buf);
+                 eb_idx += 4;
+                 Trace((stderr,"  Unix EF acctime = %ld\n", z_utim->atime));
+              } else {
+                 flags &= ~EB_UT_FL_ATIME;
+              }
+           }
+           if (flags & EB_UT_FL_CTIME) {
+              if ((eb_idx+4) <= eb_len) {
+                 z_utim->ctime = LG((EB_HEADSIZE+eb_idx) + ef_buf);
+                 /* eb_idx += 4; */  /* superfluous for now ... */
+                 Trace((stderr,"  Unix EF cretime = %ld\n", z_utim->ctime));
+              } else {
+                 flags &= ~EB_UT_FL_CTIME;
+              }
+           }
+        }
+        break;
+
+      case EF_IZUNIX2:
+        if (!have_new_type_eb) {
+           flags &= ~0x00ff;    /* ignore any previous IZUNIX field */
+           have_new_type_eb = TRUE;
+        }
+        break;
+
+      case EF_IZUNIX:
+        if (eb_len >= EB_UX_MINLEN) {
+           Trace((stderr,"ef_scan_ut_time: Found IZUNIX extra field\n"));
+           if (have_new_type_eb) {
+              break;            /* Ignore IZUNIX extra field block ! */
+           }
+           z_utim->atime = LG((EB_HEADSIZE+EB_UX_ATIME) + ef_buf);
+           z_utim->mtime = LG((EB_HEADSIZE+EB_UX_MTIME) + ef_buf);
+           Trace((stderr,"  Unix EF access time = %ld\n",z_utim->atime));
+           Trace((stderr,"  Unix EF modif. time = %ld\n",z_utim->mtime));
+           flags |= (EB_UT_FL_MTIME | EB_UT_FL_ATIME);  /* signal success */
+        }
+        break;
+
+      case EF_THEOS:
+/*      printf("Not implemented yet\n"); */
+        break;
+
+      default:
+        break;
+    }
+    /* Skip this extra field block */
+    ef_buf += (eb_len + EB_HEADSIZE);
+    ef_len -= (eb_len + EB_HEADSIZE);
+  }
+
+  return flags;
+}
+
+int get_ef_ut_ztime(z, z_utim)
+struct zlist far *z;
+iztimes *z_utim;
+{
+  int r;
+
+#ifdef IZ_CHECK_TZ
+  if (!zp_tz_is_valid) return 0;
+#endif
+
+  /* First, scan local extra field. */
+  r = ef_scan_ut_time(z->extra, z->ext, FALSE, z_utim);
+
+  /* If this was not successful, try central extra field, but only if
+     it is really different. */
+  if (!r && z->cext > 0 && z->cextra != z->extra)
+    r = ef_scan_ut_time(z->cextra, z->cext, TRUE, z_utim);
+
+  return r;
+}
+
+#endif /* USE_EF_UT_TIME */
+
+
+local void cutpath(p, delim)
+char *p;                /* path string */
+int delim;              /* path component separator char */
+/* Cut the last path component off the name *p in place.
+ * This should work on both internal and external names.
+ */
+{
+  char *r;              /* pointer to last path delimiter */
+
+#ifdef VMS                      /* change [w.x.y]z to [w.x]y.DIR */
+  if ((r = MBSRCHR(p, ']')) != NULL)
+  {
+    *r = 0;
+    if ((r = MBSRCHR(p, '.')) != NULL)
+    {
+      *r = ']';
+      strcat(r, ".DIR;1");     /* this assumes a little padding--see PAD */
+    } else {
+      *p = 0;
+    }
+  } else {
+    if ((r = MBSRCHR(p, delim)) != NULL)
+      *r = 0;
+    else
+      *p = 0;
+  }
+#else /* !VMS */
+  if ((r = MBSRCHR(p, delim)) != NULL)
+    *r = 0;
+  else
+    *p = 0;
+#endif /* ?VMS */
+}
+
+int trash()
+/* Delete the compressed files and the directories that contained the deleted
+   files, if empty.  Return an error code in the ZE_ class.  Failure of
+   destroy() or deletedir() is ignored. */
+{
+  extent i;             /* counter on deleted names */
+  extent n;             /* number of directories to delete */
+  struct zlist far **s; /* table of zip entries to handle, sorted */
+  struct zlist far *z;  /* current zip entry */
+
+  /* Delete marked names and count directories */
+  n = 0;
+  for (z = zfiles; z != NULL; z = z->nxt)
+    if (z->mark == 1 || z->trash)
+    {
+      z->mark = 1;
+      if (z->iname[z->nam - 1] != (char)0x2f) { /* don't unlink directory */
+        if (verbose)
+          fprintf(mesg, "zip diagnostic: deleting file %s\n", z->name);
+        if (destroy(z->name)) {
+          zipwarn("error deleting ", z->name);
+        }
+        /* Try to delete all paths that lead up to marked names. This is
+         * necessary only with the -D option.
+         */
+        if (!dirnames) {
+          cutpath(z->name, '/');  /* XXX wrong ??? */
+          /* Below apparently does not work for Russian OEM but
+             '/' should be same as 0x2f for ascii and most ports so
+             changed it.  Did not trace through the mappings but
+             maybe 0x2F is mapped differently on OEM_RUSS - EG 2/28/2003 */
+          /* CS, 5/14/2005: iname is the byte array read from and written
+             to the zip archive; it MUST be ASCII (compatible)!!!
+             If something goes wrong with OEM_RUSS, there is a charcode
+             mapping error between external name (z->name) and iname somewhere
+             in the in2ex & ex2in code. The charcode translation should be
+             checked.
+             This code line is changed back to the original code. */
+          /* CS, 6/12/2005: What is handled here is the difference between
+             ASCII charsets and non-ASCII charsets like the family of EBCDIC
+             charsets.  On these systems, the slash character '/' is not coded
+             as 0x2f but as 0x61 (the ASCII 'a'). The iname struct member holds
+             the name as stored in the Zip file, which are ASCII or translated
+             into ASCII for new entries, whereas the "name" struct member hold
+             the external name, coded in the native charset of the system
+             (EBCDIC on EBCDIC systems) */
+          /* cutpath(z->iname, '/'); */ /* QQQ ??? */
+          cutpath(z->iname, 0x2f); /* 0x2f = ascii['/'] */
+          z->nam = strlen(z->iname);
+          if (z->nam > 0) {
+            z->iname[z->nam - 1] = (char)0x2f;
+            z->iname[z->nam++] = '\0';
+          }
+          if (z->nam > 0) n++;
+        }
+      } else {
+        n++;
+      }
+    }
+
+  /* Construct the list of all marked directories. Some may be duplicated
+   * if -D was used.
+   */
+  if (n)
+  {
+    if ((s = (struct zlist far **)malloc(n*sizeof(struct zlist far *))) ==
+        NULL)
+      return ZE_MEM;
+    n = 0;
+    for (z = zfiles; z != NULL; z = z->nxt) {
+      if (z->mark && z->nam > 0 && z->iname[z->nam - 1] == (char)0x2f /* '/' */
+          && (n == 0 || strcmp(z->name, s[n-1]->name) != 0)) {
+        s[n++] = z;
+      }
+    }
+    /* Sort the files in reverse order to get subdirectories first.
+     * To avoid problems with strange naming conventions as in VMS,
+     * we sort on the internal names, so x/y/z will always be removed
+     * before x/y. On VMS, x/y/z > x/y but [x.y.z] < [x.y]
+     */
+    qsort((char *)s, n, sizeof(struct zlist far *), rqcmp);
+
+    for (i = 0; i < n; i++) {
+      char *p = s[i]->name;
+      if (*p == '\0') continue;
+      if (p[strlen(p) - 1] == '/') { /* keep VMS [x.y]z.dir;1 intact */
+        p[strlen(p) - 1] = '\0';
+      }
+      if (i == 0 || strcmp(s[i]->name, s[i-1]->name) != 0) {
+        if (verbose) {
+          fprintf(mesg, "deleting directory %s (if empty)                \n",
+                  s[i]->name);
+        }
+        deletedir(s[i]->name);
+      }
+    }
+    free((zvoid *)s);
+  }
+  return ZE_OK;
+}
+
+#endif /* !UTIL */
diff --git a/zipnote.c b/zipnote.c
new file mode 100644 (file)
index 0000000..5e02cb6
--- /dev/null
+++ b/zipnote.c
@@ -0,0 +1,699 @@
+/*
+  zipnote.c - Zip 3
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  zipnote.c by Mark Adler.
+ */
+#define __ZIPNOTE_C
+
+#ifndef UTIL
+#define UTIL
+#endif
+#include "zip.h"
+#define DEFCPYRT        /* main module: enable copyright string defines! */
+#include "revision.h"
+#include <signal.h>
+
+/* Calculate size of static line buffer used in write (-w) mode. */
+#define WRBUFSIZ 2047
+/* The line buffer size should be at least as large as FNMAX. */
+#if FNMAX > WRBUFSIZ
+#  undef WRBUFSIZ
+#  define WRBUFSIZ FNMAX
+#endif
+
+/* Character to mark zip entry names in the comment file */
+#define MARK '@'
+#define MARKE " (comment above this line)"
+#define MARKZ " (zip file comment below this line)"
+
+/* Temporary zip file pointer */
+local FILE *tempzf;
+
+
+/* Local functions */
+local void handler OF((int));
+local void license OF((void));
+local void help OF((void));
+local void version_info OF((void));
+local void putclean OF((char *, extent));
+/* getline name conflicts with GNU getline() function */
+local char *zgetline OF((char *, extent));
+local int catalloc OF((char * far *, char *));
+int main OF((int, char **));
+
+/* keep compiler happy until implement long options - 11/4/2003 EG */
+struct option_struct far options[] = {
+  /* short longopt        value_type        negatable        ID    name */
+    {"h",  "help",        o_NO_VALUE,       o_NOT_NEGATABLE, 'h',  "help"},
+    /* the end of the list */
+    {NULL, NULL,          o_NO_VALUE,       o_NOT_NEGATABLE, 0,    NULL} /* end has option_ID = 0 */
+  };
+
+#ifdef MACOS
+#define ziperr(c, h)    zipnoteerr(c, h)
+#define zipwarn(a, b)   zipnotewarn(a, b)
+
+void zipnoteerr(int c, ZCONST char *h);
+void zipnotewarn(ZCONST char *a, ZCONST char *b);
+#endif
+
+#ifdef QDOS
+#define exit(p1) QDOSexit()
+#endif
+
+int set_filetype(out_path)
+  char *out_path;
+{
+#ifdef __BEOS__
+  /* Set the filetype of the zipfile to "application/zip" */
+  setfiletype( out_path, "application/zip" );
+#endif
+
+#ifdef __ATHEOS__
+  /* Set the filetype of the zipfile to "application/x-zip" */
+  setfiletype(out_path, "application/x-zip");
+#endif
+
+#ifdef MACOS
+  /* Set the Creator/Type of the zipfile to 'IZip' and 'ZIP ' */
+  setfiletype(out_path, 'IZip', 'ZIP ');
+#endif
+
+#ifdef RISCOS
+  /* Set the filetype of the zipfile to &DDC */
+  setfiletype(out_path, 0xDDC);
+#endif
+  return ZE_OK;
+}
+
+/* rename a split
+ * A split has a tempfile name until it is closed, then
+ * here rename it as out_path the final name for the split.
+ */
+int rename_split(temp_name, out_path)
+  char *temp_name;
+  char *out_path;
+{
+  int r;
+  /* Replace old zip file with new zip file, leaving only the new one */
+  if ((r = replace(out_path, temp_name)) != ZE_OK)
+  {
+    zipwarn("new zip file left as: ", temp_name);
+    free((zvoid *)tempzip);
+    tempzip = NULL;
+    ZIPERR(r, "was replacing split file");
+  }
+  if (zip_attributes) {
+    setfileattr(out_path, zip_attributes);
+  }
+  return ZE_OK;
+}
+
+void zipmessage_nl(a, nl)
+ZCONST char *a;     /* message string to output */
+int nl;             /* 1 = add nl to end */
+/* If nl false, print a message to mesg without new line.
+   If nl true, print and add new line.  If logfile is
+   open then also write message to log file. */
+{
+  if (noisy) {
+    fprintf(mesg, "%s", a);
+    if (nl) {
+      fprintf(mesg, "\n");
+      mesg_line_started = 0;
+    } else {
+      mesg_line_started = 1;
+    }
+    fflush(mesg);
+  }
+}
+
+void zipmessage(a, b)
+ZCONST char *a, *b;     /* message strings juxtaposed in output */
+/* Print a message to mesg and flush.  Also write to log file if
+   open.  Write new line first if current line has output already. */
+{
+  if (noisy) {
+    if (mesg_line_started)
+      fprintf(mesg, "\n");
+    fprintf(mesg, "%s%s\n", a, b);
+    mesg_line_started = 0;
+    fflush(mesg);
+  }
+}
+
+void ziperr(c, h)
+int c;                  /* error code from the ZE_ class */
+ZCONST char *h;         /* message about how it happened */
+/* Issue a message for the error, clean up files and memory, and exit. */
+{
+  if (PERR(c))
+    perror("zipnote error");
+  fprintf(mesg, "zipnote error: %s (%s)\n", ZIPERRORS(c), h);
+  if (tempzf != NULL)
+    fclose(tempzf);
+  if (tempzip != NULL)
+  {
+    destroy(tempzip);
+    free((zvoid *)tempzip);
+  }
+  if (zipfile != NULL)
+    free((zvoid *)zipfile);
+  EXIT(c);
+}
+
+
+local void handler(s)
+int s;                  /* signal number (ignored) */
+/* Upon getting a user interrupt, abort cleanly using ziperr(). */
+{
+#ifndef MSDOS
+  putc('\n', mesg);
+#endif /* !MSDOS */
+  ziperr(ZE_ABORT, "aborting");
+  s++;                                  /* keep some compilers happy */
+}
+
+
+void zipwarn(a, b)
+ZCONST char *a, *b;     /* message strings juxtaposed in output */
+/* Print a warning message to mesg (usually stderr) and return. */
+{
+  fprintf(mesg, "zipnote warning: %s%s\n", a, b);
+}
+
+
+local void license()
+/* Print license information to stdout. */
+{
+  extent i;             /* counter for copyright array */
+
+  for (i = 0; i < sizeof(swlicense)/sizeof(char *); i++)
+    puts(swlicense[i]);
+}
+
+
+local void help()
+/* Print help (along with license info) to stdout. */
+{
+  extent i;             /* counter for help array */
+
+  /* help array */
+  static ZCONST char *text[] = {
+"",
+"ZipNote %s (%s)",
+#ifdef VM_CMS
+"Usage:  zipnote [-w] [-q] [-b fm] zipfile",
+#else
+"Usage:  zipnote [-w] [-q] [-b path] zipfile",
+#endif
+"  the default action is to write the comments in zipfile to stdout",
+"  -w   write the zipfile comments from stdin",
+#ifdef VM_CMS
+"  -b   use \"fm\" as the filemode for the temporary zip file",
+#else
+"  -b   use \"path\" for the temporary zip file",
+#endif
+"  -q   quieter operation, suppress some informational messages",
+"  -h   show this help    -v   show version info    -L   show software license",
+"",
+"Example:",
+#ifdef VMS
+"     define/user sys$output foo.tmp",
+"     zipnote foo.zip",
+"     edit foo.tmp",
+"     ... then you edit the comments, save, and exit ...",
+"     define/user sys$input foo.tmp",
+"     zipnote -w foo.zip",
+#else
+#ifdef RISCOS
+"     zipnote foo/zip > foo/tmp",
+"     <!Edit> foo/tmp",
+"     ... then you edit the comments, save, and exit ...",
+"     zipnote -w foo/zip < foo/tmp",
+#else
+#ifdef VM_CMS
+"     zipnote foo.zip > foo.tmp",
+"     xedit foo tmp",
+"     ... then you edit the comments, save, and exit ...",
+"     zipnote -w foo.zip < foo.tmp",
+#else
+"     zipnote foo.zip > foo.tmp",
+"     ed foo.tmp",
+"     ... then you edit the comments, save, and exit ...",
+"     zipnote -w foo.zip < foo.tmp",
+#endif /* VM_CMS */
+#endif /* RISCOS */
+#endif /* VMS */
+"",
+"  \"@ name\" can be followed by an \"@=newname\" line to change the name"
+  };
+
+  for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
+    printf(copyright[i], "zipnote");
+    putchar('\n');
+  }
+  for (i = 0; i < sizeof(text)/sizeof(char *); i++)
+  {
+    printf(text[i], VERSION, REVDATE);
+    putchar('\n');
+  }
+}
+
+/*
+ * XXX put this in version.c
+ */
+
+local void version_info()
+/* Print verbose info about program version and compile time options
+   to stdout. */
+{
+  extent i;             /* counter in text arrays */
+
+  /* Options info array */
+  static ZCONST char *comp_opts[] = {
+#ifdef DEBUG
+    "DEBUG",
+#endif
+    NULL
+  };
+
+  for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
+  {
+    printf(copyright[i], "zipnote");
+    putchar('\n');
+  }
+
+  for (i = 0; i < sizeof(versinfolines)/sizeof(char *); i++)
+  {
+    printf(versinfolines[i], "ZipNote", VERSION, REVDATE);
+    putchar('\n');
+  }
+
+  version_local();
+
+  puts("ZipNote special compilation options:");
+  for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++)
+  {
+    printf("\t%s\n",comp_opts[i]);
+  }
+  if (i == 0)
+      puts("\t[none]");
+}
+
+
+local void putclean(s, n)
+char *s;                /* string to write to stdout */
+extent n;               /* length of string */
+/* Write the string s to stdout, filtering out control characters that are
+   not tab or newline (mainly to remove carriage returns), and prefix MARK's
+   and backslashes with a backslash.  Also, terminate with a newline if
+   needed. */
+{
+  int c;                /* next character in string */
+  int e;                /* last character written */
+
+  e = '\n';                     /* if empty, write nothing */
+  while (n--)
+  {
+    c = *(uch *)s++;
+    if (c == MARK || c == '\\')
+      putchar('\\');
+    if (c >= ' ' || c == '\t' || c == '\n')
+      { e=c; putchar(e); }
+  }
+  if (e != '\n')
+    putchar('\n');
+}
+
+
+local char *zgetline(buf, size)
+char *buf;
+extent size;
+/* Read a line of text from stdin into string buffer 'buf' of size 'size'.
+   In case of buffer overflow or EOF, a NULL pointer is returned. */
+{
+    char *line;
+    unsigned len;
+
+    line = fgets(buf, size, stdin);
+    if (line != NULL && (len = strlen(line)) > 0) {
+        if (len == size-1 && line[len-1] != '\n') {
+            /* buffer is full and record delimiter not seen -> overflow */
+            line = NULL;
+        } else {
+            /* delete trailing record delimiter */
+            if (line[len-1] == '\n') line[len-1] = '\0';
+        }
+    }
+    return line;
+}
+
+
+local int catalloc(a, s)
+char * far *a;          /* pointer to a pointer to a malloc'ed string */
+char *s;                /* string to concatenate on a */
+/* Concatentate the string s to the malloc'ed string pointed to by a.
+   Preprocess s by removing backslash escape characters. */
+{
+  char *p;              /* temporary pointer */
+  char *q;              /* temporary pointer */
+
+  for (p = q = s; *q; *p++ = *q++)
+    if (*q == '\\' && *(q+1))
+      q++;
+  *p = 0;
+  if ((p = malloc(strlen(*a) + strlen(s) + 3)) == NULL)
+    return ZE_MEM;
+  strcat(strcat(strcpy(p, *a), **a ? "\r\n" : ""), s);
+  free((zvoid *)*a);
+  *a = p;
+  return ZE_OK;
+}
+
+
+#ifndef USE_ZIPNOTEMAIN
+int main(argc, argv)
+#else
+int zipnotemain(argc, argv)
+#endif
+int argc;               /* number of tokens in command line */
+char **argv;            /* command line tokens */
+/* Write the comments in the zipfile to stdout, or read them from stdin. */
+{
+  char abf[WRBUFSIZ+1]; /* input line buffer */
+  char *a;              /* pointer to line buffer or NULL */
+  zoff_t c;             /* start of central directory */
+  int k;                /* next argument type */
+  char *q;              /* steps through option arguments */
+  int r;                /* arg counter, temporary variable */
+  zoff_t s;             /* length of central directory */
+  int t;                /* attributes of zip file */
+  int w;                /* true if updating zip file from stdin */
+  FILE *x;              /* input file for testing if can write it */
+  struct zlist far *z;  /* steps through zfiles linked list */
+
+#ifdef THEOS
+  setlocale(LC_CTYPE, "I");
+#endif
+
+#ifdef UNICODE_SUPPORT
+# ifdef UNIX
+  /* For Unix, set the locale to UTF-8.  Any UTF-8 locale is
+     OK and they should all be the same.  This allows seeing,
+     writing, and displaying (if the fonts are loaded) all
+     characters in UTF-8. */
+  {
+    char *loc;
+
+    /*
+      loc = setlocale(LC_CTYPE, NULL);
+      printf("  Initial language locale = '%s'\n", loc);
+    */
+
+    loc = setlocale(LC_CTYPE, "en_US.UTF-8");
+
+    /*
+      printf("langinfo %s\n", nl_langinfo(CODESET));
+    */
+
+    if (loc != NULL) {
+      /* using UTF-8 character set so can set UTF-8 GPBF bit 11 */
+      using_utf8 = 1;
+      /*
+        printf("  Locale set to %s\n", loc);
+      */
+    } else {
+      /*
+        printf("  Could not set Unicode UTF-8 locale\n");
+      */
+    }
+  }
+# endif
+#endif
+
+  /* If no args, show help */
+  if (argc == 1)
+  {
+    help();
+    EXIT(ZE_OK);
+  }
+
+  /* Direct info messages to stderr; stdout is used for data output. */
+  mesg = stderr;
+
+  init_upper();           /* build case map table */
+
+  /* Go through args */
+  zipfile = tempzip = NULL;
+  tempzf = NULL;
+  signal(SIGINT, handler);
+#ifdef SIGTERM              /* AMIGA has no SIGTERM */
+  signal(SIGTERM, handler);
+#endif
+#ifdef SIGABRT
+  signal(SIGABRT, handler);
+#endif
+#ifdef SIGBREAK
+  signal(SIGBREAK, handler);
+#endif
+#ifdef SIGBUS
+  signal(SIGBUS, handler);
+#endif
+#ifdef SIGILL
+  signal(SIGILL, handler);
+#endif
+#ifdef SIGSEGV
+  signal(SIGSEGV, handler);
+#endif
+  k = w = 0;
+  for (r = 1; r < argc; r++)
+    if (*argv[r] == '-') {
+      if (argv[r][1])
+        for (q = argv[r]+1; *q; q++)
+          switch (*q)
+          {
+            case 'b':   /* Specify path for temporary file */
+              if (k)
+                ziperr(ZE_PARMS, "use -b before zip file name");
+              else
+                k = 1;          /* Next non-option is path */
+              break;
+            case 'h':   /* Show help */
+              help();  EXIT(ZE_OK);
+            case 'l':  case 'L':  /* Show copyright and disclaimer */
+              license();  EXIT(ZE_OK);
+            case 'q':   /* Quiet operation, suppress info messages */
+              noisy = 0;  break;
+            case 'v':   /* Show version info */
+              version_info();  EXIT(ZE_OK);
+            case 'w':
+              w = 1;  break;
+            default:
+              ziperr(ZE_PARMS, "unknown option");
+          }
+      else
+        ziperr(ZE_PARMS, "zip file cannot be stdin");
+    } else
+      if (k == 0)
+      {
+        if (zipfile == NULL)
+        {
+          if ((zipfile = ziptyp(argv[r])) == NULL)
+            ziperr(ZE_MEM, "was processing arguments");
+        }
+        else
+          ziperr(ZE_PARMS, "can only specify one zip file");
+      }
+      else
+      {
+        tempath = argv[r];
+        k = 0;
+      }
+  if (zipfile == NULL)
+    ziperr(ZE_PARMS, "need to specify zip file");
+
+  if ((in_path = malloc(strlen(zipfile) + 1)) == NULL) {
+    ziperr(ZE_MEM, "input");
+  }
+  strcpy(in_path, zipfile);
+
+  /* Read zip file */
+  if ((r = readzipfile()) != ZE_OK)
+    ziperr(r, zipfile);
+  if (zfiles == NULL)
+    ziperr(ZE_NAME, zipfile);
+
+  /* Put comments to stdout, if not -w */
+  if (!w)
+  {
+    for (z = zfiles; z != NULL; z = z->nxt)
+    {
+      printf("%c %s\n", MARK, z->zname);
+      putclean(z->comment, z->com);
+      printf("%c%s\n", MARK, MARKE);
+    }
+    printf("%c%s\n", MARK, MARKZ);
+    putclean(zcomment, zcomlen);
+    EXIT(ZE_OK);
+  }
+
+  /* If updating comments, make sure zip file is writeable */
+  if ((x = fopen(zipfile, "a")) == NULL)
+    ziperr(ZE_CREAT, zipfile);
+  fclose(x);
+  t = getfileattr(zipfile);
+
+  /* Process stdin, replacing comments */
+  z = zfiles;
+  while ((a = zgetline(abf, WRBUFSIZ+1)) != NULL &&
+         (a[0] != MARK || strcmp(a + 1, MARKZ)))
+  {                                     /* while input and not file comment */
+    if (a[0] != MARK || a[1] != ' ')    /* better be "@ name" */
+      ziperr(ZE_NOTE, "unexpected input");
+    while (z != NULL && strcmp(a + 2, z->zname))
+      z = z->nxt;                       /* allow missing entries in order */
+    if (z == NULL)
+      ziperr(ZE_NOTE, "unknown entry name");
+    if ((a = zgetline(abf, WRBUFSIZ+1)) != NULL && a[0] == MARK && a[1] == '=')
+    {
+      if (z->name != z->iname)
+        free((zvoid *)z->iname);
+      if ((z->iname = malloc(strlen(a+1))) == NULL)
+        ziperr(ZE_MEM, "was changing name");
+#ifdef EBCDIC
+      strtoasc(z->iname, a+2);
+#else
+      strcpy(z->iname, a+2);
+#endif
+
+/*
+ * Don't update z->nam here, we need the old value a little later.....
+ * The update is handled in zipcopy().
+ */
+      a = zgetline(abf, WRBUFSIZ+1);
+    }
+    if (z->com)                         /* change zip entry comment */
+      free((zvoid *)z->comment);
+    z->comment = malloc(1);  *(z->comment) = 0;
+    while (a != NULL && *a != MARK)
+    {
+      if ((r = catalloc(&(z->comment), a)) != ZE_OK)
+        ziperr(r, "was building new zipentry comments");
+      a = zgetline(abf, WRBUFSIZ+1);
+    }
+    z->com = strlen(z->comment);
+    z = z->nxt;                         /* point to next entry */
+  }
+  if (a != NULL)                        /* change zip file comment */
+  {
+    zcomment = malloc(1);  *zcomment = 0;
+    while ((a = zgetline(abf, WRBUFSIZ+1)) != NULL)
+      if ((r = catalloc(&zcomment, a)) != ZE_OK)
+        ziperr(r, "was building new zipfile comment");
+    zcomlen = strlen(zcomment);
+  }
+
+  /* Open output zip file for writing */
+#if defined(UNIX) && !defined(NO_MKSTEMP)
+  {
+    int yd;
+    int i;
+
+    /* use mkstemp to avoid race condition and compiler warning */
+
+    if (tempath != NULL)
+    {
+      /* if -b used to set temp file dir use that for split temp */
+      if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
+        ZIPERR(ZE_MEM, "allocating temp filename");
+      }
+      strcpy(tempzip, tempath);
+      if (lastchar(tempzip) != '/')
+        strcat(tempzip, "/");
+    }
+    else
+    {
+      /* create path by stripping name and appending template */
+      if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
+      ZIPERR(ZE_MEM, "allocating temp filename");
+      }
+      strcpy(tempzip, zipfile);
+      for(i = strlen(tempzip); i > 0; i--) {
+        if (tempzip[i - 1] == '/')
+          break;
+      }
+      tempzip[i] = '\0';
+    }
+    strcat(tempzip, "ziXXXXXX");
+
+    if ((yd = mkstemp(tempzip)) == EOF) {
+      ZIPERR(ZE_TEMP, tempzip);
+    }
+    if ((tempzf = y = fdopen(yd, FOPW)) == NULL) {
+      ZIPERR(ZE_TEMP, tempzip);
+    }
+  }
+#else
+  if ((tempzf = y = fopen(tempzip = tempname(zipfile), FOPW)) == NULL)
+    ziperr(ZE_TEMP, tempzip);
+#endif
+
+  /* Open input zip file again, copy preamble if any */
+  if ((in_file = fopen(zipfile, FOPR)) == NULL)
+    ziperr(ZE_NAME, zipfile);
+
+  if (zipbeg && (r = bfcopy(zipbeg)) != ZE_OK)
+    ziperr(r, r == ZE_TEMP ? tempzip : zipfile);
+  tempzn = zipbeg;
+
+  /* Go through local entries, copying them over as is */
+  fix = 3; /* needed for zipcopy if name changed */
+  for (z = zfiles; z != NULL; z = z->nxt) {
+    if ((r = zipcopy(z)) != ZE_OK)
+      ziperr(r, "was copying an entry");
+  }
+  fclose(x);
+
+  /* Write central directory and end of central directory with new comments */
+  if ((c = zftello(y)) == (zoff_t)-1)    /* get start of central */
+    ziperr(ZE_TEMP, tempzip);
+  for (z = zfiles; z != NULL; z = z->nxt)
+    if ((r = putcentral(z)) != ZE_OK)
+      ziperr(r, tempzip);
+  if ((s = zftello(y)) == (zoff_t)-1)    /* get end of central */
+    ziperr(ZE_TEMP, tempzip);
+  s -= c;                       /* compute length of central */
+  if ((r = putend((zoff_t)zcount, s, c, zcomlen, zcomment)) != ZE_OK)
+    ziperr(r, tempzip);
+  tempzf = NULL;
+  if (fclose(y))
+    ziperr(ZE_TEMP, tempzip);
+  if ((r = replace(zipfile, tempzip)) != ZE_OK)
+  {
+    zipwarn("new zip file left as: ", tempzip);
+    free((zvoid *)tempzip);
+    tempzip = NULL;
+    ziperr(r, "was replacing the original zip file");
+  }
+  free((zvoid *)tempzip);
+  tempzip = NULL;
+  setfileattr(zipfile, t);
+#ifdef RISCOS
+  /* Set the filetype of the zipfile to &DDC */
+  setfiletype(zipfile,0xDDC);
+#endif
+  free((zvoid *)zipfile);
+  zipfile = NULL;
+
+  /* Done! */
+  RETURN(0);
+}
diff --git a/zipnote.txt b/zipnote.txt
new file mode 100644 (file)
index 0000000..cbafd28
--- /dev/null
@@ -0,0 +1,63 @@
+zipnote(1)                                                          zipnote(1)
+
+NAME
+       zipnote  -  write  the comments in zipfile to stdout, edit comments and
+       rename files in zipfile
+
+SYNOPSIS
+       zipnote [-w] [-b path] [-h] [-v] [-L] zipfile
+
+ARGUMENTS
+       zipfile  Zipfile to read comments from or edit.
+
+OPTIONS
+       -w     Write comments to a zipfile from stdin (see below).
+
+       -b path
+              Use path for the temporary zip file.
+
+       -h     Show a short help.
+
+       -v     Show version information.
+
+       -L     Show software license.
+
+DESCRIPTION
+       zipnote writes the comments in  a  zipfile  to  stdout.   This  is  the
+       default  mode.  A second mode allows updating the comments in a zipfile
+       as well as allows changing the names  of  the  files  in  the  zipfile.
+       These modes are described below.
+
+EXAMPLES
+       To write all comments in a zipfile to stdout use for example
+
+            zipnote foo.zip > foo.tmp
+
+       This  writes all comments in the zipfile foo.zip to the file foo.tmp in
+       a specific format.
+
+       If desired, this file can then be edited to  change  the  comments  and
+       then used to update the zipfile.
+
+            zipnote -w foo.zip < foo.tmp
+
+       The  names of the files in the zipfile can also be changed in this way.
+       This is done by following lines like
+            "@ name"
+       in the created temporary file (called foo.tmp here) with lines like
+            "@=newname"
+       and then using the -w option as above.
+
+BUGS
+       The temporary file format is rather  specific  and  zipnote  is  rather
+       picky  about it.  It should be easier to change file names in a script.
+
+       Does not yet support large (> 2 GB) or split archives.
+
+SEE ALSO
+       zip(1), unzip(1)
+
+AUTHOR
+       Info-ZIP
+
+                              v3.0 of 8 May 2008                    zipnote(1)
diff --git a/zipsplit.c b/zipsplit.c
new file mode 100644 (file)
index 0000000..8db76a1
--- /dev/null
@@ -0,0 +1,978 @@
+/*
+  zipsplit.c - Zip 3
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  zipsplit.c by Mark Adler.
+ */
+#define __ZIPSPLIT_C
+
+#ifndef UTIL
+#define UTIL
+#endif
+#include "zip.h"
+#define DEFCPYRT        /* main module: enable copyright string defines! */
+#include "revision.h"
+#include <signal.h>
+
+#define DEFSIZ 36000L   /* Default split size (change in help() too) */
+#ifdef MSDOS
+#  define NL 2          /* Number of bytes written for a \n */
+#else /* !MSDOS */
+#  define NL 1          /* Number of bytes written for a \n */
+#endif /* ?MSDOS */
+#ifdef RISCOS
+#  define INDEX "zipspl/idx"      /* Name of index file */
+#  define TEMPL_FMT "%%0%dld"
+#  define TEMPL_SIZ 13
+#  define ZPATH_SEP '.'
+#else
+#ifdef QDOS
+#  define ZPATH_SEP '_'
+#  define INDEX "zipsplit_idx"    /* Name of index file */
+#  define TEMPL_FMT "%%0%dld_zip"
+#  define TEMPL_SIZ 17
+#  define exit(p1) QDOSexit()
+#else
+#ifdef VM_CMS
+#  define INDEX "zipsplit.idx"    /* Name of index file */
+#  define TEMPL_FMT "%%0%dld.zip"
+#  define TEMPL_SIZ 21
+#  define ZPATH_SEP '.'
+#else
+#  define INDEX "zipsplit.idx"    /* Name of index file */
+#  define TEMPL_FMT "%%0%dld.zip"
+#  define TEMPL_SIZ 17
+#  define ZPATH_SEP '.'
+#endif /* VM_CMS */
+#endif /* QDOS */
+#endif /* RISCOS */
+
+#ifdef MACOS
+#define ziperr(c, h)    zipspliterr(c, h)
+#define zipwarn(a, b)   zipsplitwarn(a, b)
+void zipsplitwarn(ZCONST char *a, ZCONST char *b);
+void zipspliterr(int c, ZCONST char *h);
+#endif /* MACOS */
+
+/* Local functions */
+local zvoid *talloc OF((extent));
+local void tfree OF((zvoid *));
+local void tfreeall OF((void));
+local void handler OF((int));
+local void license OF((void));
+local void help OF((void));
+local void version_info OF((void));
+local extent simple OF((uzoff_t *, extent, uzoff_t, uzoff_t));
+local int descmp OF((ZCONST zvoid *, ZCONST zvoid *));
+local extent greedy OF((uzoff_t *, extent, uzoff_t, uzoff_t));
+local int retry OF((void));
+int main OF((int, char **));
+
+
+/* Output zip files */
+local char template[TEMPL_SIZ]; /* name template for output files */
+local int zipsmade = 0;         /* number of zip files made */
+local int indexmade = 0;        /* true if index file made */
+local char *path = NULL;        /* space for full name */
+local char *name;               /* where name goes in path[] */
+
+
+/* The talloc() and tree() routines extend malloc() and free() to keep
+   track of all allocated memory.  Then the tfreeall() routine uses this
+   information to free all allocated memory before exiting. */
+
+#define TMAX 6          /* set intelligently by examining the code */
+zvoid *talls[TMAX];     /* malloc'ed pointers to track */
+int talln = 0;          /* number of entries in talls[] */
+
+
+int set_filetype(out_path)
+  char *out_path;
+{
+#ifdef __BEOS__
+  /* Set the filetype of the zipfile to "application/zip" */
+  setfiletype( out_path, "application/zip" );
+#endif
+
+#ifdef __ATHEOS__
+  /* Set the filetype of the zipfile to "application/x-zip" */
+  setfiletype(out_path, "application/x-zip");
+#endif
+
+#ifdef MACOS
+  /* Set the Creator/Type of the zipfile to 'IZip' and 'ZIP ' */
+  setfiletype(out_path, 'IZip', 'ZIP ');
+#endif
+
+#ifdef RISCOS
+  /* Set the filetype of the zipfile to &DDC */
+  setfiletype(out_path, 0xDDC);
+#endif
+  return ZE_OK;
+}
+
+/* rename a split
+ * A split has a tempfile name until it is closed, then
+ * here rename it as out_path the final name for the split.
+ *
+ * This is not used in zipsplit but is referenced by the generic split
+ * writing code.  If zipsplit is made split aware (so can write splits of
+ * splits, if that makes sense) then this would get used.  But if that
+ * happens these utility versions should be dropped and the main ones
+ * used.
+ */
+int rename_split(temp_name, out_path)
+  char *temp_name;
+  char *out_path;
+{
+  int r;
+  /* Replace old zip file with new zip file, leaving only the new one */
+  if ((r = replace(out_path, temp_name)) != ZE_OK)
+  {
+    zipwarn("new zip file left as: ", temp_name);
+    free((zvoid *)tempzip);
+    tempzip = NULL;
+    ZIPERR(r, "was replacing split file");
+  }
+  if (zip_attributes) {
+    setfileattr(out_path, zip_attributes);
+  }
+  return ZE_OK;
+}
+
+void zipmessage_nl(a, nl)
+ZCONST char *a;     /* message string to output */
+int nl;             /* 1 = add nl to end */
+/* If nl false, print a message to mesg without new line.
+   If nl true, print and add new line.  If logfile is
+   open then also write message to log file. */
+{
+  if (noisy) {
+    fprintf(mesg, "%s", a);
+    if (nl) {
+      fprintf(mesg, "\n");
+      mesg_line_started = 0;
+    } else {
+      mesg_line_started = 1;
+    }
+    fflush(mesg);
+  }
+}
+
+void zipmessage(a, b)
+ZCONST char *a, *b;     /* message strings juxtaposed in output */
+/* Print a message to mesg and flush.  Also write to log file if
+   open.  Write new line first if current line has output already. */
+{
+  if (noisy) {
+    if (mesg_line_started)
+      fprintf(mesg, "\n");
+    fprintf(mesg, "%s%s\n", a, b);
+    mesg_line_started = 0;
+    fflush(mesg);
+  }
+}
+
+local zvoid *talloc(s)
+extent s;
+/* does a malloc() and saves the pointer to free later (does not check
+   for an overflow of the talls[] list) */
+{
+  zvoid *p;
+
+  if ((p = (zvoid *)malloc(s)) != NULL)
+    talls[talln++] = p;
+  return p;
+}
+
+
+local void tfree(p)
+zvoid *p;
+/* does a free() and also removes the pointer from the talloc() list */
+{
+  int i;
+
+  free(p);
+  i = talln;
+  while (i--)
+    if (talls[i] == p)
+      break;
+  if (i >= 0)
+  {
+    while (++i < talln)
+      talls[i - 1] = talls[i];
+    talln--;
+  }
+}
+
+
+local void tfreeall()
+/* free everything talloc'ed and not tfree'd */
+{
+  while (talln)
+    free(talls[--talln]);
+}
+
+
+void ziperr(c, h)
+int c;                  /* error code from the ZE_ class */
+ZCONST char *h;         /* message about how it happened */
+/* Issue a message for the error, clean up files and memory, and exit. */
+{
+  if (PERR(c))
+    perror("zipsplit error");
+  fprintf(mesg, "zipsplit error: %s (%s)\n", ZIPERRORS(c), h);
+  if (indexmade)
+  {
+    strcpy(name, INDEX);
+    destroy(path);
+  }
+  for (; zipsmade; zipsmade--)
+  {
+    sprintf(name, template, zipsmade);
+    destroy(path);
+  }
+  tfreeall();
+  if (zipfile != NULL)
+    free((zvoid *)zipfile);
+  EXIT(c);
+}
+
+
+local void handler(s)
+int s;                  /* signal number (ignored) */
+/* Upon getting a user interrupt, abort cleanly using ziperr(). */
+{
+#ifndef MSDOS
+  putc('\n', mesg);
+#endif /* !MSDOS */
+  ziperr(ZE_ABORT, "aborting");
+  s++;                                  /* keep some compilers happy */
+}
+
+
+void zipwarn(a, b)
+ZCONST char *a, *b;     /* message strings juxtaposed in output */
+/* Print a warning message to mesg (usually stderr) and return. */
+{
+  fprintf(mesg, "zipsplit warning: %s%s\n", a, b);
+}
+
+
+local void license()
+/* Print license information to stdout. */
+{
+  extent i;             /* counter for copyright array */
+
+  for (i = 0; i < sizeof(swlicense)/sizeof(char *); i++)
+    puts(swlicense[i]);
+}
+
+
+local void help()
+/* Print help (along with license info) to stdout. */
+{
+  extent i;             /* counter for help array */
+
+  /* help array */
+  static ZCONST char *text[] = {
+"",
+"ZipSplit %s (%s)",
+#ifdef VM_CMS
+"Usage:  zipsplit [-tipqs] [-n size] [-r room] [-b fm] zipfile",
+#else
+"Usage:  zipsplit [-tipqs] [-n size] [-r room] [-b path] zipfile",
+#endif
+"  -t   report how many files it will take, but don't make them",
+#ifdef RISCOS
+"  -i   make index (" INDEX ") and count its size against first zip file",
+#else
+"  -i   make index (zipsplit.idx) and count its size against first zip file",
+#endif
+"  -n   make zip files no larger than \"size\" (default = 36000)",
+"  -r   leave room for \"room\" bytes on the first disk (default = 0)",
+#ifdef VM_CMS
+"  -b   use \"fm\" as the filemode for the output zip files",
+#else
+"  -b   use \"path\" for the output zip files",
+#endif
+"  -q   quieter operation, suppress some informational messages",
+"  -p   pause between output zip files",
+"  -s   do a sequential split even if it takes more zip files",
+"  -h   show this help    -v   show version info    -L   show software license"
+  };
+
+  for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
+    printf(copyright[i], "zipsplit");
+    putchar('\n');
+  }
+  for (i = 0; i < sizeof(text)/sizeof(char *); i++)
+  {
+    printf(text[i], VERSION, REVDATE);
+    putchar('\n');
+  }
+}
+
+
+local void version_info()
+/* Print verbose info about program version and compile time options
+   to stdout. */
+{
+  extent i;             /* counter in text arrays */
+
+  /* Options info array */
+  static ZCONST char *comp_opts[] = {
+#ifdef DEBUG
+    "DEBUG",
+#endif
+    NULL
+  };
+
+  for (i = 0; i < sizeof(versinfolines)/sizeof(char *); i++)
+  {
+    printf(versinfolines[i], "ZipSplit", VERSION, REVDATE);
+    putchar('\n');
+  }
+
+  version_local();
+
+  puts("ZipSplit special compilation options:");
+  for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++)
+  {
+    printf("\t%s\n",comp_opts[i]);
+  }
+  if (i == 0)
+      puts("\t[none]");
+}
+
+
+local extent simple(a, n, c, d)
+uzoff_t *a;     /* items to put in bins, return value: destination bins */
+extent n;       /* number of items */
+uzoff_t c;      /* capacity of each bin */
+uzoff_t d;      /* amount to deduct from first bin */
+/* Return the number of bins of capacity c that are needed to contain the
+   integers in a[0..n-1] placed sequentially into the bins.  The value d
+   is deducted initially from the first bin (space for index).  The entries
+   in a[] are replaced by the destination bins. */
+{
+  extent k;     /* current bin number */
+  uzoff_t t;    /* space used in current bin */
+
+  t = k = 0;
+  while (n--)
+  {
+    if (*a + t > c - (k == 0 ? d : 0))
+    {
+      k++;
+      t = 0;
+    }
+    t += *a;
+    *(ulg huge *)a++ = k;
+  }
+  return k + 1;
+}
+
+
+local int descmp(a, b)
+ZCONST zvoid *a, *b;          /* pointers to pointers to ulg's to compare */
+/* Used by qsort() in greedy() to do a descending sort. */
+{
+  return **(uzoff_t **)a < **(uzoff_t **)b ? 1 :
+         (**(uzoff_t **)a > **(uzoff_t **)b ? -1 : 0);
+}
+
+
+local extent greedy(a, n, c, d)
+uzoff_t *a;         /* items to put in bins, return value: destination bins */
+extent n;       /* number of items */
+uzoff_t c;          /* capacity of each bin */
+uzoff_t d;          /* amount to deduct from first bin */
+/* Return the number of bins of capacity c that are needed to contain the
+   items with sizes a[0..n-1] placed non-sequentially into the bins.  The
+   value d is deducted initially from the first bin (space for index).
+   The entries in a[] are replaced by the destination bins. */
+{
+  uzoff_t *b;   /* space left in each bin (malloc'ed for each m) */
+  uzoff_t *e;   /* copy of argument a[] (malloc'ed) */
+  extent i;     /* steps through items */
+  extent j;     /* steps through bins */
+  extent k;     /* best bin to put current item in */
+  extent m;     /* current number of bins */
+  uzoff_t **s;  /* pointers to e[], sorted descending (malloc'ed) */
+  uzoff_t t;    /* space left in best bin (index k) */
+
+  /* Algorithm:
+     1. Copy a[] to e[] and sort pointers to e[0..n-1] (in s[]), in
+        descending order.
+     2. Compute total of s[] and set m to the smallest number of bins of
+        capacity c that can hold the total.
+     3. Allocate m bins.
+     4. For each item in s[], starting with the largest, put it in the
+        bin with the smallest current capacity greater than or equal to the
+        item's size.  If no bin has enough room, increment m and go to step 4.
+     5. Else, all items ended up in a bin--return m.
+  */
+
+  /* Copy a[] to e[], put pointers to e[] in s[], and sort s[].  Also compute
+     the initial number of bins (minus 1). */
+  if ((e = (uzoff_t *)malloc(n * sizeof(uzoff_t))) == NULL ||
+      (s = (uzoff_t **)malloc(n * sizeof(uzoff_t *))) == NULL)
+  {
+    if (e != NULL)
+      free((zvoid *)e);
+    ziperr(ZE_MEM, "was trying a smart split");
+    return 0;                           /* only to make compiler happy */
+  }
+  memcpy((char *)e, (char *)a, n * sizeof(uzoff_t));
+  for (t = i = 0; i < n; i++)
+    t += *(s[i] = e + i);
+  m = (extent)((t + c - 1) / c) - 1;    /* pre-decrement for loop */
+  qsort((char *)s, n, sizeof(ulg *), descmp);
+
+  /* Stuff bins until successful */
+  do {
+    /* Increment the number of bins, allocate and initialize bins */
+    if ((b = (uzoff_t *)malloc(++m * sizeof(uzoff_t))) == NULL)
+    {
+      free((zvoid *)s);
+      free((zvoid *)e);
+      ziperr(ZE_MEM, "was trying a smart split");
+    }
+    b[0] = c - d;                       /* leave space in first bin */
+    for (j = 1; j < m; j++)
+      b[j] = c;
+
+    /* Fill the bins greedily */
+    for (i = 0; i < n; i++)
+    {
+      /* Find smallest bin that will hold item i (size s[i]) */
+      t = c + 1;
+      for (k = j = 0; j < m; j++)
+        if (*s[i] <= b[j] && b[j] < t)
+          t = b[k = j];
+
+      /* If no bins big enough for *s[i], try next m */
+      if (t == c + 1)
+        break;
+
+      /* Diminish that bin and save where it goes */
+      b[k] -= *s[i];
+      a[(int)((uzoff_t huge *)(s[i]) - (uzoff_t huge *)e)] = k;
+    }
+
+    /* Clean up */
+    free((zvoid *)b);
+
+    /* Do until all items put in a bin */
+  } while (i < n);
+
+  /* Done--clean up and return the number of bins needed */
+  free((zvoid *)s);
+  free((zvoid *)e);
+  return m;
+}
+
+/* keep compiler happy until implement long options - 11/4/2003 EG */
+struct option_struct far options[] = {
+  /* short longopt        value_type        negatable        ID    name */
+    {"h",  "help",        o_NO_VALUE,       o_NOT_NEGATABLE, 'h',  "help"},
+    /* the end of the list */
+    {NULL, NULL,          o_NO_VALUE,       o_NOT_NEGATABLE, 0,    NULL} /* end has option_ID = 0 */
+  };
+
+
+local int retry()
+{
+  char m[10];
+  fputs("Error writing to disk--redo entire disk? ", mesg);
+  fgets(m, 10, stdin);
+  return *m == 'y' || *m == 'Y';
+}
+
+
+#ifndef USE_ZIPSPLITMAIN
+int main(argc, argv)
+#else
+int zipsplitmain(argc, argv)
+#endif
+
+int argc;               /* number of tokens in command line */
+char **argv;            /* command line tokens */
+/* Split a zip file into several zip files less than a specified size.  See
+   the command help in help() above. */
+{
+  uzoff_t *a;           /* malloc'ed list of sizes, dest bins */
+  extent *b;            /* heads of bin linked lists (malloc'ed) */
+  uzoff_t c;            /* bin capacity, start of central directory */
+  int d;                /* if true, just report the number of disks */
+  FILE *e;              /* input zip file */
+  FILE *f;              /* output index and zip files */
+  extent g;             /* number of bins from greedy(), entry to write */
+  int h;                /* how to split--true means simple split, counter */
+  zoff_t i = 0;            /* size of index file plus room to leave */
+  extent j;             /* steps through zip entries, bins */
+  int k;                /* next argument type */
+  extent *n = NULL;     /* next item in bin list (heads in b) */
+  uzoff_t *p;           /* malloc'ed list of sizes, dest bins for greedy() */
+  char *q;              /* steps through option characters */
+  int r;                /* temporary variable, counter */
+  extent s;             /* number of bins needed */
+  zoff_t t;             /* total of sizes, end of central directory */
+  int u;                /* flag to wait for user on output files */
+  struct zlist far **w; /* malloc'ed table for zfiles linked list */
+  int x;                /* if true, make an index file */
+  struct zlist far *z;  /* steps through zfiles linked list */
+#ifdef AMIGA
+  char tailchar;         /* temporary variable used in name generation below */
+#endif
+  char errbuf[5000];
+
+#ifdef THEOS
+  setlocale(LC_CTYPE, "I");
+#endif
+
+#ifdef UNICODE_SUPPORT
+# ifdef UNIX
+  /* For Unix, set the locale to UTF-8.  Any UTF-8 locale is
+     OK and they should all be the same.  This allows seeing,
+     writing, and displaying (if the fonts are loaded) all
+     characters in UTF-8. */
+  {
+    char *loc;
+
+    /*
+      loc = setlocale(LC_CTYPE, NULL);
+      printf("  Initial language locale = '%s'\n", loc);
+    */
+
+    loc = setlocale(LC_CTYPE, "en_US.UTF-8");
+
+    /*
+      printf("langinfo %s\n", nl_langinfo(CODESET));
+    */
+
+    if (loc != NULL) {
+      /* using UTF-8 character set so can set UTF-8 GPBF bit 11 */
+      using_utf8 = 1;
+      /*
+        printf("  Locale set to %s\n", loc);
+      */
+    } else {
+      /*
+        printf("  Could not set Unicode UTF-8 locale\n");
+      */
+    }
+  }
+# endif
+#endif
+
+  /* If no args, show help */
+  if (argc == 1)
+  {
+    help();
+    EXIT(ZE_OK);
+  }
+
+  /* Informational messages are written to stdout. */
+  mesg = stdout;
+
+  init_upper();           /* build case map table */
+
+  /* Go through args */
+  signal(SIGINT, handler);
+#ifdef SIGTERM                 /* Amiga has no SIGTERM */
+  signal(SIGTERM, handler);
+#endif
+#ifdef SIGABRT
+  signal(SIGABRT, handler);
+#endif
+#ifdef SIGBREAK
+  signal(SIGBREAK, handler);
+#endif
+#ifdef SIGBUS
+  signal(SIGBUS, handler);
+#endif
+#ifdef SIGILL
+  signal(SIGILL, handler);
+#endif
+#ifdef SIGSEGV
+  signal(SIGSEGV, handler);
+#endif
+  k = h = x = d = u = 0;
+  c = DEFSIZ;
+  for (r = 1; r < argc; r++)
+    if (*argv[r] == '-')
+    {
+      if (argv[r][1])
+        for (q = argv[r]+1; *q; q++)
+          switch (*q)
+          {
+            case 'b':   /* Specify path for output files */
+              if (k)
+                ziperr(ZE_PARMS, "options are separate and precede zip file");
+              else
+                k = 1;          /* Next non-option is path */
+              break;
+            case 'h':   /* Show help */
+              help();  EXIT(ZE_OK);
+            case 'i':   /* Make an index file */
+              x = 1;
+              break;
+            case 'l': case 'L':  /* Show copyright and disclaimer */
+              license();  EXIT(ZE_OK);
+            case 'n':   /* Specify maximum size of resulting zip files */
+              if (k)
+                ziperr(ZE_PARMS, "options are separate and precede zip file");
+              else
+                k = 2;          /* Next non-option is size */
+              break;
+            case 'p':
+              u = 1;
+              break;
+            case 'q':   /* Quiet operation, suppress info messages */
+              noisy = 0;
+              break;
+            case 'r':
+              if (k)
+                ziperr(ZE_PARMS, "options are separate and precede zip file");
+              else
+                k = 3;          /* Next non-option is room to leave */
+              break;
+            case 's':
+              h = 1;    /* Only try simple */
+              break;
+            case 't':   /* Just report number of disks */
+              d = 1;
+              break;
+            case 'v':   /* Show version info */
+              version_info();  EXIT(ZE_OK);
+            default:
+              ziperr(ZE_PARMS, "Use option -h for help.");
+          }
+      else
+        ziperr(ZE_PARMS, "zip file cannot be stdin");
+    }
+    else
+      switch (k)
+      {
+        case 0:
+          if (zipfile == NULL)
+          {
+            if ((zipfile = ziptyp(argv[r])) == NULL)
+              ziperr(ZE_MEM, "was processing arguments");
+          }
+          else
+            ziperr(ZE_PARMS, "can only specify one zip file");
+          break;
+        case 1:
+          tempath = argv[r];
+          k = 0;
+          break;
+        case 2:
+          if ((c = (ulg)atol(argv[r])) < 100)   /* 100 is smallest zip file */
+            ziperr(ZE_PARMS, "invalid size given. Use option -h for help.");
+          k = 0;
+          break;
+        default:        /* k must be 3 */
+          i = (ulg)atol(argv[r]);
+          k = 0;
+          break;
+      }
+  if (zipfile == NULL)
+    ziperr(ZE_PARMS, "need to specify zip file");
+
+  if ((in_path = malloc(strlen(zipfile) + 1)) == NULL) {
+    ziperr(ZE_MEM, "input");
+  }
+  strcpy(in_path, zipfile);
+
+  /* Read zip file */
+  if ((r = readzipfile()) != ZE_OK)
+    ziperr(r, zipfile);
+  if (zfiles == NULL)
+    ziperr(ZE_NAME, zipfile);
+
+  /* Make a list of sizes and check against capacity.  Also compute the
+     size of the index file. */
+  c -= ENDHEAD + 4;                     /* subtract overhead/zipfile */
+  if ((a = (uzoff_t *)talloc(zcount * sizeof(uzoff_t))) == NULL ||
+      (w = (struct zlist far **)talloc(zcount * sizeof(struct zlist far *))) ==
+       NULL)
+  {
+    ziperr(ZE_MEM, "was computing split");
+    return 1;
+  }
+  t = 0;
+  for (j = 0, z = zfiles; j < zcount; j++, z = z->nxt)
+  {
+    w[j] = z;
+    if (x)
+      i += z->nam + 6 + NL;
+    /* New scanzip_reg only reads central directory so use cext for ext */
+    t += a[j] = 8 + LOCHEAD + CENHEAD +
+           2 * (zoff_t)z->nam + 2 * (zoff_t)z->cext + z->com + z->siz;
+    if (a[j] > c) {
+      sprintf(errbuf, "Entry is larger than max split size of: %s",
+       zip_fzofft(c, NULL, "u"));
+      zipwarn(errbuf, "");
+      zipwarn("use -n to set split size", "");
+      ziperr(ZE_BIG, z->zname);
+    }
+  }
+
+  /* Decide on split to use, report number of files */
+  if (h)
+    s = simple(a, zcount, c, i);
+  else
+  {
+    if ((p = (uzoff_t *)talloc(zcount * sizeof(uzoff_t))) == NULL)
+      ziperr(ZE_MEM, "was computing split");
+    memcpy((char *)p, (char *)a, zcount * sizeof(uzoff_t));
+    s = simple(a, zcount, c, i);
+    g = greedy(p, zcount, c, i);
+    if (s <= g)
+      tfree((zvoid *)p);
+    else
+    {
+      tfree((zvoid *)a);
+      a = p;
+      s = g;
+    }
+  }
+  printf("%ld zip files w%s be made (%s%% efficiency)\n",
+         (ulg)s, d ? "ould" : "ill",
+         zip_fzofft( ((200 * ((t + c - 1)/c)) / s + 1) / 2, NULL, "d"));
+  if (d)
+  {
+    tfreeall();
+    free((zvoid *)zipfile);
+    zipfile = NULL;
+    EXIT(ZE_OK);
+  }
+
+  /* Set up path for output files */
+  /* Point "name" past the path, where the filename should go */
+  if ((path = (char *)talloc(tempath == NULL ? 13 : strlen(tempath) + 14)) ==
+      NULL)
+    ziperr(ZE_MEM, "was making output file names");
+  if (tempath == NULL)
+     name = path;
+  else
+  {
+#ifndef VM_CMS
+    /* Copy the output path to the target */
+    strcpy(path, tempath);
+#endif
+#ifdef AMIGA
+    tailchar = path[strlen(path) - 1];  /* last character */
+    if (path[0] && (tailchar != '/') && (tailchar != ':'))
+      strcat(path, "/");
+#else
+#ifdef RISCOS
+    if (path[0] && path[strlen(path) - 1] != '.')
+      strcat(path, ".");
+#else
+#ifdef QDOS
+    if (path[0] && path[strlen(path) - 1] != '_')
+      strcat(path, "_");
+#else
+#ifndef VMS
+    if (path[0] && path[strlen(path) - 1] != '/')
+      strcat(path, "/");
+#endif /* !VMS */
+#endif /* ?QDOS */
+#endif /* ?RISCOS */
+#endif /* ?AMIGA */
+    name = path + strlen(path);
+  }
+
+  /* Make linked lists of results */
+  if ((b = (extent *)talloc(s * sizeof(extent))) == NULL ||
+      (n = (extent *)talloc(zcount * sizeof(extent))) == NULL)
+    ziperr(ZE_MEM, "was computing split");
+  for (j = 0; j < s; j++)
+    b[j] = (extent)-1;
+  j = zcount;
+  while (j--)
+  {
+    g = (extent)a[j];
+    n[j] = b[g];
+    b[g] = j;
+  }
+
+  /* Make a name template for the zip files that is eight or less characters
+     before the .zip, and that will not overwrite the original zip file. */
+  for (k = 1, j = s; j >= 10; j /= 10)
+    k++;
+  if (k > 7)
+    ziperr(ZE_PARMS, "way too many zip files must be made");
+/*
+ * XXX, ugly ....
+ */
+/* Find the final "path" separator character */
+#ifdef QDOS
+  q = LastDir(zipfile);
+#else
+#ifdef VMS
+  if ((q = strrchr(zipfile, ']')) != NULL)
+#else
+#ifdef AMIGA
+  if (((q = strrchr(zipfile, '/')) != NULL)
+                       || ((q = strrchr(zipfile, ':'))) != NULL)
+#else
+#ifdef RISCOS
+  if ((q = strrchr(zipfile, '.')) != NULL)
+#else
+#ifdef MVS
+  if ((q = strrchr(zipfile, '.')) != NULL)
+#else
+  if ((q = strrchr(zipfile, '/')) != NULL)
+#endif /* MVS */
+#endif /* RISCOS */
+#endif /* AMIGA */
+#endif /* VMS */
+    q++;
+  else
+    q = zipfile;
+#endif /* QDOS */
+
+  r = 0;
+  while ((g = *q++) != '\0' && g != ZPATH_SEP && r < 8 - k)
+    template[r++] = (char)g;
+  if (r == 0)
+    template[r++] = '_';
+  else if (g >= '0' && g <= '9')
+    template[r - 1] = (char)(template[r - 1] == '_' ? '-' : '_');
+  sprintf(template + r, TEMPL_FMT, k);
+#ifdef VM_CMS
+  /* For CMS, add the "path" as the filemode at the end */
+  if (tempath)
+  {
+     strcat(template,".");
+     strcat(template,tempath);
+  }
+#endif
+
+  /* Make the zip files from the linked lists of entry numbers */
+  if ((e = fopen(zipfile, FOPR)) == NULL)
+    ziperr(ZE_NAME, zipfile);
+  free((zvoid *)zipfile);
+  zipfile = NULL;
+  for (j = 0; j < s; j++)
+  {
+    /* jump here on a disk retry */
+  redobin:
+
+    current_disk = 0;
+    cd_start_disk = 0;
+    cd_entries_this_disk = 0;
+
+    /* prompt if requested */
+    if (u)
+    {
+      char m[10];
+      fprintf(mesg, "Insert disk #%ld of %ld and hit return: ",
+              (ulg)j + 1, (ulg)s);
+      fgets(m, 10, stdin);
+    }
+
+    /* write index file on first disk if requested */
+    if (j == 0 && x)
+    {
+      strcpy(name, INDEX);
+      printf("creating: %s\n", path);
+      indexmade = 1;
+      if ((f = fopen(path, "w")) == NULL)
+      {
+        if (u && retry()) goto redobin;
+        ziperr(ZE_CREAT, path);
+      }
+      for (j = 0; j < zcount; j++)
+        fprintf(f, "%5s %s\n",
+         zip_fzofft( (a[j] + 1), NULL, "d"), w[j]->zname);
+
+      if ((j = ferror(f)) != 0 || fclose(f))
+      {
+        if (j)
+          fclose(f);
+        if (u && retry()) goto redobin;
+        ziperr(ZE_WRITE, path);
+      }
+    }
+
+    /* create output zip file j */
+    sprintf(name, template, j + 1L);
+    printf("creating: %s\n", path);
+    zipsmade = j + 1;
+    if ((y = f = fopen(path, FOPW)) == NULL)
+    {
+      if (u && retry()) goto redobin;
+      ziperr(ZE_CREAT, path);
+    }
+    bytes_this_split = 0;
+    tempzn = 0;
+
+    /* write local headers and copy compressed data */
+    for (g = b[j]; g != (extent)-1; g = (extent)n[g])
+    {
+      if (zfseeko(e, w[g]->off, SEEK_SET))
+        ziperr(ferror(e) ? ZE_READ : ZE_EOF, zipfile);
+      in_file = e;
+      if ((r = zipcopy(w[g])) != ZE_OK)
+      {
+        if (r == ZE_TEMP)
+        {
+          if (u && retry()) goto redobin;
+          ziperr(ZE_WRITE, path);
+        }
+        else
+          ziperr(r, zipfile);
+      }
+    }
+
+    /* write central headers */
+    if ((c = zftello(f)) == (uzoff_t)-1)
+    {
+      if (u && retry()) goto redobin;
+      ziperr(ZE_WRITE, path);
+    }
+    for (g = b[j], k = 0; g != (extent)-1; g = n[g], k++)
+      if ((r = putcentral(w[g])) != ZE_OK)
+      {
+        if (u && retry()) goto redobin;
+        ziperr(ZE_WRITE, path);
+      }
+
+    /* write end-of-central header */
+    cd_start_offset = c;
+    total_cd_entries = k;
+    if ((t = zftello(f)) == (zoff_t)-1 ||
+        (r = putend((zoff_t)k, t - c, c, (extent)0, (char *)NULL)) !=
+        ZE_OK ||
+        ferror(f) || fclose(f))
+    {
+      if (u && retry()) goto redobin;
+      ziperr(ZE_WRITE, path);
+    }
+#ifdef RISCOS
+    /* Set the filetype to &DDC */
+    setfiletype(path,0xDDC);
+#endif
+  }
+  fclose(e);
+
+  /* Done! */
+  if (u)
+    fputs("Done.\n", mesg);
+  tfreeall();
+
+  RETURN(0);
+}
diff --git a/zipsplit.txt b/zipsplit.txt
new file mode 100644 (file)
index 0000000..bd78ad7
--- /dev/null
@@ -0,0 +1,53 @@
+zipnote(1)                                                          zipnote(1)
+
+NAME
+       zipsplit - split a zipfile into smaller zipfiles
+
+SYNOPSIS
+       zipsplit  [-t]  [-i]  [-p] [-s] [-n size] [-r room] [-b path] [-h] [-v]
+       [-L] zipfile
+
+ARGUMENTS
+       zipfile  Zipfile to split.
+
+OPTIONS
+       -t     Report how many files it will take, but don't make them.
+
+       -i     Make index (zipsplit.idx) and count its size against  first  zip
+              file.
+
+       -n size
+              Make zip files no larger than "size" (default = 36000).
+
+       -r room
+              Leave room for "room" bytes on the first disk (default = 0).
+
+       -b path
+              Use path for the output zip files.
+
+       -p     Pause between output zip files.
+
+       -s     Do a sequential split even if it takes more zip files.
+
+       -h     Show a short help.
+
+       -v     Show version information.
+
+       -L     Show software license.
+
+DESCRIPTION
+       zipsplit reads a zipfile and splits it into smaller zipfiles.
+
+EXAMPLES
+       To be filled in.
+
+BUGS
+       Does not yet support large (> 2 GB) or split archives.
+
+SEE ALSO
+       zip(1), unzip(1)
+
+AUTHOR
+       Info-ZIP
+
+                              v3.0 of 8 May 2008                    zipnote(1)
diff --git a/zipup.c b/zipup.c
new file mode 100644 (file)
index 0000000..39f7d9c
--- /dev/null
+++ b/zipup.c
@@ -0,0 +1,1922 @@
+/*
+  zipup.c - Zip 3
+
+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2007-Mar-4 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ *  zipup.c by Mark Adler and Jean-loup Gailly.
+ */
+#define __ZIPUP_C
+
+/* Found that for at least unix port zip.h has to be first or ctype.h will
+   define off_t and when using 64-bit file environment off_t in other files
+   is 8 bytes while off_t here is 4 bytes, and this makes the zlist struct
+   different sizes and needless to say leads to segmentation faults.  Putting
+   zip.h first seems to fix this.  8/14/04 EG */
+#include "zip.h"
+#include <ctype.h>
+#include <errno.h>
+
+#ifndef UTIL            /* This module contains no code for Zip Utilities */
+
+#include "revision.h"
+#include "crc32.h"
+#include "crypt.h"
+#ifdef USE_ZLIB
+#  include "zlib.h"
+#endif
+#ifdef BZIP2_SUPPORT
+#  ifdef BZIP2_USEBZIP2DIR
+#    include "bzip2/bzlib.h"
+#  else
+#    include "bzlib.h"
+#  endif
+#endif
+
+#ifdef OS2
+#  include "os2/os2zip.h"
+#endif
+
+#if defined(MMAP)
+#  include <sys/mman.h>
+#  ifndef PAGESIZE   /* used to be SYSV, what about pagesize on SVR3 ? */
+#    define PAGESIZE getpagesize()
+#  endif
+#  if defined(NO_VALLOC) && !defined(valloc)
+#    define valloc malloc
+#  endif
+#endif
+
+/* Use the raw functions for MSDOS and Unix to save on buffer space.
+   They're not used for VMS since it doesn't work (raw is weird on VMS).
+ */
+
+#ifdef AMIGA
+#  include "amiga/zipup.h"
+#endif /* AMIGA */
+
+#ifdef AOSVS
+#  include "aosvs/zipup.h"
+#endif /* AOSVS */
+
+#ifdef ATARI
+#  include "atari/zipup.h"
+#endif
+
+#ifdef __BEOS__
+#  include "beos/zipup.h"
+#endif
+
+#ifdef __ATHEOS__
+#  include "atheos/zipup.h"
+#endif /* __ATHEOS__ */
+
+#ifdef __human68k__
+#  include "human68k/zipup.h"
+#endif /* __human68k__ */
+
+#ifdef MACOS
+#  include "macos/zipup.h"
+#endif
+
+#ifdef DOS
+#  include "msdos/zipup.h"
+#endif /* DOS */
+
+#ifdef NLM
+#  include "novell/zipup.h"
+#  include <nwfattr.h>
+#endif
+
+#ifdef OS2
+#  include "os2/zipup.h"
+#endif /* OS2 */
+
+#ifdef RISCOS
+#  include "acorn/zipup.h"
+#endif
+
+#ifdef TOPS20
+#  include "tops20/zipup.h"
+#endif
+
+#ifdef UNIX
+#  include "unix/zipup.h"
+#endif
+
+#ifdef CMS_MVS
+#  include "zipup.h"
+#endif /* CMS_MVS */
+
+#ifdef TANDEM
+#  include "zipup.h"
+#endif /* TANDEM */
+
+#ifdef VMS
+#  include "vms/zipup.h"
+#endif /* VMS */
+
+#ifdef QDOS
+#  include "qdos/zipup.h"
+#endif /* QDOS */
+
+#ifdef WIN32
+#  include "win32/zipup.h"
+#endif
+
+#ifdef THEOS
+#  include "theos/zipup.h"
+#endif
+
+/* Local functions */
+#ifndef RISCOS
+   local int suffixes OF((char *, char *));
+#else
+   local int filetypes OF((char *, char *));
+#endif
+local unsigned file_read OF((char *buf, unsigned size));
+#ifdef USE_ZLIB
+  local int zl_deflate_init OF((int pack_level));
+#else /* !USE_ZLIB */
+# ifdef ZP_NEED_MEMCOMPR
+    local unsigned mem_read OF((char *buf, unsigned size));
+# endif
+#endif /* ?USE_ZLIB */
+
+/* zip64 support 08/29/2003 R.Nausedat */
+local zoff_t filecompress OF((struct zlist far *z_entry, int *cmpr_method));
+
+#ifdef BZIP2_SUPPORT
+local zoff_t bzfilecompress OF((struct zlist far *z_entry, int *cmpr_method));
+#endif
+
+/* Deflate "internal" global data (currently not in zip.h) */
+#if defined(MMAP) || defined(BIG_MEM)
+# ifdef USE_ZLIB
+    local uch *window = NULL;   /* Used to read all input file at once */
+    local ulg window_size;      /* size of said window */
+# else /* !USE_ZLIB */
+    extern uch *window;         /* Used to read all input file at once */
+#endif /* ?USE_ZLIB */
+#endif /* MMAP || BIG_MEM */
+#ifndef USE_ZLIB
+  extern ulg window_size;       /* size of said window */
+
+  unsigned (*read_buf) OF((char *buf, unsigned size)) = file_read;
+  /* Current input function. Set to mem_read for in-memory compression */
+#endif /* !USE_ZLIB */
+
+
+/* Local data */
+local ulg crc;                  /* crc on uncompressed file data */
+local ftype ifile;              /* file to compress */
+#if defined(MMAP) || defined(BIG_MEM)
+  local ulg remain;
+  /* window bytes not yet processed.
+   *  special value "(ulg)-1L" reserved to signal normal reads.
+   */
+#endif /* MMAP || BIG_MEM */
+#ifdef USE_ZLIB
+  local int deflInit = FALSE;   /* flag: zlib deflate is initialized */
+  local z_stream zstrm;         /* zlib's data interface structure */
+  local char *f_ibuf = NULL;
+  local char *f_obuf = NULL;
+#else /* !USE_ZLIB */
+  local char file_outbuf[1024]; /* output buffer for compression to file */
+
+# ifdef ZP_NEED_MEMCOMPR
+    local char *in_buf;
+    /* Current input buffer, in_buf is used only for in-memory compression. */
+    local unsigned in_offset;
+    /* Current offset in input buffer. in_offset is used only for in-memory
+     * compression. On 16 bit machines, the buffer is limited to 64K.
+     */
+    local unsigned in_size;     /* size of current input buffer */
+# endif /* ZP_NEED_MEMCOMPR */
+#endif /* ?USE_ZLIB */
+
+#ifdef BZIP2_SUPPORT
+    local int bzipInit;         /* flag: bzip2lib is initialized */
+    local bz_stream bstrm;      /* zlib's data interface structure */
+# if !defined(USE_ZLIB)
+    local char *f_ibuf = NULL;
+    local char *f_obuf = NULL;
+# endif /* !USE_ZLIB */
+#endif /* BZIP2_SUPPORT */
+
+#ifdef DEBUG
+    zoff_t isize;               /* input file size. global only for debugging */
+#else /* !DEBUG */
+    local zoff_t isize;         /* input file size. global only for debugging */
+#endif /* ?DEBUG */
+  /* If file_read detects binary it sets this flag - 12/16/04 EG */
+  local int file_binary = 0;        /* first buf */
+  local int file_binary_final = 0;  /* for bzip2 for entire file.  assume text until find binary */
+
+
+/* moved check to function 3/14/05 EG */
+int is_seekable(y)
+  FILE *y;
+{
+  zoff_t pos;
+
+#ifdef BROKEN_FSEEK
+  if (!fseekable(y)) {
+    return 0;
+  }
+#endif
+
+  pos = zftello(y);
+  if (zfseeko(y, pos, SEEK_SET)) {
+    return 0;
+  }
+
+  return 1;
+}
+
+
+int percent(n, m)
+  uzoff_t n;
+  uzoff_t m;                    /* n is the original size, m is the new size */
+/* Return the percentage compression from n to m using only integer
+   operations */
+{
+  zoff_t p;
+
+#if 0
+  if (n > 0xffffffL)            /* If n >= 16M */
+  {                             /*  then divide n and m by 256 */
+    n += 0x80;  n >>= 8;
+    m += 0x80;  m >>= 8;
+  }
+  return n > m ? (int)(1 + (200 * (n - m)/n)) / 2 : 0;
+#endif
+
+/* 2004-12-01 SMS.
+ * Changed to do big-n test only for small zoff_t.
+ * Changed big-n arithmetic to accomodate apparently negative values
+ * when a small zoff_t value exceeds 2G.
+ * Increased the reduction divisor from 256 to 512 to avoid the sign bit
+ * in a reduced intermediate, allowing signed arithmetic for the final
+ * result (which is no longer artificially limited to non-negative
+ * values).
+ * Note that right shifts must be on unsigned values to avoid undesired
+ * sign extension.
+ */
+
+/* Handle n = 0 case and account for int maybe being 16-bit.  12/28/2004 EG
+ */
+
+#define PC_MAX_SAFE 0x007fffffL    /* 9 clear bits at high end. */
+#define PC_MAX_RND  0xffffff00L    /* 8 clear bits at low end. */
+
+  if (sizeof(uzoff_t) < 8)          /* Don't fiddle with big zoff_t. */
+  {
+    if ((ulg)n > PC_MAX_SAFE)       /* Reduce large values.  (n > m) */
+    {
+      if ((ulg)n < PC_MAX_RND)      /* Divide n by 512 with rounding, */
+        n = ((ulg)n + 0x100) >> 9;  /* if boost won't overflow. */
+      else                          /* Otherwise, use max value. */
+        n = PC_MAX_SAFE;
+
+      if ((ulg)m < PC_MAX_RND)      /* Divide m by 512 with rounding, */
+        m = ((ulg)m + 0x100) >> 9;  /* if boost won't overflow. */
+      else                          /* Otherwise, use max value. */
+        m = PC_MAX_SAFE;
+    }
+  }
+  if (n != 0)
+    p = ((200 * ((zoff_t)n - (zoff_t)m) / (zoff_t)n) + 1) / 2;
+  else
+    p = 0;
+  return (int)p;  /* Return (rounded) % reduction. */
+}
+
+
+#ifndef RISCOS
+
+local int suffixes(a, s)
+  char *a;                      /* name to check suffix of */
+  char *s;                      /* list of suffixes separated by : or ; */
+/* Return true if a ends in any of the suffixes in the list s. */
+{
+  int m;                        /* true if suffix matches so far */
+  char *p;                      /* pointer into special */
+  char *q;                      /* pointer into name a */
+
+#ifdef QDOS
+  short dlen = devlen(a);
+  a = a + dlen;
+#endif
+
+  m = 1;
+#ifdef VMS
+  if( (q = strrchr(a,';')) != NULL )    /* Cut out VMS file version */
+    --q;
+  else
+    q = a + strlen(a) - 1;
+#else /* !VMS */
+  q = a + strlen(a) - 1;
+#endif /* ?VMS */
+  for (p = s + strlen(s) - 1; p >= s; p--)
+    if (*p == ':' || *p == ';')
+    {
+      if (m)
+        return 1;
+      else
+      {
+        m = 1;
+#ifdef VMS
+        if( (q = strrchr(a,';')) != NULL )      /* Cut out VMS file version */
+          --q;
+        else
+          q = a + strlen(a) - 1;
+#else /* !VMS */
+        q = a + strlen(a) - 1;
+#endif /* ?VMS */
+      }
+    }
+    else
+    {
+      m = m && q >= a && case_map(*p) == case_map(*q);
+      q--;
+    }
+  return m;
+}
+
+#else /* RISCOS */
+
+local int filetypes(a, s)
+char *a;                        /* extra field of file to check filetype of */
+char *s;                        /* list of filetypes separated by : or ; */
+/* Return true if a is any of the filetypes in the list s. */
+{
+ char *p;                       /* pointer into special */
+ char typestr[4];               /* filetype hex string taken from a */
+
+ if ((((unsigned*)a)[2] & 0xFFF00000) != 0xFFF00000) {
+ /* The file is not filestamped, always try to compress it */
+   return 0;
+ }
+
+ sprintf(typestr,"%.3X",(((unsigned*)a)[2] & 0x000FFF00) >> 8);
+
+ for (p=s;p<=s+strlen(s)-3;p+=3) { /* p+=3 to skip 3 hex type */
+   while (*p==':' || *p==';')
+     p++;
+
+   if (typestr[0] == toupper(p[0]) &&
+       typestr[1] == toupper(p[1]) &&
+       typestr[2] == toupper(p[2]))
+     return 1;
+ }
+ return 0;
+}
+#endif /* ?RISCOS */
+
+
+
+/* Note: a zip "entry" includes a local header (which includes the file
+   name), an encryption header if encrypting, the compressed data
+   and possibly an extended local header. */
+
+int zipup(z)
+struct zlist far *z;    /* zip entry to compress */
+/* Compress the file z->name into the zip entry described by *z and write
+   it to the file *y. Encrypt if requested.  Return an error code in the
+   ZE_ class.  Also, update tempzn by the number of bytes written. */
+/* y is now global */
+{
+  iztimes f_utim;       /* UNIX GMT timestamps, filled by filetime() */
+  ulg tim;              /* time returned by filetime() */
+  ulg a = 0L;           /* attributes returned by filetime() */
+  char *b;              /* malloc'ed file buffer */
+  extent k = 0;         /* result of zread */
+  int l = 0;            /* true if this file is a symbolic link */
+  int m;                /* method for this entry */
+
+  zoff_t o = 0, p;      /* offsets in zip file */
+  zoff_t q = (zoff_t) -3; /* size returned by filetime */
+  uzoff_t uq;           /* unsigned q */
+  zoff_t s = 0;         /* size of compressed data */
+
+  int r;                /* temporary variable */
+  int isdir;            /* set for a directory name */
+  int set_type = 0;     /* set if file type (ascii/binary) unknown */
+  zoff_t last_o;        /* used to detect wrap around */
+
+  ush tempext = 0;      /* temp copies of extra fields */
+  ush tempcext = 0;
+  char *tempextra = NULL;
+  char *tempcextra = NULL;
+
+
+#ifdef WINDLL
+# ifdef ZIP64_SUPPORT
+  extern _int64 filesize64;
+  extern unsigned long low;
+  extern unsigned long high;
+#  endif
+#endif
+
+  z->nam = strlen(z->iname);
+  isdir = z->iname[z->nam-1] == (char)0x2f; /* ascii[(unsigned)('/')] */
+
+  file_binary = -1;      /* not set, set after first read */
+  file_binary_final = 0; /* not set, set after first read */
+
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+  if (!no_win32_wide)
+    tim = filetimew(z->namew, &a, &q, &f_utim);
+  else
+    tim = filetime(z->name, &a, &q, &f_utim);
+#else
+  tim = filetime(z->name, &a, &q, &f_utim);
+#endif
+  if (tim == 0 || q == (zoff_t) -3)
+    return ZE_OPEN;
+
+  /* q is set to -1 if the input file is a device, -2 for a volume label */
+  if (q == (zoff_t) -2) {
+     isdir = 1;
+     q = 0;
+  } else if (isdir != ((a & MSDOS_DIR_ATTR) != 0)) {
+     /* don't overwrite a directory with a file and vice-versa */
+     return ZE_MISS;
+  }
+  /* reset dot_count for each file */
+  if (!display_globaldots)
+    dot_count = -1;
+
+  /* display uncompressed size */
+  uq = ((uzoff_t) q > (uzoff_t) -3) ? 0 : (uzoff_t) q;
+  if (noisy && display_usize) {
+    fprintf(mesg, " (");
+    DisplayNumString( mesg, uq );
+    fprintf(mesg, ")");
+    mesg_line_started = 1;
+    fflush(mesg);
+  }
+  if (logall && display_usize) {
+    fprintf(logfile, " (");
+    DisplayNumString( logfile, uq );
+    fprintf(logfile, ")");
+    logfile_line_started = 1;
+    fflush(logfile);
+  }
+
+  /* initial z->len so if error later have something */
+  z->len = uq;
+
+  z->att = (ush)UNKNOWN; /* will be changed later */
+  z->atx = 0; /* may be changed by set_extra_field() */
+
+  /* Free the old extra fields which are probably obsolete */
+  /* Should probably read these and keep any we don't update.  12/30/04 EG */
+  if (extra_fields == 2) {
+    /* If keeping extra fields, make copy before clearing for set_extra_field()
+       A better approach is to modify the port code, but maybe later */
+    if (z->ext) {
+      if ((tempextra = malloc(z->ext)) == NULL) {
+        ZIPERR(ZE_MEM, "extra fields copy");
+      }
+      memcpy(tempextra, z->extra, z->ext);
+      tempext = z->ext;
+    }
+    if (z->cext) {
+      if ((tempcextra = malloc(z->cext)) == NULL) {
+        ZIPERR(ZE_MEM, "extra fields copy");
+      }
+      memcpy(tempcextra, z->cextra, z->cext);
+      tempcext = z->cext;
+    }
+  }
+  if (z->ext) {
+    free((zvoid *)(z->extra));
+  }
+  if (z->cext && z->extra != z->cextra) {
+    free((zvoid *)(z->cextra));
+  }
+  z->extra = z->cextra = NULL;
+  z->ext = z->cext = 0;
+
+#if defined(MMAP) || defined(BIG_MEM)
+  remain = (ulg)-1L; /* changed only for MMAP or BIG_MEM */
+#endif /* MMAP || BIG_MEM */
+#if (!defined(USE_ZLIB) || defined(MMAP) || defined(BIG_MEM))
+  window_size = 0L;
+#endif /* !USE_ZLIB || MMAP || BIG_MEM */
+
+  /* Select method based on the suffix and the global method */
+#ifndef RISCOS
+  m = special != NULL && suffixes(z->name, special) ? STORE : method;
+#else /* RISCOS  must set m after setting extra field */
+  m = method;
+#endif /* ?RISCOS */
+
+  /* For now force deflate if using descriptors.  Instead zip and unzip
+     could check bytes read against compressed size in each data descriptor
+     found and skip over any that don't match.  This is how at least one
+     other zipper does it.  To be added later.  Until then it
+     probably doesn't hurt to force deflation when streaming.  12/30/04 EG
+  */
+
+  /* Now is a good time.  For now allow storing for testing.  12/16/05 EG */
+  /* By release need to force deflation based on reports some inflate
+     streamed data to find the end of the data */
+  /* Need to handle bzip2 */
+#ifdef NO_STREAMING_STORE
+  if (use_descriptors && m == STORE)
+  {
+      m = DEFLATE;
+  }
+#endif
+
+  /* Open file to zip up unless it is stdin */
+  if (strcmp(z->name, "-") == 0)
+  {
+    ifile = (ftype)zstdin;
+#if defined(MSDOS) || defined(__human68k__)
+    if (isatty(zstdin) == 0)  /* keep default mode if stdin is a terminal */
+      setmode(zstdin, O_BINARY);
+#endif
+    z->tim = tim;
+  }
+  else
+  {
+#if !(defined(VMS) && defined(VMS_PK_EXTRA))
+    if (extra_fields) {
+      /* create extra field and change z->att and z->atx if desired */
+      set_extra_field(z, &f_utim);
+# ifdef QLZIP
+      if(qlflag)
+          a |= (S_IXUSR) << 16;   /* Cross compilers don't set this */
+# endif
+# ifdef RISCOS
+      m = special != NULL && filetypes(z->extra, special) ? STORE : method;
+# endif /* RISCOS */
+
+      /* For now allow store for testing */
+#ifdef NO_STREAMING_STORE
+      /* For now force deflation if using data descriptors. */
+      if (use_descriptors && m == STORE)
+      {
+        m = DEFLATE;
+      }
+#endif
+
+    }
+#endif /* !(VMS && VMS_PK_EXTRA) */
+    l = issymlnk(a);
+    if (l) {
+      ifile = fbad;
+      m = STORE;
+    }
+    else if (isdir) { /* directory */
+      ifile = fbad;
+      m = STORE;
+      q = 0;
+    }
+#ifdef THEOS
+    else if (((a >> 16) & S_IFMT) == S_IFLIB) {   /* library */
+      ifile = fbad;
+      m = STORE;
+      q = 0;
+    }
+#endif
+    else {
+#ifdef CMS_MVS
+      if (bflag) {
+        if ((ifile = zopen(z->name, fhowb)) == fbad)
+           return ZE_OPEN;
+      }
+      else
+#endif /* CMS_MVS */
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+      if (!no_win32_wide) {
+        if ((ifile = zwopen(z->namew, fhow)) == fbad)
+          return ZE_OPEN;
+      } else {
+        if ((ifile = zopen(z->name, fhow)) == fbad)
+          return ZE_OPEN;
+      }
+#else
+      if ((ifile = zopen(z->name, fhow)) == fbad)
+        return ZE_OPEN;
+#endif
+    }
+
+    z->tim = tim;
+
+#if defined(VMS) && defined(VMS_PK_EXTRA)
+    /* vms_get_attributes must be called after vms_open() */
+    if (extra_fields) {
+      /* create extra field and change z->att and z->atx if desired */
+      vms_get_attributes(ifile, z, &f_utim);
+    }
+#endif /* VMS && VMS_PK_EXTRA */
+
+#if defined(MMAP) || defined(BIG_MEM)
+    /* Map ordinary files but not devices. This code should go in fileio.c */
+    if (!translate_eol && m != STORE && q != -1L && (ulg)q > 0 &&
+        (ulg)q + MIN_LOOKAHEAD > (ulg)q) {
+# ifdef MMAP
+      /* Map the whole input file in memory */
+      if (window != NULL)
+        free(window);  /* window can't be a mapped file here */
+      window_size = (ulg)q + MIN_LOOKAHEAD;
+      remain = window_size & (PAGESIZE-1);
+      /* If we can't touch the page beyond the end of file, we must
+       * allocate an extra page.
+       */
+      if (remain > MIN_LOOKAHEAD) {
+        window = (uch*)mmap(0, window_size, PROT_READ, MAP_PRIVATE, ifile, 0);
+      } else {
+        window = (uch*)valloc(window_size - remain + PAGESIZE);
+        if (window != NULL) {
+          window = (uch*)mmap((char*)window, window_size - remain, PROT_READ,
+                        MAP_PRIVATE | MAP_FIXED, ifile, 0);
+        } else {
+          window = (uch*)(-1);
+        }
+      }
+      if (window == (uch*)(-1)) {
+        Trace((mesg, " mmap failure on %s\n", z->name));
+        window = NULL;
+        window_size = 0L;
+        remain = (ulg)-1L;
+      } else {
+        remain = (ulg)q;
+      }
+# else /* !MMAP, must be BIG_MEM */
+      /* Read the whole input file at once */
+      window_size = (ulg)q + MIN_LOOKAHEAD;
+      window = window ? (uch*) realloc(window, (unsigned)window_size)
+                      : (uch*) malloc((unsigned)window_size);
+      /* Just use normal code if big malloc or realloc fails: */
+      if (window != NULL) {
+        remain = (ulg)zread(ifile, (char*)window, q+1);
+        if (remain != (ulg)q) {
+          fprintf(mesg, " q=%lu, remain=%lu ", (ulg)q, remain);
+          error("can't read whole file at once");
+        }
+      } else {
+        window_size = 0L;
+      }
+# endif /* ?MMAP */
+    }
+#endif /* MMAP || BIG_MEM */
+
+  } /* strcmp(z->name, "-") == 0 */
+
+  if (extra_fields == 2) {
+    unsigned len;
+    char *p;
+
+    /* step through old extra fields and copy over any not already
+       in new extra fields */
+    p = copy_nondup_extra_fields(tempextra, tempext, z->extra, z->ext, &len);
+    free(z->extra);
+    z->ext = len;
+    z->extra = p;
+    p = copy_nondup_extra_fields(tempcextra, tempcext, z->cextra, z->cext, &len);
+    free(z->cextra);
+    z->cext = len;
+    z->cextra = p;
+
+    if (tempext)
+      free(tempextra);
+    if (tempcext)
+      free(tempcextra);
+  }
+
+  if (q == 0)
+    m = STORE;
+  if (m == BEST)
+    m = DEFLATE;
+
+  /* Do not create STORED files with extended local headers if the
+   * input size is not known, because such files could not be extracted.
+   * So if the zip file is not seekable and the input file is not
+   * on disk, obey the -0 option by forcing deflation with stored block.
+   * Note however that using "zip -0" as filter is not very useful...
+   * ??? to be done.
+   */
+
+  /* An alternative used by others is to allow storing but on reading do
+   * a second check when a signature is found.  This is simply to check
+   * the compressed size to the bytes read since the start of the file data.
+   * If this is the right signature then the compressed size should match
+   * the size of the compressed data to that point.  If not look for the
+   * next signature.  We should do this.  12/31/04 EG
+   *
+   * For reading and testing we should do this, but should not write
+   * stored streamed data unless for testing as finding the end of
+   * streamed deflated data can be done by inflating.  6/26/06 EG
+   */
+
+  /* Fill in header information and write local header to zip file.
+   * This header will later be re-written since compressed length and
+   * crc are not yet known.
+   */
+
+  /* (Assume ext, cext, com, and zname already filled in.) */
+#if defined(OS2) || defined(WIN32)
+# ifdef WIN32_OEM
+  /* When creating OEM-coded names on Win32, the entries must always be marked
+     as "created on MSDOS" (OS_CODE = 0), because UnZip needs to handle archive
+     entry names just like those created by Zip's MSDOS port.
+   */
+  z->vem = (ush)(dosify ? 20 : 0 + Z_MAJORVER * 10 + Z_MINORVER);
+# else
+  z->vem = (ush)(z->dosflag ? (dosify ? 20 : /* Made under MSDOS by PKZIP 2.0 */
+                               (0 + Z_MAJORVER * 10 + Z_MINORVER))
+                 : OS_CODE + Z_MAJORVER * 10 + Z_MINORVER);
+  /* For a plain old (8+3) FAT file system, we cheat and pretend that the file
+   * was not made on OS2/WIN32 but under DOS. unzip is confused otherwise.
+   */
+# endif
+#else /* !(OS2 || WIN32) */
+  z->vem = (ush)(dosify ? 20 : OS_CODE + Z_MAJORVER * 10 + Z_MINORVER);
+#endif /* ?(OS2 || WIN32) */
+
+  z->ver = (ush)(m == STORE ? 10 : 20); /* Need PKUNZIP 2.0 except for store */
+#ifdef BZIP2_SUPPORT
+  if (method == BZIP2)
+      z->ver = (ush)(m == STORE ? 10 : 46);
+#endif
+  z->crc = 0;  /* to be updated later */
+  /* Assume first that we will need an extended local header: */
+  if (isdir)
+    /* If dir then q = 0 and extended header not needed */
+    z->flg = 0;
+  else
+    z->flg = 8;  /* to be updated later */
+#if CRYPT
+  if (!isdir && key != NULL) {
+    z->flg |= 1;
+    /* Since we do not yet know the crc here, we pretend that the crc
+     * is the modification time:
+     */
+    z->crc = z->tim << 16;
+    /* More than pretend.  File is encrypted using crypt header with that. */
+  }
+#endif /* CRYPT */
+  z->lflg = z->flg;
+  z->how = (ush)m;                              /* may be changed later  */
+  z->siz = (zoff_t)(m == STORE && q >= 0 ? q : 0); /* will be changed later */
+  z->len = (zoff_t)(q != -1L ? q : 0);          /* may be changed later  */
+  if (z->att == (ush)UNKNOWN) {
+      z->att = BINARY;                    /* set sensible value in header */
+      set_type = 1;
+  }
+  /* Attributes from filetime(), flag bits from set_extra_field(): */
+#if defined(DOS) || defined(OS2) || defined(WIN32)
+  z->atx = z->dosflag ? a & 0xff : a | (z->atx & 0x0000ff00);
+#else
+  z->atx = dosify ? a & 0xff : a | (z->atx & 0x0000ff00);
+#endif /* DOS || OS2 || WIN32 */
+
+  if ((r = putlocal(z, PUTLOCAL_WRITE)) != ZE_OK) {
+    if (ifile != fbad)
+      zclose(ifile);
+    return r;
+  }
+
+  /* now get split information set by bfwrite() */
+  z->off = current_local_offset;
+
+  /* disk local header was written to */
+  z->dsk = current_local_disk;
+
+  tempzn += 4 + LOCHEAD + z->nam + z->ext;
+
+
+#if CRYPT
+  if (!isdir && key != NULL) {
+    crypthead(key, z->crc);
+    z->siz += RAND_HEAD_LEN;  /* to be updated later */
+    tempzn += RAND_HEAD_LEN;
+  }
+#endif /* CRYPT */
+  if (ferror(y)) {
+    if (ifile != fbad)
+      zclose(ifile);
+    ZIPERR(ZE_WRITE, "unexpected error on zip file");
+  }
+
+  last_o = o;
+  o = zftello(y); /* for debugging only, ftell can fail on pipes */
+  if (ferror(y))
+    clearerr(y);
+
+  if (o != -1 && last_o > o) {
+    fprintf(mesg, "last %s o %s\n", zip_fzofft(last_o, NULL, NULL),
+                                    zip_fzofft(o, NULL, NULL));
+    ZIPERR(ZE_BIG, "seek wrap - zip file too big to write");
+  }
+
+  /* Write stored or deflated file to zip file */
+  isize = 0L;
+  crc = CRCVAL_INITIAL;
+
+  if (isdir) {
+    /* nothing to write */
+  }
+  else if (m != STORE) {
+    if (set_type) z->att = (ush)UNKNOWN;
+    /* ... is finally set in file compression routine */
+#ifdef BZIP2_SUPPORT
+    if (m == BZIP2) {
+      s = bzfilecompress(z, &m);
+    }
+    else
+#endif /* BZIP2_SUPPORT */
+    {
+      s = filecompress(z, &m);
+    }
+#ifndef PGP
+    if (z->att == (ush)BINARY && translate_eol && file_binary) {
+      if (translate_eol == 1)
+        zipwarn("has binary so -l ignored", "");
+      else
+        zipwarn("has binary so -ll ignored", "");
+    }
+    else if (z->att == (ush)BINARY && translate_eol) {
+      if (translate_eol == 1)
+        zipwarn("-l used on binary file - corrupted?", "");
+      else
+        zipwarn("-ll used on binary file - corrupted?", "");
+    }
+#endif
+  }
+  else
+  {
+    if ((b = malloc(SBSZ)) == NULL)
+       return ZE_MEM;
+
+    if (l) {
+      k = rdsymlnk(z->name, b, SBSZ);
+/*
+ * compute crc first because zfwrite will alter the buffer b points to !!
+ */
+      crc = crc32(crc, (uch *) b, k);
+      if (zfwrite(b, 1, k) != k)
+      {
+        free((zvoid *)b);
+        return ZE_TEMP;
+      }
+      isize = k;
+
+#ifdef MINIX
+      q = k;
+#endif /* MINIX */
+    }
+    else
+    {
+      while ((k = file_read(b, SBSZ)) > 0 && k != (extent) EOF)
+      {
+        if (zfwrite(b, 1, k) != k)
+        {
+          if (ifile != fbad)
+            zclose(ifile);
+          free((zvoid *)b);
+          return ZE_TEMP;
+        }
+        if (!display_globaldots) {
+          if (dot_size > 0) {
+            /* initial space */
+            if (noisy && dot_count == -1) {
+#ifndef WINDLL
+              putc(' ', mesg);
+              fflush(mesg);
+#else
+              fprintf(stdout,"%c",' ');
+#endif
+              dot_count++;
+            }
+            dot_count++;
+            if (dot_size <= (dot_count + 1) * SBSZ) dot_count = 0;
+          }
+          if ((verbose || noisy) && dot_size && !dot_count) {
+#ifndef WINDLL
+            putc('.', mesg);
+            fflush(mesg);
+#else
+            fprintf(stdout,"%c",'.');
+#endif
+            mesg_line_started = 1;
+          }
+        }
+      }
+    }
+    free((zvoid *)b);
+    s = isize;
+  }
+  if (ifile != fbad && zerr(ifile)) {
+    perror("\nzip warning");
+    if (logfile)
+      fprintf(logfile, "\nzip warning: %s\n", strerror(errno));
+    zipwarn("could not read input file: ", z->oname);
+  }
+  if (ifile != fbad)
+    zclose(ifile);
+#ifdef MMAP
+  if (remain != (ulg)-1L) {
+    munmap((caddr_t) window, window_size);
+    window = NULL;
+  }
+#endif /*MMAP */
+
+  tempzn += s;
+  p = tempzn; /* save for future fseek() */
+
+#if (!defined(MSDOS) || defined(OS2))
+#if !defined(VMS) && !defined(CMS_MVS) && !defined(__mpexl)
+  /* Check input size (but not in VMS -- variable record lengths mess it up)
+   * and not on MSDOS -- diet in TSR mode reports an incorrect file size)
+   */
+#ifndef TANDEM /* Tandem EOF does not match byte count unless Unstructured */
+  if (!translate_eol && q != -1L && isize != q)
+  {
+    Trace((mesg, " i=%lu, q=%lu ", isize, q));
+    zipwarn(" file size changed while zipping ", z->name);
+  }
+#endif /* !TANDEM */
+#endif /* !VMS && !CMS_MVS && !__mpexl */
+#endif /* (!MSDOS || OS2) */
+
+  if (isdir)
+  {
+    /* A directory */
+    z->siz = 0;
+    z->len = 0;
+    z->how = STORE;
+    z->ver = 10;
+    /* never encrypt directory so don't need extended local header */
+    z->flg &= ~8;
+    z->lflg &= ~8;
+  }
+  else
+  {
+    /* Try to rewrite the local header with correct information */
+    z->crc = crc;
+    z->siz = s;
+#if CRYPT
+    if (!isdir && key != NULL)
+      z->siz += RAND_HEAD_LEN;
+#endif /* CRYPT */
+    z->len = isize;
+    /* if can seek back to local header */
+#ifdef BROKEN_FSEEK
+    if (use_descriptors || !fseekable(y) || zfseeko(y, z->off, SEEK_SET))
+#else
+    if (use_descriptors || zfseeko(y, z->off, SEEK_SET))
+#endif
+    {
+      if (z->how != (ush) m)
+         error("can't rewrite method");
+      if (m == STORE && q < 0)
+         ZIPERR(ZE_PARMS, "zip -0 not supported for I/O on pipes or devices");
+      if ((r = putextended(z)) != ZE_OK)
+        return r;
+      /* if Zip64 and not seekable then Zip64 data descriptor */
+#ifdef ZIP64_SUPPORT
+      tempzn += (zip64_entry ? 24L : 16L);
+#else
+      tempzn += 16L;
+#endif
+      z->flg = z->lflg; /* if z->flg modified by deflate */
+    } else {
+      /* ftell() not as useful across splits */
+      if (bytes_this_entry != (uzoff_t)(key ? s + 12 : s)) {
+        fprintf(mesg, " s=%s, actual=%s ",
+                zip_fzofft(s, NULL, NULL), zip_fzofft(bytes_this_entry, NULL, NULL));
+        error("incorrect compressed size");
+      }
+#if 0
+       /* seek ok, ftell() should work, check compressed size */
+# if !defined(VMS) && !defined(CMS_MVS)
+      if (p - o != s) {
+        fprintf(mesg, " s=%s, actual=%s ",
+                zip_fzofft(s, NULL, NULL), zip_fzofft(p-o, NULL, NULL));
+        error("incorrect compressed size");
+      }
+# endif /* !VMS && !CMS_MVS */
+#endif /* 0 */
+      z->how = (ush)m;
+      switch (m)
+      {
+      case STORE:
+        z->ver = 10; break;
+      /* Need PKUNZIP 2.0 for DEFLATE */
+      case DEFLATE:
+        z->ver = 20; break;
+#ifdef BZIP2_SUPPORT
+      case BZIP2:
+        z->ver = 46; break;
+#endif
+      }
+      /*
+       * The encryption header needs the crc, but we don't have it
+       * for a new file.  The file time is used instead and the encryption
+       * header then used to encrypt the data.  The AppNote standard only
+       * can be applied to a file that the crc is known, so that means
+       * either an existing entry in an archive or get the crc before
+       * creating the encryption header and then encrypt the data.
+       */
+      if ((z->flg & 1) == 0) {
+        /* not encrypting so don't need extended local header */
+        z->flg &= ~8;
+      }
+      /* deflate may have set compression level bit markers in z->flg,
+         and we can't think of any reason central and local flags should
+         be different. */
+      z->lflg = z->flg;
+
+      /* If not using descriptors, back up and rewrite local header. */
+      if (split_method == 1 && current_local_file != y) {
+        if (zfseeko(current_local_file, z->off, SEEK_SET))
+          return ZE_READ;
+      }
+
+      /* if local header in another split, putlocal will close it */
+      if ((r = putlocal(z, PUTLOCAL_REWRITE)) != ZE_OK)
+        return r;
+
+      if (zfseeko(y, bytes_this_split, SEEK_SET))
+        return ZE_READ;
+
+      if ((z->flg & 1) != 0) {
+        /* encrypted file, extended header still required */
+        if ((r = putextended(z)) != ZE_OK)
+          return r;
+#ifdef ZIP64_SUPPORT
+        if (zip64_entry)
+          tempzn += 24L;
+        else
+          tempzn += 16L;
+#else
+        tempzn += 16L;
+#endif
+      }
+    }
+  } /* isdir */
+  /* Free the local extra field which is no longer needed */
+  if (z->ext) {
+    if (z->extra != z->cextra) {
+      free((zvoid *)(z->extra));
+      z->extra = NULL;
+    }
+    z->ext = 0;
+  }
+
+  /* Display statistics */
+  if (noisy)
+  {
+    if (verbose) {
+      fprintf( mesg, "\t(in=%s) (out=%s)",
+               zip_fzofft(isize, NULL, "u"), zip_fzofft(s, NULL, "u"));
+    }
+#ifdef BZIP2_SUPPORT
+    if (m == BZIP2)
+      fprintf(mesg, " (bzipped %d%%)\n", percent(isize, s));
+    else
+#endif
+    if (m == DEFLATE)
+      fprintf(mesg, " (deflated %d%%)\n", percent(isize, s));
+    else
+      fprintf(mesg, " (stored 0%%)\n");
+    mesg_line_started = 0;
+    fflush(mesg);
+  }
+  if (logall)
+  {
+#ifdef BZIP2_SUPPORT
+    if (m == BZIP2)
+      fprintf(logfile, " (bzipped %d%%)\n", percent(isize, s));
+    else
+#endif
+    if (m == DEFLATE)
+      fprintf(logfile, " (deflated %d%%)\n", percent(isize, s));
+    else
+      fprintf(logfile, " (stored 0%%)\n");
+    logfile_line_started = 0;
+    fflush(logfile);
+  }
+
+#ifdef WINDLL
+# ifdef ZIP64_SUPPORT
+   /* The DLL api has been updated and uses a different
+      interface.  7/24/04 EG */
+   if (lpZipUserFunctions->ServiceApplication64 != NULL)
+    {
+    if ((*lpZipUserFunctions->ServiceApplication64)(z->zname, isize))
+                ZIPERR(ZE_ABORT, "User terminated operation");
+    }
+  else
+   {
+   filesize64 = isize;
+   low = (unsigned long)(filesize64 & 0x00000000FFFFFFFF);
+   high = (unsigned long)((filesize64 >> 32) & 0x00000000FFFFFFFF);
+   if (lpZipUserFunctions->ServiceApplication64_No_Int64 != NULL) {
+    if ((*lpZipUserFunctions->ServiceApplication64_No_Int64)(z->zname, low, high))
+                ZIPERR(ZE_ABORT, "User terminated operation");
+    }
+   }
+# else
+  if (lpZipUserFunctions->ServiceApplication != NULL)
+  {
+    if ((*lpZipUserFunctions->ServiceApplication)(z->zname, isize))
+    {
+      ZIPERR(ZE_ABORT, "User terminated operation");
+    }
+  }
+# endif
+#endif
+
+  return ZE_OK;
+}
+
+
+
+
+local unsigned file_read(buf, size)
+  char *buf;
+  unsigned size;
+/* Read a new buffer from the current input file, perform end-of-line
+ * translation, and update the crc and input file size.
+ * IN assertion: size >= 2 (for end-of-line translation)
+ */
+{
+  unsigned len;
+  char *b;
+  zoff_t isize_prev;    /* Previous isize.  Used for overflow check. */
+
+#if defined(MMAP) || defined(BIG_MEM)
+  if (remain == 0L) {
+    return 0;
+  } else if (remain != (ulg)-1L) {
+    /* The window data is already in place. We still compute the crc
+     * by 32K blocks instead of once on whole file to keep a certain
+     * locality of reference.
+     */
+    Assert(buf == (char*)window + isize, "are you lost?");
+    if ((ulg)size > remain) size = (unsigned)remain;
+    if (size > WSIZE) size = WSIZE; /* don't touch all pages at once */
+    remain -= (ulg)size;
+    len = size;
+  } else
+#endif /* MMAP || BIG_MEM */
+  if (translate_eol == 0) {
+    len = zread(ifile, buf, size);
+    if (len == (unsigned)EOF || len == 0) return len;
+#ifdef OS390
+    b = buf;
+    if (aflag == ASCII) {
+      while (*b != '\0') {
+        *b = (char)ascii[(uch)*b];
+        b++;
+      }
+    }
+#endif
+  } else if (translate_eol == 1) {
+    /* translate_eol == 1 */
+    /* Transform LF to CR LF */
+    size >>= 1;
+    b = buf+size;
+    size = len = zread(ifile, b, size);
+    if (len == (unsigned)EOF || len == 0) return len;
+
+    /* check buf for binary - 12/16/04 */
+    if (file_binary == -1) {
+      /* first read */
+      file_binary = is_text_buf(b, size) ? 0 : 1;
+    }
+
+    if (file_binary != 1) {
+#ifdef EBCDIC
+      if (aflag == ASCII)
+      {
+         do {
+            char c;
+
+            if ((c = *b++) == '\n') {
+               *buf++ = CR; *buf++ = LF; len++;
+            } else {
+              *buf++ = (char)ascii[(uch)c];
+            }
+         } while (--size != 0);
+      }
+      else
+#endif /* EBCDIC */
+      {
+         do {
+            if ((*buf++ = *b++) == '\n') *(buf-1) = CR, *buf++ = LF, len++;
+         } while (--size != 0);
+      }
+      buf -= len;
+    } else { /* do not translate binary */
+      memcpy(buf, b, size);
+    }
+
+  } else {
+    /* translate_eol == 2 */
+    /* Transform CR LF to LF and suppress final ^Z */
+    b = buf;
+    size = len = zread(ifile, buf, size-1);
+    if (len == (unsigned)EOF || len == 0) return len;
+
+    /* check buf for binary - 12/16/04 */
+    if (file_binary == -1) {
+      /* first read */
+      file_binary = is_text_buf(b, size) ? 0 : 1;
+    }
+
+    if (file_binary != 1) {
+      buf[len] = '\n'; /* I should check if next char is really a \n */
+#ifdef EBCDIC
+      if (aflag == ASCII)
+      {
+         do {
+            char c;
+
+            if ((c = *b++) == '\r' && *b == '\n') {
+               len--;
+            } else {
+               *buf++ = (char)(c == '\n' ? LF : ascii[(uch)c]);
+            }
+         } while (--size != 0);
+      }
+      else
+#endif /* EBCDIC */
+      {
+         do {
+            if (( *buf++ = *b++) == CR && *b == LF) buf--, len--;
+         } while (--size != 0);
+      }
+      if (len == 0) {
+         zread(ifile, buf, 1); len = 1; /* keep single \r if EOF */
+#ifdef EBCDIC
+         if (aflag == ASCII) {
+            *buf = (char)(*buf == '\n' ? LF : ascii[(uch)(*buf)]);
+         }
+#endif
+      } else {
+         buf -= len;
+         if (buf[len-1] == CTRLZ) len--; /* suppress final ^Z */
+      }
+    }
+  }
+  crc = crc32(crc, (uch *) buf, len);
+  /* 2005-05-23 SMS.
+     Increment file size.  A small-file program reading a large file may
+     cause isize to overflow, so complain (and abort) if it goes
+     negative or wraps around.  Awful things happen later otherwise.
+  */
+  isize_prev = isize;
+  isize += (ulg)len;
+  if (isize < isize_prev) {
+    ZIPERR(ZE_BIG, "overflow in byte count");
+  }
+  return len;
+}
+
+
+#ifdef USE_ZLIB
+
+local int zl_deflate_init(pack_level)
+    int pack_level;
+{
+    unsigned i;
+    int windowBits;
+    int err = Z_OK;
+    int zp_err = ZE_OK;
+
+    if (zlib_version[0] != ZLIB_VERSION[0]) {
+        sprintf(errbuf, "incompatible zlib version (expected %s, found %s)",
+              ZLIB_VERSION, zlib_version);
+        zp_err = ZE_LOGIC;
+    } else if (strcmp(zlib_version, ZLIB_VERSION) != 0) {
+        fprintf(mesg,
+                "\twarning:  different zlib version (expected %s, using %s)\n",
+                ZLIB_VERSION, zlib_version);
+    }
+
+    /* windowBits = log2(WSIZE) */
+    for (i = ((unsigned)WSIZE), windowBits = 0; i != 1; i >>= 1, ++windowBits);
+
+    zstrm.zalloc = (alloc_func)Z_NULL;
+    zstrm.zfree = (free_func)Z_NULL;
+
+    Trace((stderr, "initializing deflate()\n"));
+    err = deflateInit2(&zstrm, pack_level, Z_DEFLATED, -windowBits, 8, 0);
+
+    if (err == Z_MEM_ERROR) {
+        sprintf(errbuf, "cannot initialize zlib deflate");
+        zp_err = ZE_MEM;
+    } else if (err != Z_OK) {
+        sprintf(errbuf, "zlib deflateInit failure (%d)", err);
+        zp_err = ZE_LOGIC;
+    }
+
+    deflInit = TRUE;
+    return zp_err;
+}
+
+
+void zl_deflate_free()
+{
+    int err;
+
+    if (f_obuf != NULL) {
+        free(f_obuf);
+        f_obuf = NULL;
+    }
+    if (f_ibuf != NULL) {
+        free(f_ibuf);
+        f_ibuf = NULL;
+    }
+    if (deflInit) {
+        err = deflateEnd(&zstrm);
+        if (err != Z_OK && err !=Z_DATA_ERROR) {
+            ziperr(ZE_LOGIC, "zlib deflateEnd failed");
+        }
+        deflInit = FALSE;
+    }
+}
+
+#else /* !USE_ZLIB */
+
+# ifdef ZP_NEED_MEMCOMPR
+/* ===========================================================================
+ * In-memory read function. As opposed to file_read(), this function
+ * does not perform end-of-line translation, and does not update the
+ * crc and input size.
+ *    Note that the size of the entire input buffer is an unsigned long,
+ * but the size used in mem_read() is only an unsigned int. This makes a
+ * difference on 16 bit machines. mem_read() may be called several
+ * times for an in-memory compression.
+ */
+local unsigned mem_read(b, bsize)
+     char *b;
+     unsigned bsize;
+{
+    if (in_offset < in_size) {
+        ulg block_size = in_size - in_offset;
+        if (block_size > (ulg)bsize) block_size = (ulg)bsize;
+        memcpy(b, in_buf + in_offset, (unsigned)block_size);
+        in_offset += (unsigned)block_size;
+        return (unsigned)block_size;
+    } else {
+        return 0; /* end of input */
+    }
+}
+# endif /* ZP_NEED_MEMCOMPR */
+
+
+/* ===========================================================================
+ * Flush the current output buffer.
+ */
+void flush_outbuf(o_buf, o_idx)
+    char *o_buf;
+    unsigned *o_idx;
+{
+    if (y == NULL) {
+        error("output buffer too small for in-memory compression");
+    }
+    /* Encrypt and write the output buffer: */
+    if (*o_idx != 0) {
+        zfwrite(o_buf, 1, (extent)*o_idx);
+        if (ferror(y)) ziperr(ZE_WRITE, "write error on zip file");
+    }
+    *o_idx = 0;
+}
+
+/* ===========================================================================
+ * Return true if the zip file can be seeked. This is used to check if
+ * the local header can be re-rewritten. This function always returns
+ * true for in-memory compression.
+ * IN assertion: the local header has already been written (ftell() > 0).
+ */
+int seekable()
+{
+    return fseekable(y);
+}
+#endif /* ?USE_ZLIB */
+
+
+/* ===========================================================================
+ * Compression to archive file.
+ */
+local zoff_t filecompress(z_entry, cmpr_method)
+    struct zlist far *z_entry;
+    int *cmpr_method;
+{
+#ifdef USE_ZLIB
+    int err = Z_OK;
+    unsigned mrk_cnt = 1;
+    int maybe_stored = FALSE;
+    ulg cmpr_size;
+#if defined(MMAP) || defined(BIG_MEM)
+    unsigned ibuf_sz = (unsigned)SBSZ;
+#else
+#   define ibuf_sz ((unsigned)SBSZ)
+#endif
+#ifndef OBUF_SZ
+#  define OBUF_SZ ZBSZ
+#endif
+    unsigned u;
+
+#if defined(MMAP) || defined(BIG_MEM)
+    if (remain == (ulg)-1L && f_ibuf == NULL)
+#else /* !(MMAP || BIG_MEM */
+    if (f_ibuf == NULL)
+#endif /* MMAP || BIG_MEM */
+        f_ibuf = (char *)malloc(SBSZ);
+    if (f_obuf == NULL)
+        f_obuf = (char *)malloc(OBUF_SZ);
+#if defined(MMAP) || defined(BIG_MEM)
+    if ((remain == (ulg)-1L && f_ibuf == NULL) || f_obuf == NULL)
+#else /* !(MMAP || BIG_MEM */
+    if (f_ibuf == NULL || f_obuf == NULL)
+#endif /* MMAP || BIG_MEM */
+        ziperr(ZE_MEM, "allocating zlib file-I/O buffers");
+
+    if (!deflInit) {
+        err = zl_deflate_init(level);
+        if (err != ZE_OK)
+            ziperr(err, errbuf);
+    }
+
+    if (level <= 2) {
+        z_entry->flg |= 4;
+    } else if (level >= 8) {
+        z_entry->flg |= 2;
+    }
+#if defined(MMAP) || defined(BIG_MEM)
+    if (remain != (ulg)-1L) {
+        zstrm.next_in = (Bytef *)window;
+        ibuf_sz = (unsigned)WSIZE;
+    } else
+#endif /* MMAP || BIG_MEM */
+    {
+        zstrm.next_in = (Bytef *)f_ibuf;
+    }
+    zstrm.avail_in = file_read(zstrm.next_in, ibuf_sz);
+    if (zstrm.avail_in < ibuf_sz) {
+        unsigned more = file_read(zstrm.next_in + zstrm.avail_in,
+                                  (ibuf_sz - zstrm.avail_in));
+        if (more == EOF || more == 0) {
+            maybe_stored = TRUE;
+        } else {
+            zstrm.avail_in += more;
+        }
+    }
+    zstrm.next_out = (Bytef *)f_obuf;
+    zstrm.avail_out = OBUF_SZ;
+
+    if (!maybe_stored) while (zstrm.avail_in != 0 && zstrm.avail_in != EOF) {
+        err = deflate(&zstrm, Z_NO_FLUSH);
+        if (err != Z_OK && err != Z_STREAM_END) {
+            sprintf(errbuf, "unexpected zlib deflate error %d", err);
+            ziperr(ZE_LOGIC, errbuf);
+        }
+        if (zstrm.avail_out == 0) {
+            if (zfwrite(f_obuf, 1, OBUF_SZ) != OBUF_SZ) {
+                ziperr(ZE_TEMP, "error writing to zipfile");
+            }
+            zstrm.next_out = (Bytef *)f_obuf;
+            zstrm.avail_out = OBUF_SZ;
+        }
+        if (zstrm.avail_in == 0) {
+            if (verbose || noisy)
+                while((unsigned)(zstrm.total_in / (uLong)WSIZE) > mrk_cnt) {
+                    mrk_cnt++;
+                    if (!display_globaldots) {
+                      if (dot_size > 0) {
+                        /* initial space */
+                        if (noisy && dot_count == -1) {
+#ifndef WINDLL
+                          putc(' ', mesg);
+                          fflush(mesg);
+#else
+                          fprintf(stdout,"%c",' ');
+#endif
+                          dot_count++;
+                        }
+                        dot_count++;
+                        if (dot_size <= (dot_count + 1) * WSIZE) dot_count = 0;
+                      }
+                      if (noisy && dot_size && !dot_count) {
+#ifndef WINDLL
+                        putc('.', mesg);
+                        fflush(mesg);
+#else
+                        fprintf(stdout,"%c",'.');
+#endif
+                        mesg_line_started = 1;
+                      }
+                    }
+                }
+#if defined(MMAP) || defined(BIG_MEM)
+            if (remain == (ulg)-1L)
+                zstrm.next_in = (Bytef *)f_ibuf;
+#else
+            zstrm.next_in = (Bytef *)f_ibuf;
+#endif
+            zstrm.avail_in = file_read(zstrm.next_in, ibuf_sz);
+        }
+    }
+
+    do {
+        err = deflate(&zstrm, Z_FINISH);
+        if (maybe_stored) {
+            if (err == Z_STREAM_END && zstrm.total_out >= zstrm.total_in &&
+                fseekable(zipfile)) {
+                /* deflation does not reduce size, switch to STORE method */
+                unsigned len_out = (unsigned)zstrm.total_in;
+                if (zfwrite(f_ibuf, 1, len_out) != len_out) {
+                    ziperr(ZE_TEMP, "error writing to zipfile");
+                }
+                zstrm.total_out = (uLong)len_out;
+                *cmpr_method = STORE;
+                break;
+            } else {
+                maybe_stored = FALSE;
+            }
+        }
+        if (zstrm.avail_out < OBUF_SZ) {
+            unsigned len_out = OBUF_SZ - zstrm.avail_out;
+            if (zfwrite(f_obuf, 1, len_out) != len_out) {
+                ziperr(ZE_TEMP, "error writing to zipfile");
+            }
+            zstrm.next_out = (Bytef *)f_obuf;
+            zstrm.avail_out = OBUF_SZ;
+        }
+    } while (err == Z_OK);
+
+    if (err != Z_STREAM_END) {
+        sprintf(errbuf, "unexpected zlib deflate error %d", err);
+        ziperr(ZE_LOGIC, errbuf);
+    }
+
+    if (z_entry->att == (ush)UNKNOWN)
+        z_entry->att = (ush)(zstrm.data_type == Z_ASCII ? ASCII : BINARY);
+    cmpr_size = (ulg)zstrm.total_out;
+
+    if ((err = deflateReset(&zstrm)) != Z_OK)
+        ziperr(ZE_LOGIC, "zlib deflateReset failed");
+    return cmpr_size;
+#else /* !USE_ZLIB */
+
+    /* Set the defaults for file compression. */
+    read_buf = file_read;
+
+    /* Initialize deflate's internals and execute file compression. */
+    bi_init(file_outbuf, sizeof(file_outbuf), TRUE);
+    ct_init(&z_entry->att, cmpr_method);
+    lm_init(level, &z_entry->flg);
+    return deflate();
+#endif /* ?USE_ZLIB */
+}
+
+#ifdef ZP_NEED_MEMCOMPR
+/* ===========================================================================
+ * In-memory compression. This version can be used only if the entire input
+ * fits in one memory buffer. The compression is then done in a single
+ * call of memcompress(). (An extension to allow repeated calls would be
+ * possible but is not needed here.)
+ * The first two bytes of the compressed output are set to a short with the
+ * method used (DEFLATE or STORE). The following four bytes contain the CRC.
+ * The values are stored in little-endian order on all machines.
+ * This function returns the byte size of the compressed output, including
+ * the first six bytes (method and crc).
+ */
+
+ulg memcompress(tgt, tgtsize, src, srcsize)
+    char *tgt, *src;       /* target and source buffers */
+    ulg tgtsize, srcsize;  /* target and source sizes */
+{
+    ulg crc;
+    unsigned out_total;
+    int method   = DEFLATE;
+#ifdef USE_ZLIB
+    int err      = Z_OK;
+#else
+    ush att      = (ush)UNKNOWN;
+    ush flags    = 0;
+#endif
+
+    if (tgtsize <= (ulg)6L) error("target buffer too small");
+    out_total = 2 + 4;
+
+#ifdef USE_ZLIB
+    if (!deflInit) {
+        err = zl_deflate_init(level);
+        if (err != ZE_OK)
+            ziperr(err, errbuf);
+    }
+
+    zstrm.next_in = (Bytef *)src;
+    zstrm.avail_in = (uInt)srcsize;
+    zstrm.next_out = (Bytef *)(tgt + out_total);
+    zstrm.avail_out = (uInt)tgtsize - (uInt)out_total;
+
+    err = deflate(&zstrm, Z_FINISH);
+    if (err != Z_STREAM_END)
+        error("output buffer too small for in-memory compression");
+    out_total += (unsigned)zstrm.total_out;
+
+    if ((err = deflateReset(&zstrm)) != Z_OK)
+        error("zlib deflateReset failed");
+#else /* !USE_ZLIB */
+    read_buf  = mem_read;
+    in_buf    = src;
+    in_size   = (unsigned)srcsize;
+    in_offset = 0;
+    window_size = 0L;
+
+    bi_init(tgt + (2 + 4), (unsigned)(tgtsize - (2 + 4)), FALSE);
+    ct_init(&att, &method);
+    lm_init((level != 0 ? level : 1), &flags);
+    out_total += (unsigned)deflate();
+    window_size = 0L; /* was updated by lm_init() */
+#endif /* ?USE_ZLIB */
+
+    crc = CRCVAL_INITIAL;
+    crc = crc32(crc, (uch *)src, (extent)srcsize);
+
+    /* For portability, force little-endian order on all machines: */
+    tgt[0] = (char)(method & 0xff);
+    tgt[1] = (char)((method >> 8) & 0xff);
+    tgt[2] = (char)(crc & 0xff);
+    tgt[3] = (char)((crc >> 8) & 0xff);
+    tgt[4] = (char)((crc >> 16) & 0xff);
+    tgt[5] = (char)((crc >> 24) & 0xff);
+
+    return (ulg)out_total;
+}
+#endif /* ZP_NEED_MEMCOMPR */
+
+#ifdef BZIP2_SUPPORT
+
+local int bz_compress_init(pack_level)
+int pack_level;
+{
+    int err = BZ_OK;
+    int zp_err = ZE_OK;
+    const char *bzlibVer;
+
+    bzlibVer = BZ2_bzlibVersion();
+
+    /* $TODO - Check BZIP2 LIB version? */
+
+    bstrm.bzalloc = NULL;
+    bstrm.bzfree = NULL;
+    bstrm.opaque = NULL;
+
+    Trace((stderr, "initializing bzlib compress()\n"));
+    err = BZ2_bzCompressInit(&bstrm, pack_level, 0, 30);
+
+    if (err == BZ_MEM_ERROR) {
+        sprintf(errbuf, "cannot initialize bzlib compress");
+        zp_err = ZE_MEM;
+    } else if (err != BZ_OK) {
+        sprintf(errbuf, "bzlib bzCompressInit failure (%d)", err);
+        zp_err = ZE_LOGIC;
+    }
+
+    bzipInit = TRUE;
+    return zp_err;
+}
+
+void bz_compress_free()
+{
+    int err;
+
+    if (f_obuf != NULL) {
+        free(f_obuf);
+        f_obuf = NULL;
+    }
+    if (f_ibuf != NULL) {
+        free(f_ibuf);
+        f_ibuf = NULL;
+    }
+    if (bzipInit) {
+        err = BZ2_bzCompressEnd(&bstrm);
+        if (err != BZ_OK && err != BZ_DATA_ERROR) {
+            ziperr(ZE_LOGIC, "bzlib bzCompressEnd failed");
+        }
+        bzipInit = FALSE;
+    }
+}
+
+/* ===========================================================================
+ * BZIP2 Compression to archive file.
+ */
+
+local zoff_t bzfilecompress(z_entry, cmpr_method)
+struct zlist far *z_entry;
+int *cmpr_method;
+{
+    FILE *zipfile = y;
+
+    int err = BZ_OK;
+    unsigned mrk_cnt = 1;
+    int maybe_stored = FALSE;
+    zoff_t cmpr_size;
+#if defined(MMAP) || defined(BIG_MEM)
+    unsigned ibuf_sz = (unsigned)SBSZ;
+#else
+#   define ibuf_sz ((unsigned)SBSZ)
+#endif
+#ifndef OBUF_SZ
+#  define OBUF_SZ ZBSZ
+#endif
+
+#if defined(MMAP) || defined(BIG_MEM)
+    if (remain == (ulg)-1L && f_ibuf == NULL)
+#else /* !(MMAP || BIG_MEM */
+    if (f_ibuf == NULL)
+#endif /* MMAP || BIG_MEM */
+        f_ibuf = (char *)malloc(SBSZ);
+    if (f_obuf == NULL)
+        f_obuf = (char *)malloc(OBUF_SZ);
+#if defined(MMAP) || defined(BIG_MEM)
+    if ((remain == (ulg)-1L && f_ibuf == NULL) || f_obuf == NULL)
+#else /* !(MMAP || BIG_MEM */
+    if (f_ibuf == NULL || f_obuf == NULL)
+#endif /* MMAP || BIG_MEM */
+        ziperr(ZE_MEM, "allocating zlib/bzlib file-I/O buffers");
+
+    if (!bzipInit) {
+        err = bz_compress_init(level);
+        if (err != ZE_OK)
+            ziperr(err, errbuf);
+    }
+
+#if defined(MMAP) || defined(BIG_MEM)
+    if (remain != (ulg)-1L) {
+        bstrm.next_in = (Bytef *)window;
+        ibuf_sz = (unsigned)WSIZE;
+    } else
+#endif /* MMAP || BIG_MEM */
+    {
+        bstrm.next_in = (char *)f_ibuf;
+    }
+    bstrm.avail_in = file_read(bstrm.next_in, ibuf_sz);
+    if (file_binary_final == 0) {
+      /* check for binary as library does not */
+      if (!is_text_buf(bstrm.next_in, ibuf_sz))
+        file_binary_final = 1;
+    }
+    if (bstrm.avail_in < ibuf_sz) {
+        unsigned more = file_read(bstrm.next_in + bstrm.avail_in,
+                                  (ibuf_sz - bstrm.avail_in));
+        if (more == (unsigned) EOF || more == 0) {
+            maybe_stored = TRUE;
+        } else {
+            bstrm.avail_in += more;
+        }
+    }
+    bstrm.next_out = (char *)f_obuf;
+    bstrm.avail_out = OBUF_SZ;
+
+    if (!maybe_stored) {
+      while (bstrm.avail_in != 0 && bstrm.avail_in != (unsigned) EOF) {
+        err = BZ2_bzCompress(&bstrm, BZ_RUN);
+        if (err != BZ_RUN_OK && err != BZ_STREAM_END) {
+            sprintf(errbuf, "unexpected bzlib compress error %d", err);
+            ziperr(ZE_LOGIC, errbuf);
+        }
+        if (bstrm.avail_out == 0) {
+            if (zfwrite(f_obuf, 1, OBUF_SZ) != OBUF_SZ) {
+                ziperr(ZE_TEMP, "error writing to zipfile");
+            }
+            bstrm.next_out = (char *)f_obuf;
+            bstrm.avail_out = OBUF_SZ;
+        }
+        /* $TODO what about high 32-bits of total-in??? */
+        if (bstrm.avail_in == 0) {
+            if (verbose || noisy)
+#ifdef LARGE_FILE_SUPPORT
+                while((unsigned)((bstrm.total_in_lo32
+                                  + (((zoff_t)bstrm.total_in_hi32) << 32))
+                                 / (zoff_t)(ulg)WSIZE) > mrk_cnt) {
+#else
+                while((unsigned)(bstrm.total_in_lo32 / (ulg)WSIZE) > mrk_cnt) {
+#endif
+                    mrk_cnt++;
+                    if (!display_globaldots) {
+                      if (dot_size > 0) {
+                        /* initial space */
+                        if (noisy && dot_count == -1) {
+#ifndef WINDLL
+                          putc(' ', mesg);
+                          fflush(mesg);
+#else
+                          fprintf(stdout,"%c",' ');
+#endif
+                          dot_count++;
+                        }
+                        dot_count++;
+                        if (dot_size <= (dot_count + 1) * WSIZE) dot_count = 0;
+                      }
+                      if (noisy && dot_size && !dot_count) {
+#ifndef WINDLL
+                        putc('.', mesg);
+                        fflush(mesg);
+#else
+                        fprintf(stdout,"%c",'.');
+#endif
+                        mesg_line_started = 1;
+                      }
+                    }
+                }
+#if defined(MMAP) || defined(BIG_MEM)
+            if (remain == (ulg)-1L)
+                bstrm.next_in = (char *)f_ibuf;
+#else
+            bstrm.next_in = (char *)f_ibuf;
+#endif
+            bstrm.avail_in = file_read(bstrm.next_in, ibuf_sz);
+            if (file_binary_final == 0) {
+              /* check for binary as library does not */
+              if (!is_text_buf(bstrm.next_in, ibuf_sz))
+                file_binary_final = 1;
+            }
+        }
+      }
+    }
+
+    /* binary or text */
+    if (file_binary_final)
+      /* found binary in file */
+      z_entry->att = (ush)BINARY;
+    else
+      /* text file */
+      z_entry->att = (ush)ASCII;
+
+    do {
+        err = BZ2_bzCompress(&bstrm, BZ_FINISH);
+        if (maybe_stored) {
+            /* This code is only executed when the complete data stream fits
+               into the input buffer (see above where maybe_stored gets set).
+               So, it is safe to assume that total_in_hi32 (and total_out_hi32)
+               are 0, because the input buffer size is well below the 32-bit
+               limit.
+             */
+            if (err == BZ_STREAM_END
+                && bstrm.total_out_lo32 >= bstrm.total_in_lo32
+                && fseekable(zipfile)) {
+                /* BZIP2 compress does not reduce size,
+                   switch to STORE method */
+                unsigned len_out = (unsigned)bstrm.total_in_lo32;
+                if (zfwrite(f_ibuf, 1, len_out) != len_out) {
+                    ziperr(ZE_TEMP, "error writing to zipfile");
+                }
+                bstrm.total_out_lo32 = (ulg)len_out;
+                *cmpr_method = STORE;
+                break;
+            } else {
+                maybe_stored = FALSE;
+            }
+        }
+        if (bstrm.avail_out < OBUF_SZ) {
+            unsigned len_out = OBUF_SZ - bstrm.avail_out;
+            if (zfwrite(f_obuf, 1, len_out) != len_out) {
+                ziperr(ZE_TEMP, "error writing to zipfile");
+            }
+            bstrm.next_out = (char *)f_obuf;
+            bstrm.avail_out = OBUF_SZ;
+        }
+    } while (err == BZ_FINISH_OK);
+
+    if (err < BZ_OK) {
+        sprintf(errbuf, "unexpected bzlib compress error %d", err);
+        ziperr(ZE_LOGIC, errbuf);
+    }
+
+    if (z_entry->att == (ush)UNKNOWN)
+        z_entry->att = (ush)BINARY;
+#ifdef LARGE_FILE_SUPPORT
+    cmpr_size = (zoff_t)bstrm.total_out_lo32
+               + (((zoff_t)bstrm.total_out_hi32) << 32);
+#else
+    cmpr_size = (zoff_t)bstrm.total_out_lo32;
+#endif
+
+    if ((err = BZ2_bzCompressEnd(&bstrm)) != BZ_OK)
+        ziperr(ZE_LOGIC, "zlib deflateReset failed");
+    bzipInit = FALSE;
+    return cmpr_size;
+}
+
+#endif /* BZIP2_SUPPORT */
+#endif /* !UTIL */