Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

v31i093: zip19 - Info-ZIP portable Zip, version 1.9, Part01/11

33 views
Skip to first unread message

Info-ZIP group

unread,
Aug 23, 1992, 2:44:52 AM8/23/92
to
Submitted-by: zip-...@cs.ucla.edu (Info-ZIP group)
Posting-number: Volume 31, Issue 93
Archive-name: zip19/part01
Supersedes: zip: Volume 23, Issue 88-96
Environment: UNIX, VMS, OS/2, MS-DOS, MACINTOSH, WIN-NT, LINUX, MINIX, XOS, !AMIGA, ATARI, symlink, SGI, DEC, Cray, Convex, Amdahl, Sun, PC

______________________________________________________________________

Zip 1.9 is a compression and file packaging utility. It is analogous
NOTE: Info-ZIP's mailing addresses and ftp site will be changing
within the next month. The current e-mail addresses should hold for
a while via mail-forwarding, but watch for the new addresses in our
next release.
______________________________________________________________________

Zip 1.9 is a compression and file packaging utility. It is analogous
to a combination of tar and compress and is compatible with PKZIP 1.93a
(Phil Katz ZIP) for MSDOS systems. There is a companion to Zip called
UnZip (of course) which is being posted concurrently, as are the encryp-
tion/decryption routines for Zip and UnZip, and a Microsoft Windows add-
on to UnZip called WizUnZip.

This version of Zip has been ported to a wide array of Unix and other
mainframes, minis, and micros including VMS, OS/2, Minix, MSDOS, Windows-
NT, Atari, and Macintosh (the latter two have not been tested recently).
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 in-
clude creation of zip files in a pipe or on a device; VMS and OS/2 ex-
tended file attributes; conversion from Unix to MSDOS text file format;
the ZipSplit and ZipNote utilities; and, of course, the ability to run
on most of your favorite operating systems. Plus it's free. :-)

------------
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.
# Contents: atari history mac msdos nt os2 tailor.h vms
# Wrapped by kent@sparky on Sun Aug 23 01:00:42 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 1 (of 11)."'
if test ! -d 'atari' ; then
echo shar: Creating directory \"'atari'\"
mkdir 'atari'
fi
if test -f 'history' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'history'\"
else
echo shar: Extracting \"'history'\" \(49244 characters\)
sed "s/^X//" >'history' <<'END_OF_FILE'
XNote, this history contains mail addresses and ftp locations that no longer
Xexist, such as addresses at wsmr-simtel20 and directory names containing
Xw8sdz, among others. For problems, the correct email address is
Xzip...@cs.ucla.edu.
X
X------------------------ Nov 7 1990 version 0.0 ------------------------
X------------------------ Nov 8 1990 version 0.1 ------------------------
X------------------------ Nov 12 1990 version 0.2 ------------------------
X------------------------ Nov 14 1990 version 0.3 ------------------------
XThank you for your comments. Here is Zip 0.3 with almost all of that fixed.
XThe changes include:
X
X1. Put \n\ for newlines in long strings (everyone had this problem).
X2. Wrote my own bsearch (called search---different args).
X3. Wrote my own timelocal (called invlocal), used whether STDC or not.
X (Note to Greg: look at the code---I found a simple way to do it.)
X4. -m now deletes empty directories also.
X5. Changed crc.c to util.c and put search() in util.c.
X6. Changed "void *" to "voidp *" and made voidp void for STDC, else char.
X7. Removed -a option.
X8. Some minor changes to zip.doc.
X
XI did not do anything about Cliff Manis's problem with DIR not being
Xdefined. DIR should have been defined in sys/dir.h. If it wasn't, then
Xthere's something wrong with dir.h, or it is missing, or the opendir, etc.
Xfunctions are missing. I don't really want to think about what to do for
Xthe latter possibility.
X
XNUnzip 3.99 does not appear to be Unix-ready. It fails for file names longer
Xthan 12 characters (Segmentation fault), cannot find explicit names that
Xdo not contain a dot, and does not notice the Unix identifier (which should
Xswitch off name to lower-case mapping).
X
X------------------------ Nov 20 1990 version 0.4 ------------------------
XYo Zippers,
X
XHere is a first attempt at a Zip intended to work on System V. Try using
X"make sysv" for such systems. I also included replacements for memset()
Xand memcmp() by Bill Davidsen and James Dugal for systems without those.
XUse "make old" to include those routines. Sun's use getdents() like Sys V,
Xeven though it's BSD, so use "make sun". For others, try just "make".
X
XWhen using "make" a second time with a different request, it's best to erase
Xall the .o files to force recompiling everything.
X
XWhat follows are the changes I made and some things to try if you get it
Xcompiled. Have fun.
X
XMark
X
X
XChanges from Zip 0.3 to Zip 0.4:
X
X1. Changed third arg of search() to size_t to make lint happier.
X2. Replaced zip.doc with a man page, zip.1 (raw) and zip.man (formatted).
X3. rename() replaced with link() and unlink().
X4. Fixed vem in central header and added REVISION and REVDATE #define's
X to zip.h. (Didn't read Phil's appnote.txt carefully enough there.)
X5. Removed prototypes except for development host (NeXT). (They're only
X there for my benefit anyway---they should not affect the resulting
X code. Consider them some meager documentation.)
X6. Changed rindex() to strrchr().
X7. Improved behavior on a write failure when -b is used.
X8. Added Bill Davidsen's and James Dugal's memset(), memcpy(), and
X memcmp() routines under the trusty ZMEM #define.
X9. Check that zip file is writeable before doing any real work.
X10. Added #ifdef REGEX to use regcmp(), regex() instead of re_comp(),
X re_exec(). (We'll see if this works.)
X11. Replaced opendir(), readdir(), closedir() with my own opend(), readd(),
X and closed() routines that use getdirentries() on BSD and getdents() on
X System V (I hope) and Sun's. An #ifdef DIRENT selects getdents().
X12. zip.h no longer #includes string.h, instead defining the string
X functions used explicitly.
X
X
XIf you get Zip 0.4 to compile, here are some things to test:
X
X1. Try zipping up some stuff, of course. Use all the options that are
X implemented. Especially try -rp and -rpm on a directory tree (use
X *test* files and directories, of course).
X2. Naturally check with unzip -t, but also check with "zip xxx" where
X xxx.zip is the zip file. This should say "nothing to do", but if it
X says "error in zip file structure", there's a problem.
X3. After zipping, check that there are no $Z* files leftover.
X4. Try using -b, specifying a path on another device. Check for $Z*'s.
X5. Try -d and a regular expression (like \*.o) on a zip file.
X6. And I'm interested in timing---try it on a 500K or so text file.
X
X------------------------ Nov 27 1990 version 0.5 ------------------------
XHail fellow zippers,
X
XHere's Zip 0.5. The biggie is it now includes implosion, courtesy of Rich
XWales. Even as we speak, he is working on new algorithms for implode that
Xpromise to be significantly faster. He might even get a paper out of it ...
X
XYou can use the -s option (shrink only) when testing to save a little time,
Xbut also try it normally to test implosion (if you test with text files
Xof reasonable length, implosion will be chosen for most of them). Also, for
Xspeed testing of implosion, use -i to not waste time trying to shrink.
X
XIncluding implosion about doubles the size of zipnn.tar.Z, so I would like
Xsome input on distributing subsequent versions. Would y'all like to keep
Xon getting the uuencoded version via mail, or would you prefer a notice
Xabout availability via anonymous ftp on simtel20.army.mil in <w8sdz.zip>?
X(I have been sending the previous versions to Keith to put there, and will
Xcontinue to do so. I do not know what the lag time is for him to move it
Xthere.)
X
XThe other important change is that this is another attempt at getting the
Xdirectory access routines working on all systems. Read the installation
Xpart of the manual page (zip.man). And if you feel like, read the whole
Xthing. I'm also taking suggestions for and bugs in the documentation.
X
XThe differences from Zip 0.4 include:
X
X1. Changed all occurences of "size_t" to "extent" and typedef'ed extent
X to size_t (after an #include <stddef.h>) for ANSI C, or unsigned int
X otherwise. If anyone finds that they have a non ANSI C, that size_t
X is defined, and that it is not the size of the compiler's int, then
X please let me know.
X2. Changed help() to put the help text in a static array of strings and
X then printf() for each line. Some compilers barfed on the long
X string. Suggested by davi...@crdos1.crd.ge.com.
X3. Added Rich Wales' implode routines, made their inclusion the default
X (changed #ifdef IMPLODE to #ifndef NOIMPLODE).
X4. Put "extern int errno;" in unixfile.c (redundant extern's should be ok).
X5. Minor changes to the man page (zip.1 and zip.man).
X6. Added warnings for names given on the command line that are not matched.
X Lack pointed out by gri...@sj.ATE.SLB.COM (George).
X7. Changed back to opendir(), etc. on BSD systems.
X8. Added NDIR #define for HPUX to #include <ndir.h> instead of <sys/dir.h>.
X9. Redid Makefile, adding next (use shared library), sysvpw (System V's
X that require linking the libPW library for regex routines), and hpux
X (see #8 above).
X
XAs usual, report problems to info...@wsmr-simtel20.army.mil. If you wish,
Xyou can, in addition, send the same report to me (mad...@piglet.caltech.edu)
Xor Rich (wa...@cs.ucla.edu) if the problem is with implosion (i* files) for
Xquicker reponse.
X
Xyour humble servant,
XMark Adler
X------------------------ Dec 7 1990 version 0.6 ------------------------
XGreetings and Felicitations Honorable Zip Compatriots,
X
XI have uploaded Zip 0.6, which incorporates most of your helpful comments,
Xto Simtel20.Army.Mil, and it should evenually end up in <W8SDZ.ZIP> as
XZIP06.TAR-Z. The most significant change is the addition of encryption
Xboth as the -e option in Zip, and a new program, ZipCloak, that encrypts
Xand decrypts zip entries. This surely adds some new portability problems,
Xdue to the getp() routine which reads a password from the terminal with no
Xechoing. We'll see how well this flies ...
X
XIf someone wants to PKZIP up the tar.Z file, please do so. I didn't zip
Xit up myself because a) I'm lazy, and b) PKZIP can compress it better
Xanyhow, and I don't have a PC.
X
XAlso, there is an EXPORT symbol used to remove encryption, so I can make
Xan export version that does not have -e or ZipCloak. This version will
Xsimply be missing a few source files and have a different Makefile.
X
XI also added a few systems to the Makefile, and made some other changes to
Xit based on all your detailed comments. If it still works after all that,
XI'll be amazed.
X
XThose and other changes from 0.5 to 0.6 are detailed at the end of this note.
X
XI have not addressed the portability problem with the implode routines,
Xsince that is Rich's domain. I have no idea what is causing it. (For those
Xwho don't know, one system produced remarkable 90% compression rates with
Ximplode, but alas, it is a bug.)
X
XOne fellow complained that zipping up the README file results in a zip file
Xthat is larger than the original, even though Zip claims it compressed it.
XWell, it did compress it, but the ZIP file format has an overhead of
X76+2*N bytes per file+22 bytes, where N is the length of the file name.
XAnd that's without comments or "extra" information. So, a zip file with a
Xsingle file whose name has six characters has an overhead of 110 bytes.
XREADME gets shrunk by 16% from 274 bytes to 230 bytes, resulting in a total
Xzip file size of 340 bytes---larger than the original file (274 bytes).
XThe moral is don't expect zip to compress a single small file. The other
Xmoral is use unzip -v to see the compression.
X
XSomeone else asked about multi-disk zip files. I'm not sure I believe in
Xthose, since PKZIP and PKUNZIP do not appear to suppport them (though it is
Xpart of the ZIP file definition in APPNOTE.TXT). What I was planning on
Xdoing for that case was to write a ZipSplit program that would take a large
Xzip file and try to optimally split it into the fewest number of zip files
Xthat are all less than the specified size. Each would be a complete, stand
Xalone zip file---not part of a single, multi-disk zip file. There would
Xalso be a ZipMerge program.
X
XThis is the version of Zip that will live in infamy (note the revision date).
XOf course, some current Presidents of the United States think that should be
XSeptember 7th, but I won't name any names.
X
XI am going on vacation for about two weeks, so I expect to find many new
Xproblems reported upon my return.
X
XAnd lastly, for my Holiday Greetings: Party On Dudes.
X
XMark Adler
Xma...@piglet.caltech.edu
X
X
XHere are the changes from Zip 0.5 to Zip 0.6:
X
X1. Minor documentation changes (zip.1 and zip.man).
X2. Fixed an embarrasing lack of recursion in opend/readd/closed functions
X that only existed in 0.5.
X3. Moved $(LDFLAGS) to end of the linking command line in Makefile.
X4. Added make dnix for DNIX 5.2, 5.3 not using optimization (no -O).
X5. Wrote ZipCloak for encryption and decryption.
X6. Rich changed the output routines of implode to use zfwrite and zputc to
X provide hooks for encryption (defined in crypt.h). Also removed
X function prototypes unless PROTO defined.
X7. Added encryption (-e) to Zip.
X8. Added make pyramid (use rindex() instead of strrchr()).
X9. Changed make to $(MAKE) and cc to $(CC) in Makefile.
X10. Took out strip in Makefile.
X11. Changed year from 1991 to 1990. (How'd *that* get in there? Of course,
X it's not as bad as when I wrote a check the other day and dated it 1977.
X I think my brain cell isn't working as well as it used to.)
X12. Added make cray (use scc instead of cc).
X13. Added make amdahl (use system() instead of rmdir()).
X14. Added entry of one-line comments for added files (-c).
X15. Put comment delimiters around name following #endif's in Rich's code.
X
X------------------------ Feb 13 1991 version 0.7 ------------------------
XFellow stuck zippers,
X
XWell folks, it's been a while since 0.6. so there have been a lot of
Xchanges on the way to 0.7. The exhaustive listing is below, but here are
Xsome highlights ...
X
XImplode now (appears) to be PKUNZIP compatible. There were many odd
Xlittle requirements implosed by the coding of PKUNZIP that were obtained
Xfrom Phil Katz and associates. Now that Rich has that working, he will
Xlikely be working on much faster string matching routines to speed up
Ximplode.
X
XUser interrupts (control-C or kill) are now caught and the temporary files
Xare deleted, making for a clean getaway.
X
XSelf-extracting zip files for MSDOS can now be processed, with the
Xextensions zip, ZIP, exe, or EXE. This allows you to make self-extracting
Xzip files for MSDOS by taking an existing one (like PKZ110.EXE) and
Xdeleting all the entries to get a prototype self-extracting zip file that
Xcan be copied and added to. Of course, you should only do this if you are
Xa registered user of PKZIP. Note that if the file does not end in .zip,
Xyou have to give the full name.
X
XI have relaxed some of the restrictions on zip files to allow processing
Xones with "authenticity verification" (applied by the PUTAV program that
Xcomes with PKZIP). Of course, the authenticity no longer checks out if
Xyou muck with the file, but at least you can muck with it now.
X
XThe Makefile has been considerably simplified, thanks to suggestions from
XJean-Loup Gailly. Also, I wrote my own sh expression matcher, eliminating
Xthe regular expression hassles, and the REGEX symbol and -lPW options in
Xthe Makefile.
X
XMany, many cosmetic changes, the most dangerous of which was turning on
Xprototypes again in the hopes we can get them to work. If they cause you
Xproblems, record the problems (for me), and then add a -DNOPROTO to the
Xappropriate line in the Makefile and try again.
X
XThis version now compiles under Microsoft C 5.1 and Turbo C++ 1.0, with
Xmuch thanks to Jean-Loup Gailly. I say "compiles" and not "works" because
XI have not thoroughly tested it. It does work, but there may be errors in
Xthe port as well as errors in the design. By the latter I mean that there
Xmay be some disagreement over what you expect it to do and what it does,
Xespecially with regards to upper and lower case names and wildcard
Xpatterns. Also, the implode routines do not yet work under MSDOS, so the
Xcompilations are done using NOIMPLODE. There are two dumb batch files to
Xdo the compile: doturboc.bat and domsc.bat. If someone would like to
Xwrite make files for the make utilities that come with those languages,
Xplease be my guest. I'm just too lazy. However, I would probably resist
Xincluding make files that require a make utility that does not come with
Xthose languages, be it commercial, shareware, or free.
X
XThere are two new programs: ZipSplit and Ship. ZipSplit tries to split a
Xbig zip file into the smallest number of zip files less than a specified
Xsize. This is to aid in using zip to backup to floppies. It has the
Xlimitation that it cannot break up an entry in a zip file, since it makes
Xcomplete, standalone zip files. This means if any entry is larger than
Xthe specified size (plus some overhead), zipsplit will give up and not do
Xthe split. It does *not* implement the multi-disk zip file format implied
Xin APPNOTE.TXT. ZipSplit will optionally write an index file and deduct
Xthe size of that file from the first zip file so both will fit on the
Xfirst disk.
X
XShip is a fixed-up version of a program I have been using myself for some
Xtime in place of uuencode/uudecode. It's purpose is to facilitate sending
Xzip files through the mail. It uses a more efficient coding scheme than
Xuuencode (four bytes per five characters instead of three bytes per four
Xcharacters) and includes a crc at the end of each file to check the
Xveracity what was received. It can split its output to a specified size
Xand recombine it automatically at the other end, verifying the sequence.
XIt can also mail the parts to a specified address, with subject lines
Xidentifying the parts, instead of making a bunch of files that you're just
Xgoing to mail and delete anyway. Example:
X
X % ship -500 -m sad...@pickle.iq README zip07.zip
X README shipped
X zip07.zip shipped
X files part0001..part0004 mailed
X
Xwill mail README and zip07.zip together in four chunks of 500 or fewer
Xlines each. At the other end, Saddam can save the parts into the files
Xnamed in the subject lines (part0001..part0004), and then do:
X
X % ship -u part*
X README received
X zip07.zip received
X
XFor now, zip.1 (and zip.doc) are incomplete as far as MSDOS goes. I'll
Xput off doing that until the MSDOS version has stabilized. Likewise, I
Xhave put off writing zipcloak.1, zipsplit.1, and ship.1 for the same
Xreason.
X
XThere are, of course, all the little changes that fix bugs (what are
Xthose?), make the Makefile work on more systems, documentation, and,
Xfor the alert reader, an undocumented option ...
X
XAs usual, send reports to info...@wsmr-simtel20.army.mil, so everyone
Xcan get a chuckle out of whatever new bugs I've introduced.
X
XMark Adler
Xma...@pooh.caltech.edu
X
X
XChanges from release 0.6 to release 0.7:
X
X1. Changed Makefile to use mv instead of -o on compiles.
X2. Added MAKE = make to Makefile.
X3. Catch user interrupt or termination and delete temporary files.
X4. Allow general purpose flags in local and central headers to differ in
X the "reserved" bits. Keep both for copying zip entries verbatim.
X5. Removed prototype for closedir--return value not used and inconsistent
X across systems.
X6. Wrote ZipSplit to break a large zip file into the smallest number of
X zip files less than a specified size. Run zipsplit with no arguments
X to see the command help.
X7. Put error messages in globals.c to be common across zip, zipcloak, and
X zipsplit. Use #define's in zip.h for error numbers.
X8. Changed getp() to open a new file for the terminal device, and added
X the echon() function to turn echoing back on when interrupted at
X password prompt.
X9. Added warn()'s to distinguish various zip file structure errors.
X10. Allow "extra" fields in local and central headers to differ.
X11. Fixed percent compression calculation to work for very large files.
X12. Included the program (makecrc.c) that generates the CRC table.
X makecrc.c is not compiled or run by the Makefile, but is present for
X completeness.
X13. Added an undocumented (except for here) option, -v, to zip that checks
X for "oddities" in the zip file structure and points them out if found
X (but continues processing).
X14. Put prototypes in crypt.h inside #ifdef NeXT to avoid redefinition
X problems with other compilers.
X15. Added "make zilog" for Zilog S8000 running Zeus 3.21.
X16. Minor changes to the manual page (zip.1 and zip.doc).
X17. Fixed bug in replace() (manifested by -b option).
X18. readzipfile() now also checks the central directory start and size in
X the end of central directory header.
X19. Allow modification of self-extracting zip files (exe instead of zip).
X20. Allow .ZIP as valid suffix as well as .zip (also .EXE and .exe).
X21. Cleaned up malloc usage, free'd everything malloc'ed.
X22. fclose'd all fopen'ed files explicitly.
X23. Corrected assignment of one ftell() result from an int to a long.
X24. Considerably simplified Makefile, based on Jean-Loup Gailly's
X suggestions.
X25. Renamed unixfile.c to fileio.c in anticipation of non-unix support.
X26. Removed const's (pesky little buggers caused too many problems).
X27. Wrote my own shell expression compare routine, took REGEX and -lPW's
X out of Makefile, which removed the sysvpw make option.
X28. Added tempname() prototype to crypt.h for the implode routines to use.
X29. Trying string.h for prototypes of string functions if __STDC__
X defined, which is what unzip.h does.
X30. Turned prototypes on if __STDC__ defined (we'll try this one more
X time). They can be turned off using NOPROTO.
X31. Improved source documentation.
X32. Changed prototype of open in fileio.c to OF((char *, int, ...)).
X33. Removed "local" from prototypes of main() (after all, it's *not*
X local).
X34. Wrote Ship program to supplant uuencode--slightly more efficient, has
X error checking, file splitting, automatic mailing, other features.
X Ship currently uses the command:
X /usr/ucb/mail -s subject < tempfile
X to send mail. Please let me know what works for your system. Note
X that I want to be able to specify a subject line.
X35. Ported to MSDOS Microsoft C 5.1, based on Jean-Loup Gailly's work.
X36. Fixed add/update bug when -p not used.
X37. Handle lower case conversion and devices (e.g. C:) for MSDOS.
X38. Indented the #ifdef/#ifndef constructs that do not contain function
X definitions, to improve the readability somewhat.
X39. Cleaned up error handling. Now use perror() for i/o errors. Put the
X errors and messages in ziperr.h.
X40. Ported to MSDOS Turbo C++ 1.0.
X41. Implemented wild card expansion on the command line for MSDOS and
X handle MSDOS matching (*.* == all, not *).
X42. Changed version required to unzip to 11 (1.10) since the implode
X routines can procude an overlapping match one away from the end of the
X window (PKUNZIP 1.00 requires two away from the end).
X43. Changed old next make option to next10 (for version 1.0) and added a
X new next make option for 2.0 (just called next) that uses the -object
X linking option for smaller executables.
X44. Added -z option to take a multi-line zip file comment from stdin.
X45. Changed temporary names from $ZXXXXXX to _ZXXXXXX, where XXXXXX is
X filled in by mktemp(). This avoids problems with "rm $Z*" in sh.
X46. Got new implode routines from Rich that are (hopefully) PKUNZIP
X compatible.
X47. When -b is not specified, put the temporary files in the same
X directory (i.e. the same device) that the zip file is (or will be) in.
X48. Added doturboc.bat and domsc.bat files to compile for Turbo C++ 1.0
X and Microsoft C 5.1. I am interested in successes and failures with
X other versions of those compilers. In this version, the implode
X routines do not work under MSDOS.
X------------------------ May 6 1991 version 0.8 ------------------------
XBuenos Dias Amigos,
X
XHeer ees dee Cinco de Mayo reeleese of seep, aka Zip 0.8. The changes
Xfrom 0.7 are in the (long) list below, but here are some highlights:
Xfaster implode, faster shrink, first attempt at a VMS version (thanks
Xto Cave Newt), and a new program, ZipNote, to aid in editing zip file
Xcomments. To compile under VMS, do an "@makevms.com". To compile using
XMircosoft C do a "make makefile.msc". To compile using Borland (Turbo)
XC, do a "make -fmakefile.bor". Please try to break any or all of these
Xprograms in every conceivable way--we're getting close a public release.
XThank yew fer your support.
X
XMark Adler
Xma...@pooh.caltech.edu
X
XChanges from 0.7 to 0.8:
X
X1. Added the -n option to prevent compressing already compressed files.
X Documented -n in zip.1.
X2. Check the length of the compressed data in zipup() in case implode or
X shrink has a bug.
X3. Fixed -v option to not complain about needing PKUNZIP 1.1.
X4. Added report of store/shrink/implode sizes when -v (verbose) used.
X5. Put in Rich's patch to fix 100% implosion bug.
X6. Fixed -i bug.
X7. Made changes to im_ctree.c and implode.c to (hopefully) make it work
X under MSDOS. (Jean-Loup said declare topmaxvals and botmaxvals as
X U_INT in im_ctree.c, and use MSDOS, not __MSDOS__ in implode.c.)
X8 Added implode routine compilation to domsc.bat and doturboc.bat.
X9. Replaced FILENAME_MAX with FNMAX, which is now always 1024. (It seems
X FILENAME_MAX is incorrectly set to 14 on some System V Unixii.)
X10. Changed BEST to -1 so it is different from STORE (=0). Redid some of
X the method logic in zipup().
X11. Changed wb+ to w+b in implode.c.
X12. Removed "nothing to do" error for -u and -f.
X13. Zip source distributions will now have tabs removed, except for
X Makefile and Makefile.exp (no feelthy tabs rule).
X14. Changed zip error on open failure to a warning. This accounts for
X files that do not have read permission or are locked, and files
X deleted during the zip. For entries being updated, the old entry is
X copied over instead. This change had the side effect of removing the
X zipskip() routine.
X15. Removed OBJC dependencies in Makefile.exp (didn't belong).
X16. Removed strip from Makefile, instead using the -s link option.
X17. Fixed -um and -fm to delete files whose entry's times were checked in
X the archive.
X18. Put portability stuff common to zip.h and crypt.h into tailor.h.
X19. Added mark tracing to -v (for debugging).
X20. Changed name and zname logic--an external name is always converted
X into an internal zname, and vice-versa. zname is now always
X malloc'ed.
X21. Fixed -z to use CRLF between lines (for PKZIP) and have no newline
X after the last (or only) line.
X22. Added clean to Makefile (deletes *.o, zip, zipcloak, zipsplit, ship).
X23. Replaced LDFLAGS with LFLAGS1 and LFLAGS2 in Makefile (splits link
X options before and after object files as in unzip).
X24. Added scodos to Makefile (from Bill Davidsen).
X25. Included stdio.h in tailor.h--removed stdio.h from zip.h and
X implode.h.
X26. Do not include stddef.h if M_XENIX defined.
X27. Cast the arguments of all free() calls to (voidp *).
X28. Added casts to char * for memset() and qsort() args in zipsplit.c.
X29. Changed implode.h to define malloc and str* properly.
X30. Fixed invlocal() to handle integer overflow correctly, as well as
X reliably across compilers.
X31. Got new implode.h from Rich with fix #29 above. Removed stdio.h
X include.
X32. Commented out the abort() calls in im_ctree.c.
X33. -ee requests a verification of the encryption password.
X34. malloc and free tempath.
X35. Documented -, SCO, and scodos in zip.1, and - in help().
X36. Added revision.h for Zip revision number and date.
X37. -u and -f with no arguments now (both) freshen the entire archive.
X38. Use /Oait instead of /Ox for MSC to avoid loop optimization (buggy on
X 5.1, and sometimes even crashes compiler!).
X39. Added ! (reverse) range matching to shmatch(), and early abort on '*'
X failures (speeds up pathological patterns). Cleaned up '\' (escape)
X handling.
X40. Changed '!' in ship to '{' (some EBCDIC translations do not include
X !). However, unship (ship -u) still understands '!'. Also added the
X -v option of ship to print out the version and revision date. Also
X now refuse to overwrite an existing file when unshipping (ship -u),
X but there is a -o option to overwrite anyway.
X41. Added a "fast" mode to ship using hard-arithmetic coding that is
X nearly as efficient as base 85 coding, but much faster on 16-bit
X machines (base 85 coding uses 32 bit multiplication and division).
X42. Put tailor.h back in ship.c, so that ship.c can stand on its own.
X43. Made -p the default, and added a new option, -j to do the opposite
X (junk directory names). -p is still there but does nothing, so as to
X avoid annoying PKZIP users. Changed documentation and help()
X accordingly.
X44. If -j is used, and two files are to be added with the same name, then
X zip exits with an error.
X45. Wrote ZipNote for editing zipfile comments. Just do zipnote for
X usage.
X46. Replaced Rich's im_lmat.c with a new one from Jean-Loup. Improves the
X speed of implode by a factor of two, and even more for very large
X files.
X47. Reduced the execution time of shrink by 33% simply by moving the code
X around (eliminated some unnecessary calls, moved some tests).
X Shrink's execution time is now about 50% more than compress (it used
X to take over twice as long). Hash tables for shrink are still
X intended for a future release.
X48. VMS mods from Greg: replace() unlinks only after copy, changed
X delete() to destroy(), added code for deletedir(), use creation time
X instead of modification time, warn if stamp() attempted, changed
X includes, make link rename and unlink delete, added findfirst,
X findnext stuff, added wild() for VMS, modified newname(), procname().
X49. Implemented internal<-->external name conversions for MSDOS and VMS.
X50. For VMS matching, changed ? to %, removed bracketed ranges.
X51. Added makevms.com, stolen from Unzip (vms_make.com).
X52. Implemented -k (force the zip file to look like it was made by PKZIP).
X53. Removed implode for VMS (it crashes--haven't tracked down where).
X54. Got Jean-Loup's makefile.dos working for MSC 5.1 (makefile.msc) and
X Turbo C++ 1.0 (makefile.bor).
X------------------------ Jul 11 1991 version 0.9 ------------------------
XHey gang,
X
XHere is our very-nearly-ready-to-release version of Zip. There will be no
Xfeatures added or changed from 0.9 to 1.0--only bugs fixed. I hope that
Xwe can get 1.0 out pretty quickly then. This is really your last chance to
Xfind bugs before it goes out, so please, please test all the programs as
Xmuch as you can. Try all the features, if possible, and perhaps try to
Xthink of ways to break the programs. Also, and this is very important, read
Xthe documentation in zip.doc and "debug" that too. I already know that it
Xis not complete in 0.9, but please send any comments about errors, omissions,
Xformat, or whatever to Info-ZIP, even if they seem obvious.
X
XThe highlights of the changes from 0.8 to 0.9 are: faster, slicker implode;
Xoperation in small model on MSDOS for speed; a new temporary file interface
Xfor faster operation on small files; some shrink improvements; and some new
Xoptions (-y, -g, -q). Also, ship has been enhanced in several ways, not the
Xleast of which is a help option (-h).
X
XHave fun.
X
XMark Adler
Xma...@tybalt.caltech.edu
X
X
XChanges from 0.8 to 0.9:
X
X1. Removed the "not implemented yet" note in help() for -k (it *is*
X implemented now). Removed from bug list in zip.1 too.
X2. Fixed Turbo C implode bug.
X3. Added /link /e in makefile.msc for ship.c.
X4. Made handler() in zipnote.c the same as handler() in zipsplit.c.
X5. Added -y option in Unix to store symbolic links as such. (We need
X Unzip to be aware of symbolic links and use symlink() to recreate them.)
X6. Ignore control characters in unship input.
X7. Use prototypes and ANSI libraries if MSDOS. (Used to check for Turbo C,
X but Microsoft C 6.0 also does not define __STDC__ unless strict ANSI
X is requested.)
X8. Added mod to ct_fsort() from Rich that should remove any qsort()
X dependencies in implode output.
X9. Removed some 32/16-bit prejudices in util.c and crypt.c that affect
X 64-bit integer (short, int, and long) machines (Cray).
X10. Added System V MAILX option to ship.c to use the mailx command. This
X is automatically activated by DIRENT if ship is compiled by the zip
X makefile.
X11. Added patches from Greg Roelofs for echo control on Cray and Amdahl.
X The patch uses termio.h and ioctl(), and is assumed for all System V,
X not just those (we'll see how this flies).
X12. Changed -Ox to -Oacegit -FPi87 in makefile.msc. Added /nologo to link.
X13. Applied J-L's 082 mods (Sinatra style): select 4K window for < 5.5K,
X 8K window for >= 5.5K files (just like PK does); various im_ctree.c
X mods verbatim (except for the treename warning, which I did differently);
X various im_lmat.c mods verbatim (except macros are done the ugly portable
X way); farmalloc'ed in shrink.c; changed makefile.msc and makefile.bor to
X use small model; added J-L to zip.1 acknowledgements (oops).
X14. Moved struct zlist's and struct flist's to far storage (needed by above
X mods). Unfortunately, I can't move the names and other things pointed to
X by those structures into the far space, since they are arguments to
X library functions like strcmp() and fwrite().
X15. Changed zipup() to both shrink and implode only on files smaller than
X BSZ. Also in that case, free up shrink data structures before allocating
X the implode data structures. Changed from fopen() to open() except for
X VMS.
X16. Fixed bug in dosmatch() to free malloc'ed space.
X17. MINIX mods (do not need minix make option): call tempname() with a unique
X character (MINIX mktemp() flawed); defined S_IWRITE as S_IWUSR if S_IWUSR
X defined; removed explicit signal dereference.
X18. Fixed bug in unship when used as a filter with no args.
X19. Changed getnam() to not use static storage.
X20. Copy permissions from old to new zip file (zip, zipcloak, zipnote).
X21. Added patches for AT&T 3B1, added 3b1 target to makefile, added to zip.1.
X22. Made FNMAX 256 for MSDOS (is 1024 otherwise).
X23. Used the "pyr" predefined symbol for Pyramid systems in tailor.h.
X24. Added Greg's VMS mods to ship.c. Added help to ship.c (-h or -?).
X Changed meaning of -nnn arg from lines to K.
X25. Moved ZMEM routines to fileio.c to properly include them in zipnote and
X zipsplit.
X26. Added -s option to ship to specify a subject line prefix.
X27. Fixed -z in zip to not trash leading blank lines in the comment.
X28. Made ship recognize "unship" in argv[0] a little more flexibly.
X29. Made sure temporary zip files are closed before being deleted by an
X error or interrupt.
X30. Added a new temporary file interface and new source files tempf.c and
X tempf.h. This avoids making temporary files for small (<16k) output.
X Both shrink and implode use this.
X31. Added OS/2 patches, files. However, left zip case-sensitive for OS/2
X names, as in Unix.
X32. Removed amdahl target in makefile, using UTS symbol instead.
X33. Changed -y to depend on definition of S_IFLNK.
X34. Avoid leading periods on lines in ship output by inserting a space.
X35. Ship is now extensible: added a warning for "unsupported keyword".
X Such keywords can appear before the "ship" line, for example.
X36. Added -g option to allow "growing" the zip file. If just adding new
X entries to a zip file, -g will write over the old zip file without
X creating a temporary. The danger is that if there is an error, the
X old zip file will be lost. If not just adding, then -g is ignored.
X37. Added aux (A/UX) target to makefile.
X38. In shrink.c, removed unnecessary FreeList and ClearList arrays, and
X the recursive Prune() routine. This also resulted in a speedup in
X shrink of about 15%. It is now only about 30% slower than Unix compress.
X39. Added -q option for quiet operation.
X------------------------ Sep 21 1991 version 1.0 ------------------------
XHello world!
X
XThis is the first public release version of Zip and its cohort utilities.
XWe hope you enjoy using it much much more than we enjoyed writing it and
Xtrying to get it to work on every fritzing raffing bliffing nobbin Unix
Xsystem in the galaxy.
X
XPlease feel free to send any problems, complaints, suggestions, kudos,
Xridicule, or whatever to zip-...@cs.ucla.edu. If there were a way to
Xsend cookies over the net, we'd accept those too.
X
XThank yew fer yur support.
X
XMark Adler
Xma...@tybalt.caltech.edu
X
X
XChanges from 0.9 to 1.0:
X
X1. Removed some pesky carriage returns masquerading as spaces in fileio.c
X and zipup.c.
X2. Removed #include memory.h in tempf.c (string.h good enough).
X3. Compile ship in doturboc.bat.
X4. Miscellaneous zip.1 (zip.doc) changes.
X5. Fixed mistake in stamp() in fileio.c (didn't double seconds).
X6. Applied Jean-Loup's mods for Cray's (do not assume 16-bit shorts).
X7. Removed pyramid make option, since #ifdef pyr seems to work.
X8. Added some casts to tempf.c to clean up some warnings.
X9. Added comment to makefile.exp saying what it is.
X10. Removed length checks in zipup.c to fix problem with using Vax variable
X record length formats.
X11. Fixed VMS replace-across-devices problem.
X12. Changed order of include's in implode.h to make tailor.h show up first.
X13. Added Convex mods and make target.
X14. Fixed path delimiter under VMS for unship.
X15. Added ship to makevms.com.
X16. Put in new copyright messages.
X17. Added aix make target.
X18. Fixed zipsplit.idx to start counting at one like the file names.
X19. Changed -a (append VMS version number) to -w to leave -a open for a
X possible future option.
X20. Back to separate makefiles for Microsoft and Borland (.msc and .bor).
X21. Workaround in fileio.c for Borland stat() bug: stat() succeeds for wild
X card names that match existing files.
X22. Added "(did you remember to use binary mode when you transferred it?)"
X to the "probably not a zip file" warning.
X23. Changed utilities to append .zip only when the zip file name does not
X contain a dot.
X24. At least mentioned the other utilities in zip.doc (zipcloak, ship, etc.),
X and documented upper case matching of names when using -d under MSDOS.
X25. Fixed bug in MSDOS version: zip foo c:autoexec.bat wouldn't work.
X26. Added hidden/system attribute bug to BUGS in zip.1
X27. Fixed recognition of unship in ship when unship is in a path.
X28. Added non-stream-LF VMS bug to zip.1 bug list.
X29. Fixed bug in #23 above when path has dots. Documented #23 in zip.1.
X30. Show disclaimer only for -l, add -h and -l to zip utilities.
X31. Applied Minix patches.
X------------------------ ??? ?? 1992 version 1.1 ------------------------
X??? To be done. Should be the last version supporting shrink and implode.
X
X------------------------ Feb 17 1992 version 1.5 ------------------------
X1. pkzip 2.0 format (deflation) now supported
X Shrink and Implode left in zip 1.1 only for backward compatibility
X
X------------------------ Mar 25 1992 version 1.6 ------------------------
X1. zip can now be used as a filter in a pipe
X2. Optimized assembler code for MSDOS and OS/2
X3. encryption is now supported
X4. Better VMS support for various file formats other than Stream-LF
X5. Better OS/2 support
X------------------------ Apr 24 1992 version 1.7a ------------------------
X1. On VMS, create new zip files in fixed length 512 format
X2. Call VMSmunch only if the zip file existed previously
X3. Avoid mktemp() and use simpler name for temporary file.
X4. Rename dir_os2.[ch] -> os2zip.[ch]
X5. On MSDOS, use fdopen() after setmode() in zip.c
X Added setmode() for stdin in zipup.c
X6. Do not split #if on two lines (some compilers don't like this)
X7. __MSDOS__ instead of __BORLANDC__ in crypt.c
X8. Added (char*) cast in deflate.c to avoid warning
X9. OS/2 support for storing file attributes in an extra field.
X
X------------------------ June 6 1992 version 1.8a ------------------------
X1. Fixed bug in tempname() for VMS
X2. Fixed type problems in zipup.c for gcc under VMS
X3. Added VMSmunch in vms subdirectory and updated makefile (descrip.mms)
X4. The extra field for OS/2 is now compressed (Kai Uwe Rommel)
X5. Added various fixes for djgcc (Onno van der Linden)
X6. Fixed long standing bug in wild() for MSDOS (Jon Saxton)
X7. Added support for ZIPOPT environment variable (Bill Davidsen
X and Antoine Verheijen).
X8. Fixed zipsplit bug for VMS (Greg Roelofs)
X9. Added fix for DEC OSF/1 (Kjetil W. J{\o}rgensen)
X10. Added fix for ultrix on DECstation (Jonathan Kamens)
X10. Added sysnopis for zipsplit, etc... in zip.1 (Jonathan Kamens)
X11. Fixed MAILX problem for SysV in ship.c (Greg Roelofs)
X12. Added Linux support (Humberto Ortiz-Zuazaga)
X13. In makefile.os2, support for $(FP), masm 5.x, match.s (Greg & Kai)
X14. Added -w-cln in makefile.bor to avoid warning (David Kirschbaum)
X15. VMS echo suppression code incorporated (Greg Roelofs)
X16. Added fix to match.asm if WSIZE != 32768
X17. Create .exe files directly for target scodos (Bill Davidsen)
X18. Fixed the -0 bug (compressed size was doubled)
X19. Changed -- (read names from stdin) to -@ to reserve -- for undoing
X the effects of ZIPOPT
X20. Create zip entries for directories with the -r option, so that
X directory attributes can be saved. (Kai Uwe Rommel)
X
X------------------------ June 17 1992 version 1.8b ------------------------
X1. Changed -s (Software license) to -L (license) to avoid clash
X with the old shrink option.
X2. read_buf declared as extern only in zip.h
X3. avoid warnings in zip.c for Turbo C: while ((ch = *s) != '\0'
X4. suppressed unused variables mem_inbuf and mem_outbuf in bits.c
X5. Speed up the search for start of zip structures (pksfx files)
X6. Allow updates of an empty pksfx file (original file was destroyed)
X7. Keep correct offsets for pksfx files
X8. On MSDOS, in2ex() was updating the input argument. Also, do not
X force upper case: keep the name as it was in the old zip file.
X This is important for -f. Similarly, force lower case in ex2in()
X on MSDOS, except when dosify (-k) is imposed. I kept however the
X old code under the flag FORCE_UPPER in case I goofed.
X9. When growing a zip file with -g and interrupting it, the whole file was
X lost. We now attempt to restore the previous state of the file.
X10. "zip -fo jjj", where jjj is a non-existent zipfile, used to dump core.
X We now emit a warning.
X11. More generally, we emit a warning for all options assuming the presence
X of a zip file (-d,-f,-u,-g) if the zip file did not exist or was empty.
X Idem for "zip -o jjj" on non-existent or empty zip file.
X12. Copy also the extended local entry in zipcopy().
X13. Updated zip.1 and vms/vms_zip.rnh to describe the new features.
X14. Fixed bug in zipsplit (wrong offsets for all files but first)
X15. Added match.s, optimized 386 version of longest_match() for Unix and
X 32 bit OS/2 (with gas).
X16. Added os2/match32.asm, optimized 386 version of longest_match() for
X 32 bit OS/2 (for assemblers using Intel syntax). NOT TESTED YET.
X17. Added "assume DS: DGROUP" in match.asm to allow SS_NEQ_DS even with MSC.
X18. Added include <malloc.h> in tailor.h for Unix. This is required on
X 16-bit Unix.
X19. Use init_upper() in os2zip.[ch]
X20. Switched back to old tempname(): the new one could overwrite an existing
X file, it ignored tempath, and it caused problems on VMS for files with a
X '.' in the name. Kept however the old code if NO_MKTEMP is defined.
X21. Use 0x1 instead of (unsigned)1 in definition of HSIZE (one compiler
X does not like the cast in an array definition).
X22. Include VMSmunch.h in zip.c
X23. On VMS, zip -o screwed up all offsets in pksfx files
X
X------------------------ June 18 1992 version 1.8c ------------------------
X1. Added missing comma in revision.h
X2. invlocal doesn't work on Cray, use mktime instead (Greg Roelofs)
X3. On VMS, use ctx=stm only to read zipfiles, not input files.
X4. Undo change 21 above, which breaks even more compilers
X5. Include dos.h in util.c and fix trivial compilation errors
X6. Undo change 1 of 1.8b: -L already used for OS/2 (Steve Salisbury)
X7. Do not create a zip entry for directory "." (Greg Roelofs)
X8. Avoid core dump when -@ is given before the zip file (and do
X the right thing).
X
X------------------------ June 19 1992 version 1.8d ------------------------
X1. Force calloc to take unsigned values. (Problem with one 16 bit
X compiler on AT&T 6300).
X2. Fixed fileio.c for Convex (Bill Davidsen)
X3. util_ was missing for zipnote and zipsplit in make_vaxc.com (Glenn Andrews)
X4. Added warning in zip.1 and below (do not update encrypted files
X with pkzip 1.10).
X5. Fixed fix 12 of 1.8b. I drink too much. (Confused bit 1 with bit 8).
X6. Updated install.doc
X7. Fixed result type of os2 version of init_upper().
X8. Added makefile entry for AT&T 6300 (Peter Mauzey)
X9. Fixed typo in descrip.mms
X10. Removed zipfile.c warning: shift count exceeds width of value shifted
X11. Fix enormous bug in init_upper for VMS (upper stayed as zero)
X
X------------------------ June 23 1992 version 1.8e ------------------------
X1. Don't include malloc.h by default (does not exist on VMS)
X2. Define calloc for 16 bit systems (required for AT&T 6300)
X3. Simpler make_vaxc.com (Greg Roelofs)
X4. New vms/descrip.mms and fixes in zipfile.c (Igor)
X5. seekable() must be true for in-memory compression.
X6. Undefine S_IFLNK if NO_SYMLINK (problems with VMS and SCO)
X7. Include descrip.h only once in fileio.c (Mike Freeman)
X8. New os2/match32.asm (untested) and makefile.os2.
X9. Added dosflag in zlist and flist entries, to force MSDOS file
X attributes. It is set if dosify is set, or (under OS/2) for a file
X on a FAT file system which does not have a long name (Kai-Uwe).
X10. Added GetFileTime on OS/2 to avoid core dump on bad dates (Kai-Uwe)
X11. New vms.c supporting deflation of extra headers
X
X------------------------ June 24 1992 version 1.8f ------------------------
X1. Incorporated (finally!) Mac support. *Untested*. (James E. O'Dell)
X2. Another long awaited change: Atari ST. Also *untested*.
X (mar...@atlantic.cs.unb.ca)
X3. New makefile.os2, as usual. (Kai-Uwe)
X4. Support for Watcom C in os2zip.c. *Not yet working*. (Kai-Uwe).
X5. I forgot to output the length for stored blocks...
X
X------------------------ June 29 1992 version 1.8g ------------------------
X1. New os2zip.c and makefile.os2 as usual.
X2. In the VMS makefiles, define the symbols systematically so that
X people won't forget to update them. (Fed up with the reports that
X zip does not accept parameters).
X3. Use -L for software License and -E for Extended attributes
X4. Added -F 1000 in makefile entry for scodos (Bill Davidsen)
X5. Replaced strcmp with namecmp in zip.c for check of zipfile name.
X6. New os2/match32.asm (still not working)
X7. Do not close stdin (check for null ifile in zipup.c).
X8. signal handlers for zip and zipcloak fixed to restore echo for VMS
X9. slightly cleaner VMS echo calls in fileio.c
X10. stricmp missing from VMS zipsplit, zipnote: since UTIL was unused for
X util.c, I used it to specify stricmp only; then I had to change some of
X the makefiles which previously used util_.* to use util.*, and I added
X util_.obj to OBJS and OBJN in all of the VMS makefiles. (Greg)
X11. ifdef'd out the debugging commentary in vms.c (Greg)
X12. new VMS makefile for use with (free) MAKE/VMS (Greg)
X13. Eliminate some compiler warnings from BCC, MSC, gcc (Onno van der Linden)
X14. Do not use MSDOS version of init_upper for djgpp (Onno van der Linden)
X15. In msdos/makefile.gcc, added util_.o to OBJN and OBJS, and used asm version
X match.o (Onno van der Linden)
X16. Added install target in makefile (Alvin Koh)
X17. Default makefile entry is named 'all'.
X18. fixes to vms.c for gcc (Igor)
X19. Define S_IWRITE as S_IWUSR for Minix only (problem on X/OS) (Fulvio Marino)
X20. Added xos makefile entry (Fulvio Marino)
X21. In VMS, files without an extension are now stored without the dot (Greg
X and Igor).
X22. Save/restore ebx in match.s and match32.asm
X23. Fixed MAX_DIST in match.s (the asm code produced different results
X than the C code)
X24. Fixed the -b option: allow ENOTSAM instead of EXDEV (used by Turbo C).
X25. Do not complain about zip files created on MSDOS with versions of zip
X above 1.0.
X
X------------------------ Aug 14 1992 version 1.9a ------------------------
X1. Changed -S to -L in help screen
X2. Do not declare chmod for aegis (George Grimes)
X3. Cleaner vms/make_gcc.com (Mike Freeman)
X4. Disabled built-in functions for Linux (Arnt Gulbrandsen)
X5. Added a description of the deflation algorithm in algorith.doc.
X6. Removed ship, now distributed separately.
X7. Added the CRC for in-memory compression. The extra-field format is now
X the official PKWare format (Kai-Uwe)
X8. On OS/2, force lower case names for FAT files if -k is not given. (Kai-Uwe)
X9. Allow coutry dependent mapping for upper to lower case. (Kai-Uwe)
X10. Use namecmp instead of stricmp which was confusing. (Onno van der Linden)
X11. Avoid some warnings in deflate.c (Onno van der Linden)
X12. Avoid one warning in crypt.c, and distribute it separately.
X13. Call init_upper() for all utilities and add util_.o in makefiles (Kai-Uwe)
X
X------------------------ Aug 18 1992 version 1.9b ------------------------
X1. Fixes for Windows NT (Dave Feinleib)
X2. Avoid two warnings for Ultrix (makefile and fileio.c)
X3. Finally removed the declaration of chmod(), which causes endless
X new patches for each new target.
X4. Allow -L for license in the utilities (zipsplit, zipnote, zipcloak).
X5. Mention funzip in zip.1.
X6. Untabify all sources files (for more reliable context diffs)
X7. Fix bug in trees.c dealing with bit length overflow.
X8. Fix bug in zipup.c when reading from stdin: if (ifile) does not
X produce the expected result.
X9. Avoid duplication of bug list in zip.1 and history.
X10. Removed ship from zip.1.
X
X------------------------ Aug 20 1992 version 1.9 ------------------------
X1. Renamed the atari files to avoid name conflicts (for unzip -j).
X2. Don't tell 'use zip -L' in zipnote and zipsplit.
X3. Add a rule for util_.ojb in the msdos and atari makefiles
X4. Fixed compilation option for util_.obj in makefile.msc (msc 5.1 bug)
X5. Added the 'Where' file.
X6. More information about zip in Readme.
X7. Fixed install.doc.
X8. Fixed vms/vms_zip.rnh
X9. Fixed init_upper() in util.c and os2zip.c (Kai-Uwe)
X
X
XThings to check or to be done (see also BUGS section in zip.1):
X
X- zip should not create 'stored' files with extended local headers
X
X- There is not (yet) a way to undo the effect of ZIPOPT
X
X- Under MSDOS, zip will find hidden and system files, but not set the
X attributes appropriately in the zip file so that unzip can restore them.
X
X- it is possible in weird cases to add a zipfile to itself
X
X- On OS/2, zip refuses to match some names, such as those beginning with an
X exclamation mark. Same for names starting with #, possibly more.
END_OF_FILE
if test 49244 -ne `wc -c <'history'`; then
echo shar: \"'history'\" unpacked with wrong size!
fi
# end of 'history'
fi
if test ! -d 'mac' ; then
echo shar: Creating directory \"'mac'\"
mkdir 'mac'
fi
if test ! -d 'msdos' ; then
echo shar: Creating directory \"'msdos'\"
mkdir 'msdos'
fi
if test ! -d 'nt' ; then
echo shar: Creating directory \"'nt'\"
mkdir 'nt'
fi
if test ! -d 'os2' ; then
echo shar: Creating directory \"'os2'\"
mkdir 'os2'
fi
if test -f 'tailor.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'tailor.h'\"
else
echo shar: Extracting \"'tailor.h'\" \(6875 characters\)
sed "s/^X//" >'tailor.h' <<'END_OF_FILE'
X/* tailor.h -- Not copyrighted 1992 Mark Adler */
X
X/* const's are inconsistently used across ANSI libraries--kill for all
X header files. */
X#ifndef __GO32__
X# define const
X#endif
X
X
X/* Define MSDOS for Turbo C as well as Microsoft C */
X#ifdef __POWERC /* For Power C too */
X# define __TURBOC__
X#endif /* __POWERC */
X#if (defined(__TURBOC__) && !defined(MSDOS))
X# define MSDOS
X#endif
X
X#ifdef ATARI_ST
X# undef MSDOS /* avoid the MS-DOS specific includes */
X#endif
X
X/* Use prototypes and ANSI libraries if _STDC__, or Microsoft or Borland C,
X * or Silicon Graphics, or IBM C Set/2, or GNU gcc under emx.
X */
X#if (defined(__STDC__) || defined(MSDOS) || defined(sgi))
X# ifndef PROTO
X# define PROTO
X# endif /* !PROTO */
X# define MODERN
X#endif /* MSDOS */
X
X#if (defined(__IBMC__) || defined(__EMX__) || defined(ATARI_ST))
X# ifndef PROTO
X# define PROTO
X# endif /* !PROTO */
X# define MODERN
X#endif
X
X
X#ifdef __IBMC__
X# define S_IFMT 0xF000
X#endif /* __IBMC__ */
X
X#ifdef __EMX__
X# define __32BIT__
X#endif /* __EMX__ */
X
X#ifdef __WATCOMC__
X# define __32BIT__
X#endif
X
X#if (defined(__OS2__) && !defined(OS2))
X# define OS2
X#endif
X
X
X/* Turn off prototypes if requested */
X#if (defined(NOPROTO) && defined(PROTO))
X# undef PROTO
X#endif
X
X
X/* Used to remove arguments in function prototypes for non-ANSI C */
X#ifdef PROTO
X# define OF(a) a
X#else /* !PROTO */
X# define OF(a) ()
X#endif /* ?PROTO */
X
X
X/* Memory allocation. */
X#ifdef MACOS
X# define DYN_ALLOC
X#endif
X#if (defined(MSDOS) && !defined(__GO32__) && !defined(WIN32))
X# ifdef __TURBOC__
X# include <alloc.h>
X# define DYN_ALLOC
X /* Turbo C 2.0 does not accept far static allocations in small model */
X void far * fcalloc OF((unsigned items, unsigned size));
X# else /* !__TURBOC__ */
X# include <malloc.h>
X# define farmalloc _fmalloc
X# define farfree _ffree
X# define fcalloc(nitems,itemsize) halloc((long)(nitems),(itemsize))
X# endif /* ?__TURBOC__ */
X#else /* !MSDOS */
X# if defined(WIN32)
X# include <malloc.h>
X# endif
X# ifdef far
X# undef huge
X# undef far
X# undef near
X# endif
X# define huge
X# define far
X# define near
X# define farmalloc malloc
X# define farfree free
X# define fcalloc(items,size) calloc((unsigned)(items), (unsigned)(size))
X# ifndef PROTO
X extern char *calloc(); /* essential for 16 bit systems (AT&T 6300) */
X# endif
X#endif /* ?MSDOS */
X
X
X#if (defined(OS2) && !defined(MSDOS))
X/* MSDOS is defined anyway with MS C 16-bit. So the block above works.
X * For the 32-bit compilers, MSDOS must not be defined in the block above. */
X# define MSDOS
X/* inherit MS-DOS file system etc. stuff */
X#endif
X
X
X/* Define MSVMS if either MSDOS or VMS defined */
X#if defined(MSDOS) || defined(VMS)
X# define MSVMS
X#endif
X
X/* case mapping functions. case_map is used to ignore case in comparisons,
X * to_up is used to force upper case even on Unix (for dosify option).
X */
X#if defined(OS2) || defined(MSDOS) || defined(VMS)
X# define case_map(c) upper[c]
X# define to_up(c) upper[c]
X#else
X# define case_map(c) (c)
X# define to_up(c) ((c) >= 'a' && (c) <= 'z' ? (c)-'a'+'A' : (c))
X#endif
X
X/* Define void, voidp, and extent (size_t) */
X#include <stdio.h>
X#ifdef MODERN
X# if (!defined(M_XENIX) && !(defined(__GNUC__) && defined(sun)))
X# include <stddef.h>
X# endif /* !M_XENIX */
X# include <stdlib.h>
X typedef size_t extent;
X typedef void voidp;
X#else /* !MODERN */
X typedef unsigned int extent;
X# define void int
X typedef char voidp;
X#endif /* ?MODERN */
X
X/* Get types and stat */
X#ifdef VMS
X# include <types.h>
X# include <stat.h>
X#else /* !VMS */
X# ifdef MACOS
X# include <types.h>
X# include <stddef.h>
X# include <Files.h>
X# include <StandardFile.h>
X# include <Think.h>
X# include <LoMem.h>
X# include <Pascal.h>
X# include "macstat.h"
X# else
X# ifdef ATARI_ST
X# include <ext.h>
X# include <tos.h>
X# else
X# include <sys/types.h>
X# include <sys/stat.h>
X# endif
X# endif
X#endif /* ?VMS */
X
X/* Some systems define S_IFLNK but do not support symbolic links */
X#if defined (S_IFLNK) && (defined(NO_SYMLINK) || defined(MACOS))
X# undef S_IFLNK
X#endif
X
X/* Cheap fix for unlink on VMS */
X#ifdef VMS
X# define unlink delete
X#endif /* VMS */
X
X
X/* For Pyramid */
X#ifdef pyr
X# define strrchr rindex
X# define ZMEM
X#endif /* pyr */
X
X
X/* File operations--use "b" for binary if allowed or fixed length 512 on VMS */
X#ifdef VMS
X# define FOPR "r","ctx=stm"
X# define FOPM "r+","ctx=stm","rfm=fix","mrs=512"
X# define FOPW "w","ctx=stm","rfm=fix","mrs=512"
X#else /* !VMS */
X# ifdef MODERN
X# define FOPR "rb"
X# define FOPM "r+b"
X# define FOPW "wb"
X# else /* !MODERN */
X# define FOPR "r"
X# define FOPM "r+"
X# define FOPW "w"
X# endif /* ?MODERN */
X#endif /* VMS */
X
X/* Open the old zip file in exclusive mode if possible (to avoid adding
X * zip file to itself).
X */
X#ifdef OS2
X# define FOPR_EX FOPM
X#else
X# define FOPR_EX FOPR
X#endif
X
X/* Define this symbol if your target allows access to unaligned data.
X * This is not mandatory, just a speed optimization. The compressed
X * output is strictly identical.
X */
X#if defined(MSDOS) || defined(i386) || defined(mc68020) || defined(vax)
X# define UNALIGNED_OK
X#endif
X
X
X/* Under MSDOS we may run out of memory when processing a large number
X * of files. Compile with MEDIUM_MEM to reduce the memory requirements or
X * with SMALL_MEM to use as little memory as possible.
X */
X#ifdef SMALL_MEM
X# define CBSZ 2048 /* buffer size for copying files */
X# define ZBSZ 2048 /* buffer size for temporary zip file */
X#else
X# ifdef MEDIUM_MEM
X# define CBSZ 8192
X# define ZBSZ 8192
X# else
X# if defined(OS2) && !defined(M_I86SM)
X# define CBSZ 0xE000
X# define ZBSZ 0x7F00
X /* The C library of some compilers does not allow a buffer size > 32K */
X# else
X# define CBSZ 16384
X# define ZBSZ 16384
X# endif
X# endif
X#endif
X
X#ifdef ATARI_ST
X# define MSDOS
X# define MSVMS
X# ifndef O_BINARY
X# define O_BINARY 0
X# endif
X# ifndef S_IFMT
X# define S_IFMT (S_IFCHR|S_IFREG|S_IFDIR)
X# endif
X
X/* a whole bunch of functions needs Tos '\\' filnames
X * instead of '/', the translation functions are in fileio.c:
X */
X# define unlink st_unlink
X# define chmod st_chmod
X# define mktemp st_mktemp
X# define fopen st_fopen
X# define open st_open
X# define SSTAT st_stat
X# define findfirst st_findfirst
X# define link st_rename
X# define rmdir st_rmdir
X
X int st_unlink OF((char *));
X int st_chmod OF((char *, int));
X char *st_mktemp OF((char *));
X FILE *st_fopen OF((char *, char *));
X int st_open OF((char *, int));
X int st_stat OF((char *, struct stat *));
X int st_findfirst OF((char *, struct ffblk *, int));
X int st_rename OF((char *, char *));
X int st_rmdir OF((char *));
X#else
X# define SSTAT stat
X#endif
X
X/* end of tailor.h */
END_OF_FILE
if test 6875 -ne `wc -c <'tailor.h'`; then
echo shar: \"'tailor.h'\" unpacked with wrong size!
fi
# end of 'tailor.h'
fi
if test ! -d 'vms' ; then
echo shar: Creating directory \"'vms'\"
mkdir 'vms'
fi
echo shar: End of archive 1 \(of 11\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 11 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0
exit 0 # Just in case...

Info-ZIP group

unread,
Aug 23, 1992, 2:45:13 AM8/23/92
to
Submitted-by: zip-...@cs.ucla.edu (Info-ZIP group)
Posting-number: Volume 31, Issue 94
Archive-name: zip19/part02

Supersedes: zip: Volume 23, Issue 88-96
Environment: UNIX, VMS, OS/2, MS-DOS, MACINTOSH, WIN-NT, LINUX, MINIX, XOS, !AMIGA, ATARI, symlink, SGI, DEC, Cray, Convex, Amdahl, Sun, PC

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: atari/stzip.lnk fileio.c


# Wrapped by kent@sparky on Sun Aug 23 01:00:42 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 2 (of 11)."'
if test -f 'atari/stzip.lnk' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'atari/stzip.lnk'\"
else
echo shar: Extracting \"'atari/stzip.lnk'\" \(180 characters\)
sed "s/^X//" >'atari/stzip.lnk' <<'END_OF_FILE'
X\TC\lib\c0.o
Xzip.o
X\TC\lib\tcstdlib.lib
Xatari.o
Xzipfile.o
Xzipup.o
Xfileio.o
Xutil.o
Xglobals.o
Xdeflate.o
Xtrees.o
Xbits.o
X\TC\lib\tcstdlib.lib
X\TC\lib\tcextlib.lib
X\TC\lib\tctoslib.lib
END_OF_FILE
if test 180 -ne `wc -c <'atari/stzip.lnk'`; then
echo shar: \"'atari/stzip.lnk'\" unpacked with wrong size!
fi
# end of 'atari/stzip.lnk'
fi
if test -f 'fileio.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'fileio.c'\"
else
echo shar: Extracting \"'fileio.c'\" \(57097 characters\)
sed "s/^X//" >'fileio.c' <<'END_OF_FILE'
X/*
X
X Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly,
X Kai Uwe Rommel and Igor Mandrichenko.
X Permission is granted to any individual or institution to use, copy, or
X redistribute this software so long as all of the original files are included
X unmodified, that it is not sold for profit, and that this copyright notice
X is retained.
X
X*/
X
X/*
X * fileio.c by Mark Adler.
X */
X
X#include "zip.h"
X
X#include <time.h>
X
X#ifdef WIN32
X# include <sys/utime.h>
X# include <windows.h> /* for findfirst/findnext */
X#endif
X
X#ifdef MACOS
X# define EXDEV 1
X#endif
X
X#ifdef OSF
X# define EXDEV 18 /* avoid a bug in the DEC OSF/1 header files. */
X#else
X# include <errno.h>
X#endif
X
X#ifdef MINIX
X# ifdef S_IWRITE
X# undef S_IWRITE
X# endif /* S_IWRITE */
X# define S_IWRITE S_IWUSR
X#endif /* S_IWUSR */


X
X#ifdef ATARI_ST
X# undef MSDOS

X#endif
X
X#ifdef MSDOS
X# include <io.h>
X# if (defined(__TURBOC__) || defined(__GO32__))
X# include <dir.h>


X# else /* !__TURBOC__ */

X# if !defined(__EMX__) && !defined(__WATCOMC__)
X# include <direct.h>
X# endif


X# endif /* ?__TURBOC__ */

X# define link rename
X# ifdef OS2
X# define MATCH shmatch
X# else /* !OS2 */
X# define MATCH dosmatch
X# endif /* ?OS2 */
X#else /* !MSDOS */
X extern int errno; /* error number from system functions */
X# ifdef VMS
X# define RMDIR
X# define link rename
X# include "VMSmunch.h"
X# endif /* VMS */
X# ifdef MACOS
X# define link rename
X# define mktemp tmpnam
X# endif
X# define MATCH shmatch


X#endif /* ?MSDOS */
X

X#ifdef ATARI_ST
X# define MSDOS 1
X#endif
X
X#ifdef UTS
X# define RMDIR
X#endif /* UTS */
X
X
X/* Extra malloc() space in names for cutpath() */
X#ifdef VMS
X# define PAD 3 /* may have to change .FOO] to ]FOO.DIR */
X#else /* !VMS */
X# define PAD 0


X#endif /* ?VMS */
X
X

X/* For now, assume DIRENT implies System V implies TERMIO */
X#if defined(DIRENT) && !defined(MINIX) && !defined(TERMIO)
X# define TERMIO
X#endif
X
X
X#ifdef CRYPT
X# ifdef MSVMS
X# ifdef MSDOS
X# ifdef __EMX__
X# define getch() _read_kbd(0, 1, 0)
X# else
X# ifdef __GO32__
X# include <pc.h>
X# define getch() getkey()
X# else
X# include <conio.h>
X# endif
X# endif
X# else /* !MSDOS */
X# define getch() getc(stderr)
X# define echoff(f) echo(0) /* for echo control */
X# define echon() echo(1)
X# include <iodef.h>
X# include <ttdef.h>
X# if !defined(SS$_NORMAL)
X# define SS$_NORMAL 1 /* only thing we need from <ssdef.h> */
X# endif
X# endif /* ?MSDOS */
X# else /* !MSVMS */
X# ifdef TERMIO /* Amdahl, Cray, all SysV? */
X# ifdef CONVEX
X# include <sys/termios.h>
X# include <sgtty.h>
X# define O_BINARY 0
X# else /* !CONVEX */
X# ifdef LINUX
X# include <termios.h>
X# else /* !LINUX */
X# include <sys/termio.h>
X# endif /* ?LINUX */
X# define sgttyb termio
X# define sg_flags c_lflag
X int ioctl OF((int, int, voidp *));
X# endif /* ?CONVEX */
X# define GTTY(f,s) ioctl(f,TCGETA,s)
X# define STTY(f,s) ioctl(f,TCSETAW,s)
X# else /* !TERMIO */
X# ifndef MINIX
X# include <sys/ioctl.h>
X# endif /* !MINIX */
X# include <sgtty.h>
X int gtty OF((int, struct sgttyb *));
X int stty OF((int, struct sgttyb *));
X# define GTTY gtty
X# define STTY stty
X# endif /* ?TERMIO */
X int isatty OF((int));
X char *ttyname OF((int));
X int open OF((char *, int, ...));
X int close OF((int));
X int read OF((int, voidp *, int));
X# endif /* ?MSVMS */
X#endif /* ?CRYPT */
X
X#ifdef VMS
X# include <descrip.h>
X# include <rms.h>
X#endif
X
X/* For directory access. (This is getting rather messy. Cleanup
X * scheduled for version 17.9.)
X */
X#ifndef UTIL
X
X#ifdef SYSV /* use readdir() */
X# include <dirent.h>
X# define dstrm DIR
X# define direct dirent
X#else
X
X#ifdef DIRENT /* use getdents() */
X# if defined(MINIX) || defined(OSF)
X# include <dirent.h>
X# else /* !MINIX */
X# include <sys/dirent.h>
X# endif /* ?MINIX */
X# define direct dirent
X# ifdef MINIX
X int getdents OF((int, char *, unsigned));
X# else /* !MINIX */
X int getdents OF((int, char *, int));
X# endif /* ?MINIX */
X# define DBSZ 4096 /* This has to be bigger than a directory block */
X typedef struct { /* directory stream buffer */
X int f; /* file descriptor for the directory "file" */
X char *p; /* pointer to next entry in buffer */
X char *q; /* pointer after end of buffer contents */
X char b[DBSZ]; /* buffer */
X } dstrm;
X
X#else /* !DIRENT */ /* use opendir(), etc. */
X# if defined(CONVEX) || defined(ultrix)
X# include <dirent.h>
X# ifdef direct
X# undef direct /* ultrix 4.2, at least if !__POSIX */
X# endif
X# define direct dirent
X# endif /* CONVEX || ultrix */
X# ifdef NDIR
X# include "ndir.h" /* for HPUX */
X# else /* !NDIR */
X# ifdef MSDOS
X# ifdef OS2
X# include "os2zip.h"
X# else /* !OS2 */
X# ifndef ATARI_ST
X# include <dos.h>
X# endif
X# if (defined(__TURBOC__) || defined(__GO32__))
X# define FATTR FA_HIDDEN+FA_SYSTEM+FA_DIREC
X# define FFIRST(n,d) findfirst(n,(struct ffblk *)d,FATTR)
X# define FNEXT(d) findnext((struct ffblk *)d)


X# else /* !__TURBOC__ */

X# define FATTR _A_HIDDEN+_A_SYSTEM+_A_SUBDIR
X# define FFIRST(n,d) _dos_findfirst(n,FATTR,(struct find_t *)d)
X# define FNEXT(d) _dos_findnext((struct find_t *)d)


X# endif /* ?__TURBOC__ */

X typedef struct direct {
X char d_reserved[30];
X char d_name[13];
X int d_first;
X#ifdef WIN32
X HANDLE d_hFindFile;
X#endif
X } DIR;
X# endif /* ?OS2 */
X# else /* !MSDOS */
X# ifdef VMS
X# include <ssdef.h>
X typedef struct direct {
X int d_wild; /* flag for wildcard vs. non-wild */
X struct FAB fab;
X struct NAM nam;
X char d_qualwildname[NAM$C_MAXRSS + 1];
X char d_name[NAM$C_MAXRSS + 1];
X } DIR;
X# else /* !VMS */
X# ifdef MACOS
X typedef struct direct {
X int d_wild; /* flag for wildcard vs. non-wild */
X char *d_name;
X } DIR;
X# endif
X# ifdef M_XENIX
X# include <sys/ndir.h>
X# else /* !M_XENIX */
X# include <sys/dir.h>
X# endif /* ?M_XENIX */
X# ifdef NODIR /* for AT&T 3B1 */
X# define dirent direct
X typedef FILE DIR;
X# define dstrm DIR
X# endif /* NODIR */
X# endif /* ?VMS */
X# endif /* ?MSDOS */
X# endif /* ?NDIR */
X# define dstrm DIR
X# ifndef NODIR
X DIR *opendir OF((char *));
X# endif /* !NODIR */
X# ifndef CONVEX
X struct direct *readdir OF((DIR *));
X# endif /* !CONVEX */
X#endif /* ?DIRENT */
X#endif /* ?SYSV */
X#endif /* !UTIL */
X
X
X/* Library functions not in (most) header files */
X
X#if defined(__IBMC__) || defined(__WATCOMC__)
X# define NO_MKTEMP
X#endif
Xchar *mktemp OF((char *));
X
X#ifdef __GO32__
X char *strlwr OF((char *));
X#else
X int link OF((char *, char *));
X int unlink OF((char *));
X# if defined(MSDOS)
X int chmod OF((char *, int));
X /* For many targets, chmod is already defined by sys/stat.h, and second
X * parameter is an unsigned long.
X */
X# endif
X#endif
X
X
X#ifndef UTIL /* the companion #endif is a bit of ways down ... */
X
X#ifndef __TURBOC__
X int utime OF((char *, time_t *));
X#endif /* !__TURBOC__ */
X#ifndef MSDOS
X int open OF((char *, int, ...));
X int close OF((int));
X# ifndef RMDIR
X int rmdir OF((char *));
X# endif /* !RMDIR */
X#endif /* !MSDOS */
X
X
X/* Local globals (kinda like "military intelligence" or "broadcast quality") */
Xlocal int exflag = 0; /* Exclude flag */
X
X#ifdef VMS
X typedef int statime;
X#else /* !VMS */
X typedef time_t statime;


X#endif /* ?VMS */
X

X/* Local functions */
X#ifdef PROTO
X# ifdef VMS
X local void vms_wild(char *, dstrm *);
X# endif /* VMS */
X# ifdef DIRENT
X local dstrm *opend(char *);
X local void closed(dstrm *);
X# endif /* DIRENT */
X local char *readd(dstrm *);
X local int fqcmp(voidp *, voidp *);
X local int fqcmpz(voidp *, voidp *);
X local char *last(char *);
X local char *msname(char *);
X# ifdef VMS
X local char *strlower(char *);
X local char *strupper(char *);
X# endif /* VMS */
X local char *ex2in(char *, int *);
X local int newname(char *);
X local void inctime(struct tm *);
X local ulg unix2dostime(statime *);
X# if !defined(__TURBOC__) && !defined(OS2) && !defined(__GO32__)
X local int cmptime(struct tm *, struct tm *);
X local time_t invlocal(struct tm *);
X# endif /* !__TURBOC__ */
X#endif /* PROTO */
X
X
X#if defined(MSDOS) && !defined(OS2)
Xdstrm *opendir(n)
Xchar *n; /* directory to open */
X/* Start searching for files in the MSDOS directory n */
X{
X dstrm *d; /* malloc'd return value */
X char *p; /* malloc'd temporary string */
X
X if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL ||
X (p = malloc(strlen(n) + 5)) == NULL)
X return NULL;
X strcat(strcpy(p, n), "/*.*");
X#ifdef WIN32
X {
X WIN32_FIND_DATA fd;
X DWORD dwAttr;
X BOOL bAttr;
X
X if ((HANDLE)0xFFFFFFFF == (d->d_hFindFile = FindFirstFile(p, &fd)))
X {
X free((voidp *)p);
X return NULL;
X }
X else
X strcpy(d->d_name, fd.cFileName);
X if (-1 != (dwAttr = GetFileAttributes(fd.cFileName)))
X {
X bAttr = FALSE;
X if (FILE_ATTRIBUTE_SYSTEM == (dwAttr & FILE_ATTRIBUTE_SYSTEM))
X bAttr = TRUE;
X if (FILE_ATTRIBUTE_HIDDEN == (dwAttr & FILE_ATTRIBUTE_HIDDEN))
X bAttr = TRUE;
X if (FILE_ATTRIBUTE_DIRECTORY == (dwAttr & FILE_ATTRIBUTE_DIRECTORY))
X bAttr = TRUE;
X if (!bAttr)
X {
X free ((voidp *)p);
X free ((void *) d);
X return NULL;
X }
X }
X
X }
X#else
X if (FFIRST(p, d))
X {
X free((voidp *)p);
X return NULL;
X }
X free((voidp *)p);
X#endif
X d->d_first = 1;
X return d;
X}
X
Xstruct direct *readdir(d)
Xdstrm *d; /* directory stream to read from */
X/* Return pointer to first or next directory entry, or NULL if end. */
X{
X if (d->d_first)
X d->d_first = 0;
X else
X#ifdef WIN32
X {
X WIN32_FIND_DATA fd;
X
X if (!FindNextFile(d->d_hFindFile, &fd))
X return NULL;
X else
X strcpy(d->d_name, fd.cFileName);
X }
X#else /* !WIN32 */
X if (FNEXT(d))
X return NULL;
X#endif
X return (struct direct *)d;
X}
X# define closedir free
X
X#endif /* MSDOS && !OS2 */
X
X
X#ifdef VMS
X
X/*---------------------------------------------------------------------------
X
X _vms_findfirst() and _vms_findnext(), based on public-domain DECUS C
X fwild() and fnext() routines (originally written by Martin Minow, poss-
X ibly modified by Jerry Leichter for bintnxvms.c), were written by Greg
X Roelofs and are still in the public domain. Routines approximate the
X behavior of MS-DOS (MSC and Turbo C) findfirst and findnext functions.
X
X ---------------------------------------------------------------------------*/
Xlocal void vms_wild(p, d)
Xchar *p;
Xdstrm *d;
X{
X /*
X * Do wildcard setup
X */
X /* set up the FAB and NAM blocks. */
X d->fab = cc$rms_fab; /* initialize fab */
X d->nam = cc$rms_nam; /* initialize nam */
X
X d->fab.fab$l_nam = &d->nam; /* fab -> nam */
X d->fab.fab$l_fna = p; /* argument wild name */
X d->fab.fab$b_fns = strlen(p); /* length */
X
X d->nam.nam$l_esa = d->d_qualwildname; /* qualified wild name */
X d->nam.nam$b_ess = NAM$C_MAXRSS; /* max length */
X d->nam.nam$l_rsa = d->d_name; /* matching file name */
X d->nam.nam$b_rss = NAM$C_MAXRSS; /* max length */
X
X /* parse the file name */
X if (sys$parse(&d->fab) != RMS$_NORMAL)
X return;
X /* Does this replace d->fab.fab$l_fna with a new string in its own space?
X I sure hope so, since p is free'ed before this routine returns. */
X
X /* have qualified wild name (i.e., disk:[dir.subdir]*.*); null-terminate
X * and set wild-flag */
X d->d_qualwildname[d->nam.nam$b_esl] = '\0';
X d->d_wild = (d->nam.nam$l_fnb & NAM$M_WILDCARD)? 1 : 0; /* not used... */
X#ifdef DEBUG
X printf(" incoming wildname: %s\n", p);
X printf(" qualified wildname: %s\n", d->d_qualwildname);
X#endif /* DEBUG */
X}
X
Xdstrm *opendir(n)
Xchar *n; /* directory to open */
X/* Start searching for files in the VMS directory n */
X{
X char *c; /* scans VMS path */
X dstrm *d; /* malloc'd return value */
X int m; /* length of name */
X char *p; /* malloc'd temporary string */
X
X if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL ||
X (p = malloc((m = strlen(n)) + 4)) == NULL)
X return NULL;
X /* Directory may be in form "[DIR.SUB1.SUB2]" or "[DIR.SUB1]SUB2.DIR;1".
X If latter, convert to former. */
X if (m > 0 && *(c = strcpy(p,n)+m-1) != ']')
X {
X while (--c > p && *c != ';')
X ;
X if (c-p < 5 || strncmp(c-4, ".DIR", 4))
X {
X free((voidp *)d); free((voidp *)p);
X return NULL;
X }
X c -= 3;
X *c-- = '\0'; /* terminate at "DIR;#" */
X *c = ']'; /* "." --> "]" */
X while (c > p && *--c != ']')
X ;
X *c = '.'; /* "]" --> "." */
X }
X strcat(p, "*.*");
X vms_wild(p, d); /* set up wildcard */
X free((voidp *)p);
X return d;
X}
X
Xstruct direct *readdir(d)
Xdstrm *d; /* directory stream to read from */
X/* Return pointer to first or next directory entry, or NULL if end. */
X{
X int r; /* return code */
X
X do {
X d->fab.fab$w_ifi = 0; /* internal file index: what does this do? */
X
X /* get next match to possible wildcard */
X if ((r = sys$search(&d->fab)) == RMS$_NORMAL)
X {
X d->d_name[d->nam.nam$b_rsl] = '\0'; /* null terminate */
X return (struct direct *)d; /* OK */
X }
X } while (r == RMS$_PRV);
X return NULL;
X}
X# define closedir free


X#endif /* VMS */
X
X

X#ifdef NODIR /* for AT&T 3B1 */
X/*
X** Apparently originally by Rich Salz.
X** Cleaned up and modified by James W. Birdsall.
X*/
X
X# define opendir(path) fopen(path, "r")
X
Xstruct direct *readdir(dirp)
XDIR *dirp;
X{
X static struct direct entry;
X
X if (dirp == NULL)
X return NULL;
X for (;;)
X if (fread (&entry, sizeof (struct direct), 1, dirp) == 0)
X return NULL;
X else if (entry.d_ino)
X return (&entry);
X} /* end of readdir() */
X
X# define closedir(dirp) fclose(dirp)
X#endif /* NODIR */
X
X
X#ifdef DIRENT
Xlocal dstrm *opend(n)
Xchar *n; /* directory name to open */
X/* Open the directory *n, returning a pointer to an allocated dstrm, or
X NULL if error. */
X{
X dstrm *d; /* pointer to malloc'ed directory stream */
X
X if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL)
X return NULL;
X if ((d->f = open(n, 0, 0)) < 0) /* open directory */
X return NULL;
X d->p = d->q = d->b; /* buffer is empty */
X return d;
X}
X#else /* !DIRENT */
X# define opend opendir /* just use opendir() */
X#endif /* ?DIRENT */
X
X
Xlocal char *readd(d)
Xdstrm *d; /* directory stream to read from */
X/* Return a pointer to the next name in the directory stream d, or NULL if
X no more entries or an error occurs. */
X{
X struct direct *e; /* directory entry read */
X
X#ifdef DIRENT
X int n; /* number of entries read by getdents */
X
X if (d->p >= d->q) /* if empty, fill buffer */
X if ((n = getdents(d->f, d->b, DBSZ)) <= 0)
X return NULL;
X else
X d->q = n + (d->p = d->b);
X e = (struct direct *)(d->p); /* point to entry */
X d->p += ((struct direct *)(d->p))->d_reclen; /* advance */
X return e->d_name; /* return name */
X#else /* !DIRENT */
X return (e = readdir(d)) == NULL ? (char *)NULL : e->d_name;
X#endif /* ?DIRENT */
X}
X
X
X#ifdef DIRENT
Xlocal void closed(d)
Xdstrm *d; /* directory stream to close */
X/* Close the directory stream */
X{
X close(d->f);
X free((voidp *)d);
X}
X#else /* !DIRENT */
X# define closed closedir
X#endif /* ?DIRENT */
X
X
X#ifdef MSDOS
X
Xint wild(w)
Xchar *w; /* path/pattern to match */
X/* If not in exclude mode, expand the pattern based on the contents of the
X file system. Return an error code in the ZE_ class. */
X{
X char *a; /* alloc'ed space for name */
X dstrm *d; /* stream for reading directory */
X char *e; /* name found in directory */
X int f; /* true if there was a match */
X char *n; /* constructed name from directory */
X char *p; /* path */
X char *q; /* name */
X int r; /* temporary variable */
X char v[5]; /* space for device current directory */
X
X /* Allocate and copy pattern */
X if ((p = a = malloc(strlen(w) + 1)) == NULL)
X return ZE_MEM;
X strcpy(p, w);
X
X /* Normalize pattern to upper case, path delimiter as '/'. */
X#if defined(FORCE_UPPER)
X#ifndef OS2
X strupr(p); /* convert to upper case */
X#else /* OS2 */
X if (IsFileSystemFAT(p)) strupr(p);
X#endif /* !OS2 */
X#endif
X for (q = p; *q; q++) /* use / consistently */
X if (*q == '\\')
X *q = '/';
X
X /* If excluding, don't bother with file system */
X if (exflag)
X {
X r = procname(p);
X free((voidp *)a);
X return r;
X }
X
X /* Only name can have special matching characters */
X if ((q = isshexp(p)) != NULL &&
X (strrchr(q, '/') != NULL || strrchr(q, ':') != NULL))
X {
X free((voidp *)a);
X return ZE_PARMS;
X }
X
X /* Separate path and name into p and q */
X if ((q = strrchr(p, '/')) != NULL && (q == p || q[-1] != ':'))
X {
X *q++ = 0; /* path/name -> path, name */
X if (*p == 0) /* path is just / */
X p = strcpy(v, "/.");
X }
X else if ((q = strrchr(p, ':')) != NULL)
X { /* has device and no or root path */
X *q++ = 0;
X p = strcat(strcpy(v, p), ":"); /* copy device as path */
X if (*q == '/') /* -> device:/., name */
X {
X strcat(p, "/");
X q++;
X }
X strcat(p, ".");
X }
X else /* no path or device */
X {
X q = p;
X p = strcpy(v, ".");
X }
X
X /* Search that level for matching names */
X if ((d = opend(p)) == NULL)
X {
X free((voidp *)a);
X return ZE_MISS;
X }
X if ((r = strlen(p)) > 1 &&
X (strcmp(p + r - 2, ":.") == 0 || strcmp(p + r - 2, "/.") == 0))
X *(p + r - 1) = 0;
X f = 0;
X while ((e = readd(d)) != NULL)
X if (strcmp(e, ".") && strcmp(e, "..") && MATCH(q, e))
X {
X f = 1;
X if (strcmp(p, ".") == 0) /* path is . */
X procname(e); /* name is name */
X else
X {
X if ((n = malloc(strlen(p) + strlen(e) + 2)) == NULL)
X {
X free((voidp *)a);
X return ZE_MEM;
X }
X n = strcpy(n, p);
X if (n[r = strlen(n) - 1] != '/' && n[r] != ':')
X strcat(n, "/");
X r = procname(strcat(n, e)); /* name is path/name */
X free((voidp *)n);
X if (r)
X {
X free((voidp *)a);
X return r;
X }
X }
X }
X closed(d);
X
X /* Done */
X free((voidp *)a);
X return f ? ZE_OK : ZE_MISS;
X}
X


X#endif /* MSDOS */
X
X

X#ifdef VMS
Xint wild(p)
Xchar *p; /* path/pattern to match */
X/* Expand the pattern based on the contents of the file system. Return an
X error code in the ZE_ class. */
X{
X dstrm *d; /* stream for reading directory */
X char *e; /* name found in directory */
X int f; /* true if there was a match */
X
X /* Search given pattern for matching names */
X if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL)
X return ZE_MEM;
X vms_wild(p, d); /* pattern may be more than just directory name */
X f = 0;
X while ((e = readd(d)) != NULL) /* "dosmatch" is already built in */
X if (procname(e) == ZE_OK)
X f = 1;
X closed(d);
X
X /* Done */
X return f ? ZE_OK : ZE_MISS;
X}


X#endif /* VMS */
X
X

Xchar *getnam(n)
Xchar *n; /* where to put name (must have >=FNMAX+1 bytes) */
X/* Read a space, \n, \r, or \t delimited name from stdin into n, and return
X n. If EOF, then return NULL. Also, if the name read is too big, return
X NULL. */
X{
X int c; /* last character read */
X char *p; /* pointer into name area */
X
X p = n;
X while ((c = getchar()) == ' ' || c == '\n' || c == '\r' || c == '\t')
X ;
X if (c == EOF)
X return NULL;
X do {
X if (p - n >= FNMAX)
X return NULL;
X *p++ = (char)c;
X c = getchar();
X } while (c != EOF && c != ' ' && c != '\n' && c != '\r' && c != '\t');
X *p = 0;
X return n;
X}
X
X
Xstruct flist far *fexpel(f)
Xstruct flist far *f; /* entry to delete */
X/* Delete the entry *f in the doubly-linked found list. Return pointer to
X next entry to allow stepping through list. */
X{
X struct flist far *t; /* temporary variable */
X
X t = f->nxt;
X *(f->lst) = t; /* point last to next, */
X if (t != NULL)
X t->lst = f->lst; /* and next to last */
X if (f->name != NULL) /* free memory used */
X free((voidp *)(f->name));
X if (f->zname != NULL)
X free((voidp *)(f->zname));
X farfree((voidp far *)f);
X fcount--; /* decrement count */
X return t; /* return pointer to next */
X}
X
X
Xlocal int fqcmp(a, b)
Xvoidp *a, *b; /* pointers to pointers to found entries */
X/* Used by qsort() to compare entries in the found list by name. */
X{
X return strcmp((*(struct flist far **)a)->name,
X (*(struct flist far **)b)->name);
X}
X
X
Xlocal int fqcmpz(a, b)
Xvoidp *a, *b; /* pointers to pointers to found entries */
X/* Used by qsort() to compare entries in the found list by zname. */
X{
X return strcmp((*(struct flist far **)a)->zname,
X (*(struct flist far **)b)->zname);
X}
X
X
Xlocal char *last(p)
Xchar *p; /* sequence of / delimited path components */
X/* Return a pointer to the start of the last path component. */
X{
X char *t; /* temporary variable */
X
X#ifdef VMS
X if ((t = strrchr(p, ']')) != NULL)
X#else /* !VMS */
X if ((t = strrchr(p, '/')) != NULL)
X#endif /* ?VMS */
X return t + 1;
X else
X return p;
X}
X
X
Xlocal char *msname(n)
Xchar *n;
X/* Reduce all path components to MSDOS upper case 8.3 style names. Probably
X should also check for invalid characters, but I don't know which ones
X those are. */
X{
X int c; /* current character */
X int f; /* characters in current component */
X char *p; /* source pointer */
X char *q; /* destination pointer */
X
X p = q = n;
X f = 0;
X while ((c = *p++) != 0)
X if (c == '/')
X {
X *q++ = (char)c;
X f = 0; /* new component */
X }
X else if (c == '.')
X if (f < 9)
X {
X *q++ = (char)c;
X f = 9; /* now in file type */
X }
X else
X f = 12; /* now just excess characters */
X else
X if (f < 12 && f != 8)
X {
X *q++ = (char)(to_up(c));
X f++; /* do until end of name or type */
X }
X *q = 0;
X return n;
X}
X
X
X#ifdef VMS
Xlocal char *strlower(s)
Xchar *s; /* string to convert */
X/* Convert all uppercase letters to lowercase in string s */
X{
X char *p; /* scans string */
X
X for (p = s; *p; p++)
X if (*p >= 'A' && *p <= 'Z')
X *p += 'a' - 'A';
X return s;
X}
X
Xlocal char *strupper(s)
Xchar *s; /* string to convert */
X/* Convert all lowercase letters to uppercase in string s */
X{
X char *p; /* scans string */
X
X for (p = s; *p; p++)
X if (*p >= 'a' && *p <= 'z')
X *p -= 'a' - 'A';
X return s;
X}


X#endif /* VMS */
X

Xlocal char *ex2in(x, pdosflag)
Xchar *x; /* external file name */
Xint *pdosflag; /* output: force MSDOS file attributes? */
X/* Convert the external file name to a zip file name, returning the malloc'ed
X string or NULL if not enough memory. */
X{
X char *n; /* internal file name (malloc'ed) */
X char *t; /* shortened name */
X int dosflag;
X
X#ifdef OS2
X dosflag = dosify || IsFileSystemFAT(x);
X if ( !dosify && use_longname_ea && (t = GetLongPathEA(x)) != NULL )
X {
X x = t;
X dosflag = 0;
X }
X#else
X# ifdef MSDOS
X dosflag = 1;
X# else /* !MSDOS */
X dosflag = dosify; /* default for non-DOS and non-OS/2 */
X# endif /* MSDOS */
X#endif /* OS2 */
X
X /* Find starting point in name before doing malloc */
X#ifdef MSDOS /* msdos */
X t = *x && *(x + 1) == ':' ? x + 2 : x;
X while (*t == '/' || *t == '\\')
X t++;
X#else /* !MSDOS */
X# ifdef VMS /* vms */
X t = x;
X if ((n = strrchr(t, ':')) != NULL)
X t = n + 1;
X if (*t == '[' && (n = strrchr(t, ']')) != NULL)
X if ((x = strchr(t, '.')) != NULL && x < n)
X t = x + 1;
X else
X t = n + 1;
X# else /* !VMS */ /* unix */
X for (t = x; *t == '/'; t++)
X ;
X# endif /* ?VMS */


X#endif /* ?MSDOS */
X

X /* Make changes, if any, to the copied name (leave original intact) */
X#ifdef MSDOS
X for (n = t; *n; n++)
X if (*n == '\\')
X *n = '/';


X#endif /* MSDOS */
X

X if (!pathput)
X t = last(t);
X
X /* Malloc space for internal name and copy it */
X if ((n = malloc(strlen(t) + 1)) == NULL)
X return NULL;
X strcpy(n, t);
X
X#ifdef VMS
X if ((t = strrchr(n, ']')) != NULL)
X {
X *t = '/';
X while (--t > n)
X if (*t == '.')
X *t = '/';
X }
X
X /* Fix from Greg Roelofs: */
X /* Get current working directory and strip from n (t now = n) */
X {
X char cwd[256], *p, *q;
X int c;
X
X if (getcwd(cwd, 256) && ((p = strchr(cwd, '.')) != NULL))
X {
X ++p;
X if ((q = strrchr(p, ']')) != NULL)
X {
X *q = '/';
X while (--q > p)
X if (*q == '.')
X *q = '/';
X /* strip bogus path parts from n */
X if (strncmp(n, p, (c=strlen(p))) == 0)
X {
X q = n + c;
X while (*t++ = *q++)
X ;
X }
X }
X }
X }
X strlower(n);
X if (!vmsver)
X if ((t = strrchr(n, ';')) != NULL)
X *t = 0;
X
X if( (t = strrchr(n, '.')) != NULL )
X {
X if( t[1] == 0 ) /* "filename." -> "filename" */
X *t = 0;
X else if( t[1] == ';' ) /* "filename.;vvv" -> "filename;vvv" */
X {
X char *f;
X for( f=t+1; *t++ = *f++; )
X ;
X }
X }
X#endif /* VMS */
X if (dosify)
X msname(n);
X#if defined(MSDOS) && !defined(OS2) && !defined(FORCE_UPPER)
X else
X strlwr(n);
X#endif
X /* Returned malloc'ed name */
X if (pdosflag)
X *pdosflag = dosflag;
X return n;
X}
X
X
Xchar *in2ex(n)
Xchar *n; /* internal file name */
X/* Convert the zip file name to an external file name, returning the malloc'ed
X string or NULL if not enough memory. */
X{
X char *x; /* external file name */
X#ifdef VMS
X char *t; /* scans name */
X
X if ((t = strrchr(n, '/')) == NULL)


X#endif /* VMS */
X {

X if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
X return NULL;
X strcpy(x, n);
X }
X#ifdef VMS
X else
X {
X if ((x = malloc(strlen(n) + 3 + PAD)) == NULL)
X return NULL;
X strcpy(x, "[.");
X strcpy(x + 2, n);
X *(t = x + 2 + (t - n)) = ']';
X while (--t > x)
X if (*t == '/')
X *t = '.';
X }
X strupper(x);
X#endif /* VMS */
X#ifdef OS2
X if ( !IsFileNameValid(x) )
X ChangeNameForFAT(x);
X#endif /* !OS2 */
X#if defined(FORCE_UPPER) && defined(MSDOS)
X /* Don't convert to upper case, causes wrong warnings. Keep the
X * name as it was before in the old zip file.
X */
X strupr(x);
X#endif
X return x;
X}
X
X
Xint exclude()
X/* Change from including to excluding names when procname() called. Return
X an error code in the ZE_ class. */
X{
X struct flist far *f; /* steps through found linked list */
X extent j; /* index for s */
X struct flist far **s; /* sorted table */
X
X /* sort found list, remove duplicates */
X if (fcount)
X {
X if ((s = (struct flist far **)malloc(
X fcount * sizeof(struct flist far *))) == NULL)
X return ZE_MEM;
X for (j = 0, f = found; f != NULL; f = f->nxt)
X s[j++] = f;
X qsort((char *)s, fcount, sizeof(struct flist far *), fqcmp);
X for (j = fcount - 1; j > 0; j--)
X if (strcmp(s[j - 1]->name, s[j]->name) == 0)
X fexpel(s[j]); /* fexpel() changes fcount */
X qsort((char *)s, fcount, sizeof(struct flist far *), fqcmpz);
X for (j = 1; j < fcount; j++)
X if (strcmp(s[j - 1]->zname, s[j]->zname) == 0)
X {
X warn("name in zip file repeated: ", s[j]->zname);
X warn(" first full name: ", s[j - 1]->name);
X warn(" second full name: ", s[j]->name);
X return ZE_PARMS;
X }
X free((voidp *)s);
X }
X exflag = 1;
X return ZE_OK;
X}
X
X
Xlocal int newname(n)
Xchar *n; /* name to add (or exclude) */
X/* Add (or exclude) a name that is not in the zip file. Return an error
X code in the ZE_ class. */
X{
X char *m;
X struct flist far *f; /* where in found, or new found entry */
X struct zlist far *z; /* where in zfiles (if found) */
X int dosflag;
X
X /* Search for name in zip file. If there, mark it, else add to
X list of new names to do (or remove from that list). */
X if ((m = ex2in(n, &dosflag)) == NULL)
X return ZE_MEM;
X if ((z = zsearch(m)) != NULL)
X if (exflag)
X {
X z->mark = 0;
X free((voidp *)m);
X if (verbose)
X printf("zip diagnostic: excluding %s\n", z->name);
X }
X else
X {
X free((voidp *)(z->name));
X free((voidp *)(z->zname));
X if ((z->name = malloc(strlen(n) + 1 + PAD)) == NULL)
X return ZE_MEM;
X strcpy(z->name, n);
X z->zname = m;
X z->mark = 1;
X z->dosflag = dosflag;
X if (verbose)
X printf("zip diagnostic: including %s\n", z->name);
X }
X else
X if (exflag)
X {
X /* search list for name--if there, remove it */
X for (f = found; f != NULL; f = f->nxt)
X if (namecmp(n, f->name) == 0)
X {
X fexpel(f);
X break;
X }
X free((voidp *)m);
X }
X else
X {
X /* allocate space and add to list */
X if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL ||
X (f->name = malloc(strlen(n) + 1 + PAD)) == NULL)
X {
X if (f != NULL)
X farfree((voidp far *)f);
X return ZE_MEM;
X }
X strcpy(f->name, n);
X f->zname = m;
X f->dosflag = dosflag;
X *fnxt = f;
X f->lst = fnxt;
X f->nxt = NULL;
X fnxt = &f->nxt;
X fcount++;
X }
X return ZE_OK;
X}
X
X
Xint procname(n)
Xchar *n; /* name to process */
X/* Process a name or sh expression to operate on (or exclude). Return
X an error code in the ZE_ class. */
X{
X char *a; /* path and name for recursion */
X dstrm *d; /* directory stream from opend() */
X char *e; /* pointer to name from readd() */
X struct flist far *f; /* steps through found list */
X int m; /* matched flag */
X char *p; /* path for recursion */
X struct stat s; /* result of stat() */
X struct zlist far *z; /* steps through zfiles list */
X
X if (strcmp(n, "-") == 0) /* if compressing stdin */
X return newname(n);
X else if (
X#ifdef S_IFLNK /* if symbolic links exist ... */
X linkput ? lstat(n, &s) :
X#endif /* S_IFLNK */
X SSTAT(n, &s)
X#if defined(__TURBOC__) || defined(VMS)
X /* Borland and VMS C bug: stat() succeeds on wild card names! */
X || isshexp(n)
X#endif
X )
X {
X /* Not a file or directory--search for shell expression in zip file */
X p = ex2in(n, NULL); /* shouldn't affect matching chars */
X m = 1;
X for (z = zfiles; z != NULL; z = z->nxt)
X if (MATCH(p, z->zname))
X {
X z->mark = !exflag;
X if (verbose)
X printf("zip diagnostic: %scluding %s\n",
X exflag ? "ex" : "in", z->name);
X m = 0;
X }
X /* If excluding, also search for expression in found list */
X if (exflag)
X {
X for (f = found; f != NULL;)
X if (MATCH(p, f->zname))
X {
X f = fexpel(f);
X m = 0;
X }
X else
X f = f->nxt;
X }
X free((voidp *)p);
X if (m)
X return ZE_MISS; /* no match */
X }
X else
X {
X /* Live name--use if file, recurse if directory */
X#if defined(FORCE_UPPER) && defined(MSDOS)
X# ifndef OS2
X strupr(n); /* convert to upper case */
X# else /* OS2 */
X if (IsFileSystemFAT(n)) strupr(n);
X# endif /* !OS2 */
X#endif
X
X#ifdef MSDOS
X for (p = n; *p; p++) /* use / consistently */
X if (*p == '\\')
X *p = '/';
X#endif /* MSDOS */
X if ((s.st_mode & S_IFDIR) == 0)
X {
X /* add or remove name of file */
X if ((m = newname(n)) != ZE_OK)
X return m;
X } else {
X /* recurse into directory */
X if (recurse && (d = opend(n)) != NULL)
X {
X#ifdef VMS
X while ((e = readd(d)) != NULL)
X if ((m = procname(e)) != ZE_OK) /* recurse on name */
X {
X /* want to just set warning error and continue */
X closed(d);
X return m;
X }
X#else /* !VMS */
X if ((p = malloc(strlen(n)+2)) == NULL)
X return ZE_MEM;
X if (strcmp(n, ".") == 0)
X *p = 0; /* avoid "./" prefix and do not create zip entry */
X else
X {
X strcpy(p, n);
X a = p + strlen(p);
X if (a[-1] != '/')
X strcpy(a, "/");
X if ((m = newname(p)) != ZE_OK)
X return m;
X }
X while ((e = readd(d)) != NULL)
X if (strcmp(e, ".") && strcmp(e, ".."))
X {
X if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
X {
X free((voidp *)p);
X closed(d);
X return ZE_MEM;
X }
X strcat(strcpy(a, p), e);
X if ((m = procname(a)) != ZE_OK) /* recurse on name */
X {
X free((voidp *)a); free((voidp *)p);
X closed(d);
X return m;
X }
X free((voidp *)a);
X }
X free((voidp *)p);
X#endif /* ?VMS */
X closed(d);
X }
X }
X }
X return ZE_OK;
X}
X
X
X#if !defined(CRAY) && !defined(__TURBOC__) && !defined(OS2) /* and ... */
X#if !defined( __GO32__)
X
Xlocal int cmptime(p, q)
Xstruct tm *p, *q; /* times to compare */
X/* Return negative if time p is before time q, positive if after, and
X zero if the same */
X{
X int r; /* temporary variable */
X
X if (p == NULL)
X return -1;
X else if ((r = p->tm_year - q->tm_year) != 0)
X return r;
X else if ((r = p->tm_mon - q->tm_mon) != 0)
X return r;
X else if ((r = p->tm_mday - q->tm_mday) != 0)
X return r;
X else if ((r = p->tm_hour - q->tm_hour) != 0)
X return r;
X else if ((r = p->tm_min - q->tm_min) != 0)
X return r;
X else
X return p->tm_sec - q->tm_sec;
X}
X
X
Xlocal time_t invlocal(t)
Xstruct tm *t; /* time to convert */
X/* Find inverse of localtime() using bisection. This routine assumes that
X time_t is an integer type, either signed or unsigned. The expectation
X is that sometime before the year 2038, time_t will be made a 64-bit
X integer, and this routine will still work. */
X{
X time_t i; /* midpoint of current root range */
X time_t l; /* lower end of root range */
X time_t u; /* upper end of root range */
X
X /* Bracket the root [0,largest time_t]. Note: if time_t is a 32-bit signed
X integer, then the upper bound is GMT 1/19/2038 03:14:07, after which all
X the Unix systems in the world come to a grinding halt. Either that, or
X all those systems will suddenly find themselves transported to December
X of 1901 ... */
X l = 0;
X u = 1;
X while (u < (u << 1))
X u = (u << 1) + 1;
X
X /* Find the root */
X while (u - l > 1)
X {
X i = l + ((u - l) >> 1);
X if (cmptime(localtime(&i), t) <= 0)
X l = i;
X else
X u = i;
X }
X return l;
X}
X#endif
X#endif
X
X
Xvoid stamp(f, d)
Xchar *f; /* name of file to change */
Xulg d; /* dos-style time to change it to */
X/* Set last updated and accessed time of file f to the DOS time d. */
X{
X#if defined(MACOS)
X warn("timestamp not implemented yet", "");
X#else
X#ifdef __TURBOC__
X int h; /* file handle */
X
X if ((h = open(f, 0)) != -1)
X {
X#ifdef ATARI_ST
X d = ( d >> 16 ) | ( d << 16 );
X#endif
X setftime(h, (struct ftime *)&d);
X close(h);
X }
X#else /* !__TURBOC__ */
X#ifdef VMS
X int tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year;
X char timbuf[24];
X static char *month[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
X "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
X struct VMStimbuf {
X char *actime; /* VMS revision date, ASCII format */
X char *modtime; /* VMS creation date, ASCII format */
X } ascii_times = {timbuf, timbuf};
X
X /* Convert DOS time to ASCII format for VMSmunch */
X tm_sec = (int)(d << 1) & 0x3e;
X tm_min = (int)(d >> 5) & 0x3f;
X tm_hour = (int)(d >> 11) & 0x1f;
X tm_mday = (int)(d >> 16) & 0x1f;
X tm_mon = ((int)(d >> 21) & 0xf) - 1;
X tm_year = ((int)(d >> 25) & 0x7f) + 1980;
X sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", tm_mday, month[tm_mon],
X tm_year, tm_hour, tm_min, tm_sec);
X
X /* Set updated and accessed times of f */
X if (VMSmunch(f, SET_TIMES, &ascii_times) != RMS$_NMF)
X warn("can't set zipfile time: ", f);
X
X#else /* !VMS */
X#ifdef OS2
X SetFileTime(f, d);
X#else /* !OS2 */
X struct tm t; /* argument for mktime() or invlocal() */
X time_t u[2]; /* argument for utime() */
X#ifndef __GO32__
X extern time_t mktime OF((struct tm *));
X#endif
X
X /* Convert DOS time to time_t format in u[0] and u[1] */
X t.tm_sec = (int)(d << 1) & 0x3e;
X t.tm_min = (int)(d >> 5) & 0x3f;
X t.tm_hour = (int)(d >> 11) & 0x1f;
X t.tm_mday = (int)(d >> 16) & 0x1f;
X t.tm_mon = ((int)(d >> 21) & 0xf) - 1;
X t.tm_year = ((int)(d >> 25) & 0x7f) + 80;
X#if defined(MSDOS) || defined(OS2) || defined(CRAY)
X /* mktime() is more reliable than invlocal() because the time range is
X * wider on MSDOS than on Unix; required for Cray because invlocal assumes
X * 32-bit ints
X */
X u[0] = u[1] = mktime(&t);
X#else
X u[0] = u[1] = invlocal(&t);
X#endif
X
X /* Set updated and accessed times of f */
X utime(f, u);
X#endif /* ?OS2 */
X#endif /* ?VMS */
X#endif /* ?__TURBOC__ */
X#endif /* ?MACOS */
X}
X
X
Xlocal void inctime(s)
Xstruct tm *s; /* time to increment in place */
X/* Increment the time structure *s by one second, return the result in
X place. */
X{
X int y; /* temporary variable */
X
X /* days in each month, except for February */
X static int days[] = {31,0,31,30,31,30,31,31,30,31,30,31};
X
X /* Set days in February from year (1900 is a leap year, 2000 is not) */
X y = s->tm_year + 1900;
X days[1] = y % 4 == 0 && (y % 100 != 0 || y % 400 == 0) ? 29 : 28;
X
X /* Increment time with carry */
X if (s->tm_sec != 59)
X s->tm_sec++;
X else if (s->tm_sec = 0, s->tm_min != 59)
X s->tm_min++;
X else if (s->tm_min = 0, s->tm_hour != 23)
X s->tm_hour++;
X else if (s->tm_hour = 0, s->tm_mday != days[s->tm_mon])
X s->tm_mday++;
X else if (s->tm_mday = 1, s->tm_mon != 11)
X s->tm_mon++;
X else
X {
X s->tm_mon = 0;
X s->tm_year++;
X }
X}
X
X
Xulg dostime(y, n, d, h, m, s)
Xint y; /* year */
Xint n; /* month */
Xint d; /* day */
Xint h; /* hour */
Xint m; /* minute */
Xint s; /* second */
X/* Convert the date y/n/d and time h:m:s to a four byte DOS date and
X time (date in high two bytes, time in low two bytes allowing magnitude
X comparison). */
X{
X return y < 1980 ? dostime(1980, 1, 1, 0, 0, 0) :
X (((ulg)y - 1980) << 25) | ((ulg)n << 21) | ((ulg)d << 16) |
X ((ulg)h << 11) | ((ulg)m << 5) | ((ulg)s >> 1);
X}
X
X
Xlocal ulg unix2dostime(t)
Xstatime *t; /* unix time to convert */
X/* Return the Unix time t in DOS format, rounded up to the next two
X second boundary. */
X{
X struct tm *s; /* result of localtime() */
X
X s = localtime(t); /* Use local time since MSDOS does */
X inctime(s); /* Add one second to round up */
X return dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday,
X s->tm_hour, s->tm_min, s->tm_sec);
X}
X
X
Xulg filetime(f, a, n)
Xchar *f; /* name of file to get info on */
Xulg *a; /* return value: file attributes */
Xlong *n; /* return value: file size */
X/* If file *f does not exist, return 0. Else, return the file's last
X modified date and time as an MSDOS date and time. The date and
X time is returned in a long with the date most significant to allow
X unsigned integer comparison of absolute times. Also, if a is not
X a NULL pointer, store the file attributes there, with the high two
X bytes being the Unix attributes, and the low byte being a mapping
X of that to DOS attributes. If n is not NULL, store the file size
X there.
X If f is "-", use standard input as the file. If f is a device, return
X a file size of -1 */
X{
X struct stat s; /* results of stat() */
X char name[FNMAX];
X int len = strlen(f);
X
X strcpy(name, f);
X if (name[len - 1] == '/')
X name[len - 1] = 0;
X /* not all systems allow stat'ing a file with / appended */
X
X if (strcmp(f, "-") == 0) {
X if (fstat(fileno(stdin), &s) != 0)
X error("fstat(stdin)");
X } else if ((
X#ifdef S_IFLNK
X linkput ? lstat(name, &s) :
X#endif
X SSTAT(name, &s)) != 0 /* || (s.st_mode & S_IFDIR) != 0 */ )
X /* Accept about any file kind except directories */
X return 0;
X
X if (a != NULL)
X#ifdef OS2
X *a = (s.st_mode << 16) | GetFileMode(name);
X#else
X *a = (s.st_mode << 16) | !(s.st_mode & S_IWRITE);
X#endif
X if (n != NULL)
X *n = (s.st_mode & S_IFREG) == 0 ? -1L : s.st_size;
X
X#ifdef OS2
X return GetFileTime(name);
X#else /* !OS2 */
X# ifdef VMS
X return unix2dostime(&s.st_ctime); /* Use creation time in VMS */
X# else /* !VMS */
X# ifdef ATARI_ST
X return s.st_mtime; /* Turbo C doesn't use UNIX times */
X# else
X return unix2dostime(&s.st_mtime);
X# endif
X# endif /* ?VMS */
X#endif /* ?OS2 */
X}
X
X
Xint issymlnk(a)
Xulg a; /* Attributes returned by filetime() */
X/* Return true if the attributes are those of a symbolic link */
X{
X#ifdef S_IFLNK
X return ((a >> 16) & S_IFMT) == S_IFLNK;
X#else /* !S_IFLNK */
X return (int)a & 0; /* avoid warning on unused parameter */
X#endif /* ?S_IFLNK */
X}
X
X
Xint deletedir(d)
Xchar *d; /* directory to delete */
X/* Delete the (empty) directory *d. Return the result of rmdir(), delete(),
X or system(). */
X{
X#ifdef MACOS
X warn("deletedir not implemented yet", "");
X return 127;
X#else
X#ifdef RMDIR
X /* code from Greg Roelofs, who horked it from Mark Edwards (unzip) */
X int r, len;
X char *s; /* malloc'd string for system command */
X
X len = strlen(d);
X if ((s = malloc(len + 34)) == NULL)
X return 127;
X
X#ifdef VMS
X {
X char *c; /* pointer into VMS path */
X /* convert "DEV:[DIR.SUB1.SUB2]" form to "DEV:[DIR.SUB1]SUB2.DIR;0" */
X strcat(strcpy(s, "set prot=(o:rwed) "), d); /* d starts at s+18 */
X if (*(c = s+17+len) != ']')
X {
X free(s);
X return 127;
X }
X strcpy(c, ".DIR;0"); /* 0 translates to highest version */
X while (--c > s+18 && *c != '.' && *c != '[') ;
X if (c == s+18)
X {
X free(s);
X return 127;
X }
X if (*c == '.')
X *c = ']';
X else if (*--c == ']') /* presumably of form "DEV:[DIR.SUB1.][SUB2]" */
X { /* (possible to have "DEV:[DIR.SUB1.][][SUB2]"?) */
X char *b = c + 2;
X c[-1] = ']';
X while (*c++ = *b++) ;
X }
X else /* must have reached device name: can't delete top level */
X {
X free(s);
X return 127;
X }
X }
X /* unprotect directory and delete it as a file. May fail if exists
X normal file "foo.dir" on top of directory "foo.dir" */
X system(s);
X r = delete(s+18);
X#else /* !VMS */
X sprintf(s, "IFS=\" \t\n\" /bin/rmdir %s 2>/dev/null", d);
X r = system(s);
X#endif /* ?VMS */
X free(s);
X return r;
X#else /* !RMDIR */
X return rmdir(d);
X#endif /* ?RMDIR */
X#endif /* ?MACOS */
X}
X
X
X#endif /* !UTIL */
X
Xint destroy(f)
Xchar *f; /* file to delete */
X/* Delete the file *f, returning non-zero on failure. */
X{
X return unlink(f);
X}
X
X
Xint replace(d, s)
Xchar *d, *s; /* destination and source file names */
X/* Replace file *d by file *s, removing the old *s. Return an error code
X in the ZE_ class. */
X{
X struct stat t; /* results of stat() */
X
X if (SSTAT(d, &t) == 0 && unlink(d))
X return ZE_CREAT; /* Can't erase zip file--give up */
X if (link(s, d)) /* Just move s on top of d */
X#if !defined(VMS) && !defined(ATARI_ST)
X /* For VMS & ATARI assume failure is EXDEV */
X if (errno != EXDEV
X# ifdef ENOTSAM
X && errno != ENOTSAM /* Used at least on Turbo C */
X# endif
X ) return ZE_CREAT;
X else
X#endif
X {
X FILE *f, *g; /* source and destination files */
X int r; /* temporary variable */
X
X if ((f = fopen(s, FOPR)) == NULL) {
X fprintf(stderr," replace: can't open %s\n", s);
X return ZE_TEMP;
X }
X if ((g = fopen(d, FOPW)) == NULL)
X {
X fclose(f);
X return ZE_CREAT;
X }
X r = fcopy(f, g, (ulg)-1L);
X fclose(f);
X if (fclose(g) || r != ZE_OK)
X {
X unlink(d);
X return r ? (r == ZE_TEMP ? ZE_WRITE : r) : ZE_WRITE;
X }
X#ifdef VMS /* only delete if rename failed: previous version may exist */
X unlink(s);
X }
X#else /* !VMS */
X }
X unlink(s);
X#endif /* !VMS */
X return ZE_OK;
X}
X
X
Xint getfileattr(f)
Xchar *f; /* file path */
X/* Return the file attributes for file f or 0 if failure */
X{
X struct stat s;
X
X return SSTAT(f, &s) == 0 ? s.st_mode : 0;
X}
X
X
Xint setfileattr(f, a)
Xchar *f; /* file path */
Xint a; /* attributes returned by getfileattr() */
X/* Give the file f the attributes a, return non-zero on failure */
X{
X#if defined (VMS) || defined(MACOS)
X return 0;
X#else /* !VMS */
X return chmod(f, a);


X#endif /* ?VMS */
X}
X

X
X#ifdef NO_MKTEMP
X
Xchar *tempname(zip)
X char *zip; /* path name of zip file to generate temp name for */
X
X/* Return a temporary file name in its own malloc'ed space.
X * This function might accidentally destroy an existing file
X * with extension .$z$ . Use mktemp below if you have it on your system.
X */
X{
X char *p; /* temporary pointer */
X char *t; /* malloc'ed space for name */
X
X if ((t = malloc(strlen(zip)+5)) == NULL)
X return NULL;
X strcpy(t, zip);
X if ((p = strrchr(t, '.')) != NULL &&
X (!strncmp(p, ".zip", 4) || !strncmp(p, ".ZIP", 4)))
X /* strncmp to avoid problems with VMS ';' */
X strcpy(p, ".$z$");
X else
X strcat(t, ".$z$");
X
X return t;
X}
X#else /* !NO_MKTEMP */
X
Xchar *tempname(zip)
X char *zip; /* path name of zip file to generate temp name for */
X
X/* Return a temporary file name in its own malloc'ed space, using tempath. */
X{
X char *t = zip; /* malloc'ed space for name (use zip to avoid warning) */
X
X if (tempath != NULL)
X {
X if ((t = malloc(strlen(tempath)+10)) == NULL)
X return NULL;
X strcpy(t, tempath);
X#ifndef VMS
X if (t[strlen(t)-1] != '/')
X strcat(t, "/");
X#endif
X }
X else
X {
X if ((t = malloc(9)) == NULL)
X return NULL;
X *t = 0;
X }
X strcat(t, "_ZXXXXXX");
X return mktemp(t);
X}
X
X#endif /* NO_MKTEMP */
X
X
Xint fcopy(f, g, n)
XFILE *f, *g; /* source and destination files */
Xulg n; /* number of bytes to copy or -1 for all */
X/* Copy n bytes from file *f to file *g, or until EOF if n == -1. Return
X an error code in the ZE_ class. */
X{
X char *b; /* malloc'ed buffer for copying */
X extent k; /* result of fread() */
X ulg m; /* bytes copied so far */
X
X if ((b = malloc(CBSZ)) == NULL)
X return ZE_MEM;
X m = 0;
X while (n == -1L || m < n)
X {
X if ((k = fread(b, 1, n == -1 ?
X CBSZ : (n - m < CBSZ ? (extent)(n - m) : CBSZ), f)) == 0)
X if (ferror(f))
X {
X free((voidp *)b);
X return ZE_READ;
X }
X else
X break;
X if (fwrite(b, 1, k, g) != k)
X {
X free((voidp *)b);
X fprintf(stderr," fcopy: write error\n");
X return ZE_TEMP;
X }
X m += k;
X }
X free((voidp *)b);
X return ZE_OK;
X}
X
X
X#ifdef CRYPT
X
X#ifndef MSDOS
X
X#ifdef VMS
X
Xint echo(opt)
X int opt;
X{
X/*---------------------------------------------------------------------------
X Based on VMSmunch.c, which in turn was based on Joe Meadows' file.c code.
X ---------------------------------------------------------------------------
X * For VMS v5.x:
X * IO$_SENSEMODE/SETMODE info: Programming, Vol. 7A, System Programming,
X * I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6
X * sys$assign(), sys$qio() info: Programming, Vol. 4B, System Services,
X * System Services Reference Manual, pp. sys-23, sys-379
X * fixed-length descriptor info: Programming, Vol. 3, System Services,
X * Intro to System Routines, sec. 2.9.2
X * GRR, 15 Aug 91
X ---------------------------------------------------------------------------*/
X static struct dsc$descriptor_s DevDesc =
X {9, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$INPUT"};
X /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */
X static short DevChan, iosb[4];
X static long i, status;
X static unsigned long oldmode[2], newmode[2]; /* each = 8 bytes */
X
X
X/*---------------------------------------------------------------------------
X Assign a channel to standard input.
X ---------------------------------------------------------------------------*/
X
X status = sys$assign(&DevDesc, &DevChan, 0, 0);
X if (!(status & 1))
X return status;
X
X/*---------------------------------------------------------------------------
X Use sys$qio and the IO$_SENSEMODE function to determine the current tty
X status (for password reading, could use IO$_READVBLK function instead,
X but echo on/off will be more general).
X ---------------------------------------------------------------------------*/
X
X status = sys$qio(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0,
X oldmode, 8, 0, 0, 0, 0);
X if (!(status & 1))
X return status;
X status = iosb[0];
X if (!(status & 1))
X return status;
X
X/*---------------------------------------------------------------------------
X Copy old mode into new-mode buffer, then modify to be either NOECHO or
X ECHO (depending on function argument opt).
X ---------------------------------------------------------------------------*/
X
X newmode[0] = oldmode[0];
X newmode[1] = oldmode[1];
X if (opt == 0)
X newmode[1] |= TT$M_NOECHO; /* set NOECHO bit */
X else
X newmode[1] &= ~((unsigned long) TT$M_NOECHO); /* clear NOECHO bit */
X
X/*---------------------------------------------------------------------------
X Use the IO$_SETMODE function to change the tty status.
X ---------------------------------------------------------------------------*/
X
X status = sys$qio(0, DevChan, IO$_SETMODE, &iosb, 0, 0,
X newmode, 8, 0, 0, 0, 0);
X if (!(status & 1))
X return status;
X status = iosb[0];
X if (!(status & 1))
X return status;
X
X/*---------------------------------------------------------------------------
X Deassign the sys$input channel by way of clean-up, then exit happily.
X ---------------------------------------------------------------------------*/
X
X status = sys$dassgn(DevChan);
X if (!(status & 1))
X return status;
X
X return SS$_NORMAL; /* we be happy */
X
X} /* end function echo() */
X
X
X#else /* !VMS */
X
Xlocal int echofd = -1; /* file descriptor whose echo is off */
X
Xvoid echoff(f)
Xint f; /* file descriptor to turn echo off on */
X/* Turn echo off for file descriptor f. Assumes that f is a tty device. */
X{
X struct sgttyb sg; /* tty device structure */
X
X echofd = f;
X GTTY(f, &sg); /* get settings */
X sg.sg_flags &= ~ECHO; /* turn echo off */
X STTY(f, &sg);
X}
X
Xvoid echon()
X/* Turn echo back on for file descriptor echofd. */
X{
X struct sgttyb sg; /* tty device structure */
X
X if (echofd != -1)
X {
X GTTY(echofd, &sg); /* get settings */
X sg.sg_flags |= ECHO; /* turn echo on */
X STTY(echofd, &sg);
X echofd = -1;
X }
X}
X


X#endif /* ?VMS */
X

X#endif /* !MSDOS */
X
X
Xchar *getp(m, p, n)
Xchar *m; /* prompt for password */
Xchar *p; /* return value: line input */
Xint n; /* bytes available in p[] */
X/* Get a password of length n-1 or less into *p using the prompt *m.
X The entered password is not echoed. Return p on success, NULL on
X failure (can't get controlling tty). */
X{
X char c; /* one-byte buffer for read() to use */
X int i; /* number of characters input */
X char *w; /* warning on retry */
X
X#ifndef MSDOS
X#ifndef VMS
X int f; /* file decsriptor for tty device */
X
X /* Turn off echo on tty */
X if (!isatty(2))
X return NULL; /* error if not tty */
X if ((f = open(ttyname(2), 0, 0)) == -1)
X return NULL;
X#endif /* !VMS */
X echoff(f); /* turn echo off */
X#endif /* !MSDOS */
X
X /* Get password */
X w = "";
X do {
X#ifdef VMS /* bug: VMS adds '\n' to NULL fputs (apparently) */
X if (*w)
X#endif /* VMS */
X fputs(w, stderr); /* warning if back again */
X fputs(m, stderr); /* prompt */
X fflush(stderr);
X i = 0;
X do { /* read line, keeping n */
X#ifdef MSVMS
X if ((c = (char)getch()) == '\r')
X c = '\n';
X#else /* !MSVMS */
X read(f, &c, 1);
X#endif /* ?MSVMS */
X if (i < n)
X p[i++] = c;
X } while (c != '\n');
X putc('\n', stderr); fflush(stderr);
X w = "(line too long--try again)\n";
X } while (p[i-1] != '\n');
X p[i-1] = 0; /* terminate at newline */
X
X#ifndef MSDOS
X echon(); /* turn echo back on */
X#ifndef VMS
X close(f);
X#endif /* !VMS */
X#endif /* !MSDOS */
X
X /* Return pointer to password */
X return p;
X}
X
X#endif /* ?CRYPT */
X
X
X#ifdef ZMEM
X
X/************************/
X/* Function memset() */
X/************************/
X
X/*
X * memset - for systems without it
X * bill davidsen - March 1990
X */
X
Xchar *
Xmemset(buf, init, len)
Xregister char *buf; /* buffer loc */
Xregister int init; /* initializer */
Xregister unsigned int len; /* length of the buffer */
X{
X char *start;
X
X start = buf;
X while (len--) *(buf++) = init;
X return(start);
X}
X
X
X/************************/
X/* Function memcpy() */
X/************************/
X
Xchar *
Xmemcpy(dst,src,len) /* v2.0f */
Xregister char *dst, *src;
Xregister unsigned int len;
X{
X char *start;
X
X start = dst;
X while (len--)
X *dst++ = *src++;
X return(start);
X}
X
X
X/************************/
X/* Function memcmp() */
X/************************/
X
Xint
Xmemcmp(b1,b2,len) /* j...@usl.edu -- 11/16/90 */
Xregister char *b1, *b2;
Xregister unsigned int len;
X{
X
X if (len) do { /* examine each byte (if any) */
X if (*b1++ != *b2++)
X return (*((uch *)b1-1) - *((uch *)b2-1)); /* exit when miscompare */
X } while (--len);
X
X return(0); /* no miscompares, yield 0 result */
X}
X
X#endif /* ZMEM */
X
X#ifdef __TURBOC__
X
X/************************/
X/* Function fcalloc() */
X/************************/
X
X/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
X * and farmalloc(64K) returns a pointer with an offset of 8, so we
X * must fix the pointer. Warning: the pointer must be put back to its
X * original form in order to free it.
X * For MSC, use halloc instead of this function (see tailor.h).
X */
Xvoid far * fcalloc(items, size)
X unsigned items; /* number of items */
X unsigned size; /* item size */
X{
X void far * buf = farmalloc((ulg)items*size + 16L);
X /* Normalize the pointer to seg:0 */
X *((int*)&buf+1) += ((unsigned)((uch*)buf-0) + 15) >> 4;
X *(int*)&buf = 0;
X return buf; /* buf stays NULL if alloc failed */
X}
X
X#endif /* __TURBOC__ */
END_OF_FILE
if test 57097 -ne `wc -c <'fileio.c'`; then
echo shar: \"'fileio.c'\" unpacked with wrong size!
fi
# end of 'fileio.c'
fi
echo shar: End of archive 2 \(of 11\).
cp /dev/null ark2isdone

Info-ZIP group

unread,
Aug 23, 1992, 2:45:51 AM8/23/92
to
Submitted-by: zip-...@cs.ucla.edu (Info-ZIP group)
Posting-number: Volume 31, Issue 95
Archive-name: zip19/part03

Supersedes: zip: Volume 23, Issue 88-96
Environment: UNIX, VMS, OS/2, MS-DOS, MACINTOSH, WIN-NT, LINUX, MINIX, XOS, !AMIGA, ATARI, symlink, SGI, DEC, Cray, Convex, Amdahl, Sun, PC

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: trees.c util.c vms/makefile.vms
# Wrapped by kent@sparky on Sun Aug 23 01:00:43 1992


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 3 (of 11)."'
if test -f 'trees.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'trees.c'\"
else
echo shar: Extracting \"'trees.c'\" \(40777 characters\)
sed "s/^X//" >'trees.c' <<'END_OF_FILE'


X/*
X
X Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly,
X Kai Uwe Rommel and Igor Mandrichenko.
X Permission is granted to any individual or institution to use, copy, or
X redistribute this software so long as all of the original files are included
X unmodified, that it is not sold for profit, and that this copyright notice
X is retained.
X
X*/
X
X/*

X * trees.c by Jean-loup Gailly
X *
X * This is a new version of im_ctree.c originally written by Richard B. Wales
X * for the defunct implosion method.
X *
X * PURPOSE
X *
X * Encode various sets of source values using variable-length
X * binary code trees.
X *
X * DISCUSSION
X *
X * The PKZIP "deflation" process uses several Huffman trees. The more
X * common source values are represented by shorter bit sequences.
X *
X * Each code tree is stored in the ZIP file in a compressed form
X * which is itself a Huffman encoding of the lengths of
X * all the code strings (in ascending order by source values).
X * The actual code strings are reconstructed from the lengths in
X * the UNZIP process, as described in the "application note"
X * (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
X *
X * REFERENCES
X *
X * Lynch, Thomas J.
X * Data Compression: Techniques and Applications, pp. 53-55.
X * Lifetime Learning Publications, 1985. ISBN 0-534-03418-7.
X *
X * Storer, James A.
X * Data Compression: Methods and Theory, pp. 49-50.
X * Computer Science Press, 1988. ISBN 0-7167-8156-5.
X *
X * Sedgewick, R.
X * Algorithms, p290.
X * Addison-Wesley, 1983. ISBN 0-201-06672-6.
X *
X * INTERFACE
X *
X * void ct_init (ush *attr, int *method)
X * Allocate the match buffer, initialize the various tables and save
X * the location of the internal file attribute (ascii/binary) and
X * method (DEFLATE/STORE)
X *
X * void ct_tally (int dist, int lc);
X * Save the match info and tally the frequency counts.
X *
X * long flush_block (char *buf, ulg stored_len, int eof)
X * Determine the best encoding for the current block: dynamic trees,
X * static trees or store, and output the encoded block to the zip
X * file. Returns the total compressed length for the file so far.
X *
X */
X
X#include <ctype.h>
X#include "zip.h"
X
X/* ===========================================================================
X * Constants
X */
X
X#define MAX_BITS 15
X/* All codes must not exceed MAX_BITS bits */
X
X#define MAX_BL_BITS 7
X/* Bit length codes must not exceed MAX_BL_BITS bits */
X
X#define LENGTH_CODES 29
X/* number of length codes, not counting the special END_BLOCK code */
X
X#define LITERALS 256
X/* number of literal bytes 0..255 */
X
X#define END_BLOCK 256
X/* end of block literal code */
X
X#define L_CODES (LITERALS+1+LENGTH_CODES)
X/* number of Literal or Length codes, including the END_BLOCK code */
X
X#define D_CODES 30
X/* number of distance codes */
X
X#define BL_CODES 19
X/* number of codes used to transfer the bit lengths */
X
X
Xlocal int near extra_lbits[LENGTH_CODES] /* extra bits for each length code */
X = {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};
X
Xlocal int near extra_dbits[D_CODES] /* extra bits for each distance code */
X = {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};
X
Xlocal int near extra_blbits[BL_CODES]/* extra bits for each bit length code */
X = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
X
X#define STORED_BLOCK 0
X#define STATIC_TREES 1
X#define DYN_TREES 2
X/* The three kinds of block type */
X
X#ifndef LIT_BUFSIZE
X# ifdef SMALL_MEM
X# define LIT_BUFSIZE 0x2000
X# else
X# ifdef MEDIUM_MEM
X# define LIT_BUFSIZE 0x4000
X# else
X# define LIT_BUFSIZE 0x8000


X# endif
X# endif
X#endif

X#define DIST_BUFSIZE LIT_BUFSIZE
X/* Sizes of match buffers for literals/lengths and distances. There are
X * 4 reasons for limiting LIT_BUFSIZE to 64K:
X * - frequencies can be kept in 16 bit counters
X * - if compression is not successful for the first block, all input data is
X * still in the window so we can still emit a stored block even when input
X * comes from standard input. (This can also be done for all blocks if
X * LIT_BUFSIZE is not greater than 32K.)
X * - if compression is not successful for a file smaller than 64K, we can
X * even emit a stored file instead of a stored block (saving 5 bytes).
X * - creating new Huffman trees less frequently may not provide fast
X * adaptation to changes in the input data statistics. (Take for
X * example a binary file with poorly compressible code followed by
X * a highly compressible string table.) Smaller buffer sizes give
X * fast adaptation but have of course the overhead of transmitting trees
X * more frequently.
X * - I can't count above 4
X * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
X * memory at the expense of compression). Some optimizations would be possible
X * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
X */
X
X#define REP_3_6 16
X/* repeat previous bit length 3-6 times (2 bits of repeat count) */
X
X#define REPZ_3_10 17
X/* repeat a zero length 3-10 times (3 bits of repeat count) */
X
X#define REPZ_11_138 18
X/* repeat a zero length 11-138 times (7 bits of repeat count) */
X
X/* ===========================================================================
X * Local data
X */
X
X/* Data structure describing a single value and its code string. */
Xtypedef struct ct_data {
X union {
X ush freq; /* frequency count */
X ush code; /* bit string */
X } fc;
X union {
X ush dad; /* father node in Huffman tree */
X ush len; /* length of bit string */
X } dl;
X} ct_data;
X
X#define Freq fc.freq
X#define Code fc.code
X#define Dad dl.dad
X#define Len dl.len
X
X#define HEAP_SIZE (2*L_CODES+1)
X/* maximum heap size */
X
Xlocal ct_data near dyn_ltree[HEAP_SIZE]; /* literal and length tree */
Xlocal ct_data near dyn_dtree[2*D_CODES+1]; /* distance tree */
X
Xlocal ct_data near static_ltree[L_CODES+2];
X/* The static literal tree. Since the bit lengths are imposed, there is no
X * need for the L_CODES extra codes used during heap construction. However
X * The codes 286 and 287 are needed to build a canonical tree (see ct_init
X * below).
X */
X
Xlocal ct_data near static_dtree[D_CODES];
X/* The static distance tree. (Actually a trivial tree since all codes use
X * 5 bits.)
X */
X
Xlocal ct_data near bl_tree[2*BL_CODES+1];
X/* Huffman tree for the bit lengths */
X
Xtypedef struct tree_desc {
X ct_data near *dyn_tree; /* the dynamic tree */
X ct_data near *static_tree; /* corresponding static tree or NULL */
X int near *extra_bits; /* extra bits for each code or NULL */
X int extra_base; /* base index for extra_bits */
X int elems; /* max number of elements in the tree */
X int max_length; /* max bit length for the codes */
X int max_code; /* largest code with non zero frequency */
X} tree_desc;
X
Xlocal tree_desc near l_desc =
X{dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0};
X
Xlocal tree_desc near d_desc =
X{dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0};
X
Xlocal tree_desc near bl_desc =
X{bl_tree, NULL, extra_blbits, 0, BL_CODES, MAX_BL_BITS, 0};
X
X
Xlocal ush near bl_count[MAX_BITS+1];
X/* number of codes at each bit length for an optimal tree */
X
Xlocal uch near bl_order[BL_CODES]
X = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
X/* The lengths of the bit length codes are sent in order of decreasing
X * probability, to avoid transmitting the lengths for unused bit length codes.
X */
X
Xlocal int near heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
Xlocal int heap_len; /* number of elements in the heap */
Xlocal int heap_max; /* element of largest frequency */
X/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
X * The same heap array is used to build all trees.
X */
X
Xlocal uch near depth[2*L_CODES+1];
X/* Depth of each subtree used as tie breaker for trees of equal frequency */
X
Xlocal uch length_code[MAX_MATCH-MIN_MATCH+1];
X/* length code for each normalized match length (0 == MIN_MATCH) */
X
Xlocal uch dist_code[512];
X/* distance codes. The first 256 values correspond to the distances
X * 3 .. 258, the last 256 values correspond to the top 8 bits of
X * the 15 bit distances.
X */
X
Xlocal int near base_length[LENGTH_CODES];
X/* First normalized length for each code (0 = MIN_MATCH) */
X
Xlocal int near base_dist[D_CODES];
X/* First normalized distance for each code (0 = distance of 1) */
X
X#ifndef DYN_ALLOC
X local uch far l_buf[LIT_BUFSIZE]; /* buffer for literals/lengths */
X local ush far d_buf[DIST_BUFSIZE]; /* buffer for distances */
X#else
X local uch far *l_buf;
X local ush far *d_buf;
X#endif
X
Xlocal uch near flag_buf[(LIT_BUFSIZE/8)];
X/* flag_buf is a bit array distinguishing literals from lengths in
X * l_buf, and thus indicating the presence or absence of a distance.
X */
X
Xlocal unsigned last_lit; /* running index in l_buf */
Xlocal unsigned last_dist; /* running index in d_buf */
Xlocal unsigned last_flags; /* running index in flag_buf */
Xlocal uch flags; /* current flags not yet saved in flag_buf */
Xlocal uch flag_bit; /* current bit used in flags */
X/* bits are filled in flags starting at bit 0 (least significant).
X * Note: these flags are overkill in the current code since we don't
X * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
X */
X
Xlocal ulg opt_len; /* bit length of current block with optimal trees */
Xlocal ulg static_len; /* bit length of current block with static trees */
X
Xlocal ulg compressed_len; /* total bit length of compressed file */
X
Xlocal ulg input_len; /* total byte length of input file */
X/* input_len is for debugging only since we can get it by other means. */
X
Xush *file_type; /* pointer to UNKNOWN, BINARY or ASCII */
Xint *file_method; /* pointer to DEFLATE or STORE */
X
X#ifdef DEBUG
Xextern ulg bits_sent; /* bit length of the compressed data */
Xextern ulg isize; /* byte length of input file */
X#endif
X
Xextern long block_start; /* window offset of current block */
Xextern unsigned near strstart; /* window offset of current string */
X
X/* ===========================================================================
X * Local (static) routines in this file.
X */
X
Xlocal void init_block OF((void));
Xlocal void pqdownheap OF((ct_data near *tree, int k));
Xlocal void gen_bitlen OF((tree_desc near *desc));
Xlocal void gen_codes OF((ct_data near *tree, int max_code));
Xlocal void build_tree OF((tree_desc near *desc));
Xlocal void scan_tree OF((ct_data near *tree, int max_code));
Xlocal void send_tree OF((ct_data near *tree, int max_code));
Xlocal int build_bl_tree OF((void));
Xlocal void send_all_trees OF((int lcodes, int dcodes, int blcodes));
Xlocal void compress_block OF((ct_data near *ltree, ct_data near *dtree));
Xlocal void set_file_type OF((void));
X
X
X#ifndef DEBUG
X# define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len)
X /* Send a code of the given tree. c and tree must not have side effects */
X
X#else /* DEBUG */
X# define send_code(c, tree) \
X { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \
X send_bits(tree[c].Code, tree[c].Len); }
X#endif
X
X#define d_code(dist) \
X ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
X/* Mapping from a distance to a distance code. dist is the distance - 1 and
X * must not have side effects. dist_code[256] and dist_code[257] are never
X * used.
X */
X
X#define MAX(a,b) (a >= b ? a : b)
X/* the arguments must not have side effects */
X
X/* ===========================================================================
X * Allocate the match buffer, initialize the various tables and save the
X * location of the internal file attribute (ascii/binary) and method
X * (DEFLATE/STORE).
X */
Xvoid ct_init(attr, method)
X ush *attr; /* pointer to internal file attribute */
X int *method; /* pointer to compression method */
X{
X int n; /* iterates over tree elements */
X int bits; /* bit counter */
X int length; /* length value */
X int code; /* code value */
X int dist; /* distance index */
X
X file_type = attr;
X file_method = method;
X compressed_len = input_len = 0L;
X
X if (static_dtree[0].Len != 0) return; /* ct_init already called */
X
X#ifdef DYN_ALLOC
X d_buf = (ush far*) fcalloc(DIST_BUFSIZE, sizeof(ush));
X l_buf = (uch far*) fcalloc(LIT_BUFSIZE/2, 2);
X /* Avoid using the value 64K on 16 bit machines */
X if (l_buf == NULL || d_buf == NULL) error("ct_init: out of memory");
X#endif
X
X /* Initialize the mapping length (0..255) -> length code (0..28) */
X length = 0;
X for (code = 0; code < LENGTH_CODES-1; code++) {
X base_length[code] = length;
X for (n = 0; n < (1<<extra_lbits[code]); n++) {
X length_code[length++] = (uch)code;
X }
X }
X Assert (length == 256, "ct_init: length != 256");
X /* Note that the length 255 (match length 258) can be represented
X * in two different ways: code 284 + 5 bits or code 285, so we
X * overwrite length_code[255] to use the best encoding:
X */
X length_code[length-1] = (uch)code;
X
X /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
X dist = 0;
X for (code = 0 ; code < 16; code++) {
X base_dist[code] = dist;
X for (n = 0; n < (1<<extra_dbits[code]); n++) {
X dist_code[dist++] = (uch)code;
X }
X }
X Assert (dist == 256, "ct_init: dist != 256");
X dist >>= 7; /* from now on, all distances are divided by 128 */
X for ( ; code < D_CODES; code++) {
X base_dist[code] = dist << 7;
X for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
X dist_code[256 + dist++] = (uch)code;
X }
X }
X Assert (dist == 256, "ct_init: 256+dist != 512");
X
X /* Construct the codes of the static literal tree */
X for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
X n = 0;
X while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
X while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
X while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
X while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
X /* Codes 286 and 287 do not exist, but we must include them in the
X * tree construction to get a canonical Huffman tree (longest code
X * all ones)
X */
X gen_codes(static_ltree, L_CODES+1);
X
X /* The static distance tree is trivial: */
X for (n = 0; n < D_CODES; n++) {
X static_dtree[n].Len = 5;
X static_dtree[n].Code = bi_reverse(n, 5);
X }
X
X /* Initialize the first block of the first file: */
X init_block();
X}
X
X/* ===========================================================================
X * Initialize a new block.
X */
Xlocal void init_block()
X{
X int n; /* iterates over tree elements */
X
X /* Initialize the trees. */
X for (n = 0; n < L_CODES; n++) dyn_ltree[n].Freq = 0;
X for (n = 0; n < D_CODES; n++) dyn_dtree[n].Freq = 0;
X for (n = 0; n < BL_CODES; n++) bl_tree[n].Freq = 0;
X
X dyn_ltree[END_BLOCK].Freq = 1;
X opt_len = static_len = 0L;
X last_lit = last_dist = last_flags = 0;
X flags = 0; flag_bit = 1;
X}
X
X#define SMALLEST 1
X/* Index within the heap array of least frequent node in the Huffman tree */
X
X
X/* ===========================================================================
X * Remove the smallest element from the heap and recreate the heap with
X * one less element. Updates heap and heap_len.
X */
X#define pqremove(tree, top) \
X{\
X top = heap[SMALLEST]; \
X heap[SMALLEST] = heap[heap_len--]; \
X pqdownheap(tree, SMALLEST); \
X}
X
X/* ===========================================================================
X * Compares to subtrees, using the tree depth as tie breaker when
X * the subtrees have equal frequency. This minimizes the worst case length.
X */
X#define smaller(tree, n, m) \
X (tree[n].Freq < tree[m].Freq || \
X (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
X
X/* ===========================================================================
X * Restore the heap property by moving down the tree starting at node k,
X * exchanging a node with the smallest of its two sons if necessary, stopping
X * when the heap property is re-established (each father smaller than its
X * two sons).
X */
Xlocal void pqdownheap(tree, k)
X ct_data near *tree; /* the tree to restore */
X int k; /* node to move down */
X{
X int v = heap[k];
X int j = k << 1; /* left son of k */
X while (j <= heap_len) {
X /* Set j to the smallest of the two sons: */
X if (j < heap_len && smaller(tree, heap[j+1], heap[j])) j++;
X
X /* Exit if v is smaller than both sons */
X if (smaller(tree, v, heap[j])) break;
X
X /* Exchange v with the smallest son */
X heap[k] = heap[j], k = j;
X
X /* And continue down the tree, setting j to the left son of k */
X j <<= 1;
X }
X heap[k] = v;
X}
X
X/* ===========================================================================
X * Compute the optimal bit lengths for a tree and update the total bit length
X * for the current block.
X * IN assertion: the fields freq and dad are set, heap[heap_max] and
X * above are the tree nodes sorted by increasing frequency.
X * OUT assertions: the field len is set to the optimal bit length, the
X * array bl_count contains the frequencies for each bit length.
X * The length opt_len is updated; static_len is also updated if stree is
X * not null.
X */
Xlocal void gen_bitlen(desc)
X tree_desc near *desc; /* the tree descriptor */
X{
X ct_data near *tree = desc->dyn_tree;
X int near *extra = desc->extra_bits;
X int base = desc->extra_base;
X int max_code = desc->max_code;
X int max_length = desc->max_length;
X ct_data near *stree = desc->static_tree;
X int h; /* heap index */
X int n, m; /* iterate over the tree elements */
X int bits; /* bit length */
X int xbits; /* extra bits */
X ush f; /* frequency */
X int overflow = 0; /* number of elements with bit length too large */
X
X for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
X
X /* In a first pass, compute the optimal bit lengths (which may
X * overflow in the case of the bit length tree).
X */
X tree[heap[heap_max]].Len = 0; /* root of the heap */
X
X for (h = heap_max+1; h < HEAP_SIZE; h++) {
X n = heap[h];
X bits = tree[tree[n].Dad].Len + 1;
X if (bits > max_length) bits = max_length, overflow++;
X tree[n].Len = bits;
X /* We overwrite tree[n].Dad which is no longer needed */
X
X if (n > max_code) continue; /* not a leaf node */
X
X bl_count[bits]++;
X xbits = 0;
X if (n >= base) xbits = extra[n-base];
X f = tree[n].Freq;
X opt_len += (ulg)f * (bits + xbits);
X if (stree) static_len += (ulg)f * (stree[n].Len + xbits);
X }
X if (overflow == 0) return;
X
X Trace((stderr,"\nbit length overflow\n"));
X /* This happens for example on obj2 and pic of the Calgary corpus */
X
X /* Find the first bit length which could increase: */
X do {
X bits = max_length-1;
X while (bl_count[bits] == 0) bits--;
X bl_count[bits]--; /* move one leaf down the tree */
X bl_count[bits+1] += 2; /* move one overflow item as its brother */
X bl_count[max_length]--;
X /* The brother of the overflow item also moves one step up,
X * but this does not affect bl_count[max_length]
X */
X overflow -= 2;
X } while (overflow > 0);
X
X /* Now recompute all bit lengths, scanning in increasing frequency.
X * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
X * lengths instead of fixing only the wrong ones. This idea is taken
X * from 'ar' written by Haruhiko Okumura.)
X */
X for (bits = max_length; bits != 0; bits--) {
X n = bl_count[bits];
X while (n != 0) {
X m = heap[--h];
X if (m > max_code) continue;
X if (tree[m].Len != (unsigned) bits) {
X Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
X opt_len += ((long)bits-(long)tree[m].Len)*(long)tree[m].Freq;
X tree[m].Len = bits;
X }
X n--;
X }
X }
X}
X
X/* ===========================================================================
X * Generate the codes for a given tree and bit counts (which need not be
X * optimal).
X * IN assertion: the array bl_count contains the bit length statistics for
X * the given tree and the field len is set for all tree elements.
X * OUT assertion: the field code is set for all tree elements of non
X * zero code length.
X */
Xlocal void gen_codes (tree, max_code)
X ct_data near *tree; /* the tree to decorate */
X int max_code; /* largest code with non zero frequency */
X{
X ush next_code[MAX_BITS+1]; /* next code value for each bit length */
X ush code = 0; /* running code value */
X int bits; /* bit index */
X int n; /* code index */
X
X /* The distribution counts are first used to generate the code values
X * without bit reversal.
X */
X for (bits = 1; bits <= MAX_BITS; bits++) {
X next_code[bits] = code = (code + bl_count[bits-1]) << 1;
X }
X /* Check that the bit counts in bl_count are consistent. The last code
X * must be all ones.
X */
X Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
X "inconsistent bit counts");
X Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
X
X for (n = 0; n <= max_code; n++) {
X int len = tree[n].Len;
X if (len == 0) continue;
X /* Now reverse the bits */
X tree[n].Code = bi_reverse(next_code[len]++, len);
X
X Tracec(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
X n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
X }
X}
X
X/* ===========================================================================
X * Construct one Huffman tree and assigns the code bit strings and lengths.
X * Update the total bit length for the current block.
X * IN assertion: the field freq is set for all tree elements.
X * OUT assertions: the fields len and code are set to the optimal bit length
X * and corresponding code. The length opt_len is updated; static_len is
X * also updated if stree is not null. The field max_code is set.
X */
Xlocal void build_tree(desc)
X tree_desc near *desc; /* the tree descriptor */
X{
X ct_data near *tree = desc->dyn_tree;
X ct_data near *stree = desc->static_tree;
X int elems = desc->elems;
X int n, m; /* iterate over heap elements */
X int max_code = -1; /* largest code with non zero frequency */
X int node = elems; /* next internal node of the tree */
X
X /* Construct the initial heap, with least frequent element in
X * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
X * heap[0] is not used.
X */
X heap_len = 0, heap_max = HEAP_SIZE;
X
X for (n = 0; n < elems; n++) {
X if (tree[n].Freq != 0) {
X heap[++heap_len] = max_code = n;
X depth[n] = 0;
X } else {
X tree[n].Len = 0;
X }
X }
X
X /* The pkzip format requires that at least one distance code exists,
X * and that at least one bit should be sent even if there is only one
X * possible code. So to avoid special checks later on we force at least
X * two codes of non zero frequency.
X */
X while (heap_len < 2) {
X int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0);
X tree[new].Freq = 1;
X depth[new] = 0;
X opt_len--; if (stree) static_len -= stree[new].Len;
X /* new is 0 or 1 so it does not have extra bits */
X }
X desc->max_code = max_code;
X
X /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
X * establish sub-heaps of increasing lengths:
X */
X for (n = heap_len/2; n >= 1; n--) pqdownheap(tree, n);
X
X /* Construct the Huffman tree by repeatedly combining the least two
X * frequent nodes.
X */
X do {
X pqremove(tree, n); /* n = node of least frequency */
X m = heap[SMALLEST]; /* m = node of next least frequency */
X
X heap[--heap_max] = n; /* keep the nodes sorted by frequency */
X heap[--heap_max] = m;
X
X /* Create a new node father of n and m */
X tree[node].Freq = tree[n].Freq + tree[m].Freq;
X depth[node] = (uch) (MAX(depth[n], depth[m]) + 1);
X tree[n].Dad = tree[m].Dad = node;
X#ifdef DUMP_BL_TREE
X if (tree == bl_tree) {
X fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
X node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
X }
X#endif
X /* and insert the new node in the heap */
X heap[SMALLEST] = node++;
X pqdownheap(tree, SMALLEST);
X
X } while (heap_len >= 2);
X
X heap[--heap_max] = heap[SMALLEST];
X
X /* At this point, the fields freq and dad are set. We can now
X * generate the bit lengths.
X */
X gen_bitlen(desc);
X
X /* The field len is now set, we can generate the bit codes */
X gen_codes (tree, max_code);
X}
X
X/* ===========================================================================
X * Scan a literal or distance tree to determine the frequencies of the codes
X * in the bit length tree. Updates opt_len to take into account the repeat
X * counts. (The contribution of the bit length codes will be added later
X * during the construction of bl_tree.)
X */
Xlocal void scan_tree (tree, max_code)
X ct_data near *tree; /* the tree to be scanned */
X int max_code; /* and its largest code of non zero frequency */
X{
X int n; /* iterates over all tree elements */
X int prevlen = -1; /* last emitted length */
X int curlen; /* length of current code */
X int nextlen = tree[0].Len; /* length of next code */
X int count = 0; /* repeat count of the current code */
X int max_count = 7; /* max repeat count */
X int min_count = 4; /* min repeat count */
X
X if (nextlen == 0) max_count = 138, min_count = 3;
X tree[max_code+1].Len = (ush)-1; /* guard */
X
X for (n = 0; n <= max_code; n++) {
X curlen = nextlen; nextlen = tree[n+1].Len;
X if (++count < max_count && curlen == nextlen) {
X continue;
X } else if (count < min_count) {
X bl_tree[curlen].Freq += count;
X } else if (curlen != 0) {
X if (curlen != prevlen) bl_tree[curlen].Freq++;
X bl_tree[REP_3_6].Freq++;
X } else if (count <= 10) {
X bl_tree[REPZ_3_10].Freq++;
X } else {
X bl_tree[REPZ_11_138].Freq++;
X }
X count = 0; prevlen = curlen;
X if (nextlen == 0) {
X max_count = 138, min_count = 3;
X } else if (curlen == nextlen) {
X max_count = 6, min_count = 3;
X } else {
X max_count = 7, min_count = 4;
X }
X }
X}
X
X/* ===========================================================================
X * Send a literal or distance tree in compressed form, using the codes in
X * bl_tree.
X */
Xlocal void send_tree (tree, max_code)
X ct_data near *tree; /* the tree to be scanned */
X int max_code; /* and its largest code of non zero frequency */
X{
X int n; /* iterates over all tree elements */
X int prevlen = -1; /* last emitted length */
X int curlen; /* length of current code */
X int nextlen = tree[0].Len; /* length of next code */
X int count = 0; /* repeat count of the current code */
X int max_count = 7; /* max repeat count */
X int min_count = 4; /* min repeat count */
X
X /* tree[max_code+1].Len = -1; */ /* guard already set */
X if (nextlen == 0) max_count = 138, min_count = 3;
X
X for (n = 0; n <= max_code; n++) {
X curlen = nextlen; nextlen = tree[n+1].Len;
X if (++count < max_count && curlen == nextlen) {
X continue;
X } else if (count < min_count) {
X do { send_code(curlen, bl_tree); } while (--count != 0);
X
X } else if (curlen != 0) {
X if (curlen != prevlen) {
X send_code(curlen, bl_tree); count--;
X }
X Assert(count >= 3 && count <= 6, " 3_6?");
X send_code(REP_3_6, bl_tree); send_bits(count-3, 2);
X
X } else if (count <= 10) {
X send_code(REPZ_3_10, bl_tree); send_bits(count-3, 3);
X
X } else {
X send_code(REPZ_11_138, bl_tree); send_bits(count-11, 7);
X }
X count = 0; prevlen = curlen;
X if (nextlen == 0) {
X max_count = 138, min_count = 3;
X } else if (curlen == nextlen) {
X max_count = 6, min_count = 3;
X } else {
X max_count = 7, min_count = 4;
X }
X }
X}
X
X/* ===========================================================================
X * Construct the Huffman tree for the bit lengths and return the index in
X * bl_order of the last bit length code to send.
X */
Xlocal int build_bl_tree()
X{
X int max_blindex; /* index of last bit length code of non zero freq */
X
X /* Determine the bit length frequencies for literal and distance trees */
X scan_tree(dyn_ltree, l_desc.max_code);
X scan_tree(dyn_dtree, d_desc.max_code);
X
X /* Build the bit length tree: */
X build_tree(&bl_desc);
X /* opt_len now includes the length of the tree representations, except
X * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
X */
X
X /* Determine the number of bit length codes to send. The pkzip format
X * requires that at least 4 bit length codes be sent. (appnote.txt says
X * 3 but the actual value used is 4.)
X */
X for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
X if (bl_tree[bl_order[max_blindex]].Len != 0) break;
X }
X /* Update opt_len to include the bit length tree and counts */
X opt_len += 3*(max_blindex+1) + 5+5+4;
X Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len, static_len));
X
X return max_blindex;
X}
X
X/* ===========================================================================
X * Send the header for a block using dynamic Huffman trees: the counts, the
X * lengths of the bit length codes, the literal tree and the distance tree.
X * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
X */
Xlocal void send_all_trees(lcodes, dcodes, blcodes)
X int lcodes, dcodes, blcodes; /* number of codes for each tree */
X{
X int rank; /* index in bl_order */
X
X Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
X Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
X "too many codes");
X Tracev((stderr, "\nbl counts: "));
X send_bits(lcodes-257, 5); /* not -255 as stated in appnote.txt */
X send_bits(dcodes-1, 5);
X send_bits(blcodes-4, 4); /* not -3 as stated in appnote.txt */
X for (rank = 0; rank < blcodes; rank++) {
X Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
X send_bits(bl_tree[bl_order[rank]].Len, 3);
X }
X Tracev((stderr, "\nbl tree: sent %ld", bits_sent));
X
X send_tree(dyn_ltree, lcodes-1); /* send the literal tree */
X Tracev((stderr, "\nlit tree: sent %ld", bits_sent));
X
X send_tree(dyn_dtree, dcodes-1); /* send the distance tree */
X Tracev((stderr, "\ndist tree: sent %ld", bits_sent));
X}
X
X/* ===========================================================================
X * Determine the best encoding for the current block: dynamic trees, static
X * trees or store, and output the encoded block to the zip file. This function
X * returns the total compressed length for the file so far.
X */
Xulg flush_block(buf, stored_len, eof)
X char *buf; /* input block, or NULL if too old */
X ulg stored_len; /* length of input block */
X int eof; /* true if this is the last block for a file */
X{
X ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
X int max_blindex; /* index of last bit length code of non zero freq */
X
X flag_buf[last_flags] = flags; /* Save the flags for the last 8 items */
X
X /* Check if the file is ascii or binary */
X if (*file_type == (ush)UNKNOWN) set_file_type();
X
X /* Construct the literal and distance trees */
X build_tree(&l_desc);
X Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len));
X
X build_tree(&d_desc);
X Tracev((stderr, "\ndist data: dyn %ld, stat %ld", opt_len, static_len));
X /* At this point, opt_len and static_len are the total bit lengths of
X * the compressed block data, excluding the tree representations.
X */
X
X /* Build the bit length tree for the above two trees, and get the index
X * in bl_order of the last bit length code to send.
X */
X max_blindex = build_bl_tree();
X
X /* Determine the best encoding. Compute first the block length in bytes */
X opt_lenb = (opt_len+3+7)>>3;
X static_lenb = (static_len+3+7)>>3;
X input_len += stored_len; /* for debugging only */
X
X Trace((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
X opt_lenb, opt_len, static_lenb, static_len, stored_len,
X last_lit, last_dist));
X
X if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
X
X /* If compression failed and this is the first and last block,
X * and if the zip file can be seeked (to rewrite the local header),
X * the whole file is transformed into a stored file:
X */
X#ifdef FORCE_METHOD
X if (level == 1 && eof && compressed_len == 0L) { /* force stored file */
X#else
X if (stored_len <= opt_lenb && eof && compressed_len == 0L && seekable()) {
X#endif
X /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
X if (buf == NULL) error ("block vanished");
X
X copy_block(buf, (unsigned)stored_len, 0); /* without header */
X compressed_len = stored_len << 3;
X *file_method = STORE;
X
X#ifdef FORCE_METHOD
X } else if (level == 2 && buf != NULL) { /* force stored block */
X#else
X } else if (stored_len+4 <= opt_lenb && buf != NULL) {
X /* 4: two words for the lengths */
X#endif
X /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
X * Otherwise we can't have processed more than WSIZE input bytes since
X * the last block flush, because compression would have been
X * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
X * transform a block into a stored block.
X */
X send_bits((STORED_BLOCK<<1)+eof, 3); /* send block type */
X compressed_len = (compressed_len + 3 + 7) & ~7L;
X compressed_len += (stored_len + 4) << 3;
X
X copy_block(buf, (unsigned)stored_len, 1); /* with header */
X
X#ifdef FORCE_METHOD
X } else if (level == 3) { /* force static trees */
X#else
X } else if (static_lenb == opt_lenb) {
X#endif
X send_bits((STATIC_TREES<<1)+eof, 3);
X compress_block(static_ltree, static_dtree);
X compressed_len += 3 + static_len;
X } else {
X send_bits((DYN_TREES<<1)+eof, 3);
X send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1);
X compress_block(dyn_ltree, dyn_dtree);
X compressed_len += 3 + opt_len;
X }
X Assert (compressed_len == bits_sent, "bad compressed size");
X init_block();
X
X if (eof) {
X Assert (input_len == isize, "bad input size");
X bi_windup();
X compressed_len += 7; /* align on byte boundary */
X }
X Tracev((stderr,"\ncomprlen %lu(%lu) ", compressed_len>>3,
X compressed_len-7*eof));
X
X return compressed_len >> 3;
X}
X
X/* ===========================================================================
X * Save the match info and tally the frequency counts. Return true if
X * the current block must be flushed.
X */
Xint ct_tally (dist, lc)
X int dist; /* distance of matched string */
X int lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
X{
X l_buf[last_lit++] = (uch)lc;
X if (dist == 0) {
X /* lc is the unmatched char */
X dyn_ltree[lc].Freq++;
X } else {
X /* Here, lc is the match length - MIN_MATCH */
X dist--; /* dist = match distance - 1 */
X Assert((ush)dist < (ush)MAX_DIST &&
X (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
X (ush)d_code(dist) < (ush)D_CODES, "ct_tally: bad match");
X
X dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
X dyn_dtree[d_code(dist)].Freq++;
X
X d_buf[last_dist++] = dist;
X flags |= flag_bit;
X }
X flag_bit <<= 1;
X
X /* Output the flags if they fill a byte: */
X if ((last_lit & 7) == 0) {
X flag_buf[last_flags++] = flags;
X flags = 0, flag_bit = 1;
X }
X /* Try to guess if it is profitable to stop the current block here */
X if (level > 2 && (last_lit & 0xfff) == 0) {
X /* Compute an upper bound for the compressed length */
X ulg out_length = (ulg)last_lit*8L;
X ulg in_length = (ulg)strstart-block_start;
X int dcode;
X for (dcode = 0; dcode < D_CODES; dcode++) {
X out_length += (ulg)dyn_dtree[dcode].Freq*(5L+extra_dbits[dcode]);
X }
X out_length >>= 3;
X Trace((stderr,"\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
X last_lit, last_dist, in_length, out_length,
X 100L - out_length*100L/in_length));
X if (last_dist < last_lit/2 && out_length < in_length/2) return 1;
X }
X return (last_lit == LIT_BUFSIZE-1 || last_dist == DIST_BUFSIZE);
X /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
X * on 16 bit machines and because stored blocks are restricted to
X * 64K-1 bytes.
X */
X}
X
X/* ===========================================================================
X * Send the block data compressed using the given Huffman trees
X */
Xlocal void compress_block(ltree, dtree)
X ct_data near *ltree; /* literal tree */
X ct_data near *dtree; /* distance tree */
X{
X unsigned dist; /* distance of matched string */
X int lc; /* match length or unmatched char (if dist == 0) */
X unsigned lx = 0; /* running index in l_buf */
X unsigned dx = 0; /* running index in d_buf */
X unsigned fx = 0; /* running index in flag_buf */
X uch flag = 0; /* current flags */
X unsigned code; /* the code to send */
X int extra; /* number of extra bits to send */
X
X if (last_lit != 0) do {
X if ((lx & 7) == 0) flag = flag_buf[fx++];
X lc = l_buf[lx++];
X if ((flag & 1) == 0) {
X send_code(lc, ltree); /* send a literal byte */
X Tracecv(isgraph(lc), (stderr," '%c' ", lc));
X } else {
X /* Here, lc is the match length - MIN_MATCH */
X code = length_code[lc];
X send_code(code+LITERALS+1, ltree); /* send the length code */
X extra = extra_lbits[code];
X if (extra != 0) {
X lc -= base_length[code];
X send_bits(lc, extra); /* send the extra length bits */
X }
X dist = d_buf[dx++];
X /* Here, dist is the match distance - 1 */
X code = d_code(dist);
X Assert (code < D_CODES, "bad d_code");
X
X send_code(code, dtree); /* send the distance code */
X extra = extra_dbits[code];
X if (extra != 0) {
X dist -= base_dist[code];
X send_bits(dist, extra); /* send the extra distance bits */
X }
X } /* literal or match pair ? */
X flag >>= 1;
X } while (lx < last_lit);
X
X send_code(END_BLOCK, ltree);
X}
X
X/* ===========================================================================
X * Set the file type to ASCII or BINARY, using a crude approximation:
X * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
X * IN assertion: the fields freq of dyn_ltree are set and the total of all
X * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
X */
Xlocal void set_file_type()
X{
X int n = 0;
X unsigned ascii_freq = 0;
X unsigned bin_freq = 0;
X while (n < 7) bin_freq += dyn_ltree[n++].Freq;
X while (n < 128) ascii_freq += dyn_ltree[n++].Freq;
X while (n < LITERALS) bin_freq += dyn_ltree[n++].Freq;
X *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII;
X if (*file_type == BINARY && translate_eol) {
X warn("-l used on binary file", "");
X }
X}
END_OF_FILE
if test 40777 -ne `wc -c <'trees.c'`; then
echo shar: \"'trees.c'\" unpacked with wrong size!
fi
# end of 'trees.c'
fi
if test -f 'util.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'util.c'\"
else
echo shar: Extracting \"'util.c'\" \(12887 characters\)
sed "s/^X//" >'util.c' <<'END_OF_FILE'


X/*
X
X Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly,
X Kai Uwe Rommel and Igor Mandrichenko.
X Permission is granted to any individual or institution to use, copy, or
X redistribute this software so long as all of the original files are included
X unmodified, that it is not sold for profit, and that this copyright notice
X is retained.
X
X*/
X
X/*

X * util.c by Mark Adler.


X */
X
X#include "zip.h"

X#include <ctype.h>
X
X#if defined(MSDOS) && !defined(OS2) && !defined(__GO32__) && !defined(WIN32)
X# include <dos.h>
X#endif
X
Xuch upper[256], lower[256];
X/* Country-dependent case map table */
X
X
X#ifndef UTIL /* UTIL picks out namecmp code (all utils) and crc32 (zipcloak) */


X
X/* Local functions */
X#ifdef PROTO

X local int recmatch(char *, char *);
X local unsigned ident(unsigned chr);


X#endif /* PROTO */
X

Xchar *isshexp(p)
Xchar *p; /* candidate sh expression */
X/* If p is a sh expression, a pointer to the first special character is
X returned. Otherwise, NULL is returned. */
X{
X for (; *p; p++)
X if (*p == '\\' && *(p+1))
X p++;
X#ifdef VMS
X else if (*p == '%' || *p == '*')
X#else /* !VMS */
X else if (*p == '?' || *p == '*' || *p == '[')
X#endif /* ?VMS */
X return p;


X return NULL;
X}
X
X

Xlocal int recmatch(p, s)
Xchar *p; /* sh pattern to match */
Xchar *s; /* string to match it to */
X/* Recursively compare the sh pattern p with the string s and return 1 if
X they match, and 0 or 2 if they don't or if there is a syntax error in the
X pattern. This routine recurses on itself no deeper than the number of
X characters in the pattern. */
X{
X int c; /* pattern char or start of range in [-] loop */
X
X /* Get first character, the pattern for new recmatch calls follows */
X c = *p++;
X
X /* If that was the end of the pattern, match if string empty too */
X if (c == 0)
X return *s == 0;
X
X /* '?' (or '%') matches any character (but not an empty string) */
X#ifdef VMS
X if (c == '%')
X#else /* !VMS */
X if (c == '?')
X#endif /* ?VMS */
X return *s ? recmatch(p, s + 1) : 0;
X
X /* '*' matches any number of characters, including zero */
X if (c == '*')
X {


X if (*p == 0)

X return 1;
X for (; *s; s++)
X if ((c = recmatch(p, s)) != 0)
X return c;
X return 2; /* 2 means give up--shmatch will return false */
X }
X
X#ifndef VMS /* No bracket matching in VMS */
X /* Parse and process the list of characters and ranges in brackets */
X if (c == '[')
X {
X int e; /* flag true if next char to be taken literally */
X char *q; /* pointer to end of [-] group */
X int r; /* flag true to match anything but the range */
X
X if (*s == 0) /* need a character to match */
X return 0;
X p += (r = *p == '!'); /* see if reverse */
X for (q = p, e = 0; *q; q++) /* find closing bracket */
X if (e)
X e = 0;
X else


X if (*q == '\\')

X e = 1;
X else if (*q == ']')
X break;
X if (*q != ']') /* nothing matches if bad syntax */
X return 0;
X for (c = 0, e = *p == '-'; p < q; p++) /* go through the list */
X {
X if (e == 0 && *p == '\\') /* set escape flag if \ */
X e = 1;
X else if (e == 0 && *p == '-') /* set start of range if - */
X c = *(p-1);
X else
X {
X if (*(p+1) != '-')
X for (c = c ? c : *p; c <= *p; c++) /* compare range */
X if (case_map(c) == case_map(*s))
X return r ? 0 : recmatch(q + 1, s + 1);
X c = e = 0; /* clear range, escape flags */
X }
X }
X return r ? recmatch(q + 1, s + 1) : 0; /* bracket match failed */
X }


X#endif /* !VMS */
X

X /* If escape ('\'), just compare next character */
X if (c == '\\')
X if ((c = *p++) == 0) /* if \ at end, then syntax error */
X return 0;
X
X /* Just a character--compare it */
X return case_map(c) == case_map(*s) ? recmatch(p, ++s) : 0;
X}
X
X
Xint shmatch(p, s)
Xchar *p; /* sh pattern to match */
Xchar *s; /* string to match it to */
X/* Compare the sh pattern p with the string s and return true if they match,
X false if they don't or if there is a syntax error in the pattern. */
X{
X return recmatch(p, s) == 1;
X}


X
X
X#ifdef MSDOS
X

Xint dosmatch(p, s)
Xchar *p; /* dos pattern to match */
Xchar *s; /* string to match it to */
X/* Break the pattern and string into name and extension parts and match
X each separately using shmatch(). */
X{
X char *p1, *p2; /* pattern sections */
X char *s1, *s2; /* string sections */
X int r; /* result */
X
X if ((p1 = malloc(strlen(p) + 1)) == NULL ||
X (s1 = malloc(strlen(s) + 1)) == NULL)
X {
X if (p1 != NULL)
X free((voidp *)p1);
X return 0;
X }
X strcpy(p1, p);
X strcpy(s1, s);
X if ((p2 = strrchr(p1, '.')) != NULL)
X *p2++ = 0;
X else
X p2 = "";
X if ((s2 = strrchr(s1, '.')) != NULL)
X *s2++ = 0;
X else
X s2 = "";
X r = shmatch(p2, s2) && shmatch(p1, s1);
X free((voidp *)p1);
X free((voidp *)s1);
X return r;
X}


X#endif /* MSDOS */
X

Xvoidp far **search(b, a, n, cmp)
Xvoidp *b; /* pointer to value to search for */
Xvoidp far **a; /* table of pointers to values, sorted */
Xextent n; /* number of pointers in a[] */
Xint (*cmp) OF((voidp *, voidp far *)); /* comparison function for search */
X/* Search for b in the pointer list a[0..n-1] using the compare function
X cmp(b, c) where c is an element of a[i] and cmp() returns negative if
X *b < *c, zero if *b == *c, or positive if *b > *c. If *b is found,
X search returns a pointer to the entry in a[], else search() returns
X NULL. The nature and size of *b and *c (they can be different) are
X left up to the cmp() function. A binary search is used, and it is
X assumed that the list is sorted in ascending order. */
X{
X voidp far **i; /* pointer to midpoint of current range */
X voidp far **l; /* pointer to lower end of current range */
X int r; /* result of (*cmp)() call */
X voidp far **u; /* pointer to upper end of current range */
X
X l = (voidp far **)a; u = l + (n-1);
X while (u >= l)
X if ((r = (*cmp)(b, *(i = l + ((u - l) >> 1)))) < 0)
X u = i - 1;
X else if (r > 0)
X l = i + 1;
X else
X return (voidp far **)i;
X return NULL; /* If b were in list, it would belong at l */
X}
X


X#endif /* !UTIL */
X
X

X/* Table of CRC-32's of all single byte values (made by makecrc.c) */
Xlocal ulg crctab[] = {
X 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
X 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
X 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
X 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
X 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
X 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
X 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
X 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
X 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
X 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
X 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
X 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
X 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
X 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
X 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
X 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
X 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
X 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
X 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
X 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
X 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
X 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
X 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
X 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
X 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
X 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
X 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
X 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
X 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
X 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
X 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
X 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
X 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
X 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
X 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
X 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
X 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
X 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
X 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
X 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
X 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
X 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
X 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
X 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
X 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
X 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
X 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
X 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
X 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
X 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
X 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
X 0x2d02ef8dL
X};
X
X
Xulg crc32(c, b)
Xulg c; /* current contents of crc shift register */
Xint b; /* byte (eight bits) to run through */
X/* Return the CRC-32 c updated with the eight bits in b. */
X{
X return crctab[((int)c ^ b) & 0xff] ^ (c >> 8);
X}
X
X
X#ifndef UTIL /* UTIL picks out namecmp code (all utils) and crc32 (zipcloak) */
X
Xulg updcrc(s, n)
Xchar *s; /* pointer to bytes to pump through */
Xextent n; /* number of bytes in s[] */
X/* Run a set of bytes through the crc shift register. If s is a NULL
X pointer, then initialize the crc shift register contents instead.
X Return the current crc in either case. */
X{
X register ulg c; /* temporary variable */
X
X static ulg crc = 0xffffffffL; /* shift register contents */
X
X if (s == NULL)
X c = 0xffffffffL;
X else
X {
X c = crc;
X while (n--)
X c = crctab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
X }
X crc = c;
X return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */
X}
X
X#endif /* !UTIL */
X
X
X#if (defined(MSDOS) && !defined(OS2) && !defined(__GO32__) && !defined(WIN32))
X
Xlocal unsigned ident(unsigned chr)
X{
X return chr; /* in al */
X}
X
Xvoid init_upper()
X{
X static struct country {
X uch ignore[18];
X int (far *casemap)(int);
X uch filler[16];
X } country_info;
X
X struct country far *info = &country_info;
X union REGS regs;
X struct SREGS sregs;
X int c;
X
X regs.x.ax = 0x3800; /* get country info */
X regs.x.dx = FP_OFF(info);
X sregs.ds = FP_SEG(info);
X intdosx(&regs, &regs, &sregs);
X for (c = 0; c < 128; c++) {
X upper[c] = (uch) toupper(c);
X lower[c] = (uch) c;
X }
X for (; c < sizeof(upper); c++) {
X upper[c] = (uch) (*country_info.casemap)(ident(c));
X /* ident() required because casemap takes its parameter in al */
X lower[c] = (uch) c;
X }
X for (c = 0; c < sizeof(upper); c++ ) {
X int u = upper[c];
X if (u != c && lower[u] == (uch) u) {
X lower[u] = (uch)c;
X }
X }
X for (c = 'A'; c <= 'Z'; c++) {
X lower[c] = (uch) (c - 'A' + 'a');
X }
X}
X#else
X# ifndef OS2
X
Xvoid init_upper()
X{
X int c;
X for (c = 0; c < sizeof(upper); c++) upper[c] = lower[c] = c;
X for (c = 'a'; c <= 'z'; c++) upper[c] = c - 'a' + 'A';
X for (c = 'A'; c <= 'Z'; c++) lower[c] = c - 'A' + 'a';
X}
X# endif /* OS2 */
X
X#endif /* MSDOS && !__GO32__ && !OS2 */
X
Xint namecmp(string1, string2)
X char *string1, *string2;
X/* Compare the two strings ignoring case, and correctly taking into
X * account national language characters. For operating systems with
X * case sensitive file names, this function is equivalent to strcmp.
X */
X{
X int d;
X
X for (;;)
X {
X d = (int) (unsigned char) case_map(*string1)
X - (int) (unsigned char) case_map(*string2);
X
X if (d || *string1 == 0 || *string2 == 0)
X return d;
X
X string1++;
X string2++;
X }
X}
END_OF_FILE
if test 12887 -ne `wc -c <'util.c'`; then
echo shar: \"'util.c'\" unpacked with wrong size!
fi
# end of 'util.c'
fi
if test -f 'vms/makefile.vms' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'vms/makefile.vms'\"
else
echo shar: Extracting \"'vms/makefile.vms'\" \(3279 characters\)
sed "s/^X//" >'vms/makefile.vms' <<'END_OF_FILE'
X#============================================================================
X# Makefile for VMS Zip, ZipCloak, ZipNote and ZipSplit Greg Roelofs
X# Version: 1.8f [for use with Todd Aven's MAKE/VMS 3.4] 25 June 1992
X#============================================================================
X
X# Most recent revisions: 25 June 1992
X
X
X#####################
X# MACRO DEFINITIONS #
X#####################
X
XCRYPTO =
XCLOAK =
XCFLAGS =
XUFLAGS = /def=UTIL
X# Uncomment next three lines for decryption version:
X#CRYPTO = crypt.obj,
X#CLOAK = zipcloak.exe
X#CFLAGS = /def=CRYPT
X#UFLAGS = /def=(UTIL,CRYPT)
X
XCC = cc
XLIB =
X# Uncomment next two lines to use the GNU compiler (also add /undef=__STDC__
X# to CFLAGS and UFLAGS, possibly split UFLAGS into two /def's, and possibly
X# replace /obj=$@ [below] with copy/rename/delete setup). NOT TESTED.
X#CC = gcc
X#LIB = gnu_cc:[000000]gcclib.olb/lib,
X
XE = .exe
XO = .obj
XLD = link
XLDFLAGS =
X
XZIPS = zip$E zipnote$E zipsplit$E $(CLOAK)
X
X# object file lists
XOBJZ = zip$O, zipfile$O, zipup$O, fileio$O, $(CRYPTO) util$O,-
X globals$O, VMSmunch$O, vms$O
XOBJI = deflate$O, trees$O, bits$O
XOBJN = zipnote$O, zipfile_$O, zipup_$O, fileio_$O, util_$O,-
X globals$O, VMSmunch$O
XOBJS = zipsplit$O, zipfile_$O, zipup_$O, fileio_$O, util_$O,-
X globals$O, VMSmunch$O
XOBJC = zipcloak$O, zipfile_$O, zipup_$O, fileio_$O, util$O,-
X globals$O, VMSmunch$O, crypt_$O
X
X
X###############################################
X# BASIC COMPILE INSTRUCTIONS AND DEPENDENCIES #
X###############################################
X
Xdefault: $(ZIPS)
X
X
X# suffix rules
X*.obj: *.c # `*.c' necessary?
X $(CC) $(CFLAGS) $<
X
X*_.obj: *.c # `$*' not legal
X $(CC) $(UFLAGS) /obj=$@ $<
X
X
X# executables makerules (trailing `$' makes line a data line)
Xzip$E: $(OBJZ), $(OBJI)
X $(LD) $(LDFLAGS) $(OBJZ), $(OBJI), $(LIB) sys$input/opt
X sys$share:vaxcrtl.exe/shareable $
X
Xzipnote$E: $(OBJN)
X $(LD) $(LDFLAGS) $(OBJN), $(LIB) sys$input/opt
X sys$share:vaxcrtl.exe/shareable $
X
Xzipcloak$E: $(OBJC)
X $(LD) $(LDFLAGS) $(OBJC), $(LIB) sys$input/opt
X sys$share:vaxcrtl.exe/shareable $
X
Xzipsplit$E: $(OBJS)
X $(LD) $(LDFLAGS) $(OBJS), $(LIB) sys$input/opt
X sys$share:vaxcrtl.exe/shareable $
X
X# dependencies for zip, zipnote, zipcloak, and zipsplit
X$(OBJZ): zip.h ziperr.h tailor.h
X$(OBJI): zip.h ziperr.h tailor.h
X$(OBJN): zip.h ziperr.h tailor.h
X$(OBJS): zip.h ziperr.h tailor.h
X$(OBJC): zip.h ziperr.h tailor.h
Xfileio$O: VMSmunch.h
Xvms$O: vms.c zip.h
XVMSmunch$O: VMSmunch.c VMSmunch.h
Xzip$O: revision.h
Xzipcloak$O: revision.h
Xzipfile$O: VMSmunch.h
Xzipnote$O: revision.h
Xzipsplit$O: revision.h
Xzipup$O: revision.h
X
X
Xclean:
X del *.obj;*
X del *.exe;* # use "purge/log" instead?
X
X
X# the backslash '\' is the continuation character if it occurs as
X# the last non-white character on the line.
X# the hyphen '-' is the DCL continuation character, so if it occurs
X# as the last non-white character on the line, the next line will
X# not have the dollar sign '$' prepended.
X
X
X################################
X# INDIVIDUAL MACHINE MAKERULES #
X################################
X
Xgeneric: default # first try if unknown
Xgeneric2: default # second try if unknown
Xvax: default
Xvms: default
X
Xall: $(ZIPS)
Xzip: zip$E
Xzipcloak: zipcloak$E
Xzipnote: zipnote$E
Xzipsplit: zipsplit$E
END_OF_FILE
if test 3279 -ne `wc -c <'vms/makefile.vms'`; then
echo shar: \"'vms/makefile.vms'\" unpacked with wrong size!
fi
# end of 'vms/makefile.vms'
fi
echo shar: End of archive 3 \(of 11\).
cp /dev/null ark3isdone

Info-ZIP group

unread,
Aug 23, 1992, 2:46:28 AM8/23/92
to
Submitted-by: zip-...@cs.ucla.edu (Info-ZIP group)
Posting-number: Volume 31, Issue 96
Archive-name: zip19/part04

Supersedes: zip: Volume 23, Issue 88-96
Environment: UNIX, VMS, OS/2, MS-DOS, MACINTOSH, WIN-NT, LINUX, MINIX, XOS, !AMIGA, ATARI, symlink, SGI, DEC, Cray, Convex, Amdahl, Sun, PC

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: mac/macstat.h zip.c zip.doc
# Wrapped by kent@sparky on Sun Aug 23 01:00:44 1992


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 4 (of 11)."'
if test -f 'mac/macstat.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mac/macstat.h'\"
else
echo shar: Extracting \"'mac/macstat.h'\" \(974 characters\)
sed "s/^X//" >'mac/macstat.h' <<'END_OF_FILE'
X/*****************************************************************
X *
X * stat.h
X *
X *****************************************************************/
X
X#include <time.h>
Xextern int macstat(char *path, struct stat *buf, short nVRefNum, long lDirID );
Xtypedef long dev_t;
Xtypedef long ino_t;
Xtypedef long off_t;
X
Xstruct stat {
X dev_t st_dev;
X ino_t st_ino;
X unsigned short st_mode;
X short st_nlink;
X short st_uid;
X short st_gid;
X dev_t st_rdev;
X off_t st_size;
X time_t st_atime, st_mtime, st_ctime;
X long st_blksize;
X long st_blocks;
X};
X
X#define S_IFMT 0xF000
X#define S_IFIFO 0x1000
X#define S_IFCHR 0x2000
X#define S_IFDIR 0x4000
X#define S_IFBLK 0x6000
X#define S_IFREG 0x8000
X#define S_IFLNK 0xA000
X#define S_IFSOCK 0xC000
X#define S_ISUID 0x800
X#define S_ISGID 0x400
X#define S_ISVTX 0x200
X#define S_IREAD 0x100
X#define S_IWRITE 0x80
X#define S_IEXEC 0x40
END_OF_FILE
if test 974 -ne `wc -c <'mac/macstat.h'`; then
echo shar: \"'mac/macstat.h'\" unpacked with wrong size!
fi
# end of 'mac/macstat.h'
fi
if test -f 'zip.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'zip.c'\"
else
echo shar: Extracting \"'zip.c'\" \(32880 characters\)
sed "s/^X//" >'zip.c' <<'END_OF_FILE'


X/*
X
X Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly,
X Kai Uwe Rommel and Igor Mandrichenko.
X Permission is granted to any individual or institution to use, copy, or
X redistribute this software so long as all of the original files are included
X unmodified, that it is not sold for profit, and that this copyright notice
X is retained.
X
X*/
X
X/*

X * zip.c by Mark Adler.
X */
X
X#include "revision.h"
X#include "zip.h"
X#ifdef VMS
X# include "VMSmunch.h"
X# define echon() echo(1)
X#endif
X#include <signal.h>
X
X#ifdef MACOS
X# include <console.h>
X#endif
X
X#define PWLEN 80 /* Input buffer size for reading encryption key */
X#define MAXCOM 256 /* Maximum one-line comment size */
X
X
X/* Local option flags */
X#define DELETE 0
X#define ADD 1
X#define UPDATE 2
X#define FRESHEN 3
Xlocal int action = ADD; /* one of ADD, UPDATE, FRESHEN, or DELETE */
Xlocal int comadd = 0; /* 1=add comments for new files */
Xlocal int zipedit = 0; /* 1=edit zip comment and all file comments */
Xlocal int dispose = 0; /* 1=remove files after put in zip file */
Xlocal int latest = 0; /* 1=set zip file time to time of latest file */
Xlocal ulg before = 0; /* 0=ignore, else exclude files before this time */
X
X
X/* Temporary zip file name and file pointer */
Xlocal char *tempzip;
Xlocal FILE *tempzf;
X


X
X/* Local functions */
X#ifdef PROTO

X local void freeup(void);
X local void leave(int);
X local void handler(int);
X local void license(void);
X local void help(void);
X local void zipstdout(void);
X void main(int, char **);
X local int count_args(char *s);
X local void envargs(int *Pargc, char ***Pargv, char *envstr);


X#endif /* PROTO */
X
X

X
Xlocal void freeup()
X/* Free all allocations in the found list and the zfiles list */
X{


X struct flist far *f; /* steps through found list */

X struct zlist far *z; /* pointer to next entry in zfiles list */
X
X for (f = found; f != NULL; f = fexpel(f))
X ;
X while (zfiles != NULL)
X {
X z = zfiles->nxt;
X free((voidp *)(zfiles->name));
X free((voidp *)(zfiles->zname));
X if (zfiles->ext)
X free((voidp *)(zfiles->extra));
X if (zfiles->cext && zfiles->cextra != zfiles->extra)
X free((voidp *)(zfiles->cextra));
X if (zfiles->com)
X free((voidp *)(zfiles->comment));
X farfree((voidp far *)zfiles);
X zfiles = z;
X zcount--;
X }
X}
X
X
Xlocal void leave(e)
Xint e; /* exit code */
X/* Process -o and -m options (if specified), free up malloc'ed stuff, and
X exit with the code e. */
X{
X int r; /* return value from trash() */
X ulg t; /* latest time in zip file */
X struct zlist far *z; /* pointer into zfile list */
X
X /* If latest, set time to zip file to latest file in zip file */
X if (latest && strcmp(zipfile, "-"))
X {
X diag("changing time of zip file to time of latest file in it");
X /* find latest time in zip file */
X if (zfiles == NULL)
X warn("zip file is empty, can't make it as old as latest entry", "");
X else {
X t = zfiles->tim;
X for (z = zfiles->nxt; z != NULL; z = z->nxt)
X if (t < z->tim)
X t = z->tim;
X /* set modified time of zip file to that time */
X stamp(zipfile, t);
X }


X }
X if (tempath != NULL)
X {

X free((voidp *)tempath);
X tempath = NULL;
X }
X if (zipfile != NULL)
X {
X free((voidp *)zipfile);
X zipfile = NULL;
X }
X
X
X /* If dispose, delete all files in the zfiles list that are marked */
X if (dispose)
X {
X diag("deleting files that were added to zip file");
X if ((r = trash()) != ZE_OK)
X err(r, "was deleting moved files and directories");
X }
X
X
X /* Done! */
X freeup();
X#ifdef VMS
X exit(0);
X#else /* !VMS */
X exit(e);


X#endif /* ?VMS */
X}
X

X
Xvoid err(c, h)
Xint c; /* error code from the ZE_ class */
Xchar *h; /* message about how it happened */
X/* Issue a message for the error, clean up files and memory, and exit. */
X{
X static int error_level;
X if (error_level++ > 0) exit(0); /* avoid recursive err() */
X
X if (PERR(c))
X perror("zip error");
X fprintf(stderr, "zip error: %s (%s)\n", errors[c-1], h);
X if (tempzip != NULL)
X {
X if (tempzip != zipfile) {
X if (tempzf != NULL)
X fclose(tempzf);
X#ifndef DEBUG
X destroy(tempzip);
X#endif
X free((voidp *)tempzip);
X } else {
X /* -g option, attempt to restore the old file */
X int k = 0; /* keep count for end header */
X ulg cb = cenbeg; /* get start of central */
X struct zlist far *z; /* steps through zfiles linked list */
X
X fprintf(stderr, "attempting to restore %s to its previous state\n",
X zipfile);
X fseek(tempzf, cenbeg, SEEK_SET);
X tempzn = cenbeg;


X for (z = zfiles; z != NULL; z = z->nxt)

X {
X putcentral(z, tempzf);
X tempzn += 4 + CENHEAD + z->nam + z->cext + z->com;
X k++;
X }
X putend(k, tempzn - cb, cb, zcomlen, zcomment, tempzf);
X tempzf = NULL;
X fclose(tempzf);
X }
X }
X if (key != NULL)
X free((voidp *)key);


X if (tempath != NULL)

X free((voidp *)tempath);
X if (zipfile != NULL)
X free((voidp *)zipfile);
X freeup();
X#ifdef VMS
X c = 0;
X#endif
X exit(c);
X}
X
X
Xvoid error(h)
X char *h;
X/* Internal error, should never happen */
X{
X err(ZE_LOGIC, h);
X}
X
Xlocal void handler(s)
Xint s; /* signal number (ignored) */
X/* Upon getting a user interrupt, turn echo back on for tty and abort
X cleanly using err(). */
X{
X#ifndef MSDOS
X# ifdef CRYPT
X echon();
X# endif


X putc('\n', stderr);

X#endif /* !MSDOS */
X err(ZE_ABORT, "aborting");
X s++; /* keep some compilers happy */
X}
X
X
Xvoid warn(a, b)
Xchar *a, *b; /* message strings juxtaposed in output */
X/* Print a warning message to stderr and return. */
X{
X fprintf(stderr, "zip warning: %s%s\n", a, b);
X}
X
X
Xlocal void license()
X/* Print license information to stdout. */
X{
X extent i; /* counter for copyright array */
X
X for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
X printf(copyright[i], "zip");
X putchar('\n');
X }
X for (i = 0; i < sizeof(disclaimer)/sizeof(char *); i++)
X puts(disclaimer[i]);
X}
X
X
Xlocal void help()
X/* Print help (along with license info) to stdout. */
X{
X extent i; /* counter for help array */
X
X /* help array */
X static char *text[] = {
X"",
X"Zip %d.%d (%s). Usage:",
X"zip [-options] [-b path] [-t mmddyy] [-n suffixes] [zipfile list] [-x list]",
X" The default action is to add or replace zipfile entries from list, which",
X" can include the special name - to compress standard input.",
X" If zipfile and list are ommitted, zip compresses stdin to stdout.",
X" -f freshen: only changed files -u update: only changed or new files",
X" -d delete entries in zipfile -m move into zipfile (delete files)",
X" -k simulate PKZIP made zipfile -g allow growing existing zipfile",
X" -h show this help -L show software license",
X" -r recurse into directories -j junk (don't record) directory names",
X" -0 store only -l translate end-of-line",
X" -1 compress faster -9 compress better",
X" -q quiet operation -n don't compress these suffixes",
X" -c add one-line comments -z add zipfile comment",
X" -b use \"path\" for temp files -t only do files after \"mmddyy\"",
X" -@ read names from stdin -o make zipfile as old as latest entry",
X#ifdef CRYPT
X" -e encrypt (-ee verify key)",
X#endif
X#ifdef VMS
X" -w append the VMS version number to the name stored in the zip file",
X" -V save VMS file attributes",


X#endif /* VMS */
X#ifdef OS2

X" -E use the .LONGNAME Extended attribute (if found) as filename",
X#endif /* OS2 */
X#ifdef S_IFLNK
X" -y store symbolic links as the link instead of the referenced file",
X#endif /* !S_IFLNK */
X" -x exclude the names that follow from those operated on"
X };
X
X for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
X {
X printf(copyright[i], "zip");
X putchar('\n');
X }
X for (i = 0; i < sizeof(text)/sizeof(char *); i++)
X {
X printf(text[i], REVISION / 10, REVISION % 10, REVDATE);
X putchar('\n');
X }
X}
X
X
X/* Do command line expansion for MSDOS and VMS */
X#if defined(MSVMS) && !defined(__GO32__)
X# define PROCNAME(n) (action==ADD||action==UPDATE?wild(n):procname(n))
X#else /* !MSVMS */
X# define PROCNAME(n) procname(n)


X#endif /* ?MSVMS */
X

Xlocal void zipstdout()
X/* setup for writing zip file on stdout */
X{
X int r;
X mesg = stderr;
X if (isatty(1))
X err(ZE_PARMS, "no zip file provided");
X if ((zipfile = malloc(4)) == NULL)
X err(ZE_MEM, "was processing arguments");
X strcpy(zipfile, "-");
X if ((r = readzipfile()) != ZE_OK)
X err(r, zipfile);
X}
X
X
Xvoid main(argc, argv)
Xint argc; /* number of tokens in command line */
Xchar **argv; /* command line tokens */
X/* Add, update, freshen, or delete zip entries in a zip file. See the
X command help in help() above. */
X{
X int a; /* attributes of zip file */
X ulg c; /* start of central directory */
X int d; /* true if just adding to a zip file */
X char *e; /* malloc'd comment buffer */
X struct flist far *f; /* steps through found linked list */
X int i; /* arg counter, root directory flag */
X int k; /* next argument type, marked counter,
X comment size, entry count */
X ulg n; /* total of entry len's */
X int o; /* true if there were any ZE_OPEN errors */
X char *p; /* steps through option arguments */
X char *pp; /* temporary pointer */
X int r; /* temporary variable */
X ulg t; /* file time, length of central directory */
X struct zlist far *v; /* temporary variable */
X struct zlist far * far *w; /* pointer to last link in zfiles list */
X FILE *x, *y; /* input and output zip files */
X struct zlist far *z; /* steps through zfiles linked list */
X char *zipbuf; /* stdio buffer for the zip file */
X
X mesg = (FILE *) stdout; /* cannot be made at link time for VMS */
X init_upper(); /* build case map table */
X
X#ifdef MACOS
X argc = ccommand(&argv);
X#endif
X
X /* Process arguments */
X diag("processing arguments");
X if (argc == 1 && isatty(1))
X {
X help();
X exit(0);
X }
X envargs(&argc, &argv, "ZIPOPT"); /* get options from environment */
X
X zipfile = tempzip = NULL;
X tempzf = NULL;
X d = 0; /* disallow adding to a zip file */
X signal(SIGINT, handler);
X signal(SIGTERM, handler);
X k = 0; /* Next non-option argument type */
X for (i = 1; i < argc; i++)
X {
X if (argv[i][0] == '-')
X if (argv[i][1])
X for (p = argv[i]+1; *p; p++)
X switch(*p)
X {
X case '0':
X method = STORE; level = 0; break;
X case '1': case '2': case '3': case '4':
X case '5': case '6': case '7': case '8': case '9':
X /* Set the compression efficacy */
X level = *p - '0'; break;
X case 'b': /* Specify path for temporary file */
X if (k != 0)
X err(ZE_PARMS, "use -b before zip file name");
X else
X k = 1; /* Next non-option is path */
X break;
X case 'c': /* Add comments for new files in zip file */
X comadd = 1; break;
X case 'd': /* Delete files from zip file */
X if (action != ADD)
X err(ZE_PARMS, "specify just one action");
X action = DELETE;
X break;
X#ifdef CRYPT
X case 'e': /* Encrypt */
X e = key == NULL ? (char *)NULL : key;
X if ((key = malloc(PWLEN+1)) == NULL)
X err(ZE_MEM, "was getting encryption password");
X if (getp(e == NULL ? "Enter password: " : "Verify password: ",
X key, PWLEN+1) == NULL)
X err(ZE_PARMS, "stderr is not a tty");
X if (e != NULL)
X {
X r = strcmp(key, e);
X free((voidp *)e);
X if (r)
X err(ZE_PARMS, "password not verified");
X }
X latest = 1; /* to make breaking the code harder */
X break;
X#endif /* CRYPT */
X case 'f': /* Freshen zip file--overwrite only */
X if (action != ADD)
X err(ZE_PARMS, "specify just one action");
X action = FRESHEN;
X break;
X case 'g': /* Allow appending to a zip file */
X d = 1; break;
X case 'h': case 'H': case '?': /* Help */
X help();
X leave(ZE_OK);
X case 'j': /* Junk directory names */
X pathput = 0; break;
X case 'k': /* Make entries using DOS names (k for Katz) */
X dosify = 1; break;
X case 'l': /* Translate end-of-line */
X translate_eol = 1; break;
X case 'L': /* Show license, version */
X license();
X leave(ZE_OK);
X case 'm': /* Delete files added or updated in zip file */
X dispose = 1; break;
X case 'n': /* Don't compress files with a special suffix */
X special = NULL;
X break;
X case 'o': /* Set zip file time to time of latest file in it */
X latest = 1; break;
X case 'p': /* Store path with name */
X break; /* (do nothing as annoyance avoidance) */
X case 'q': /* Quiet operation */
X noisy = 0; break;
X case 'r': /* Recurse into subdirectories */
X recurse = 1; break;
X case 't': /* Exclude files earlier than specified date */
X if (before)
X err(ZE_PARMS, "can only have one -t");
X k = 2; break;
X case 'u': /* Update zip file--overwrite only if newer */
X if (action != ADD)
X err(ZE_PARMS, "specify just one action");
X action = UPDATE;
X break;
X case 'v': /* Mention oddities in zip file structure */
X verbose++;
X break;
X#ifdef VMS
X case 'w': /* Append the VMS version number */
X vmsver = 1; break;
X case 'V': /* Store in VMS format */
X vms_native = 1; break;
X#endif /* VMS */
X case 'x': /* Exclude following files */
X if (k != 4 &&
X (k != 3 || (action != UPDATE && action != FRESHEN)))
X err(ZE_PARMS, "nothing to exclude (-x) from");
X if (k == 3) /* must be -u or -f */


X for (z = zfiles; z != NULL; z = z->nxt)

X z->mark = 1; /* mark all of them */
X k = 5;
X if ((r = exclude()) != ZE_OK)
X if (r == ZE_PARMS)
X err(r, "cannot repeat names in zip file");
X else
X err(r, "was processing list of files");
X break;
X#ifdef S_IFLNK
X case 'y': /* Store symbolic links as such */
X linkput = 1; break;
X#endif /* S_IFLNK */
X case 'z': /* Edit zip file comment */
X zipedit = 1; break;
X case '@': /* read file names from stdin */
X while ((pp = getnam(errbuf)) != NULL)
X {
X if ((r = PROCNAME(pp)) != ZE_OK)
X if (r == ZE_MISS)
X warn("name not matched: ", pp);
X else
X err(r, pp);
X }
X break;
X#ifdef OS2
X case 'E':
X /* use the .LONGNAME EA (if any) as the file's name. */
X use_longname_ea = 1;
X break;
X#endif
X default:
X {
X sprintf(errbuf, "no such option: %c", *p);
X err(ZE_PARMS, errbuf);
X }
X }
X else /* just a dash */
X switch (k)
X {
X case 0:
X zipstdout();
X k = 3;
X break;
X case 1:
X err(ZE_PARMS, "invalid path");
X break;
X case 2:
X err(ZE_PARMS, "invalid time");
X break;
X case 3: case 4: case 5:
X if ((r = PROCNAME(argv[i])) != ZE_OK)
X if (r == ZE_MISS)
X warn("name not matched: ", argv[i]);
X else
X err(r, argv[i]);
X if (k == 3)
X k = 4;
X }
X else /* not an option */
X {
X if (special == NULL)
X special = argv[i];
X else
X switch (k)
X {
X case 0:
X if ((zipfile = ziptyp(argv[i])) == NULL)
X err(ZE_MEM, "was processing arguments");
X if ((r = readzipfile()) != ZE_OK)
X err(r, zipfile);
X k = 3;
X break;
X case 1:
X if ((tempath = malloc(strlen(argv[i]) + 1)) == NULL)
X err(ZE_MEM, "was processing arguments");
X strcpy(tempath, argv[i]);
X k = 0;
X break;
X case 2:
X {
X int yy, mm, dd; /* results of sscanf() */
X
X if (sscanf(argv[i], "%2d%2d%2d", &mm, &dd, &yy) != 3 ||
X mm < 1 || mm > 12 || dd < 1 || dd > 31)
X err(ZE_PARMS, "invalid date entered for -t option");
X before = dostime(yy + (yy < 80 ? 2000 : 1900), mm, dd, 0, 0, 0);
X k = 0;
X break;
X }
X case 3: case 4: case 5:
X if ((r = PROCNAME(argv[i])) != ZE_OK)
X if (r == ZE_MISS)
X warn("name not matched: ", argv[i]);
X else
X err(r, argv[i]);
X if (k == 3)
X k = 4;
X }
X }
X }
X if (k < 3) { /* zip used as filter */
X zipstdout();
X if ((r = procname("-")) != ZE_OK)
X if (r == ZE_MISS)
X warn("name not matched: ", "-");
X else
X err(r, "-");
X k = 4;
X }
X
X if (k != 5) /* Clean up selections */
X {
X if (k == 3 && (action == UPDATE || action == FRESHEN))


X for (z = zfiles; z != NULL; z = z->nxt)

X z->mark = 1; /* if -u or -f with no args, do all */
X if ((r = exclude()) != ZE_OK) /* remove duplicates in found list */
X if (r == ZE_PARMS)
X err(r, "cannot repeat names in zip file");
X else
X err(r, "was processing list of files");
X }
X if (zcount)
X free((voidp *)zsort);
X
X /* Check option combinations */
X if (action == DELETE && (method != BEST || dispose || recurse ||
X key != NULL || comadd || zipedit))
X err(ZE_PARMS, "invalid option(s) used with -d");
X if (linkput && dosify)
X err(ZE_PARMS, "can't use -y with -k");
X if ((action != ADD || d) && !strcmp(zipfile, "-"))
X err(ZE_PARMS, "can't use -d,-f,-u or -g on standard output");
X#ifdef VMS
X if (vms_native && translate_eol)
X err(ZE_PARMS, "can't use -V with -l");
X#endif
X if (zcount == 0 && (action != ADD || d))
X warn(zipfile, " not found or empty");
X
X
X /* If -b not specified, make temporary path the same as the zip file */
X#ifdef MSDOS
X if (tempath == NULL && ((p = strrchr(zipfile, '/')) != NULL ||
X (p = strrchr(zipfile, '\\')) != NULL ||
X (p = strrchr(zipfile, ':')) != NULL))
X {
X if (*p == ':')
X p++;
X#else /* !MSDOS */
X if (tempath == NULL && (p = strrchr(zipfile, '/')) != NULL)
X {
X#endif /* ?MSDOS */
X if ((tempath = malloc((int)(p - zipfile) + 1)) == NULL)
X err(ZE_MEM, "was processing arguments");
X r = *p; *p = 0;
X strcpy(tempath, zipfile);
X *p = (char)r;
X }
X
X /* For each marked entry, if not deleting, check if it exists, and if
X updating or freshening, compare date with entry in old zip file.
X Unmark if it doesn't exist or is too old, else update marked count. */
X diag("stating marked entries");
X k = 0; /* Initialize marked count */


X for (z = zfiles; z != NULL; z = z->nxt)

X if (z->mark)
X if (action != DELETE &&
X ((t = filetime(z->name, (ulg *)NULL, (long *)NULL)) == 0 ||
X t < before ||
X ((action == UPDATE || action == FRESHEN) && t <= z->tim)))


X {
X z->mark = 0;

X z->trash = t && t >= before; /* delete if -um or -fm */
X if (verbose)
X fprintf(mesg, "zip diagnostic: %s %s\n", z->name,
X z->trash ? "up to date" : "missing or early");
X }
X else
X k++;
X
X
X /* Remove entries from found list that do not exist or are too old */
X diag("stating new entries");


X for (f = found; f != NULL;)

X if (action == DELETE || action == FRESHEN ||
X (t = filetime(f->name, (ulg *)NULL, (long *)NULL)) == 0 ||
X t < before || (namecmp(f->name, zipfile) == 0 && strcmp(zipfile, "-")))
X f = fexpel(f);


X else
X f = f->nxt;
X

X /* Make sure there's something left to do */
X if (k == 0 && found == NULL && !(zfiles != NULL && (latest || zipedit)))
X if (action == UPDATE || action == FRESHEN)
X leave(ZE_OK);
X else if (zfiles == NULL && latest)
X err(ZE_NAME, zipfile);
X else
X err(ZE_NONE, zipfile);
X d = (d && k == 0 && (zipbeg || zfiles != NULL)); /* d true if appending */
X
X
X /* Before we get carried away, make sure zip file is writeable */
X if (strcmp(zipfile, "-"))
X {
X x = zfiles == NULL && zipbeg == 0 ? fopen(zipfile, FOPW) :
X fopen(zipfile, FOPM);
X /* Note: FOPW and FOPM expand to several parameters for VMS */
X if (x == NULL)
X err(ZE_CREAT, zipfile);
X fclose(x);
X a = getfileattr(zipfile);
X if (zfiles == NULL && zipbeg == 0)
X destroy(zipfile);
X }
X else
X a = 0;
X
X
X /* Open zip file and temporary output file */
X diag("opening zip file and creating temporary zip file");
X x = NULL;
X tempzn = 0;
X if (strcmp(zipfile, "-") == 0)
X {
X#ifdef MSDOS
X /* Set stdout mode to binary for MSDOS systems */
X setmode(fileno(stdout), O_BINARY);
X tempzf = y = fdopen(fileno(stdout), FOPW);
X#else
X tempzf = y = stdout;
X#endif
X tempzip = "-";
X }
X else if (d) /* d true if just appending (-g) */
X {
X if ((y = fopen(zipfile, FOPM)) == NULL)
X err(ZE_NAME, zipfile);
X tempzip = zipfile;
X tempzf = y;
X if (fseek(y, cenbeg, SEEK_SET))
X err(ferror(y) ? ZE_READ : ZE_EOF, zipfile);
X tempzn = cenbeg;
X }
X else
X {
X if ((zfiles != NULL || zipbeg) && (x = fopen(zipfile, FOPR_EX)) == NULL)
X err(ZE_NAME, zipfile);
X if ((tempzip = tempname(zipfile)) == NULL)
X err(ZE_MEM, tempzip);
X if ((tempzf = y = fopen(tempzip, FOPW)) == NULL)
X err(ZE_TEMP, tempzip);
X if (zipbeg && (r = fcopy(x, y, zipbeg)) != ZE_OK)
X err(r, r == ZE_TEMP ? tempzip : zipfile);
X tempzn = zipbeg;
X }
X#ifndef VMS
X /* Use large buffer to speed up stdio: */
X zipbuf = (char *)malloc(ZBSZ);
X if (zipbuf == NULL)
X err(ZE_MEM, tempzip);
X# ifdef _IOFBF
X setvbuf(y, zipbuf, _IOFBF, ZBSZ);
X# else
X setbuf(y, zipbuf);
X# endif /* _IOBUF */
X#endif /* VMS */
X o = 0; /* no ZE_OPEN errors yet */
X
X
X /* Process zip file, updating marked files */
X if (zfiles != NULL)
X diag("going through old zip file");
X w = &zfiles;
X while ((z = *w) != NULL)
X if (z->mark)
X {
X /* if not deleting, zip it up */
X if (action != DELETE)
X {
X if (noisy)
X {
X fprintf(mesg, "updating %s", z->zname);
X fflush(mesg);
X }
X if ((r = zipup(z, y)) != ZE_OK && r != ZE_OPEN)
X {
X if (noisy)
X {
X putc('\n', mesg);
X fflush(mesg);
X }
X sprintf(errbuf, "was zipping %s", z->name);
X err(r, errbuf);
X }
X if (r == ZE_OPEN)
X {
X o = 1;
X if (noisy)
X {
X putc('\n', mesg);
X fflush(mesg);
X }
X perror("zip warning");
X warn("could not open for reading: ", z->name);
X warn("will just copy entry over: ", z->zname);
X if ((r = zipcopy(z, x, y)) != ZE_OK)
X {
X sprintf(errbuf, "was copying %s", z->zname);
X err(r, errbuf);


X }
X z->mark = 0;
X }

X w = &z->nxt;
X }
X else
X {
X if (noisy)
X {
X fprintf(mesg, "deleting %s\n", z->zname);
X fflush(mesg);
X }
X v = z->nxt; /* delete entry from list */


X free((voidp *)(z->name));
X free((voidp *)(z->zname));

X if (z->ext)
X free((voidp *)(z->extra));
X if (z->cext && z->cextra != z->extra)
X free((voidp *)(z->cextra));
X if (z->com)
X free((voidp *)(z->comment));
X farfree((voidp far *)z);
X *w = v;
X zcount--;
X }
X }
X else
X {
X /* copy the original entry verbatim */
X if (!d && (r = zipcopy(z, x, y)) != ZE_OK)
X {
X sprintf(errbuf, "was copying %s", z->zname);
X err(r, errbuf);
X }
X w = &z->nxt;
X }
X
X
X /* Process the edited found list, adding them to the zip file */
X diag("zipping up new entries, if any");
X for (f = found; f != NULL; f = fexpel(f))
X {
X /* add a new zfiles entry and set the name */
X if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL)
X err(ZE_MEM, "was adding files to zip file");
X z->nxt = NULL;
X z->name = f->name;
X f->name = NULL;
X z->zname = f->zname;
X f->zname = NULL;
X z->ext = z->cext = z->com = 0;


X z->mark = 1;

X z->dosflag = f->dosflag;
X /* zip it up */
X if (noisy)
X {
X fprintf(mesg, "adding %s", z->zname);
X fflush(mesg);
X }
X if ((r = zipup(z, y)) != ZE_OK && r != ZE_OPEN)
X {
X if (noisy)
X {
X putc('\n', mesg);
X fflush(mesg);
X }
X sprintf(errbuf, "was zipping %s", z->name);
X err(r, errbuf);
X }
X if (r == ZE_OPEN)
X {
X o = 1;
X if (noisy)
X {
X putc('\n', mesg);
X fflush(mesg);
X }
X perror("zip warning");
X warn("could not open for reading: ", z->name);


X free((voidp *)(z->name));
X free((voidp *)(z->zname));

X farfree((voidp far *)z);
X }
X else
X {
X *w = z;
X w = &z->nxt;
X zcount++;
X }
X }
X if (key != NULL)
X {
X free((voidp *)key);
X key = NULL;
X }
X
X
X /* Get one line comment for each new entry */
X if (comadd)
X {
X if ((e = malloc(MAXCOM + 1)) == NULL)
X err(ZE_MEM, "was reading comment lines");


X for (z = zfiles; z != NULL; z = z->nxt)

X if (z->mark)
X {
X if (noisy)
X fprintf(mesg, "Enter comment for %s:\n", z->name);
X /* ??? reopen /dev/tty if one file was zipped from stdin
X * or if file names were read from stdin.
X */
X if (fgets(e, MAXCOM+1, stdin) != NULL)
X {
X if ((p = malloc((k = strlen(e))+1)) == NULL)
X {
X free((voidp *)e);
X err(ZE_MEM, "was reading comment lines");
X }
X strcpy(p, e);
X if (p[k-1] == '\n')
X p[--k] = 0;
X z->comment = p;
X z->com = k;
X }
X }
X free((voidp *)e);
X }
X
X /* Get multi-line comment for the zip file */
X if (zipedit)
X {
X if ((e = malloc(MAXCOM + 1)) == NULL)
X err(ZE_MEM, "was reading comment lines");
X if (noisy && zcomlen)
X {
X fputs("current zip file comment is:\n", mesg);
X fwrite(zcomment, 1, zcomlen, mesg);
X if (zcomment[zcomlen-1] != '\n')
X putc('\n', mesg);
X free((voidp *)zcomment);
X }
X zcomment = malloc(1);
X *zcomment = 0;
X if (noisy)
X fputs("enter new zip file comment (end with .):\n", mesg);
X /* ??? reopen /dev/tty if one file was zipped from stdin
X * or if file names were read from stdin.
X */
X while (fgets(e, MAXCOM+1, stdin) != NULL && strcmp(e, ".\n"))
X {
X if (e[(r = strlen(e)) - 1] == '\n')
X e[--r] = 0;
X if ((p = malloc((*zcomment ? strlen(zcomment) + 3 : 1) + r)) == NULL)
X {
X free((voidp *)e);
X err(ZE_MEM, "was reading comment lines");
X }
X if (*zcomment)
X strcat(strcat(strcpy(p, zcomment), "\r\n"), e);
X else
X strcpy(p, *e ? e : "\r\n");
X free((voidp *)zcomment);
X zcomment = p;
X }
X zcomlen = strlen(zcomment);
X free((voidp *)e);
X }
X
X
X /* Write central directory and end header to temporary zip */
X diag("writing central directory");
X k = 0; /* keep count for end header */
X c = tempzn; /* get start of central */
X n = t = 0;


X for (z = zfiles; z != NULL; z = z->nxt)

X {
X if ((r = putcentral(z, y)) != ZE_OK)
X err(r, tempzip);
X tempzn += 4 + CENHEAD + z->nam + z->cext + z->com;
X n += z->len;
X t += z->siz;
X k++;
X }
X if (k == 0)
X warn("zip file empty", "");
X if (verbose)
X fprintf(mesg, "total bytes=%lu, compressed=%lu -> %d%% savings\n",
X n, t, percent(n, t));
X t = tempzn - c; /* compute length of central */
X diag("writing end of central directory");
X if ((r = putend(k, t, c, zcomlen, zcomment, y)) != ZE_OK)
X err(r, tempzip);
X tempzf = NULL;
X if (fclose(y))
X err(d ? ZE_WRITE : ZE_TEMP, tempzip);
X if (x != NULL)
X fclose(x);
X
X
X /* Replace old zip file with new zip file, leaving only the new one */
X if (strcmp(zipfile, "-") && !d)
X {
X diag("replacing old zip file with new zip file");
X if ((r = replace(zipfile, tempzip)) != ZE_OK)
X {
X warn("new zip file left as: ", tempzip);
X free((voidp *)tempzip);
X tempzip = NULL;
X err(r, "was replacing the original zip file");
X }
X free((voidp *)tempzip);
X }
X tempzip = NULL;
X if (strcmp(zipfile, "-")) {
X setfileattr(zipfile, a);
X#ifdef VMS
X /* If the zip file existed previously, restore its record format: */
X if (x != NULL)
X VMSmunch(zipfile, RESTORE_RTYPE, NULL);
X#endif
X }
X
X /* Finish up (process -o, -m, clean up). Exit code depends on o. */
X leave(o ? ZE_OPEN : ZE_OK);
X}
X
X/*****************************************************************
X | envargs - add default options from environment to command line
X |----------------------------------------------------------------
X | Author: Bill Davidsen, original 10/13/91, revised 23 Oct 1991.
X | This program is in the public domain.
X |----------------------------------------------------------------
X | Minor program notes:
X | 1. Yes, the indirection is a tad complex
X | 2. Parenthesis were added where not needed in some cases
X | to make the action of the code less obscure.
X ****************************************************************/
X
Xlocal void
Xenvargs(Pargc, Pargv, envstr)
Xint *Pargc;
Xchar ***Pargv;
Xchar *envstr;
X{
X char *getenv();
X char *envptr; /* value returned by getenv */
X char *bufptr; /* copy of env info */
X int argc = 0; /* internal arg count */
X int ch; /* spare temp value */
X char **argv; /* internal arg vector */
X char **argvect; /* copy of vector address */
X
X /* see if anything in the environment */
X envptr = getenv(envstr);
X if (envptr == NULL || *envptr == 0) return;
X
X /* count the args so we can allocate room for them */
X argc = count_args(envptr);
X bufptr = malloc(1+strlen(envptr));
X if (bufptr == NULL)
X err(ZE_MEM, "Can't get memory for arguments");
X
X strcpy(bufptr, envptr);
X
X /* allocate a vector large enough for all args */
X argv = (char **)malloc((argc+*Pargc+1)*sizeof(char *));
X if (argv == NULL)
X err(ZE_MEM, "Can't get memory for arguments");
X argvect = argv;
X
X /* copy the program name first, that's always true */
X *(argv++) = *((*Pargv)++);
X
X /* copy the environment args first, may be changed */
X do {
X *(argv++) = bufptr;
X /* skip the arg and any trailing blanks */
X while ((ch = *bufptr) != '\0' && ch != ' ') ++bufptr;
X if (ch == ' ') *(bufptr++) = '\0';
X while ((ch = *bufptr) != '\0' && ch == ' ') ++bufptr;
X } while (ch);
X
X /* now save old argc and copy in the old args */
X argc += *Pargc;
X while (--(*Pargc)) *(argv++) = *((*Pargv)++);
X
X /* finally, add a NULL after the last arg, like UNIX */
X *argv = NULL;
X
X /* save the values and return */
X *Pargv = argvect;
X *Pargc = argc;
X}
X
Xstatic int
Xcount_args(s)
Xchar *s;
X{


X int count = 0;

X int ch;
X
X do {
X /* count and skip args */
X ++count;
X while ((ch = *s) != '\0' && ch != ' ') ++s;
X while ((ch = *s) != '\0' && ch == ' ') ++s;
X } while (ch);
X
X return count;
X}
END_OF_FILE
if test 32880 -ne `wc -c <'zip.c'`; then
echo shar: \"'zip.c'\" unpacked with wrong size!
fi
# end of 'zip.c'
fi
if test -f 'zip.doc' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'zip.doc'\"
else
echo shar: Extracting \"'zip.doc'\" \(23559 characters\)
sed "s/^X//" >'zip.doc' <<'END_OF_FILE'
X
XZIP(1) USER COMMANDS ZIP(1)
X
XNAME
X zip, zipcloak, zipnote, zipsplit - package and compress
X (archive) files
X
XSYNOPSIS
X zip [ -cdeEfghjklmoqruwyz@ ] [ -b temppath ] [ -n suffixes ]
X [ -t mmddyy ] [ zipfile list ] [ -x list ]
X
X zipcloak [ -d ] [ -b path ] zipfile
X
X zipnote [ -w ] [ -b path ] zipfile
X
X zipsplit [ -ti ] [ -n size ] [ -b path ] zipfile
X
XDESCRIPTION
X zip is a compression and file packaging utility for Unix,
X VMS, MSDOS, OS/2, Windows NT, Minix, Atari and Macintosh.
X It is analogous to a combination of tar and compress and is
X compatible with PKZIP (Phil Katz ZIP) for MSDOS systems.
X
X There is a companion to zip called unzip (of course) which
X you should be able to find the same place you got zip. zip
X and unzip can work with files produced by PKZIP under MSDOS,
X and PKZIP and PKUNZIP can work with files produced by zip.
X
X zip version 1.9 is compatible with pkzip 1.93a. Note that
X pkunzip 1.10 cannot extract files produced by pkzip 1.93a or
X zip 1.9b. You must use pkunzip 1.93a or unzip 5.0 to extract
X them.
X
X For a brief help on zip and unzip, run each without specify-
X ing any parameters on the command line.
X
X zip puts one or more compressed files into a single "zip
X file" along with information about the files, including the
X name, path if requested, date and time last modified, pro-
X tection, and check information to verify the fidelity of
X each entry. zip can also be used as a filter, compressing
X standard input to standard output. zip can pack an entire
X directory structure in a zip file with a single command.
X Compression ratios of 2:1 to 3:1 are common for text files.
X zip has one compression method (deflation) and can also
X store files without compression. It automatically chooses
X the better of the two for each file to be compressed.
X
X zip is useful for packaging a set of files to send to some-
X one or for distribution; for archiving or backing up files;
X and for saving disk space by temporarily compressing unused
X files or directories.
X
XHOW TO USE ZIP
X The simplest use of zip is as follows:
X
X zip stuff *
X
X This will create the file "stuff.zip" (assuming it does not
X exist) and put all the files in the current directory in
X stuff.zip in a compressed form. The .zip suffix is added
X automatically, unless that file name given contains a dot
X already. This allows specifying suffixes other than ".zip".
X
X Because of the way the shell does filename substitution,
X files that start with a "." are not included. To include
X those as well, you can:
X
X zip stuff .* *
X
X Even this will not include any subdirectories that are in
X the current directory. To zip up an entire directory, the
X command:
X
X zip -r foo foo
X
X will create the file "foo.zip" containing all the files and
X directories in the directory "foo" that is in the current
X directory. (The first "foo" denotes the zip file, the second
X one denotes the directory.) The "r" option means recurse
X through the directory structure. In this case, all the
X files and directories in foo are zipped, including the ones
X that start with a ".", since the recursion does not use the
X shell's file-name substitution. You should not use -r with
X the name ".*", since that matches ".." which will attempt to
X zip up the parent directory--probably not what was intended.
X
X You may want to make a zip file that contains the files in
X foo, but not record the directory name, foo. You can use
X the -j (junk path) option to leave off the path:
X
X zip -j foo foo/*
X
X The -y option (only under Unix) will store symbolic links as
X such in the zip file, instead of compressing and storing the
X file referred to in the link.
X
X You might be zipping to save disk space, in which case you
X could:
X
X zip -rm foo foo
X
X where the "m" option means "move". This will delete foo and
X its contents after making foo.zip. No deletions will be
X done until the zip has completed with no errors. This
X option is obviously more dangerous and should be used with
X care.
X
X If the zip file already exists, these commands will replace
X existing or add new entries to the zip file. For example,
X if you were really short on disk space, you might not have
X enough room simultaneously to hold the directory foo and the
X compressed foo.zip. In this case, you could do it in steps.
X If foo contained the subdirectories tom, dick, and harry,
X then you could:
X
X zip -rm foo foo/tom
X zip -rm foo foo/dick
X zip -rm foo foo/harry
X
X where the first command would create foo.zip, and the next
X two would add to it. At the completion of each zip command,
X the directory just zipped would be deleted, making room in
X which the next zip command could work.
X
X zip will also accept a single dash ("-") as the zip file
X name, in which case it will write the zip file to stdout,
X allowing the output to be piped to another program. For
X example:
X
X zip -r - . | dd of=/dev/nrst0 obs=16k
X
X would write the zip output directly to a tape with the
X specified block size for the purpose of backing up the
X current directory.
X
X zip also accepts a single dash ("-") as the name of a file
X to be compressed, in which case it will read the zip file
X from stdin, allowing zip to take input from another program.
X For example:
X
X tar cf - . | zip backup -
X
X would compress the output of the tar command for the purpose
X of backing up the current directory. This generally produces
X better compression than the previous example using the -r
X option, because zip can take advantage of redundancy between
X files. The backup can be restored using the command
X
X unzip -p backup | tar xf -
X
X When no zip file name is given and stdout is not a terminal,
X zip acts as a filter, compressing standard input to standard
X output. For example,
X
X tar cf - . | zip | dd of=/dev/nrst0
X
X is equivalent to
X
X tar cf - . | zip - - | dd of=/dev/nrst0
X
X Zip archives created in this manner can be extracted with
X the program funzip which is provided in the unzip package.
X For example,
X
X dd if=/dev/nrst0 | funzip | tar xvf -
X
XMODIFYING EXISTING ZIP FILES
X When given the name of an existing zip file with the above
X commands, zip will replace identically named entries in the
X zip file or add entries for new names. For example, if
X foo.zip exists and contains foo/file1 and foo/file2, and the
X directory foo contains the files foo/file1 and foo/file3,
X then:
X
X zip -r foo foo
X
X will replace foo/file1 in foo.zip and add foo/file3 to
X foo.zip. After this, foo.zip contains foo/file1, foo/file2,
X and foo/file3, with foo/file2 unchanged from before.
X
X When changing an existing zip file, zip will write a tem-
X porary file with the new contents, and only replace the old
X one when the zip has completed with no errors. You can use
X the -b option to specify a different path (usually a dif-
X ferent device) to put the temporary file in. For example:
X
X zip -b /tmp stuff *
X
X will put the temporary zip file and the temporary compres-
X sion files in the directory "/tmp", copying over stuff.zip
X in the current directory when done.
X
X If you are only adding entries to a zip file, not replacing,
X and the -g option is given, then zip grows (appends to) the
X file instead of copying it. The danger of this is that if
X the operation fails, the original zip file is corrupted and
X lost.
X
X There are two other ways to change or add entries in a zip
X file that are restrictions of simple addition or replace-
X ment. The first is -u (update) which will add new entries
X to the zip file as before but will replace existing entries
X only if the modified date of the file is more recent than
X the date recorded for that name in the zip file. For exam-
X ple:
X
X zip -u stuff *
X
X will add any new files in the current directory, and update
X any changed files in the zip file stuff.zip. Note that zip
X will not try to pack stuff.zip into itself when you do this.
X zip will always exclude the zip file from the files on which
X to be operated.
X
X The second restriction is -f (freshen) which, like update,
X will only replace entries with newer files; unlike update,
X will not add files that are not already in the zip file.
X For this option, you may want to simply freshen all of the
X files that are in the specified zip file. To do this you
X would simply:
X
X zip -f foo
X
X Note that the -f option with no arguments freshens all the
X entries in the zip file. The same is true of -u, and hence
X "zip -u foo" and "zip -f foo" both do the same thing.
X
X This command should be run from the same directory from
X which the original zip command was run, since paths stored
X in zip files are always relative.
X
X Another restriction that can be used with adding, updating,
X or freshening is -t (time), which will not operate on files
X modified earlier than the specified date. For example:
X
X zip -rt 120791 infamy foo
X
X will add all the files in foo and its subdirectories that
X were last modified on December 7, 1991, or later to the zip
X file infamy.zip.
X
X Also, files can be explicitly excluded using the -x option:
X
X zip -r foo foo -x \*.o
X
X which will zip up the contents of foo into foo.zip but
X exclude all the files that end in ".o". Here the backslash
X causes zip to match file names that were found when foo was
X searched.
X
X The last operation is -d (delete) which will remove entries
X from a zip file. An example might be:
X
X zip -d foo foo/tom/junk foo/harry/\* \*.o
X
X which will remove the entry foo/tom/junk, all of the files
X that start with "foo/harry/", and all of the files that end
X with ".o" (in any path). Note that once again, the shell
X expansion has been inhibited with backslashes, so that zip
X can see the asterisks. zip can then match on the contents of
X the zip file instead of the contents of the current direc-
X tory.
X
X Under MSDOS, -d is case sensitive when it matches names in
X the zip file. This allows deleting names that were zipped
X on other systems, but requires that the names be entered in
X upper case if they were zipped on an MSDOS system, so that
X the names can be found in the zip file and deleted.
X
XMORE OPTIONS
X As mentioned before, zip will use the best of two methods:
X deflate or store.
X
X The option -0 will force zip to use store on all files. For
X example:
X
X zip -r0 foo foo
X
X will zip up the directory foo into foo.zip using only store.
X
X The speed of deflation can also be controlled with options
X -1 (fastest method but less compression) to -9 (best
X compression but slower). The default value is -5. For exam-
X ple:
X
X zip -r8 foo foo
X
X In nearly all cases, a file that is already compressed can-
X not be compressed further by zip, or if it can, the effect
X is minimal. The -n option prevents zip from trying to
X compress files that have the given suffixes. Such files are
X simply stored (0% compression) in the output zip file, so
X that zip doesn't waste its time trying to compress them.
X The suffixes are separated by either colons or semicolons.
X For example:
X
X zip -rn ".Z:.zip:.tiff:.gif:.snd" foo foo
X
X will put everything in foo into foo.zip, but will store any
X files that end in .Z, .zip, .tiff, .gif, or .snd without
X trying to compress them. (Image and sound files often have
X their own specialized compression methods.) The default suf-
X fix list is ".Z:.zip;.zoo:.arc:.lzh:.arj". The environment
X variable ZIPOPT can be used to change this default. For
X example under Unix with csh:
X
X setenv ZIPOPT "-n .gif:.zip"
X
X The variable ZIPOPT can be used for any option and can
X include several options.
X
X Under Unix and under OS/2 (if files from an HPFS are
X stored), zip will store the full path (relative to the
X current path) and name of the file (or just the name if -j
X is specified) in the zip file along with the Unix
X attributes, and it will mark the entry as made under Unix.
X If the zip file is intended for PKUNZIP under MSDOS, then
X the -k (Katz) option should be used to attempt to convert
X the names and paths to conform to MSDOS, store only the
X MSDOS attribute (just the user write attribute from Unix),
X and mark the entry as made under MSDOS (even though it
X wasn't).
X
X The -o (older) option will set the "last modified" time of
X the zip file to the latest "last modified" time of the
X entries in the zip file. This can be used without any other
X operations, if desired. For example:
X
X zip -o foo
X
X will change the last modified time of foo.zip to the latest
X time of the entries in foo.zip.
X
X The -e and -c options operate on all files updated or added
X to the zip file. Encryption (-e) will prompt for a password
X on the terminal and will not echo the password as it is
X typed (if stderr is not a TTY, zip will exit with an error).
X New zip entries will be encrypted using that password. For
X added peace of mind, you can use -ee, which will prompt for
X the password twice, checking that the two are the same
X before using it. The encryption code is distributed
X separately, so the -e option may not be available in your
X version.
X
X One-line comments can be added for each file with the -c
X option. The zip file operations (adding or updating) will
X be done first, and you will then be prompted for a one-line
X comment for each file. You can then enter the comment fol-
X lowed by return, or just return for no comment.
X
X The -z option will prompt you for a multi-line comment for
X the entire zip file. This option can be used by itself, or
X in combination with other options. The comment is ended by
X a line containing just a period, or an end of file condition
X (^D on Unix, ^Z on MSDOS, OS/2, and VAX/VMS). Since -z
X reads the lines from stdin, you can simply take the comment
X from a file:
X
X zip -z foo < foowhat
X
X The -q (quiet) option eliminates the informational messages
X and comment prompts while zip is operating. This might be
X used in shell scripts, for example, or if the zip operation
X is being performed as a background task ("zip -q foo *.c
X &").
X
X zip can take a list of file names to operate on from stdin
X using the -@ option. In Unix, this option can be used with
X the find command to extend greatly the functionality of zip.
X For example, to zip up all the C source files in the current
X directory and its subdirectories, you can:
X
X find . -type f -name "*.[ch]" -print | zip source -@
X
X Note that the pattern must be quoted to keep the shell from
X expanding it.
X
X Under VMS only, the -w option will append the version number
X of the files to the name and zip up multiple versions of
X files. Without -w, zip will only use the most recent ver-
X sion of the specified file(s).
X
X The -l option translates the Unix end-of-line character LF
X into the MSDOS convention CR LF. This option should not be
X used on binary files. This option can be used on Unix if
X the zip file is intended for PKUNZIP under MSDOS. If the
X input files already contain CR LF, this option adds an extra
X CR. This ensure that "unzip -a" on Unix will get back an
X exact copy of the original file, to undo the effect of "zip
X -l".
X
X If zip is run with the -h option, or with no arguments and
X standard output is a terminal, the license and the command-
X argument and option help is shown. The -L option just shows
X the license.
X
XABOUT PATTERN MATCHING
X (Note: this section applies to Unix. Watch this space for
X details on MSDOS and VMS operation.)
X
X The Unix shell (sh or csh) does filename substitution on
X command arguments. The special characters are ?, which
X matches any single character; * which matches any number of
X characters (including none); and [] which matches any char-
X acter in the range inside the brackets (like [a-f] or
X [0-9]). When these characters are encountered (and not
X escaped with a backslash or quotes), the shell will look for
X files relative to the current path that match the pattern,
X and replace the argument with a list of the names that
X matched.
X
X zip can do the same matching on names that are in the zip
X file being modified or, in the case of the -x (exclude)
X option, on the list of files to be operated on, by using
X backslashes or quotes to tell the shell not to do the name
X expansion. In general, when zip encounters a name in the
X list of files to do, it first looks for the name in the file
X system. If it finds it, it then adds it to the list of
X files to do. If it does not find it, it will look for the
X name in the zip file being modified (if it exists), using
X the pattern matching characters above, if any. For each
X match, it will add that name to the list of files to do.
X After -x (exclude), the names are removed from the to-do
X list instead of added.
X
X The pattern matching includes the path, and so patterns like
X \*.o match names that end in ".o", no matter what the path
X prefix is. Note that the backslash must precede every spe-
X cial character (i.e. ?*[]), or the entire argument must be
X enclosed in double quotes ("").
X
X In general, using backslash to make zip do the pattern
X matching is used with the -f (freshen) and -d (delete)
X options, and sometimes after the -x (exclude) option when
X used with any operation (add, -u, -f, or -d). zip will
X never use pattern matching to search the file system. If
X zip has recursed into a directory, all files (and all direc-
X tories) in there are fair game.
X
XCOPYRIGHT


X Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-

X loup Gailly, Kai Uwe Rommel and Igor Mandrichenko. Permis-
X sion is granted to any individual or institution to use,
X copy, or redistribute this software so long as all of the
X original files are included unmodified, that it is not sold
X for profit, and that this copyright notice is retained.
X
XACKNOWLEDGEMENTS
X Thanks to R. P. Byrne for his Shrink.Pas program which
X inspired this project; to Phil Katz for making the zip file
X format, compression format, and .zip filename extension all
X public domain; to Steve Burg and Phil Katz for help on
X unclear points of the deflate format; to Keith Petersen and
X Rich Wales for providing a mailing list and ftp site for the
X INFO-ZIP group to use; and most importantly, to the INFO-ZIP
X group itself (listed in the file infozip.who) without whose
X tireless testing and bug-fixing efforts a portable zip would
X not have been possible. Finally we should thank (blame) the
X INFO-ZIP moderator, David Kirschbaum for getting us into
X this mess in the first place.
X
XSEE ALSO
X unzip(1), tar(1), compress(1)
X
XBUGS
X WARNING: zip files produced by this version of zip must not
X be *updated* by zip 1.0 or pkzip 1.10 or pkzip 1.93a, if
X they contain encrypted members, or if they have been pro-
X duced in a pipe or on a non seekable device. The old ver-
X sions of zip or pkzip would destroy the zip structure. The
X old versions can list the contents of the zip file but can-
X not extract it anyway (because of the new compression algo-
X rithm). If you do not use encryption and use regular disk
X files, you do not have to care about this problem.
X
X zip 1.9 is compatible with pkzip 1.93a, except when two
X features are used: encryption or zip file created in a pipe
X or on a non seekable device. pkzip versions above 2.0 will
X support such files, and unzip 5.0 already supports them.
X
X Without -y, when zip must compress a symbolic link to an non
X existing file, it only displays a warning "name not
X matched". A better warnign should be given.
X
X Under VMS, not all of the odd file formats are treated prop-
X erly. Only zip files of format stream-LF and fixed length
X 512 are expected to work with zip. Others can be converted
X using Rahul Dhesi's BILF program. This version of zip does
X handle some of the conversion internally. When using Kermit
X to transfer zip files from Vax to MSDOS, type "set file type
X block" on the Vax. When transfering from MSDOS to Vax, type
X "set file type fixed" on the Vax. In both cases, type "set
X file type binary" on MSDOS.
X
X Under VMS, zip hangs for file specification that uses DECnet
X syntax (foo::*.*).
X
X Under OS/2, the amount of External Attributes displayed by
X DIR is (for compatibility) the amount returned by the 16-bit
X version of DosQueryPathInfo(). Otherwise OS/2 1.3 and 2.0
X would report different EA sizes when DIRing a file. How-
X ever, the structure layout returned by the 32-bit
X DosQueryPathInfo() is a bit different, it uses extra padding
X bytes and link pointers (it's a linked list) to have all
X fields on 4-byte boundaries for portability to future RISC
X OS/2 versions. Therefore the value reported by ZIP (which
X uses this 32-bit-mode size) differs from that reported by
X DIR. ZIP stores the 32-bit format for portability, even the
X 16-bit MS-C-compiled version running on OS/2 1.3, so even
X this one shows the 32-bit-mode size.
X
X LIKE ANYTHING ELSE THAT'S FREE, ZIP AND ITS ASSOCIATED UTIL-
X ITIES ARE PROVIDED AS IS AND COME WITH NO WARRANTY OF ANY
X KIND, EITHER EXPRESSED OR IMPLIED. IN NO EVENT WILL THE
X COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES RESULTING FROM
X THE USE OF THIS SOFTWARE.
X
X That having been said, please send any problems or comments
X via email to the Internet address zip-...@cs.ucla.edu. For
X bug reports, please include the version of zip, the make
X options you used to compile it, the machine and operating
X system you are using, and as much additional information as
X possible. Thank you for your support.
END_OF_FILE
if test 23559 -ne `wc -c <'zip.doc'`; then
echo shar: \"'zip.doc'\" unpacked with wrong size!
fi
# end of 'zip.doc'
fi
echo shar: End of archive 4 \(of 11\).
cp /dev/null ark4isdone

Info-ZIP group

unread,
Aug 23, 1992, 2:46:51 AM8/23/92
to
Submitted-by: zip-...@cs.ucla.edu (Info-ZIP group)
Posting-number: Volume 31, Issue 97
Archive-name: zip19/part05

Supersedes: zip: Volume 23, Issue 88-96
Environment: UNIX, VMS, OS/2, MS-DOS, MACINTOSH, WIN-NT, LINUX, MINIX, XOS, !AMIGA, ATARI, symlink, SGI, DEC, Cray, Convex, Amdahl, Sun, PC

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: deflate.c msdos/tcconfig.tc.UU os2/os2zip.c.UU
# Wrapped by kent@sparky on Sun Aug 23 01:00:44 1992


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 5 (of 11)."'
if test -f 'deflate.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'deflate.c'\"
else
echo shar: Extracting \"'deflate.c'\" \(26162 characters\)
sed "s/^X//" >'deflate.c' <<'END_OF_FILE'


X/*
X
X Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly,
X Kai Uwe Rommel and Igor Mandrichenko.
X Permission is granted to any individual or institution to use, copy, or
X redistribute this software so long as all of the original files are included
X unmodified, that it is not sold for profit, and that this copyright notice
X is retained.
X
X*/
X
X/*

X * deflate.c by Jean-loup Gailly.


X *
X * PURPOSE
X *

X * Identify new text as repetitions of old text within a fixed-
X * length sliding window trailing behind the new text.


X *
X * DISCUSSION
X *

X * The "deflation" process depends on being able to identify portions
X * of the input text which are identical to earlier input (within a
X * sliding window trailing behind the input currently being processed).
X *
X * The most straightforward technique turns out to be the fastest for
X * most input files: try all possible matches and select the longest.
X * The key feature is of this algorithm is that insertion and deletions
X * from the string dictionary are very simple and thus fast. Insertions
X * and deletions are performed at each input character, whereas string
X * matches are performed only when the previous match ends. So it is
X * preferable to spend more time in matches to allow very fast string
X * insertions and deletions. The matching algorithm for small strings
X * is inspired from that of Rabin & Karp. A brute force approach is
X * used to find longer strings when a small match has been found.
X * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
X * (by Leonid Broukhis).
X * A previous version of this file used a more sophisticated algorithm
X * (by Fiala and Greene) which is guaranteed to run in linear amortized
X * time, but has a larger average cost and uses more memory. However
X * the F&G algorithm may be faster for some highly redundant files if
X * the parameter max_chain_length (described below) is too large.
X *
X * ACKNOWLEDGEMENTS
X *
X * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
X * I found it in 'freeze' written by Leonid Broukhis.
X * Thanks to many info-zippers for bug reports and testing.


X *
X * REFERENCES
X *

X * APPNOTE.TXT documentation file in PKZIP 2.0 distribution.
X *
X * A description of the Rabin and Karp algorithm is given in the book
X * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
X *
X * Fiala,E.R., and Greene,D.H.
X * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595


X *
X * INTERFACE
X *

X * void lm_init (int pack_level, ush *flags)
X * Initialize the "longest match" routines for a new file
X *
X * ulg deflate (void)
X * Processes a new input file and return its compressed length. Sets
X * the compressed length, crc, deflate flags and internal file
X * attributes.


X */
X
X#include "zip.h"

X
X/* ===========================================================================
X * Configuration parameters
X */
X
X/* Compile with MEDIUM_MEM to reduce the memory requirements or


X * with SMALL_MEM to use as little memory as possible.

X * Warning: defining these symbols affects MATCH_BUFSIZE and HASH_BITS
X * (see below) and thus affects the compression ratio. The compressed output
X * is still correct, and might even be smaller in some cases.
X */
X
X#ifdef SMALL_MEM
X# define HASH_BITS 13 /* Number of bits used to hash strings */
X#else
X#ifdef MEDIUM_MEM
X# define HASH_BITS 14
X#else
X# define HASH_BITS 15
X /* For portability to 16 bit machines, do not use values above 15. */
X#endif
X#endif
X
X#define HASH_SIZE (unsigned)(1<<HASH_BITS)
X#define HASH_MASK (HASH_SIZE-1)
X#define WMASK (WSIZE-1)
X/* HASH_SIZE and WSIZE must be powers of two */
X
X#define NIL 0
X/* Tail of hash chains */
X
X#define FAST 4
X#define SLOW 2
X/* speed options for the general purpose bit flag */
X
X#ifndef TOO_FAR
X# define TOO_FAR 4096
X#endif
X/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
X
X/* ===========================================================================
X * Local data used by the "longest match" routines.
X */
X
Xtypedef ush Pos;
Xtypedef unsigned IPos;
X/* A Pos is an index in the character window. We use short instead of int to
X * save space in the various tables. IPos is used only for parameter passing.
X */
X
X#ifndef DYN_ALLOC
X uch far window[2L*WSIZE];
X /* Sliding window. Input bytes are read into the second half of the window,
X * and move to the first half later to keep a dictionary of at least WSIZE
X * bytes. With this organization, matches are limited to a distance of
X * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
X * performed with a length multiple of the block size. Also, it limits
X * the window size to 64K, which is quite useful on MSDOS.
X * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would
X * be less efficient since the data would have to be copied WSIZE/BSZ times)
X */
X Pos far prev[WSIZE];
X /* Link to older string with same hash index. To limit the size of this
X * array to 64K, this link is maintained only for the last 32K strings.
X * An index in this array is thus a window index modulo 32K.
X */
X Pos far head[HASH_SIZE];
X /* Heads of the hash chains or NIL */
X#else
X uch far * near window = NULL;
X Pos far * near prev = NULL;
X Pos far * near head;
X#endif
X
Xlong block_start;
X/* window position at the beginning of the current output block. Gets
X * negative when the window is moved backwards.
X */
X
Xlocal unsigned near ins_h; /* hash index of string to be inserted */
X
X#define H_SHIFT ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
X/* Number of bits by which ins_h and del_h must be shifted at each
X * input step. It must be such that after MIN_MATCH steps, the oldest
X * byte no longer takes part in the hash key, that is:
X * H_SHIFT * MIN_MATCH >= HASH_BITS
X */
X
Xunsigned int near prev_length;
X/* Length of the best match at previous step. Matches not greater than this
X * are discarded. This is used in the lazy match evaluation.
X */
X
X unsigned near strstart; /* start of string to insert */
X unsigned near match_start; /* start of matching string */
Xlocal int near eofile; /* flag set at end of input file */
Xlocal unsigned near lookahead; /* number of valid bytes ahead in window */
X
Xunsigned near max_chain_length;
X/* To speed up deflation, hash chains are never searched beyond this length.
X * A higher limit improves compression ratio but degrades the speed.
X */
X
Xlocal unsigned int max_lazy_match;
X/* Attempt to find a better match only when the current match is strictly
X * smaller than this value.
X */
X
Xint near good_match;
X/* Use a faster search when the previous match is longer than this */
X
X
X/* Values for max_lazy_match, good_match and max_chain_length, depending on
X * the desired pack level (0..9). The values given below have been tuned to
X * exclude worst case performance for pathological files. Better values may be
X * found for specific files.
X */
Xtypedef struct config {
X int good_length;
X int max_lazy;
X unsigned max_chain;
X uch flag;
X} config;
X
Xlocal config configuration_table[10] = {
X/* good lazy chain flag */
X/* 0 */ {0, 0, 0, 0}, /* store only */
X/* 1 */ {4, 4, 16, FAST}, /* maximum speed */
X/* 2 */ {6, 8, 16, 0},
X/* 3 */ {8, 16, 32, 0},
X/* 4 */ {8, 32, 64, 0},
X/* 5 */ {8, 64, 128, 0},
X/* 6 */ {8, 128, 256, 0},
X/* 7 */ {8, 128, 512, 0},
X/* 8 */ {32, 258, 1024, 0},
X/* 9 */ {32, 258, 4096, SLOW}}; /* maximum compression */
X
X/* Note: the current code requires max_lazy >= MIN_MATCH and max_chain >= 4
X * but these restrictions can easily be removed at a small cost.
X */
X
X#define EQUAL 0
X/* result of memcmp for equal strings */
X
X/* ===========================================================================
X * Prototypes for local functions. Use asm version by default for
X * MSDOS but not Unix. However the asm version version is recommended
X * for 386 Unix.
X */
X#ifdef ATARI_ST
X# undef MSDOS /* avoid the processor specific parts */
X#endif
X#if defined(MSDOS) && !defined(NO_ASM) && !defined(ASM)
X# define ASM
X#endif
X
Xlocal void fill_window OF((void));
X int longest_match OF((IPos cur_match));
X#ifdef ASM
X void match_init OF((void)); /* asm code initialization */
X#endif
X
X#ifdef DEBUG
Xlocal void check_match OF((IPos start, IPos match, int length));
X#endif
X
X#define MIN(a,b) ((a) <= (b) ? (a) : (b))
X/* The arguments must not have side effects. */
X
X/* ===========================================================================
X * Update a hash value with the given input byte
X * IN assertion: all calls to to UPDATE_HASH are made with consecutive
X * input characters, so that a running hash key can be computed from the
X * previous key instead of complete recalculation each time.
X */
X#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
X
X/* ===========================================================================
X * Insert string s in the dictionary and set match_head to the previous head
X * of the hash chain (the most recent string with same hash key). Return
X * the previous length of the hash chain.
X * IN assertion: all calls to to INSERT_STRING are made with consecutive
X * input characters and the first MIN_MATCH bytes of s are valid
X * (except for the last MIN_MATCH-1 bytes of the input file).
X */
X#define INSERT_STRING(s, match_head) \
X (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
X prev[(s) & WMASK] = match_head = head[ins_h], \
X head[ins_h] = (s))
X
X/* ===========================================================================
X * Initialize the "longest match" routines for a new file
X */
Xvoid lm_init (pack_level, flags)
X int pack_level; /* 0: store, 1: best speed, 9: best compression */
X ush *flags; /* general purpose bit flag */
X{
X register unsigned j;
X
X if (pack_level < 1 || pack_level > 9) error("bad pack level");
X
X /* Use dynamic allocation if compiler does not like big static arrays: */
X#ifdef DYN_ALLOC
X if (window == NULL) {
X window = (uch far*) fcalloc(WSIZE, 2*sizeof(uch));
X prev = (Pos far*) fcalloc(WSIZE, sizeof(Pos));
X head = (Pos far*) fcalloc(HASH_SIZE, sizeof(Pos));
X
X if (window == NULL || prev == NULL || head == NULL) {
X err(ZE_MEM, "window allocation");
X }
X }
X#endif /* DYN_ALLOC */
X#ifdef ASM
X match_init(); /* initialize the asm code */
X#endif
X /* Initialize the hash table. */
X for (j = 0; j < HASH_SIZE; j++) head[j] = NIL;
X /* prev will be initialized on the fly */
X
X /* Set the default configuration parameters:
X */
X max_lazy_match = configuration_table[pack_level].max_lazy;
X good_match = configuration_table[pack_level].good_length;
X max_chain_length = configuration_table[pack_level].max_chain;
X *flags |= configuration_table[pack_level].flag;
X /* ??? reduce max_chain_length for binary files */
X
X strstart = 0;
X block_start = 0L;
X
X#if defined(MSDOS) && !defined(__32BIT__)
X /* Can't read a 64K block under MSDOS */
X lookahead = read_buf((char*)window, (unsigned)WSIZE);
X#else
X lookahead = read_buf((char*)window, 2*WSIZE);
X#endif
X if (lookahead == 0 || lookahead == (unsigned)EOF) {
X eofile = 1, lookahead = 0;
X return;
X }
X eofile = 0;
X /* Make sure that we always have enough lookahead. This is important
X * if input comes from a device such as a tty.
X */
X while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
X
X ins_h = 0;
X for (j=0; j<MIN_MATCH-1; j++) UPDATE_HASH(ins_h, window[j]);
X /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
X * not important since only literal bytes will be emitted.


X */
X}
X
X/* ===========================================================================

X * Set match_start to the longest match starting at the given string and
X * return its length. Matches shorter or equal to prev_length are discarded,
X * in which case the result is equal to prev_length and match_start is
X * garbage.
X * IN assertions: cur_match is the head of the hash chain for the current
X * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
X */
X#ifndef ASM
X/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm. The code
X * is functionally equivalent, so you can use the C version if desired.
X */
Xint longest_match(cur_match)
X IPos cur_match; /* current match */
X{
X unsigned chain_length = max_chain_length; /* max hash chain length */
X register uch far *scan = window + strstart; /* current string */
X register uch far *match = scan; /* matched string */
X register int len; /* length of current match */
X int best_len = prev_length; /* best match length so far */
X IPos limit = strstart > (IPos)MAX_DIST ? strstart - (IPos)MAX_DIST : NIL;
X /* Stop when cur_match becomes <= limit. To simplify the code,
X * we prevent matches with the string of window index 0.
X */
X#ifdef UNALIGNED_OK
X register ush scan_start = *(ush*)scan;
X register ush scan_end = *(ush*)(scan+best_len-1);
X#else
X register uch scan_start = *scan;
X register uch scan_end1 = scan[best_len-1];
X register uch scan_end = scan[best_len];
X#endif
X
X /* Do not waste too much time if we already have a good match: */
X if (prev_length >= good_match) {
X chain_length >>= 2;
X }
X
X do {
X Assert(cur_match < strstart, "no future");
X match = window + cur_match;
X
X /* Skip to next match if the match length cannot increase
X * or if the match length is less than 2:
X */
X#if (defined(UNALIGNED_OK) && HASH_BITS >= 8)
X /* This code assumes sizeof(unsigned short) == 2 and
X * sizeof(unsigned long) == 4. Do not use UNALIGNED_OK if your
X * compiler uses different sizes.
X */
X if (*(ush*)(match+best_len-1) != scan_end ||
X *(ush*)match != scan_start) continue;
X
X len = MIN_MATCH - 4;
X /* It is not necessary to compare scan[2] and match[2] since they are
X * always equal when the other bytes match, given that the hash keys
X * are equal and that HASH_BITS >= 8.
X */
X do {} while ((len+=4) < MAX_MATCH-3 &&
X *(ulg*)(scan+len) == *(ulg*)(match+len));
X /* The funny do {} generates better code for most compilers */
X
X if (*(ush*)(scan+len) == *(ush*)(match+len)) len += 2;
X if (scan[len] == match[len]) len++;
X
X#else /* UNALIGNED_OK */
X if (match[best_len] != scan_end ||
X match[best_len-1] != scan_end1 || *match != scan_start)
X continue;
X /* It is not necessary to compare scan[1] and match[1] since they
X * are always equal when the other bytes match, given that
X * the hash keys are equal and that h_shift+8 <= HASH_BITS,
X * that is, when the last byte is entirely included in the hash key.
X * The condition is equivalent to
X * (HASH_BITS+2)/3 + 8 <= HASH_BITS
X * or: HASH_BITS >= 13
X * Also, we check for a match at best_len-1 to get rid quickly of
X * the match with the suffix of the match made at the previous step,
X * which is known to fail.
X */
X#if HASH_BITS >= 13
X len = 1;
X#else
X len = 0;
X#endif
X do {} while (++len < MAX_MATCH && scan[len] == match[len]);
X
X#endif /* UNALIGNED_OK */
X
X if (len > best_len) {
X match_start = cur_match;
X best_len = len;
X if (len == MAX_MATCH) break;
X#ifdef UNALIGNED_OK
X scan_end = *(ush*)(scan+best_len-1);
X#else
X scan_end1 = scan[best_len-1];
X scan_end = scan[best_len];
X#endif
X }
X } while (--chain_length != 0 &&
X (cur_match = prev[cur_match & WMASK]) > limit);
X
X return best_len;
X}
X#endif /* NO_ASM */
X
X#ifdef DEBUG
X/* ===========================================================================
X * Check that the match at match_start is indeed a match.
X */
Xlocal void check_match(start, match, length)
X IPos start, match;
X int length;
X{
X /* check that the match is indeed a match */
X if (memcmp((char*)window + match,
X (char*)window + start, length) != EQUAL) {
X fprintf(stderr,
X " start %d, match %d, length %d\n",
X start, match, length);
X error("invalid match");
X }
X if (verbose > 1) {
X fprintf(stderr,"\\[%d,%d]", start-match, length);
X do { putc(window[start++], stderr); } while (--length != 0);
X }
X}
X#else
X# define check_match(start, match, length)
X#endif
X
X/* ===========================================================================
X * Fill the window when the lookahead becomes insufficient.
X * Updates strstart and lookahead, and sets eofile if end of input file.
X * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
X * OUT assertion: at least one byte has been read, or eofile is set.
X */
Xlocal void fill_window()
X{
X register unsigned n, m;
X unsigned more = (unsigned)((ulg)2*WSIZE - (ulg)lookahead - (ulg)strstart);
X /* Amount of free space at the end of the window. */
X
X /* If the window is full, move the upper half to the lower one to make
X * room in the upper half.
X */
X if (more == 0) {
X /* By the IN assertion, the window is not empty so we can't confuse
X * more == 0 with more == 64K on a 16 bit machine.
X */
X memcpy((char*)window, (char*)window+WSIZE, (unsigned)WSIZE);
X match_start -= WSIZE;
X strstart -= WSIZE;
X /* strstart - WSIZE = WSIZE - lookahead > WSIZE - MIN_LOOKAHEAD
X * so we now have strstart > MAX_DIST:
X */
X Assert (strstart > MAX_DIST, "window slide too early");
X block_start -= (long) WSIZE;
X
X for (n = 0; n < HASH_SIZE; n++) {
X m = head[n];
X head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
X }
X for (n = 0; n < WSIZE; n++) {
X m = prev[n];
X prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
X /* If n is not on any hash chain, prev[n] is garbage but
X * its value will never be used.
X */
X }
X more = WSIZE;
X if (verbose) putc('.', stderr);
X
X } else if (more == (unsigned)EOF) {
X /* Very unlikely, but possible on 16 bit machine if strstart == 0
X * and lookahead == 1 (input done one byte at time)
X */
X more--;
X }
X n = read_buf((char*)window+strstart+lookahead, more);
X if (n == 0 || n == (unsigned)EOF) {
X eofile = 1;
X } else {
X lookahead += n;


X }
X}
X
X/* ===========================================================================

X * Flush the current block, with given end-of-file flag.
X * IN assertion: strstart is set to the end of the current match.
X */
X#define FLUSH_BLOCK(eof) \
X flush_block(block_start >= 0L ? (char*)&window[block_start] : (char*)NULL,\
X (long)strstart - block_start, (eof))
X
X/* ===========================================================================
X * Processes a new input file and return its compressed length.
X */
X#ifdef NO_LAZY
Xulg deflate()
X{
X IPos hash_head; /* head of the hash chain */
X int flush; /* set if current block must be flushed */
X unsigned match_length = 0; /* length of best match */
X
X prev_length = MIN_MATCH-1;
X while (lookahead != 0) {
X /* Insert the string window[strstart .. strstart+2] in the
X * dictionary, and set hash_head to the head of the hash chain:
X */
X INSERT_STRING(strstart, hash_head);
X
X /* Find the longest match, discarding those <= prev_length.
X * At this point we have always match_length < MIN_MATCH
X */
X if (hash_head != NIL && strstart - hash_head <= MAX_DIST) {
X /* To simplify the code, we prevent matches with the string
X * of window index 0 (in particular we have to avoid a match
X * of the string with itself at the start of the input file).
X */
X match_length = longest_match (hash_head);
X /* longest_match() sets match_start */
X if (match_length > lookahead) match_length = lookahead;
X }
X if (match_length >= MIN_MATCH) {
X check_match(strstart, match_start, match_length);
X
X flush = ct_tally(strstart-match_start, match_length - MIN_MATCH);
X
X lookahead -= match_length;
X match_length--; /* string at strstart already in hash table */
X do {
X strstart++;
X INSERT_STRING(strstart, hash_head);
X /* strstart never exceeds WSIZE-MAX_MATCH, so there are
X * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
X * these bytes are garbage, but it does not matter since the
X * next lookahead bytes will always be emitted as literals.
X */
X } while (--match_length != 0);
X } else {
X /* No match, output a literal byte */
X flush = ct_tally (0, window[strstart]);
X lookahead--;
X }
X strstart++;
X if (flush) FLUSH_BLOCK(0), block_start = strstart;
X
X /* Make sure that we always have enough lookahead, except
X * at the end of the input file. We need MAX_MATCH bytes
X * for the next match, plus MIN_MATCH bytes to insert the
X * string following the next match.
X */
X while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
X
X }
X return FLUSH_BLOCK(1); /* eof */
X}
X#else /* LAZY */
X/* ===========================================================================
X * Same as above, but achieves better compression. We use a lazy
X * evaluation for matches: a match is finally adopted only if there is
X * no better match at the next window position.
X */
Xulg deflate()
X{
X IPos hash_head; /* head of hash chain */
X IPos prev_match; /* previous match */
X int flush; /* set if current block must be flushed */
X int match_available = 0; /* set if previous match exists */
X register unsigned match_length = MIN_MATCH-1; /* length of best match */
X#ifdef DEBUG
X extern ulg isize; /* byte length of input file, for debug only */
X#endif
X
X /* Process the input block. */
X while (lookahead != 0) {
X /* Insert the string window[strstart .. strstart+2] in the
X * dictionary, and set hash_head to the head of the hash chain:
X */
X INSERT_STRING(strstart, hash_head);
X
X /* Find the longest match, discarding those <= prev_length.
X */
X prev_length = match_length, prev_match = match_start;
X match_length = MIN_MATCH-1;
X
X if (hash_head != NIL && prev_length < max_lazy_match &&
X strstart - hash_head <= MAX_DIST) {
X /* To simplify the code, we prevent matches with the string
X * of window index 0 (in particular we have to avoid a match
X * of the string with itself at the start of the input file).
X */
X match_length = longest_match (hash_head);
X /* longest_match() sets match_start */
X if (match_length > lookahead) match_length = lookahead;
X /* Ignore a length 3 match if it is too distant: */
X if (match_length == MIN_MATCH && strstart-match_start > TOO_FAR){
X /* If prev_match is also MIN_MATCH, match_start is garbage
X * but we will ignore the current match anyway.
X */
X match_length--;
X }
X }
X /* If there was a match at the previous step and the current
X * match is not better, output the previous match:
X */
X if (prev_length >= MIN_MATCH && match_length <= prev_length) {
X
X check_match(strstart-1, prev_match, prev_length);
X
X flush = ct_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
X
X /* Insert in hash table all strings up to the end of the match.
X * strstart-1 and strstart are already inserted.
X */
X lookahead -= prev_length-1;
X prev_length -= 2;
X do {
X strstart++;
X INSERT_STRING(strstart, hash_head);
X /* strstart never exceeds WSIZE-MAX_MATCH, so there are
X * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
X * these bytes are garbage, but it does not matter since the
X * next lookahead bytes will always be emitted as literals.
X */
X } while (--prev_length != 0);
X match_available = 0;
X match_length = MIN_MATCH-1;
X
X } else if (match_available) {
X /* If there was no match at the previous position, output a
X * single literal. If there was a match but the current match
X * is longer, truncate the previous match to a single literal.
X */
X flush = ct_tally (0, window[strstart-1]);
X Tracevv((stderr,"%c",window[strstart-1]));
X lookahead--;
X } else {
X /* There is no previous match to compare with, wait for
X * the next step to decide.
X */
X match_available = 1;
X flush = 0;
X lookahead--;
X }
X if (flush) FLUSH_BLOCK(0), block_start = strstart;
X strstart++;
X Assert (strstart <= isize && lookahead <= isize, "a bit too far");
X
X /* Make sure that we always have enough lookahead, except
X * at the end of the input file. We need MAX_MATCH bytes
X * for the next match, plus MIN_MATCH bytes to insert the
X * string following the next match.
X */
X while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
X }
X if (match_available) ct_tally (0, window[strstart-1]);
X
X return FLUSH_BLOCK(1); /* eof */
X}
X#endif /* LAZY */
END_OF_FILE
if test 26162 -ne `wc -c <'deflate.c'`; then
echo shar: \"'deflate.c'\" unpacked with wrong size!
fi
# end of 'deflate.c'
fi
if test -f 'msdos/tcconfig.tc.UU' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'msdos/tcconfig.tc.UU'\"
else
echo shar: Extracting \"'msdos/tcconfig.tc.UU'\" \(2366 characters\)
sed "s/^X//" >'msdos/tcconfig.tc.UU' <<'END_OF_FILE'
Xbegin 666 msdos/tcconfig.tc
XM5'5R8F\@0R!#;VYF:6=U<F%T:6]N($9I;&4@&@ !#1(7 1H @$! ( "
XM ( 0 # ( @ $ $ 4 0 !@ ! ( $ PD @ T @ ! X
XM @ !$ 0 ($@ " $ $P " !D % " %0 " $ %@ " ( %P " $
XM& " 9 ! %E $ 68 0 !9P ! %H $ 6D 0 !:@ ! %K $
XM &P 0 !;0 ! %N $ 6\ 0 !< ! %Q $ '( 0 !<P ! !T $
XM 74 0 !=@ ! %W $ 7@ 0 !>0 ! %Z $ 7L 0 ? ! %] $
XM 7X 0 !?P ! & $ (( 0 A ! &% $ <@ 0 R0 ! '* $
XM ,L 0 S ! #- $ ,X 0 !SP ! #0 $ &=$ 0!DT@ ! "#5 $
XM -< 0 V ! '9 $ =H 0 !VP ! #< $ =T 0 !W@ ! #? $
XM . 0 X0 ! #B $ 2P!1
XM "T!
XM@ !#.EQ40UQ)3D-,541%
XM
XM "X!@ !#
XM.EQ40UQ,24(
XM
XM "\!4 !:25 N
XM4%)*
XM # !! S,@ ,0$% #(U
XM ,@$% #$P, ,P%_
XM
XM
XM T 1X *@ -0$>
XM "H #8!'@ J
XM W 1X *@
XM . $> "H #D!
XM'@ J Z 1X *@
XM .P$> "H
XM #P!'@ J ]
XM 8
XM
XM ^ 00
XM. #\!4
XM $ !
XM1 !#.EQ40P
XM $$!4
XM
X9 /__ @ :
X
Xend
END_OF_FILE
if test 2366 -ne `wc -c <'msdos/tcconfig.tc.UU'`; then
echo shar: \"'msdos/tcconfig.tc.UU'\" unpacked with wrong size!
else
echo shar: Uudecoding \"'msdos/tcconfig.tc'\" \(1690 characters\)
cat msdos/tcconfig.tc.UU | uudecode
if test 1690 -ne `wc -c <'msdos/tcconfig.tc'`; then
echo shar: \"'msdos/tcconfig.tc'\" uudecoded with wrong size!
else
rm msdos/tcconfig.tc.UU
fi
fi
# end of 'msdos/tcconfig.tc.UU'
fi
if test -f 'os2/os2zip.c.UU' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'os2/os2zip.c.UU'\"
else
echo shar: Extracting \"'os2/os2zip.c.UU'\" \(28901 characters\)
sed "s/^X//" >'os2/os2zip.c.UU' <<'END_OF_FILE'
Xbegin 666 os2/os2zip.c
XM+RH-"B J($ H(RED:7(N8R Q+C0@.#<O,3$O,#8@4'5B;&EC($1O;6%I;BX-
XM"B J#0H@*B @02!P=6)L:6,@9&]M86EN(&EM<&QE;65N=&%T:6]N(&]F($)3
XM1"!D:7)E8W1O<GD@<F]U=&EN97,@9F]R#0H@*B @35,M1$]3+B @5W)I='1E
XM;B!B>2!-:6-H865L(%)E;F1E;&P@*'MU=6YE="QU=&%I?6UI8VAA96Q 9V%R
XM9FEE;&0I+ T*("H@($%U9W5S=" Q.#DW#0H@*B @4&]R=&5D('1O($]3+S(@
XM8GD@2V%I(%5W92!2;VUM96P-"B J("!$96-E;6)E<B Q.3@Y+"!&96)R=6%R
XM>2 Q.3DP#0H@*B @0VAA;F=E(&9O<B!(4$93('-U<'!O<G0L($]C=&]B97(@
XM,3DY, T*("HO#0H-"B\J(&1O97,@86QS;R!C;VYT86EN($5!(&%C8V5S<R!C
XM;V1E(&9O<B!U<V4@:6X@6DE0("HO#0H-"@T*(VEF9&5F(%]?14U87U\-"B-D
XM969I;F4@7U\S,D))5%]?#0HC96YD:68-"@T*(VEN8VQU9&4@(GII<"YH(@T*
XM#0HC:6YC;'5D92 \<W1D;&EB+F@^#0HC:6YC;'5D92 \=&EM92YH/@T*(VEN
XM8VQU9&4@/&-T>7!E+F@^#0H-"B-I9F1E9B!?7U=!5$-/34-?7PT*(VEN8VQU
XM9&4@/&UA;&QO8RYH/@T*=6YS:6=N960@8VAA<B!?7VYE87(@7V]S;6]D92 ]
XM($]3,E]-3T1%.PT*(V5N9&EF#0H-"B-D969I;F4@24Y#3%].3U!-#0HC9&5F
XM:6YE($E.0TQ?1$]33DQ3#0HC9&5F:6YE($E.0TQ?1$]315)23U)3#0HC:6YC
XM;'5D92 \;W,R+F@^#0H-"B-I;F-L=61E(")O<S)Z:7 N:"(-"@T*#0HC9&5F
XM:6YE($5!240@(" @(#!X,# P.0T*#0H-"B-I9F1E9B!?7S,R0DE47U\-"B-D
XM969I;F4@1&]S1FEN9$9I<G-T*' Q+"!P,BP@<#,L(' T+"!P-2P@<#8I(%P-
XM"B @(" @(" @1&]S1FEN9$9I<G-T*' Q+"!P,BP@<#,L(' T+"!P-2P@<#8L
XM(#$I#0HC96QS90T*(V1E9FEN92!$;W-1=65R>4-U<G)E;G1$:7-K($1O<U%#
XM=7)$:7-K#0HC9&5F:6YE($1O<U%U97)Y1E-!='1A8V@H<#$L(' R+"!P,RP@
XM<#0L(' U*2!<#0H@(" @(" @($1O<U%&4T%T=&%C:"AP,2P@<#(L(' S+"!P
XM-"P@<#4L(# I#0HC9&5F:6YE($1O<U%U97)Y4&%T:$EN9F\H<#$L(' R+"!P
XM,RP@<#0I(%P-"B @(" @(" @1&]S45!A=&A);F9O*' Q+"!P,BP@<#,L(' T
XM+" P*0T*(V1E9FEN92!$;W-39710871H26YF;RAP,2P@<#(L(' S+"!P-"P@
XM<#4I(%P-"B @(" @(" @1&]S4V5T4&%T:$EN9F\H<#$L(' R+"!P,RP@<#0L
XM(' U+" P*0T*(V1E9FEN92!$;W-%;G5M071T<FEB=71E*' Q+"!P,BP@<#,L
XM(' T+"!P-2P@<#8L(' W*2!<#0H@(" @(" @($1O<T5N=6U!='1R:6)U=&4H
XM<#$L(' R+"!P,RP@<#0L(' U+"!P-BP@<#<L(# I#0HC9&5F:6YE($1O<T9I
XM;F1&:7)S="AP,2P@<#(L(' S+"!P-"P@<#4L(' V*2!<#0H@(" @(" @($1O
XM<T9I;F1&:7)S="AP,2P@<#(L(' S+"!P-"P@<#4L(' V+" P*0T*(V1E9FEN
XM92!$;W--87!#87-E($1O<T-A<V5-87 -"B-E;F1I9@T*#0H-"B-I9FYD968@
XM551)3 T*#0IE>'1E<FX@:6YT(&YO:7-Y.PT*#0HC:69N9&5F(%-?249-5 T*
XM(V1E9FEN92!37TE&350@,'A&,# P#0HC96YD:68-"@T*<W1A=&EC(&EN="!A
XM='1R:6)U=&5S(#T@05]$25(@?"!!7TA)1$1%3B!\($%?4UE35$5-.PT*#0IS
XM=&%T:6,@8VAA<B J9V5T9&ER96YT*&-H87(@*BD[#0IS=&%T:6,@=F]I9"!F
XM<F5E7V1I<F-O;G1E;G1S*'-T<G5C="!?9&ER8V]N=&5N=',@*BD[#0H-"B-I
XM9F1E9B!?7S,R0DE47U\-"G-T871I8R!(1$E2(&AD:7([#0IS=&%T:6,@54Q/
XM3D<@8V]U;G0[#0IS=&%T:6,@1DE,149)3D1"548S(&9I;F0[#0HC96QS90T*
XM<W1A=&EC($A$25(@:&1I<CL-"G-T871I8R!54TA/4E0@8V]U;G0[#0IS=&%T
XM:6,@1DE,149)3D1"548@9FEN9#L-"B-E;F1I9@T*#0H-"D1)4B J;W!E;F1I
XM<BAC:&%R("IN86UE*0T*>PT*("!S=')U8W0@<W1A="!S=&%T8CL-"B @1$E2
XM("ID:7)P.PT*("!C:&%R(&,[#0H@(&-H87(@*G,[#0H@('-T<G5C="!?9&ER
XM8V]N=&5N=',@*F1P.PT*("!C:&%R(&YB=69;34%84$%42$Q%3B K(#%=.PT*
XM("!I;G0@;&5N.PT*#0H@('-T<F-P>2AN8G5F+"!N86UE*3L-"B @;&5N(#T@
XM<W1R;&5N("AN8G5F*3L-"B @<R ](&YB=68@*R!L96X[#0H-"B @:68@*" H
XM*&,@/2!N8G5F6W-T<FQE;BAN8G5F*2 M(#%=*2 ]/2 G7%PG('Q\(&,@/3T@
XM)R\G*2 F)@T*(" @(" @("AS=')L96XH;F)U9BD@/B Q*2 I#0H@('L-"B @
XM("!N8G5F6W-T<FQE;BAN8G5F*2 M(#%=(#T@,#L-"@T*(" @(&EF("@@;F)U
XM9EMS=')L96XH;F)U9BD@+2 Q72 ]/2 G.B<@*0T*(" @(" @<W1R8V%T*&YB
XM=68L(")<7"XB*3L-"B @?0T*("!E;'-E#0H@(" @:68@*"!N8G5F6W-T<FQE
XM;BAN8G5F*2 M(#%=(#T]("<Z)R I#0H@(" @("!S=')C870H;F)U9BP@(BXB
XM*3L-"@T*("!I9B H<W1A="AN8G5F+" F<W1A=&(I(#P@,"!\?" H<W1A=&(N
XM<W1?;6]D92 F(%-?249-5"D@(3T@4U])1D1)4BD-"B @("!R971U<FX@3E5,
XM3#L-"@T*("!I9B H("AD:7)P(#T@;6%L;&]C*'-I>F5O9BA$25(I*2D@/3T@
XM3E5,3" I#0H@(" @<F5T=7)N($Y53$P[#0H-"B @:68@*"!N8G5F6W-T<FQE
XM;BAN8G5F*2 M(#%=(#T]("<N)R I#0H@(" @<W1R8W!Y*&YB=68@*R!S=')L
XM96XH;F)U9BD@+2 Q+" B*BXJ(BD[#0H@(&5L<V4-"B @("!I9B H("@H8R ]
XM(&YB=69;<W1R;&5N*&YB=68I("T@,5TI(#T]("=<7"<@?'P@8R ]/2 G+R<I
XM("8F#0H@(" @(" @(" H<W1R;&5N*&YB=68I(#T](#$I("D-"B @(" @('-T
XM<F-A="AN8G5F+" B*BXJ(BD[#0H@(" @96QS90T*(" @(" @<W1R8V%T*&YB
XM=68L(")<7"HN*B(I.PT*#0H@(&1I<G @+3X@9&1?;&]C(#T@,#L-"B @9&ER
XM<" M/B!D9%]C;VYT96YT<R ](&1I<G @+3X@9&1?8W @/2!.54Q,.PT*#0H@
XM(&EF("@H<R ](&=E=&1I<F5N="AN8G5F*2D@/3T@3E5,3"D-"B @("!R971U
XM<FX@9&ER<#L-"@T*("!D;PT*("![#0H@(" @:68@*"@H9' @/2!M86QL;V,H
XM<VEZ96]F*'-T<G5C="!?9&ER8V]N=&5N=',I*2D@/3T@3E5,3"D@?'P-"B @
XM(" @(" @*"AD<" M/B!?9%]E;G1R>2 ](&UA;&QO8RAS=')L96XH<RD@*R Q
XM*2D@/3T@3E5,3"D@(" @(" I#0H@(" @>PT*(" @(" @:68@*&1P*0T*(" @
XM(" @("!F<F5E*&1P*3L-"B @(" @(&9R965?9&ER8V]N=&5N=',H9&ER<" M
XM/B!D9%]C;VYT96YT<RD[#0H-"B @(" @(')E='5R;B!.54Q,.PT*(" @('T-
XM"@T*(" @(&EF("AD:7)P("T^(&1D7V-O;G1E;G1S*0T*(" @('L-"B @(" @
XM(&1I<G @+3X@9&1?8W @+3X@7V1?;F5X=" ](&1P.PT*(" @(" @9&ER<" M
XM/B!D9%]C<" ](&1I<G @+3X@9&1?8W @+3X@7V1?;F5X=#L-"B @("!]#0H@
XM(" @96QS90T*(" @(" @9&ER<" M/B!D9%]C;VYT96YT<R ](&1I<G @+3X@
XM9&1?8W @/2!D<#L-"@T*(" @('-T<F-P>2AD<" M/B!?9%]E;G1R>2P@<RD[
XM#0H@(" @9' @+3X@7V1?;F5X=" ]($Y53$P[#0H-"B @("!D<" M/B!?9%]S
XM:7IE(#T@9FEN9"YC8D9I;&4[#0H@(" @9' @+3X@7V1?;6]D92 ](&9I;F0N
XM871T<D9I;&4[#0H@(" @9' @+3X@7V1?=&EM92 ]("HH=6YS:6=N960@*BD@
XM)BAF:6YD+F9T:6UE3&%S=%=R:71E*3L-"B @("!D<" M/B!?9%]D871E(#T@
XM*BAU;G-I9VYE9" J*2 F*&9I;F0N9F1A=&5,87-T5W)I=&4I.PT*("!]#0H@
XM('=H:6QE("@H<R ](&=E=&1I<F5N="A.54Q,*2D@(3T@3E5,3"D[#0H-"B @
XM9&ER<" M/B!D9%]C<" ](&1I<G @+3X@9&1?8V]N=&5N=',[#0H-"B @<F5T
XM=7)N(&1I<G [#0I]#0H-"@T*=F]I9"!C;&]S961I<BA$25(@*B!D:7)P*0T*
XM>PT*("!F<F5E7V1I<F-O;G1E;G1S*&1I<G @+3X@9&1?8V]N=&5N=',I.PT*
XM("!F<F5E*&1I<G I.PT*?0T*#0H-"G-T<G5C="!D:7)E8W0@*G)E861D:7(H
XM1$E2("H@9&ER<"D-"GL-"B @<W1A=&EC('-T<G5C="!D:7)E8W0@9' [#0H-
XM"B @:68@*&1I<G @+3X@9&1?8W @/3T@3E5,3"D-"B @("!R971U<FX@3E5,
XM3#L-"@T*("!D<"YD7VYA;6QE;B ](&1P+F1?<F5C;&5N(#T-"B @("!S=')L
XM96XH<W1R8W!Y*&1P+F1?;F%M92P@9&ER<" M/B!D9%]C<" M/B!?9%]E;G1R
XM>2DI.PT*#0H@(&1P+F1?:6YO(#T@,#L-"@T*("!D<"YD7W-I>F4@/2!D:7)P
XM("T^(&1D7V-P("T^(%]D7W-I>F4[#0H@(&1P+F1?;6]D92 ](&1I<G @+3X@
XM9&1?8W @+3X@7V1?;6]D93L-"B @9' N9%]T:6UE(#T@9&ER<" M/B!D9%]C
XM<" M/B!?9%]T:6UE.PT*("!D<"YD7V1A=&4@/2!D:7)P("T^(&1D7V-P("T^
XM(%]D7V1A=&4[#0H-"B @9&ER<" M/B!D9%]C<" ](&1I<G @+3X@9&1?8W @
XM+3X@7V1?;F5X=#L-"B @9&ER<" M/B!D9%]L;V,K*SL-"@T*("!R971U<FX@
XM)F1P.PT*?0T*#0H-"G9O:60@<V5E:V1I<BA$25(@*B!D:7)P+"!L;VYG(&]F
XM9BD-"GL-"B @;&]N9R!I(#T@;V9F.PT*("!S=')U8W0@7V1I<F-O;G1E;G1S
XM("ID<#L-"@T*("!I9B H;V9F(#X](# I#0H@('L-"B @("!F;W(@*&1P(#T@
XM9&ER<" M/B!D9%]C;VYT96YT<SL@+2UI(#X](# @)B8@9' [(&1P(#T@9' @
XM+3X@7V1?;F5X="D[#0H-"B @("!D:7)P("T^(&1D7VQO8R ](&]F9B M("AI
XM("L@,2D[#0H@(" @9&ER<" M/B!D9%]C<" ](&1P.PT*("!]#0I]#0H-"@T*
XM;&]N9R!T96QL9&ER*$1)4B J(&1I<G I#0I[#0H@(')E='5R;B!D:7)P("T^
XM(&1D7VQO8SL-"GT-"@T*#0IS=&%T:6,@=F]I9"!F<F5E7V1I<F-O;G1E;G1S
XM*'-T<G5C="!?9&ER8V]N=&5N=',@*B!D<"D-"GL-"B @<W1R=6-T(%]D:7)C
XM;VYT96YT<R J;V1P.PT*#0H@('=H:6QE("AD<"D-"B @>PT*(" @(&EF("AD
XM<" M/B!?9%]E;G1R>2D-"B @(" @(&9R964H9' @+3X@7V1?96YT<GDI.PT*
XM#0H@(" @9' @/2 H;V1P(#T@9' I("T^(%]D7VYE>'0[#0H@(" @9G)E92AO
XM9' I.PT*("!]#0I]#0H-"@T*<W1A=&EC(&-H87(@*F=E=&1I<F5N="AC:&%R
XM("ID:7(I#0I[#0H@(&EN="!D;VYE.PT*("!S=&%T:6,@:6YT(&QO=V5R.PT*
XM#0H@(&EF("AD:7(@(3T@3E5,3"D-"B @>R @(" @(" @(" @(" @(" @(" @
XM(" @(" @(" @(" @(" @("\J(&=E="!F:7)S="!E;G1R>2 J+PT*(" @(&AD
XM:7(@/2!(1$E27T-214%413L-"B @("!C;W5N=" ](#$[#0H@(" @9&]N92 ]
XM($1O<T9I;F1&:7)S="AD:7(L("9H9&ER+"!A='1R:6)U=&5S+" F9FEN9"P@
XM<VEZ96]F*&9I;F0I+" F8V]U;G0I.PT*(" @(&QO=V5R(#T@27-&:6QE4WES
XM=&5M1D%4*&1I<BD[#0H@('T-"B @96QS92 @(" @(" @(" @(" @(" @(" @
XM(" @(" @(" @(" @("\J(&=E="!N97AT(&5N=')Y("HO#0H@(" @9&]N92 ]
XM($1O<T9I;F1.97AT*&AD:7(L("9F:6YD+"!S:7IE;V8H9FEN9"DL("9C;W5N
XM="D[#0H-"B @:68@*&1O;F4@/3T@,"D-"B @>PT*(" @(&EF("@@;&]W97(@
XM*0T*(" @(" @4W1R:6YG3&]W97(H9FEN9"YA8VA.86UE*3L-"B @("!R971U
XM<FX@9FEN9"YA8VA.86UE.PT*("!]#0H@(&5L<V4-"B @>PT*(" @($1O<T9I
XM;F1#;&]S92AH9&ER*3L-"B @("!R971U<FX@3E5,3#L-"B @?0T*?0T*#0H-
XM"B\J($9!5" O($A01E,@9&5T96-T:6]N("HO#0H-"FEN="!)<T9I;&53>7-T
XM96U&050H8VAA<B J9&ER*0T*>PT*("!S=&%T:6,@55-(3U)4(&Y,87-T1')I
XM=F4@/2 M,2P@;E)E<W5L=#L-"B @54Q/3D<@;$UA<#L-"B @0EE412!B1&%T
XM85LV-%TL(&).86UE6S-=.PT*(VEF9&5F(%]?,S)"251?7PT*("!53$].1R!N
XM1')I=F4L(&-B1&%T83L-"B @4$9344)51D9%4C(@<$1A=&$@/2 H4$9344)5
XM1D9%4C(I(&)$871A.PT*(V5L<V4-"B @55-(3U)4(&Y$<FEV92P@8V)$871A
XM.PT*("!01E-10E5&1D52('!$871A(#T@*%!&4U%"549&15(I(&)$871A.PT*
XM(V5N9&EF#0H-"B @:68@*"!?;W-M;V1E(#T]($1/4U]-3T1%("D-"B @("!R
XM971U<FX@5%)513L-"B @96QS90T*("![#0H@(" @+RH@5V4@<V5P87)A=&4@
XM1D%4(&%N9"!(4$93*V]T:&5R(&9I;&4@<WES=&5M<R!H97)E+@T*(" @(" @
XM(&%T('1H92!M;VUE;G0@22!C;VYS:61E<B!O=&AE<B!S>7-T96US('1O(&)E
XM('-I;6EL87(@=&\@2%!&4RP-"B @(" @("!I+F4N('-U<'!O<G0@;&]N9R!F
XM:6QE(&YA;65S(&%N9"!B965I;F<@8V%S92!S96YS:71I=F4@*B\-"@T*(" @
XM(&EF("@@:7-A;'!H82AD:7);,%TI("8F("AD:7);,5T@/3T@)SHG*2 I#0H@
XM(" @("!N1')I=F4@/2!T;U]U<"AD:7);,%TI("T@)T G.PT*(" @(&5L<V4-
XM"B @(" @($1O<U%U97)Y0W5R<F5N=$1I<VLH)FY$<FEV92P@)FQ-87 I.PT*
XM#0H@(" @:68@*"!N1')I=F4@/3T@;DQA<W1$<FEV92 I#0H@(" @("!R971U
XM<FX@;E)E<W5L=#L-"@T*(" @(&).86UE6S!=(#T@*&-H87(I("AN1')I=F4@
XM*R G0"<I.PT*(" @(&).86UE6S%=(#T@)SHG.PT*(" @(&).86UE6S)=(#T@
XM,#L-"@T*(" @(&Y,87-T1')I=F4@/2!N1')I=F4[#0H@(" @8V)$871A(#T@
XM<VEZ96]F*&)$871A*3L-"@T*(" @(&EF("@@(41O<U%U97)Y1E-!='1A8V@H
XM8DYA;64L(# L($9304E,7U%515)93D%-12P@*%!63TE$*2!P1&%T82P@)F-B
XM1&%T82D@*0T*(" @(" @;E)E<W5L=" ]("%S=')C;7 H<$1A=&$@+3X@<WI&
XM4T1.86UE("L@<$1A=&$@+3X@8V).86UE+" B1D%4(BD[#0H@(" @96QS90T*
XM(" @(" @;E)E<W5L=" ]($9!3%-%.PT*#0H@(" @+RH@16YD(&]F('1H:7,@
XM=6=L>2!C;V1E("HO#0H@(" @<F5T=7)N(&Y297-U;'0[#0H@('T-"GT-"@T*
XM#0HO*B!A8V-E<W,@;6]D92!B:71S(&%N9"!T:6UE('-T86UP("HO#0H-"FEN
XM="!'971&:6QE36]D92AC:&%R("IN86UE*0T*>PT*(VEF9&5F(%]?,S)"251?
XM7PT*("!&24Q%4U1!5%53,R!F<SL-"B @<F5T=7)N($1O<U%U97)Y4&%T:$EN
XM9F\H;F%M92P@,2P@)F9S+"!S:7IE;V8H9G,I*2 _("TQ(#H@9G,N871T<D9I
XM;&4[#0HC96QS90T*("!54TA/4E0@;6]D93L-"B @<F5T=7)N($1O<U%&:6QE
XM36]D92AN86UE+" F;6]D92P@,$PI(#\@+3$@.B!M;V1E.PT*(V5N9&EF#0I]
XM#0H-"FQO;F<@1V5T1FEL951I;64H8VAA<B J;F%M92D-"GL-"B-I9F1E9B!?
XM7S,R0DE47U\-"B @1DE,15-405154S,@9G,[#0HC96QS90T*("!&24Q%4U1!
XM5%53(&9S.PT*(V5N9&EF#0H@(%532$]25"!N1&%T92P@;E1I;64[#0H-"B @
XM:68@*"!$;W-1=65R>5!A=&A);F9O*&YA;64L(#$L("A00EE412D@)F9S+"!S
XM:7IE;V8H9G,I*2 I#0H@(" @<F5T=7)N("TQ.PT*#0H@(&Y$871E(#T@*B H
XM55-(3U)4("HI("9F<RYF9&%T94QA<W17<FET93L-"B @;E1I;64@/2 J("A5
XM4TA/4E0@*BD@)F9S+F9T:6UE3&%S=%=R:71E.PT*#0H@(')E='5R;B H*%5,
XM3TY'*2!N1&%T92D@/#P@,38@?"!N5&EM93L-"GT-"@T*=F]I9"!3971&:6QE
XM5&EM92AC:&%R("IP871H+"!L;VYG('-T86UP*0T*>PT*("!&24Q%4U1!5%53
XM(&9S.PT*("!54TA/4E0@9F0L(&9T.PT*("!54TA/4E0@;DQE;F=T:#L-"B @
XM8VAA<B!S>DYA;65;0T-(34%84$%42%T[#0H-"B @:68@*"!$;W-1=65R>5!A
XM=&A);F9O*'!A=&@L($9)3%]35$%.1$%21"P@*%!"651%*2 F9G,L('-I>F5O
XM9BAF<RDI("D-"B @("!R971U<FX[#0H-"B @9F0@/2 H55-(3U)4*2 H<W1A
XM;7 @/CX@,38I.PT*("!F=" ]("A54TA/4E0I('-T86UP.PT*("!F<RYF9&%T
XM94QA<W17<FET92 ](&9S+F9D871E0W)E871I;VX@/2 J("A&1$%412 J*2 F
XM9F0[#0H@(&9S+F9T:6UE3&%S=%=R:71E(#T@9G,N9G1I;65#<F5A=&EO;