Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 6724 → Rev 6725

/programs/fs/unzip60/human68k/Contents
0,0 → 1,7
Contents of the "human68k" sub-archive for UnZip 5.50 and later:
 
Contents this file
Makefile (shorter) Makefile for GNU C on X680x0/Human68k
human68k.c Human68k-specific routines for UnZip
crc_68.s assembler version of crc32.c
flate.s assembler version of inflate_codes() (define ASM_INFLATECODES)
/programs/fs/unzip60/human68k/Makefile
0,0 → 1,229
# Makefile for UnZip 5.53 and later: Human68k with gcc NIIMI Satoshi
#
# The original Makefile maybe works fine, but X680x0 is too slow
# to process it. So I split out needed part.
#
# Last revised: 25 Dec 06
#
# 1999/09/23: Modified by Shimazaki Ryo.
 
ifeq "$(TARGET)" "X68030"
COPT = -m68020-40
AOPT = -m68020
LDFLAGS = -L/usr/local/lib/lib060
endif
 
CC = gcc2
CFLAGS = $(COPT) -Wall -O2 -I. -fomit-frame-pointer -fstrength-reduce \
-DHAVE_TWONCALL_H -D__DOS_INLINE__ -DASM_CRC -DASM_INFLATECODES
#LDFLAGS = -Wl,-x
LIBS = -lhmem -lttyi -lsignal
 
AS = g2as
ASFLAGS = $(AOPT) -1 -c4 -y
 
# UnZipSFX flags
XC = -DSFX
 
# fUnZip flags
FC = -DFUNZIP
 
# object files
OBJS = unzip.o crc32.o crc_68.o crypt.o envargs.o explode.o extract.o \
fileio.o globals.o inflate.o flate.o list.o match.o process.o \
ttyio.o ubz2err.o unreduce.o unshrink.o zipinfo.o human68k.o
OBJX = unzipsfx.o crc32_.o crc_68.o crypt_.o extract_.o fileio_.o globals_.o \
inflate_.o flate_.o match_.o process_.o ttyio_.o ubz2err_.o human68k_.o
OBJF = funzip.o crc32f.o crc_68.o cryptf.o globalsf.o inflatef.o flatef.o \
ttyiof.o
 
UNZIP_H = unzip.h unzpriv.h globals.h
 
UNZIPS = unzip.x unzipsfx.x funzip.x
DOCS = unzip.txt unzipsfx.txt zipinfo.txt funzip.txt
 
.c.o:
$(CC) $(CFLAGS) -I. -c $< -o $@
 
# for debugging
.c.s:
$(CC) $(CFLAGS) -c $< -o $@
 
all: unzips
unzips: $(UNZIPS)
docs: $(DOCS)
unzipsman: unzips docs
unzipsdocs: unzips docs
 
clean:
rm -f $(OBJS) $(OBJF) $(OBJX) $(UNZIPS)
 
unzip.x: $(OBJS)
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
 
unzipsfx.x: $(OBJX)
$(CC) $(LDFLAGS) -o $@ $(OBJX) $(LIBS)
 
funzip.x: $(OBJF)
$(CC) $(LDFLAGS) -o $@ $(OBJF) $(LIBS)
 
crc32.o: crc32.c $(UNZIP_H) zip.h crc32.h
crypt.o: crypt.c $(UNZIP_H) zip.h crypt.h ttyio.h
envargs.o: envargs.c $(UNZIP_H)
explode.o: explode.c $(UNZIP_H)
extract.o: extract.c $(UNZIP_H) crc32.h crypt.h
fileio.o: fileio.c $(UNZIP_H) crc32.h crypt.h ttyio.h ebcdic.h
funzip.o: funzip.c $(UNZIP_H) crc32.h crypt.h ttyio.hh
globals.o: globals.c $(UNZIP_H)
inflate.o: inflate.c inflate.h $(UNZIP_H)
list.o: list.c $(UNZIP_H)
match.o: match.c $(UNZIP_H)
process.o: process.c $(UNZIP_H) crc32.h
ttyio.o: ttyio.c $(UNZIP_H) zip.h crypt.h ttyio.h
ubz2err.o: ubz2err.c $(UNZIP_H)
unreduce.o: unreduce.c $(UNZIP_H)
unshrink.o: unshrink.c $(UNZIP_H)
unzip.o: unzip.c $(UNZIP_H) crypt.h unzvers.h consts.h
zipinfo.o: zipinfo.c $(UNZIP_H)
 
 
# unzipsfx
crc32_.o: crc32.c $(UNZIP_H) zip.h crc32.h
$(CC) $(CFLAGS) $(XC) -c $< -o $@
 
crypt_.o: crypt.c $(UNZIP_H) zip.h crypt.h ttyio.h
$(CC) $(CFLAGS) $(XC) -c $< -o $@
 
extract_.o: extract.c $(UNZIP_H) crc32.h crypt.h
$(CC) $(CFLAGS) $(XC) -c $< -o $@
 
fileio_.o: fileio.c $(UNZIP_H) crc32.h crypt.h ttyio.h ebcdic.h
$(CC) $(CFLAGS) $(XC) -c $< -o $@
 
globals_.o: globals.c $(UNZIP_H)
$(CC) $(CFLAGS) $(XC) -c $< -o $@
 
inflate_.o: inflate.c inflate.h $(UNZIP_H) crypt.h
$(CC) $(CFLAGS) $(XC) -c $< -o $@
 
match_.o: match.c $(UNZIP_H)
$(CC) $(CFLAGS) $(XC) -c $< -o $@
 
process_.o: process.c $(UNZIP_H) crc32.h
$(CC) $(CFLAGS) $(XC) -c $< -o $@
 
ttyio_.o: ttyio.c $(UNZIP_H) zip.h crypt.h ttyio.h
$(CC) $(CFLAGS) $(XC) -c $< -o $@
 
ubz2err_.o: ubz2err.c $(UNZIP_H)
$(CC) $(CFLAGS) $(XC) -c $< -o $@
 
unzipsfx.o: unzip.c $(UNZIP_H) crypt.h unzvers.h consts.h
$(CC) $(CFLAGS) $(XC) -c $< -o $@
 
 
# funzip
crc32f.o: crc32.c $(UNZIP_H) zip.h crc32.h
$(CC) $(CFLAGS) $(FC) -c $< -o $@
 
cryptf.o: crypt.c $(UNZIP_H) zip.h crypt.h crc32.h ttyio.h
$(CC) $(CFLAGS) $(FC) -c $< -o $@
 
globalsf.o: globals.c $(UNZIP_H)
$(CC) $(CFLAGS) $(FC) -c $< -o $@
 
inflatef.o: inflate.c inflate.h $(UNZIP_H) crypt.h
$(CC) $(CFLAGS) $(FC) -c $< -o $@
 
ttyiof.o: ttyio.c $(UNZIP_H) zip.h crypt.h ttyio.h
$(CC) $(CFLAGS) $(FC) -c $< -o $@
 
 
human68k.o: human68k/human68k.c $(UNZIP_H)
$(CC) $(CFLAGS) -I. -c human68k/human68k.c -o $@
 
human68k_.o: human68k/human68k.c $(UNZIP_H) # unzipsfx
$(CC) $(CFLAGS) $(XC) -I. -c human68k/human68k.c -o $@
 
crc_68.o: human68k/crc_68.s
$(AS) $(ASFLAGS) $< -o $@
 
flate.o: human68k/flate.s human68k/g_offs.mac
$(AS) $(ASFLAGS) $< -o $@
 
flate_.o: human68k/flate.s human68k/g_offs_.mac # unzipsfx
$(AS) $(ASFLAGS) $< -o $@ -sSFX
 
flatef.o: human68k/flate.s human68k/g_offsf.mac # funzip
$(AS) $(ASFLAGS) $< -o $@ -sFUNZIP
 
human68k/g_offs.mac: human68k/gbloffs.x
human68k/mkgoff.x >! $@
 
human68k/g_offs_.mac: human68k/gbloffs_.x # unzipsfx
human68k/mkgoff_.x >! $@
 
human68k/g_offsf.mac: human68k/gbloffsf.x # funzip
human68k/mkgofff.x >! $@
 
human68k/gbloffs.x: gbloffs.c $(UNZIP_H) crypt.h
$(CC) $(CFLAGS) gbloffs.c -o $@
 
human68k/gbloffs_.x: gbloffs.c $(UNZIP_H) crypt.h # unzipsfx
$(CC) $(CFLAGS) gbloffs.c -o $@ $(XC)
 
human68k/gbloffsf.x: gbloffs.c $(UNZIP_H) crypt.h # funzip
$(CC) $(CFLAGS) gbloffs.c -o $@ $(FC)
 
# the test zipfile
TESTZIP = testmake.zip
 
# test some basic features of the build
test: check
 
check: unzips
@if test ! -f $(TESTZIP); then \
echo "##### ERROR: can't find test file $(TESTZIP)"; exit 1; fi
#
@echo "##### testing extraction"
@./unzip -bo $(TESTZIP) testmake.zipinfo
@if test ! -f testmake.zipinfo ; then \
echo "##### ERROR: file extraction from $(TESTZIP) failed"; \
exit 1; fi
#
@echo '##### testing zipinfo (unzip -Z)'
@./unzip -Z $(TESTZIP) > testmake.unzip-Z
@if diff testmake.unzip-Z testmake.zipinfo; then echo "OK."; else \
echo "##### WARNING: zipinfo output doesn't match stored version"; \
echo '##### (If the only difference is the file times, compare your'; \
echo '##### timezone with the Central European timezone, which is one'; \
echo '##### hour east of Greenwich but effectively 2 hours east'; \
echo '##### during summer Daylight Savings Time. The upper two'; \
echo '##### lines should correspond to your local time when the'; \
echo '##### files were created, on 19 November 1998 at 10:46pm CET.'; \
echo '##### If the times are consistent, please ignore this warning.)'; \
fi
@rm -f testmake.unzip-Z testmake.zipinfo
#
@echo '##### testing unzip -d exdir option'
@./unzip -bo $(TESTZIP) -d testun notes
@cat testun/notes
#
@echo '##### testing unzip -o and funzip (ignore funzip warning)'
@./unzip -boq $(TESTZIP) notes -d testun
@./funzip < $(TESTZIP) > testun/notes2
@if diff testun/notes testun/notes2; then true; else \
echo '##### ERROR: funzip output disagrees with unzip'; fi
#
@echo '##### testing unzipsfx (self-extractor)'
@cat unzipsfx.x $(TESTZIP) > testsfx.x
@chmod 0700 testsfx.x
@./testsfx -bo notes
@if diff notes testun/notes; then true; else \
echo '##### ERROR: unzipsfx file disagrees with unzip'; fi
@rm -f testsfx.x notes testun/notes testun/notes2
@rmdir testun
#
@echo '##### testing complete.'
 
# EOF
/programs/fs/unzip60/human68k/crc_68.s
0,0 → 1,144
;===========================================================================
; Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
;
; See the accompanying file LICENSE, version 2000-Apr-09 or later
; (the contents of which are also included in zip.h) for terms of use.
; If, for some reason, all these files are missing, the Info-ZIP license
; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
;===========================================================================
; crc_68 created by Paul Kienitz, last modified 04 Jan 96.
;
; Return an updated 32 bit CRC value, given the old value and a block of data.
; The CRC table used to compute the value is gotten by calling get_crc_table().
; This replaces the older updcrc() function used in Zip and fUnZip. The
; prototype of the function is:
;
; ulg crc32(ulg crcval, uch *text, extent textlen);
;
; On the Amiga, type extent is always unsigned long, not unsigned int, because
; int can be short or long at whim, but size_t is long.
;
; If using this source on a non-Amiga 680x0 system, note that we treat
; a0/a1/d0/d1 as scratch registers not preserved across function calls.
; We do not bother to support registerized arguments for crc32() -- the
; textlen parm is usually large enough so that savings outside the loop
; are pointless.
;
; Define NO_UNROLLED_LOOPS to use a simple short loop which might be more
; efficient on certain machines with dinky instruction caches ('020?), or for
; processing short strings. If loops are unrolled, the textlen parm must be
; less than 512K; if not unrolled, it must be less than 64K.
;
; 1999/09/23: for Human68k: Modified by Shimazaki Ryo.
 
xdef _crc32 ; (ulg val, uch *buf, extent bufsize)
 
DO_CRC0 MACRO
moveq #0,ltemp
move.b (textbuf)+,ltemp
eor.b crcval,ltemp
lsl.w #2,ltemp
move.l (crc_table,ltemp.w),ltemp
lsr.l #8,crcval
eor.l ltemp,crcval
ENDM
 
 
DO_CRC2 MACRO
move.b (textbuf)+,btemp
eor.b crcval,btemp
lsr.l #8,crcval
move.l (crc_table,btemp.w*4),ltemp
eor.l ltemp,crcval
ENDM
 
crc_table reg a0 array of unsigned long
crcval reg d0 unsigned long initial value
textbuf reg a1 array of unsigned char
textbufsize reg d1 unsigned long (count of bytes in textbuf)
btemp reg d2
ltemp reg d3
 
 
xref _get_crc_table ; ulg *get_crc_table(void)
 
 
 
quad
_crc32:
move.l 8(sp),d0
bne.s valid
;;;;; moveq #0,d0
rts
valid: movem.l btemp/ltemp,-(sp)
jsr _get_crc_table
movea.l d0,crc_table
move.l 12(sp),crcval
move.l 16(sp),textbuf
move.l 20(sp),textbufsize
not.l crcval
 
ifdef NO_UNROLLED_LOOPS
 
if CPU==68000
bra.s decr
loop: DO_CRC0
decr: dbra textbufsize,loop
bra.s done
 
else
twenty: moveq #0,btemp
bra.s decr2
loop2: DO_CRC2
decr2: dbra textbufsize,loop2
endif
 
ELSE ; !NO_UNROLLED_LOOPS
 
if CPU==68000
moveq #7,btemp
and textbufsize,btemp
lsr.l #3,textbufsize
bra decr8
loop8: DO_CRC0
DO_CRC0
DO_CRC0
DO_CRC0
DO_CRC0
DO_CRC0
DO_CRC0
DO_CRC0
decr8: dbra textbufsize,loop8
bra.s decr1
loop1: DO_CRC0
decr1: dbra btemp,loop1
bra done
 
else
twenty: moveq #0,btemp
move.l textbufsize,-(sp)
lsr.l #3,textbufsize
bra decr82
quad
loop82: DO_CRC2
DO_CRC2
DO_CRC2
DO_CRC2
DO_CRC2
DO_CRC2
DO_CRC2
DO_CRC2
decr82: dbra textbufsize,loop82
moveq #7,textbufsize
and.l (sp)+,textbufsize
bra.s decr12
loop12: DO_CRC2
decr12: dbra textbufsize,loop12
endif
 
ENDC ; ?NO_UNROLLED_LOOPS
 
done: movem.l (sp)+,btemp/ltemp
not.l crcval
;;;;; move.l crcval,d0 ; crcval already is d0
rts
/programs/fs/unzip60/human68k/flate.s
0,0 → 1,499
;===========================================================================
; Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
;
; See the accompanying file LICENSE, version 2000-Apr-09 or later
; (the contents of which are also included in unzip.h) for terms of use.
; If, for some reason, all these files are missing, the Info-ZIP license
; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
;===========================================================================
; flate.a created by Paul Kienitz, 20 June 94. Last modified 23 Mar 2002.
;
; 68000 assembly language version of inflate_codes(), for Amiga. Prototype:
;
; int inflate_codes(__GPRO__ struct huft *tl, struct huft *td,
; unsigned bl, unsigned bd);
;
; Where __GPRO__ expands to "Uz_Globs *G," if REENTRANT is defined,
; otherwise to nothing. In the latter case G is a global variable.
;
; Define the symbol FUNZIP if this is for fUnZip. It overrides REENTRANT.
;
; Define AZTEC to use the Aztec C macro version of getc() instead of the
; library getc() with FUNZIP. AZTEC is ignored if FUNZIP is not defined.
;
; Define NO_CHECK_EOF to not use the fancy paranoid version of NEEDBITS --
; this is equivalent to removing the #define CHECK_EOF from inflate.c.
;
; Define INT16 if ints are short, otherwise it assumes ints are long.
;
; Define USE_DEFLATE64 if we're supporting Deflate64 decompression.
;
; Do NOT define WSIZE; it is always 32K or 64K depending on USE_DEFLATE64.
;
; 1999/09/23: for Human68k: Modified by Shimazaki Ryo.
 
X: EQU $7ffe
 
IFDEF INT16
MOVINT MACRO _1,_2
move.w _1,_2
ENDM
INTSIZE equ 2
ELSE ; !INT16
MOVINT MACRO _1,_2
move.l _1,_2
ENDM
INTSIZE equ 4
ENDC
 
IFDEF REENTRANT
IFNDEF FUNZIP
REENT_G equ 1
ENDC
ENDC
 
; The following include file is generated from globals.h, and gives us equates
; that give the offsets in Uz_Globs of the fields we use, which are:
; ulg bb
; unsigned int bk, wp
; (either array of unsigned char, or pointer to unsigned char) redirslide
; For fUnZip:
; FILE *in
; For regular UnZip but not fUnZip:
; int incnt, mem_mode
; long csize
; uch *inptr
; It also defines a value SIZEOF_slide, which tells us whether the appropriate
; slide field in G (either area.Slide or redirect_pointer) is a pointer or an
; array instance. It is 4 in the former case and a large value in the latter.
; Lastly, this include will define CRYPT as 1 if appropriate.
 
IFDEF FUNZIP
INCLUDE human68k/G_offs_.mac
ELSE
IFDEF SFX
INCLUDE human68k/G_offsf.mac"
ELSE
INCLUDE human68k/G_offs.mac
ENDC
ENDC
 
; struct huft is defined as follows:
;
; struct huft {
; uch e; /* number of extra bits or operation */
; uch b; /* number of bits in this code or subcode */
; union {
; ush n; /* literal, length base, or distance base */
; struct huft *t; /* pointer to next level of table */
; } v;
; }; /* sizeof(struct huft) == 6 */
;
; The G_offs include defines offsets h_e, h_b, h_v_n, and h_v_t in this
; struct, plus SIZEOF_huft.
 
; G.bb is the global buffer that holds bits from the huffman code stream, which
; we cache in the register variable b. G.bk is the number of valid bits in it,
; which we cache in k. The macros NEEDBITS(n) and DUMPBITS(n) have side effects
; on b and k.
 
IFDEF REENT_G
G_SIZE equ 4
G_PUSH MACRO ; this macro passes "__G__" to functions
move.l G,-(sp)
ENDM
ELSE
xref _G ; Uz_Globs
G_SIZE equ 0
G_PUSH MACRO
ds.b 0 ; does nothing; the assembler dislikes MACRO ENDM
ENDM
ENDC ; REENT_G
 
;; xref _mask_bits ; const unsigned mask_bits[17];
IFDEF FUNZIP
IF CRYPT
xref _encrypted ; int -- boolean flag
xref _update_keys ; int update_keys(__GPRO__ int)
xref _decrypt_byte ; int decrypt_byte(__GPRO)
ENDC ; CRYPT
ELSE ; !FUNZIP
xref _memflush ; int memflush(__GPRO__ uch *, ulg)
xref _readbyte ; int readbyte(__GPRO)
ENDC ; FUNZIP
 
xref _flush ; if FUNZIP: int flush(__GPRO__ ulg)
; else: int flush(__GPRO__ uch *, ulg, int)
 
; Here are our register variables.
 
b reg d2 ; unsigned long
k reg d3 ; unsigned short <= 32
e reg d4 ; unsigned int, mostly used as unsigned char
w reg d5 ; unsigned long (was short before deflate64)
n reg d6 ; unsigned long (was short before deflate64)
d reg d7 ; unsigned int, used as unsigned short
 
t reg a2 ; struct huft *
lmask reg a3 ; ulg *
G reg a6 ; Uz_Globs *
 
; Couple other items we need:
 
savregs reg d2-d7/a2/a3/a6
IFDEF USE_DEFLATE64
WSIZE equ $10000 ; 64K... be careful not to treat as short!
ELSE
WSIZE equ $08000 ; 32K... be careful not to treat as negative!
ENDC
EOF equ -1
INVALID equ 99
 
; inflate_codes() returns one of the following status codes:
; 0 OK
; 1 internal inflate error or EOF on input stream
; the following return codes are passed through from FLUSH() errors
; 50 (PK_DISK) "overflow of output space"
; 80 (IZ_CTRLC) "canceled by user's request"
 
RET_OK equ 0
RET_ERR equ 1
 
IFDEF FUNZIP
; This does getc(in). LIBC version is based on #define getc(fp) in stdio.h
 
GETC MACRO
xref _fgetc ; int fgetc(FILE *)
move.l in-X(G),-(sp)
jsr _fgetc
addq.l #4,sp
ENDM
ENDC ; FUNZIP
 
; Input depends on the NEXTBYTE macro. This exists in three different forms.
; The first two are for fUnZip, with and without decryption. The last is for
; regular UnZip with or without decryption. The resulting byte is returned
; in d0 as a longword, and d1, a0, and a1 are clobbered.
 
; FLUSH also has different forms for UnZip and fUnZip. Arg must be a longword.
; The same scratch registers are trashed.
 
IFDEF FUNZIP
 
NEXTBYTE MACRO
move.l d2,-(sp)
GETC
IF CRYPT
tst.w _encrypted+INTSIZE-2 ; test low word if long
beq.s @nbe
MOVINT d0,-(sp) ; save thru next call
G_PUSH
jsr _decrypt_byte
eor.w d0,G_SIZE+INTSIZE-2(sp) ; becomes arg to update_keys
jsr _update_keys
addq #INTSIZE+G_SIZE,sp
@nbe:
ENDC ; !CRYPT
IFEQ INTSIZE-2
ext.l d0 ; assert -1 <= d0 <= 255
ENDC
move.l (sp)+,d2
ENDM
 
FLUSH MACRO _1
move.l d2,-(sp)
move.l _1,-(sp)
G_PUSH
jsr _flush
addq #4+G_SIZE,sp
move.l (sp)+,d2
ENDM
 
ELSE ; !FUNZIP
 
NEXTBYTE MACRO
subq.w #1,incnt+INTSIZE-2-X(G) ; treat as short
bge.s @nbs
IFNE INTSIZE-2
subq.w #1,incnt-X(G)
bge.s @nbs
ENDIF
move.l d2,-(sp)
G_PUSH
jsr _readbyte
IFNE G_SIZE
addq #G_SIZE,sp
ENDC
move.l (sp)+,d2
IFEQ 2-INTSIZE
ext.l d0 ; assert -1 <= d0 <= 255
ENDC
bra.s @nbe
@nbs: moveq #0,d0
move.l inptr-X(G),a0
move.b (a0)+,d0
move.l a0,inptr-X(G)
@nbe:
ENDM
 
FLUSH MACRO _1
move.l d2,-(sp)
clr.l -(sp) ; unshrink flag: always false
move.l _1,-(sp) ; length
IF SIZEOF_slide>4
pea redirslide-X(G) ; buffer to flush
ELSE
move.l redirslide-X(G),-(sp)
ENDC
G_PUSH
tst.w mem_mode+INTSIZE-2-X(G) ; test lower word if long
beq.s @fm
jsr _memflush ; ignores the unshrink flag
bra.s @fe
@fm: jsr _flush
@fe: lea 8+INTSIZE+G_SIZE(sp),sp
move.l (sp)+,d2
ENDM
 
ENDC ; ?FUNZIP
 
; Here are the two bit-grabbing macros, defined in their NO_CHECK_EOF form:
;
; #define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE)<<k;k+=8;}}
; #define DUMPBITS(n) {b>>=(n);k-=(n);}
;
; Without NO_CHECK_EOF, NEEDBITS reads like this:
;
; {while((int)k<(int)(n)){int c=NEXTBYTE;
; if(c==EOF){if((int)k>=0)break;return 1};
; b|=((ulg)c)<<k;k+=8;}}
;
; NEEDBITS clobbers d0, d1, a0, and a1, none of which can be used as the arg to
; the macro specifying the number of bits. The arg can be a shortword memory
; address, or d2-d7. The result is copied into d1 as a word ready for masking.
; DUMPBITS has no side effects; the arg must be a d-register (or immediate in
; the range 1-8?) and only the lower byte is significant.
 
NEEDBITS MACRO _1
@nb: cmp.w _1,k ; assert 0 < k <= 32 ... arg may be 0
bge.s @ne ; signed compare!
@loop:
NEXTBYTE ; returns in d0.l
IFNDEF NO_CHECK_EOF
cmp.w #EOF,d0
bne.s @nok
tst.w k
bge.s @ne
bra error_return
ENDC ; !NO_CHECK_EOF
@nok: lsl.l k,d0
or.l d0,b
addq.w #8,k
cmp.w _1,k ;bra.s @nb
bcs @loop ;
@ne: move.l b,d1 ; return a copy of b in d1
ENDM
 
DUMPBITS MACRO _1
lsr.l _1,b ; upper bits of _1 are ignored??
sub.b _1,k
ENDM
 
 
; This is a longword version of the mask_bits constant array:
longmasks: dc.l $00000000,$00000001,$00000003,$00000007,$0000000F
dc.l $0000001F,$0000003F,$0000007F,$000000FF,$000001FF
dc.l $000003FF,$000007FF,$00000FFF,$00001FFF,$00003FFF
dc.l $00007FFF,$0000FFFF,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 
 
; ******************************************************************************
; Here we go, finally:
 
xdef _inflate_codes
 
_inflate_codes:
link a5,#-8
movem.l savregs,-(sp)
; 8(a5) = tl, 12(a5) = td, 16(a5) = bl, 18|20(a5) = bd... add 4 for REENT_G
; -4(a5) = ml, -8(a5) = md, both unsigned long.
; Here we cache some globals and args:
IFDEF REENT_G
move.l 8(a5),G
ELSE
lea _G,G ; G is now a global instance
IFDEF X
lea (X,G),G
ENDIF
ENDC
lea longmasks,lmask
move.l bb-X(G),b
MOVINT bk-X(G),k
IFDEF INT16
moveq #0,w ; keep this usable as longword
ENDC
MOVINT wp-X(G),w
moveq #0,e ; keep this usable as longword too
MOVINT 16+G_SIZE(a5),d0
asl.w #2,d0
move.l (lmask,d0.w),-4(a5) ; ml = mask_bits[bl]
MOVINT 16+INTSIZE+G_SIZE(a5),d0
asl.w #2,d0
move.l (lmask,d0.w),-8(a5) ; md = mask_bits[bd]
 
main_loop:
NEEDBITS 14+INTSIZE+G_SIZE(a5) ; (unsigned) bl
and.l -4(a5),d1 ; ml
IFNE SIZEOF_huft-8
mulu #SIZEOF_huft,d1
ELSE
asl.l #3,d1
ENDC
move.l 8+G_SIZE(a5),t ; tl
add.l d1,t
newtop: move.b h_b(t),d0
DUMPBITS d0
move.b h_e(t),e
cmp.b #32,e ; is it a literal?
bne nonlit ; no
move.w h_v_n(t),d0 ; yes
IFGT SIZEOF_slide-4
lea redirslide-X(G),a0
ELSE
move.l redirslide-X(G),a0
ENDC
move.b d0,(a0,w.l) ; stick in the decoded byte
addq.l #1,w
cmp.l #WSIZE,w
blo main_loop
FLUSH w
ext.l d0 ; does a test as it casts long
bne return
moveq #0,w
bra main_loop ; break (newtop loop)
 
nonlit: cmp.b #31,e ; is it a length?
beq finish ; no, it's the end marker
bhi nonleng ; no, it's something else
NEEDBITS e ; yes: a duplicate string
move.w e,d0
asl.w #2,d0
and.l (lmask,d0.w),d1
moveq #0,n ; cast h_v_n(t) to long
move.w h_v_n(t),n
add.l d1,n ; length of block to copy
DUMPBITS e
NEEDBITS 14+(2*INTSIZE)+G_SIZE(a5) ; bd, lower word if long
and.l -8(a5),d1 ; md
IFNE SIZEOF_huft-8
mulu #SIZEOF_huft,d1
ELSE
asl.l #3,d1
ENDC
move.l 12+G_SIZE(a5),t ; td
add.l d1,t
distop: move.b h_b(t),d0
DUMPBITS d0
move.b h_e(t),e
cmp.b #32,e ; is it a literal?
blo.s disbrk ; then stop doing this
cmp.b #INVALID,e ; is it bogus?
bne.s disgo
bra error_return ; then fail
disgo: and.w #$001F,e
NEEDBITS e
move.w e,d0
asl.w #2,d0
and.l (lmask,d0.w),d1
IFNE SIZEOF_huft-8
mulu #SIZEOF_huft,d1
ELSE
asl.l #3,d1
ENDC
move.l h_v_t(t),t
add.l d1,t
bra distop
disbrk: NEEDBITS e
move.l e,d0
asl.w #2,d0
and.l (lmask,d0.w),d1
move.l w,d
move.w h_v_n(t),d0 ; assert top word of d0 is zero
sub.l d0,d
sub.l d1,d ; distance back to copy the block
DUMPBITS e
 
docopy: move.l #WSIZE,e ; copy the duplicated string
and.l #WSIZE-1,d ; ...but first check if the length
cmp.l d,w ; will overflow the window...
blo.s ddgw
sub.l w,e
bra.s dadw
ddgw: sub.l d,e
dadw: cmp.l #$08000,e ; also, only copy <= 32K, so we can
bls.s dnox ; use a dbra loop to do it
move.l #$08000,e
dnox: cmp.l n,e
bls.s delen
move.l n,e
delen: sub.l e,n ; size of sub-block to copy in this pass
IF SIZEOF_slide>4
lea redirslide-X(G),a0
ELSE
move.l redirslide-X(G),a0
ENDC
move.l a0,a1
add.l w,a0 ; w and d are valid longwords
add.l d,a1
; Now at this point we could do tests to see if we should use an optimized
; large block copying method such as movem's, but since (a) such methods require
; the source and destination to be compatibly aligned -- and odd bytes at each
; end have to be handled separately, (b) it's only worth checking for if the
; block is pretty large, and (c) most strings are only a few bytes long, we're
; just not going to bother. Therefore we check above to make sure we move at
; most 32K in one sub-block, so a dbra loop can handle it.
dshort: move.l e,d0
subq #1,d0 ; assert >= 0
dspin: move.b (a1)+,(a0)+
dbra d0,dspin
add.l e,w
add.l e,d
cmp.l #WSIZE,w
blo.s dnfl
FLUSH w
ext.l d0 ; does a test as it casts to long
bne return
moveq #0,w
dnfl: tst.l n ; need to do more sub-blocks?
bne docopy ; yes
moveq #0,e ; restore zeroness in upper bytes of e
bra main_loop ; break (newtop loop)
 
nonleng: cmp.w #INVALID,e ; bottom of newtop loop -- misc. code
bne.s tailgo ; invalid code?
bra error_return ; then fail
tailgo: and.w #$001F,e
NEEDBITS e
move.w e,d0
asl.w #2,d0
and.l (lmask,d0.w),d1
IFNE SIZEOF_huft-8
mulu #SIZEOF_huft,d1
ELSE
asl.l #3,d1
ENDC
move.l h_v_t(t),t
add.l d1,t
bra newtop
 
finish: MOVINT w,wp-X(G) ; done: restore cached globals
MOVINT k,bk-X(G)
move.l b,bb-X(G)
moveq #RET_OK,d0 ; return "no error"
return: movem.l (sp)+,savregs
unlk a5
rts
 
error_return:
moveq #RET_ERR,d0 ; return "error occured"
bra return
/programs/fs/unzip60/human68k/human68k.c
0,0 → 1,976
/*
Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
 
See the accompanying file LICENSE, version 2000-Apr-09 or later
(the contents of which are also included in unzip.h) for terms of use.
If, for some reason, all these files are missing, the Info-ZIP license
also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
*/
/*---------------------------------------------------------------------------
 
human68k.c
 
Human68k-specific routines for use with Info-ZIP's UnZip 5.41 and later.
 
Contains: do_wild()
mapattr()
mapname()
checkdir()
close_outfile()
stamp_file() (TIMESTAMP only)
version()
main() (for UnZipSFX)
 
---------------------------------------------------------------------------*/
 
 
#include <dirent.h>
#include <string.h>
#include <sys/dos.h>
#include <sys/xunistd.h>
#ifdef HAVE_TWONCALL_H
#include <twoncall.h>
#endif
#define UNZIP_INTERNAL
#include "unzip.h"
 
#if defined (SFX) && defined (MAIN)
#include <sys/xstart.h>
int MAIN(int argc, char *argv[]);
#endif
 
static void map2fat(char *pathcomp, char *last_dot);
static char *trunc_name(char *name, int maxlen);
 
static int created_dir; /* used in mapname(), checkdir() */
static int renamed_fullpath; /* ditto */
 
static char multi_period, special_char;
 
#ifndef SFX
 
/**********************/
/* Function do_wild() */
/**********************/
 
char *do_wild(__G__ wildspec)
__GDEF
ZCONST char *wildspec; /* only used first time on a given dir */
{
static DIR *wild_dir = (DIR *)NULL;
static ZCONST char *wildname;
static char *dirname, matchname[FILNAMSIZ];
static int notfirstcall=FALSE, have_dirname, dirnamelen;
struct dirent *file;
 
/* Even when we're just returning wildspec, we *always* do so in
* matchname[]--calling routine is allowed to append four characters
* to the returned string, and wildspec may be a pointer to argv[].
*/
if (!notfirstcall) { /* first call: must initialize everything */
notfirstcall = TRUE;
 
if (!iswild(wildspec)) {
strncpy(matchname, wildspec, FILNAMSIZ);
matchname[FILNAMSIZ-1] = '\0';
have_dirname = FALSE;
wild_dir = (DIR *)NULL;
return matchname;
}
 
/* break the wildspec into a directory part and a wildcard filename */
if ((wildname = strrchr(wildspec, '/')) == NULL) {
dirname = ".";
dirnamelen = 1;
have_dirname = FALSE;
wildname = wildspec;
} else {
++wildname; /* point at character after '/' */
dirnamelen = wildname - wildspec;
if ((dirname = (char *)malloc(dirnamelen+1)) == NULL) {
Info(slide, 1, ((char *)slide,
"warning: cannot allocate wildcard buffers\n"));
strcpy(matchname, wildspec);
return matchname; /* but maybe filespec was not a wildcard */
}
strncpy(dirname, wildspec, dirnamelen);
dirname[dirnamelen] = '\0'; /* terminate for strcpy below */
have_dirname = TRUE;
}
Trace((stderr, "do_wild: dirname = [%s]\n", FnFilter1(dirname)));
 
if ((wild_dir = opendir(dirname)) != (DIR *)NULL) {
while ((file = readdir(wild_dir)) != (struct dirent *)NULL) {
Trace((stderr, "do_wild: readdir returns %s\n",
FnFilter1(file->d_name)));
if (file->d_name[0] == '.' && wildname[0] != '.')
continue; /* Unix: '*' and '?' do not match leading dot */
if (match(file->d_name, wildname, 0 WISEP) && /* 0=case sens.*/
/* skip "." and ".." directory entries */
strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) {
Trace((stderr, "do_wild: match() succeeds\n"));
if (have_dirname) {
strcpy(matchname, dirname);
strcpy(matchname+dirnamelen, file->d_name);
} else
strcpy(matchname, file->d_name);
return matchname;
}
}
/* if we get to here directory is exhausted, so close it */
closedir(wild_dir);
wild_dir = (DIR *)NULL;
}
#ifdef DEBUG
else {
Trace((stderr, "do_wild: Opendir(%s) returns NULL\n",
FnFilter1(dirname)));
}
#endif /* DEBUG */
 
/* return the raw wildspec in case that works (e.g., directory not
* searchable, but filespec was not wild and file is readable) */
strncpy(matchname, wildspec, FILNAMSIZ);
matchname[FILNAMSIZ-1] = '\0';
return matchname;
}
 
/* last time through, might have failed opendir but returned raw wildspec */
if (wild_dir == (DIR *)NULL) {
notfirstcall = FALSE; /* nothing left to try--reset for new wildspec */
if (have_dirname)
free(dirname);
return (char *)NULL;
}
 
/* If we've gotten this far, we've read and matched at least one entry
* successfully (in a previous call), so dirname has been copied into
* matchname already.
*/
while ((file = readdir(wild_dir)) != (struct dirent *)NULL) {
Trace((stderr, "do_wild: readdir returns %s\n",
FnFilter1(file->d_name)));
if (file->d_name[0] == '.' && wildname[0] != '.')
continue; /* Unix: '*' and '?' do not match leading dot */
if (match(file->d_name, wildname, 0 WISEP)) { /* 0 == case sens. */
Trace((stderr, "do_wild: match() succeeds\n"));
if (have_dirname) {
/* strcpy(matchname, dirname); */
strcpy(matchname+dirnamelen, file->d_name);
} else
strcpy(matchname, file->d_name);
return matchname;
}
}
 
closedir(wild_dir); /* have read at least one entry; nothing left */
wild_dir = (DIR *)NULL;
notfirstcall = FALSE; /* reset for new wildspec */
if (have_dirname)
free(dirname);
return (char *)NULL;
 
} /* end function do_wild() */
 
#endif /* !SFX */
 
 
 
 
/**********************/
/* Function mapattr() */
/**********************/
 
int mapattr(__G)
__GDEF
{
ulg tmp = G.crec.external_file_attributes;
 
switch (G.pInfo->hostnum) {
case UNIX_:
if (tmp & 0xff)
break;
/* fall through */
case VMS_:
case ACORN_:
case ATARI_:
case ATHEOS_:
case BEOS_:
case QDOS_:
G.pInfo->file_attr = _mode2dos(tmp >> 16);
return 0;
default:
break;
}
 
/* set archive bit (file is not backed up) */
if((tmp & 0x08) == 0)
tmp |= 0x20;
G.pInfo->file_attr = tmp & 0xff;
return 0;
 
} /* end function mapattr() */
 
 
 
 
 
/**********************/
/* Function mapname() */
/**********************/
 
int mapname(__G__ renamed)
__GDEF
int renamed;
/*
* returns:
* MPN_OK - no problem detected
* MPN_INF_TRUNC - caution (truncated filename)
* MPN_INF_SKIP - info "skip entry" (dir doesn't exist)
* MPN_ERR_SKIP - error -> skip entry
* MPN_ERR_TOOLONG - error -> path is too long
* MPN_NOMEM - error (memory allocation failed) -> skip entry
* [also MPN_VOL_LABEL, MPN_CREATED_DIR]
*/
{
char pathcomp[FILNAMSIZ]; /* path-component buffer */
char *pp, *cp=(char *)NULL; /* character pointers */
char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
char *last_dot=(char *)NULL; /* last dot */
int error = MPN_OK;
register unsigned workch; /* hold the character being tested */
 
#ifdef HAVE_TWONCALL_H
static char twentyone_flag;
 
/* Get TwentyOne options */
if (twentyone_flag == 0) {
twentyone_flag++;
if (GetTwentyOneID () == TWON_ID) {
int flags = GetTwentyOneOptions ();
 
if (flags & (1 << TWON_PERIOD_BIT))
multi_period = TRUE;
if (flags & (1 << TWON_SPECIAL_BIT))
special_char = TRUE;
}
}
#endif
 
/*---------------------------------------------------------------------------
Initialize various pointers and counters and stuff.
---------------------------------------------------------------------------*/
 
/* can create path as long as not just freshening, or if user told us */
G.create_dirs = (!uO.fflag || renamed);
 
created_dir = FALSE; /* not yet */
renamed_fullpath = FALSE;
 
if (renamed) {
cp = G.filename - 1; /* point to beginning of renamed name... */
while (*++cp)
if (*cp == '\\') /* convert backslashes to forward */
*cp = '/';
cp = G.filename;
if ((G.filename[0] == '/')
|| (isalpha(G.filename[0]) && G.filename[1] == ':')) {
/* user gave full pathname: don't prepend rootpath */
renamed_fullpath = TRUE;
}
}
 
if ((error = checkdir(__G__ (char *)NULL, INIT)) != 0)
return error; /* initialize path buffer, unless no memory */
 
*pathcomp = '\0'; /* initialize translation buffer */
pp = pathcomp; /* point to translation buffer */
if (uO.jflag) /* junking directories */
cp = (char *)strrchr(G.filename, '/');
if (cp == (char *)NULL) /* no '/' or not junking dirs */
cp = G.filename; /* point to internal zipfile-member pathname */
else
++cp; /* point to start of last component of path */
 
/*---------------------------------------------------------------------------
Begin main loop through characters in filename.
---------------------------------------------------------------------------*/
 
while ((workch = (uch)*cp++) != 0) {
 
if (_ismbblead((unsigned char)workch)) {
if (*cp) {
*pp++ = (char)workch;
*pp++ = (char)*cp++;
}
else
*pp++ = '_';
continue;
}
 
switch (workch) {
case '/': /* can assume -j flag not given */
*pp = '\0';
map2fat(pathcomp, last_dot); /* 18.3 trunc. (in place) */
if (strcmp(pathcomp, ".") == 0) {
/* don't bother appending "./" to the path */
*pathcomp = '\0';
} else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
/* "../" dir traversal detected, skip over it */
*pathcomp = '\0';
killed_ddot = TRUE; /* set "show message" flag */
}
/* when path component is not empty, append it now */
if (*pathcomp != '\0' &&
((error = checkdir(__G__ pathcomp, APPEND_DIR))
& MPN_MASK) > MPN_INF_TRUNC)
return error;
pp = pathcomp; /* reset conversion buffer for next piece */
lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
break;
 
/* drive names are not stored in zipfile, so no colons allowed;
* no brackets or most other punctuation either (all of which
* can appear in Unix-created archives; backslash is particularly
* bad unless all necessary directories exist) */
 
case '[': /* these punctuation characters forbidden */
case ']': /* only on plain FAT file systems */
case '+':
case ',':
case '=':
case '<':
case '>':
case '|':
case '\"':
case '\'':
if (!special_char)
workch = '_';
*pp++ = (char)workch;
break;
 
case '-':
if (pp == pathcomp && !special_char)
workch = '_';
*pp++ = (char)workch;
break;
 
case ':':
case '\\':
case '*':
case '?':
*pp++ = '_';
break;
 
case ';': /* VMS version (or DEC-20 attrib?) */
lastsemi = pp;
if (!special_char)
workch = '_';
*pp++ = (char)workch; /* keep for now; remove VMS ";##" */
break; /* later, if requested */
 
case ' ': /* change spaces to underscores */
#if 0 /* do it always */
if (uO.sflag) /* only if requested */
#endif
workch = '_';
*pp++ = (char)workch;
break;
 
default:
/* allow European characters in filenames: */
if (isprint(workch) || workch >= 128)
*pp++ = (char)workch;
 
} /* end switch */
} /* end while loop */
 
/* Show warning when stripping insecure "parent dir" path components */
if (killed_ddot && QCOND2) {
Info(slide, 0, ((char *)slide,
"warning: skipped \"../\" path component(s) in %s\n",
FnFilter1(G.filename)));
if (!(error & ~MPN_MASK))
error = (error & MPN_MASK) | PK_WARN;
}
 
/*---------------------------------------------------------------------------
Report if directory was created (and no file to create: filename ended
in '/'), check name to be sure it exists, and combine path and name be-
fore exiting.
---------------------------------------------------------------------------*/
 
if (G.filename[strlen(G.filename) - 1] == '/') {
checkdir(__G__ G.filename, GETPATH);
if (created_dir) {
if (QCOND2) {
Info(slide, 0, ((char *)slide, " creating: %s\n",
FnFilter1(G.filename)));
}
/* set dir time (note trailing '/') */
return (error & ~MPN_MASK) | MPN_CREATED_DIR;
}
/* dir existed already; don't look for data to extract */
return (error & ~MPN_MASK) | MPN_INF_SKIP;
}
 
*pp = '\0'; /* done with pathcomp: terminate it */
 
/* if not saving them, remove VMS version numbers (appended ";###") */
if (!uO.V_flag && lastsemi) {
pp = lastsemi + 1;
while (isdigit((uch)(*pp)))
++pp;
if (*pp == '\0') /* only digits between ';' and end: nuke */
*lastsemi = '\0';
}
 
map2fat(pathcomp, last_dot); /* 18.3 truncation (in place) */
 
if (*pathcomp == '\0') {
Info(slide, 1, ((char *)slide, "mapname: conversion of %s failed\n",
FnFilter1(G.filename)));
return (error & ~MPN_MASK) | MPN_ERR_SKIP;
}
 
checkdir(__G__ pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */
checkdir(__G__ G.filename, GETPATH);
 
if (G.pInfo->vollabel) { /* set the volume label now */
int fd;
 
if (QCOND2)
Info(slide, 0, ((char *)slide, " labelling: %s\n",
FnFilter1(G.filename)));
if ((fd = _dos_newfile(G.filename, G.pInfo->file_attr)) < 0) {
Info(slide, 1, ((char *)slide,
"mapname: error setting volume label\n"));
return (error & ~MPN_MASK) | MPN_ERR_SKIP;
}
_dos_close(fd);
/* success: skip the "extraction" quietly */
return (error & ~MPN_MASK) | MPN_INF_SKIP;
}
 
return error;
 
} /* end function mapname() */
 
 
 
 
/**********************/
/* Function map2fat() */
/**********************/
 
static void map2fat(pathcomp, last_dot)
char *pathcomp, *last_dot;
{
char *np;
 
if (pathcomp == last_dot) { /* dotfile(e.g. ".foo") */
pathcomp = last_dot;
last_dot = (char *)NULL;
}
 
if (multi_period) {
if (strlen(pathcomp) <= 18)
return;
}
else {
char *p;
 
for (p = pathcomp; *p; p++)
if (*p == (char)'.' && p != last_dot)
*p = '_';
}
 
if (last_dot) {
*last_dot++ = '\0';
trunc_name(last_dot, 3);
}
np = trunc_name(pathcomp, 18);
if (last_dot) {
*--last_dot = '.';
if (np)
strcpy(np, last_dot);
}
 
} /* end function map2fat() */
 
static char *trunc_name(char *name, int maxlen)
{
 
if (strlen(name) <= maxlen)
return (char *)NULL;
 
do {
if (_ismbblead((unsigned char)*name)) {
if (--maxlen == 0)
break;
name++;
}
name++;
maxlen--;
} while (maxlen > 0);
*name = '\0';
 
return name;
}
 
 
 
 
/***********************/
/* Function checkdir() */
/***********************/
 
int checkdir(__G__ pathcomp, flag)
__GDEF
char *pathcomp;
int flag;
/*
* returns:
* MPN_OK - no problem detected
* MPN_INF_TRUNC - (on APPEND_NAME) truncated filename
* MPN_INF_SKIP - path doesn't exist, not allowed to create
* MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path
* exists and is not a directory, but is supposed to be
* MPN_ERR_TOOLONG - path is too long
* MPN_NOMEM - can't allocate memory for filename buffers
*/
{
static int rootlen = 0; /* length of rootpath */
static char *rootpath; /* user's "extract-to" directory */
static char *buildpath; /* full path (so far) to extracted file */
static char *end; /* pointer to end of buildpath ('\0') */
 
# define FN_MASK 7
# define FUNCTION (flag & FN_MASK)
 
 
/*---------------------------------------------------------------------------
APPEND_DIR: append the path component to the path being built and check
for its existence. If doesn't exist and we are creating directories, do
so for this one; else signal success or error as appropriate.
---------------------------------------------------------------------------*/
 
if (FUNCTION == APPEND_DIR) {
int too_long = FALSE;
 
Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
while ((*end = *pathcomp++) != '\0')
++end;
 
/* GRR: could do better check, see if overrunning buffer as we go:
* check end-buildpath after each append, set warning variable if
* within 20 of FILNAMSIZ; then if var set, do careful check when
* appending. Clear variable when begin new path. */
 
if ((end-buildpath) > FILNAMSIZ-3) /* need '/', one-char name, '\0' */
too_long = TRUE; /* check if extracting directory? */
if (SSTAT(buildpath, &G.statbuf)) /* path doesn't exist */
{
if (!G.create_dirs) { /* told not to create (freshening) */
free(buildpath);
return MPN_INF_SKIP; /* path doesn't exist: nothing to do */
}
if (too_long) {
Info(slide, 1, ((char *)slide,
"checkdir error: path too long: %s\n",
FnFilter1(buildpath)));
free(buildpath);
/* no room for filenames: fatal */
return MPN_ERR_TOOLONG;
}
if (mkdir(buildpath, 0777) == -1) { /* create the directory */
Info(slide, 1, ((char *)slide,
"checkdir error: cannot create %s\n\
unable to process %s.\n",
FnFilter2(buildpath), FnFilter1(G.filename)));
free(buildpath);
/* path didn't exist, tried to create, failed */
return MPN_ERR_SKIP;
}
created_dir = TRUE;
} else if (!S_ISDIR(G.statbuf.st_mode)) {
Info(slide, 1, ((char *)slide,
"checkdir error: %s exists but is not directory\n\
unable to process %s.\n",
FnFilter2(buildpath), FnFilter1(G.filename)));
free(buildpath);
/* path existed but wasn't dir */
return MPN_ERR_SKIP;
}
if (too_long) {
Info(slide, 1, ((char *)slide,
"checkdir error: path too long: %s\n", FnFilter1(buildpath)));
free(buildpath);
/* no room for filenames: fatal */
return MPN_ERR_TOOLONG;
}
*end++ = '/';
*end = '\0';
Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
return MPN_OK;
 
} /* end if (FUNCTION == APPEND_DIR) */
 
/*---------------------------------------------------------------------------
GETPATH: copy full path to the string pointed at by pathcomp, and free
buildpath.
---------------------------------------------------------------------------*/
 
if (FUNCTION == GETPATH) {
strcpy(pathcomp, buildpath);
Trace((stderr, "getting and freeing path [%s]\n",
FnFilter1(pathcomp)));
free(buildpath);
buildpath = end = (char *)NULL;
return MPN_OK;
}
 
/*---------------------------------------------------------------------------
APPEND_NAME: assume the path component is the filename; append it and
return without checking for existence.
---------------------------------------------------------------------------*/
 
if (FUNCTION == APPEND_NAME) {
 
Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
while ((*end = *pathcomp++) != '\0') {
++end;
if ((end-buildpath) >= FILNAMSIZ) {
*--end = '\0';
Info(slide, 1, ((char *)slide,
"checkdir warning: path too long; truncating\n\
%s\n -> %s\n",
FnFilter1(G.filename), FnFilter2(buildpath)));
return MPN_INF_TRUNC; /* filename truncated */
}
}
Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
/* could check for existence here, prompt for new name... */
return MPN_OK;
}
 
/*---------------------------------------------------------------------------
INIT: allocate and initialize buffer space for the file currently being
extracted. If file was renamed with an absolute path, don't prepend the
extract-to path.
---------------------------------------------------------------------------*/
 
if (FUNCTION == INIT) {
Trace((stderr, "initializing buildpath to "));
/* allocate space for full filename, root path, and maybe "./" */
if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+3)) ==
(char *)NULL)
return MPN_NOMEM;
if ((rootlen > 0) && !renamed_fullpath) {
strcpy(buildpath, rootpath);
end = buildpath + rootlen;
} else {
*buildpath = '\0';
end = buildpath;
}
Trace((stderr, "[%s]\n", FnFilter1(buildpath)));
return MPN_OK;
}
 
/*---------------------------------------------------------------------------
ROOT: if appropriate, store the path in rootpath and create it if neces-
sary; else assume it's a zipfile member and return. This path segment
gets used in extracting all members from every zipfile specified on the
command line.
---------------------------------------------------------------------------*/
 
#if (!defined(SFX) || defined(SFX_EXDIR))
if (FUNCTION == ROOT) {
Trace((stderr, "initializing root path to [%s]\n",
FnFilter1(pathcomp)));
if (pathcomp == (char *)NULL) {
rootlen = 0;
return MPN_OK;
}
if (rootlen > 0) /* rootpath was already set, nothing to do */
return MPN_OK;
if ((rootlen = strlen(pathcomp)) > 0) {
int had_trailing_pathsep=FALSE, has_drive=FALSE, add_dot=FALSE;
char *tmproot;
 
if ((tmproot = (char *)malloc(rootlen+3)) == (char *)NULL) {
rootlen = 0;
return MPN_NOMEM;
}
strcpy(tmproot, pathcomp);
if (isalpha((uch)tmproot[0]) && tmproot[1] == ':')
has_drive = TRUE; /* drive designator */
if (tmproot[rootlen-1] == '/' || tmproot[rootlen-1] == '\\') {
tmproot[--rootlen] = '\0';
had_trailing_pathsep = TRUE;
}
if (has_drive && (rootlen == 2)) {
if (!had_trailing_pathsep) /* i.e., original wasn't "x:/" */
add_dot = TRUE; /* relative path: add '.' before '/' */
} else if (rootlen > 0 && (SSTAT(tmproot, &G.statbuf) ||
!S_ISDIR(G.statbuf.st_mode))) /* path does not exist */
{
if (!G.create_dirs /* || iswild(tmproot) */ ) {
free(tmproot);
rootlen = 0;
/* skip (or treat as stored file) */
return MPN_INF_SKIP;
}
/* create the directory (could add loop here scanning tmproot
* to create more than one level, but why really necessary?) */
if (mkdir(tmproot, 0777) == -1) {
Info(slide, 1, ((char *)slide,
"checkdir: cannot create extraction directory: %s\n",
FnFilter1(tmproot)));
free(tmproot);
rootlen = 0;
/* path didn't exist, tried to create, and failed: */
/* file exists, or 2+ subdir levels required */
return MPN_ERR_SKIP;
}
}
if (add_dot) /* had just "x:", make "x:." */
tmproot[rootlen++] = '.';
tmproot[rootlen++] = '/';
tmproot[rootlen] = '\0';
if ((rootpath = (char *)realloc(tmproot, rootlen+1)) == NULL) {
free(tmproot);
rootlen = 0;
return MPN_NOMEM;
}
Trace((stderr, "rootpath now = [%s]\n", FnFilter1(rootpath)));
}
return MPN_OK;
}
#endif /* !SFX || SFX_EXDIR */
 
/*---------------------------------------------------------------------------
END: free rootpath, immediately prior to program exit.
---------------------------------------------------------------------------*/
 
if (FUNCTION == END) {
Trace((stderr, "freeing rootpath\n"));
if (rootlen > 0) {
free(rootpath);
rootlen = 0;
}
return MPN_OK;
}
 
return MPN_INVALID; /* should never reach */
 
} /* end function checkdir() */
 
 
 
 
#if (defined(USE_EF_UT_TIME) || defined(TIMESTAMP))
/* The following DOS date/time structure is machine-dependent as it
* assumes "little-endian" byte order. For MSDOS-specific code, which
* is run on ix86 CPUs (or emulators), this assumption is valid; but
* care should be taken when using this code as template for other ports.
*/
typedef union {
ulg z_dostime;
struct { /* date and time words */
ush ztime; /* DOS file modification time word */
ush zdate; /* DOS file modification date word */
} zft;
struct { /* DOS date/time components bitfield */
unsigned zt_se : 5;
unsigned zt_mi : 6;
unsigned zt_hr : 5;
unsigned zd_dy : 5;
unsigned zd_mo : 4;
unsigned zd_yr : 7;
} z_dtf;
} dos_fdatetime;
#endif /* USE_EF_UT_TIME || TIMESTAMP */
 
 
/****************************/
/* Function close_outfile() */
/****************************/
 
void close_outfile(__G)
__GDEF
{
/* skip restoring time stamps on user's request */
if (uO.D_flag <= 1) {
#ifdef USE_EF_UT_TIME
dos_fdatetime dos_dt;
iztimes z_utime;
struct tm *t;
#endif /* USE_EF_UT_TIME */
 
 
#ifdef USE_EF_UT_TIME
if (G.extra_field &&
#ifdef IZ_CHECK_TZ
G.tz_is_valid &&
#endif
(ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
G.lrec.last_mod_dos_datetime, &z_utime, NULL)
& EB_UT_FL_MTIME))
{
TTrace((stderr, "close_outfile: Unix e.f. modif. time = %ld\n",
z_utime.mtime));
/* round up (down if "up" overflows) to even seconds */
if (z_utime.mtime & 1)
z_utime.mtime = (z_utime.mtime + 1 > z_utime.mtime) ?
z_utime.mtime + 1 : z_utime.mtime - 1;
TIMET_TO_NATIVE(z_utime.mtime) /* NOP unless MSC 7 or Macintosh */
t = localtime(&(z_utime.mtime));
} else
t = (struct tm *)NULL;
if (t != (struct tm *)NULL) {
if (t->tm_year < 80) {
dos_dt.z_dtf.zt_se = 0;
dos_dt.z_dtf.zt_mi = 0;
dos_dt.z_dtf.zt_hr = 0;
dos_dt.z_dtf.zd_dy = 1;
dos_dt.z_dtf.zd_mo = 1;
dos_dt.z_dtf.zd_yr = 0;
} else {
dos_dt.z_dtf.zt_se = t->tm_sec >> 1;
dos_dt.z_dtf.zt_mi = t->tm_min;
dos_dt.z_dtf.zt_hr = t->tm_hour;
dos_dt.z_dtf.zd_dy = t->tm_mday;
dos_dt.z_dtf.zd_mo = t->tm_mon + 1;
dos_dt.z_dtf.zd_yr = t->tm_year - 80;
}
} else {
dos_dt.z_dostime = G.lrec.last_mod_dos_datetime;
}
_dos_filedate(fileno(G.outfile), dos_dt.z_dostime);
#else /* !USE_EF_UT_TIME */
_dos_filedate(fileno(G.outfile), G.lrec.last_mod_dos_datetime);
#endif /* ?USE_EF_UT_TIME */
}
 
fclose(G.outfile);
 
_dos_chmod(G.filename, G.pInfo->file_attr);
 
} /* end function close_outfile() */
 
 
 
 
 
#ifdef TIMESTAMP
 
/*************************/
/* Function stamp_file() */
/*************************/
 
int stamp_file(fname, modtime)
ZCONST char *fname;
time_t modtime;
{
dos_fdatetime dos_dt;
time_t t_even;
struct tm *t;
int fd; /* file handle */
 
/* round up (down if "up" overflows) to even seconds */
t_even = ((modtime + 1 > modtime) ? modtime + 1 : modtime) & (~1);
TIMET_TO_NATIVE(t_even) /* NOP unless MSC 7.0 or Macintosh */
t = localtime(&t_even);
if (t == (struct tm *)NULL)
return -1; /* time conversion error */
if (t->tm_year < 80) {
dos_dt.z_dtf.zt_se = 0;
dos_dt.z_dtf.zt_mi = 0;
dos_dt.z_dtf.zt_hr = 0;
dos_dt.z_dtf.zd_dy = 1;
dos_dt.z_dtf.zd_mo = 1;
dos_dt.z_dtf.zd_yr = 0;
} else {
dos_dt.z_dtf.zt_se = t->tm_sec >> 1;
dos_dt.z_dtf.zt_mi = t->tm_min;
dos_dt.z_dtf.zt_hr = t->tm_hour;
dos_dt.z_dtf.zd_dy = t->tm_mday;
dos_dt.z_dtf.zd_mo = t->tm_mon + 1;
dos_dt.z_dtf.zd_yr = t->tm_year - 80;
}
if (((fd = open((char *)fname, 0)) == -1) ||
(_dos_filedate(fd, dos_dt.z_dostime)))
{
if (fd != -1)
close(fd);
return -1;
}
close(fd);
return 0;
 
} /* end function stamp_file() */
 
#endif /* TIMESTAMP */
 
 
 
 
#ifndef SFX
 
/************************/
/* Function version() */
/************************/
 
void version(__G)
__GDEF
{
int len;
#if 0
char buf[40];
#endif
 
len = sprintf((char *)slide, LoadFarString(CompiledWith),
 
#ifdef __GNUC__
"gcc ", __VERSION__,
#else
# if 0
"cc ", (sprintf(buf, " version %d", _RELEASE), buf),
# else
"unknown compiler", "",
# endif
#endif
 
"Human68k",
#ifdef __MC68020__
" (X68030)",
#else
" (X680x0)",
#endif
 
#ifdef __DATE__
" on ", __DATE__
#else
"", ""
#endif
);
 
(*G.message)((zvoid *)&G, slide, (ulg)len, 0);
 
} /* end function version() */
 
#endif /* !SFX */
 
 
#if defined (SFX) && defined (MAIN)
int main(int argc, char *argv[])
{
char argv0[92];
 
/* make true argv[0] (startup routine makes it inaccuracy) */
argv[0] = strcat (strcpy (argv0, _procp->exe_path), _procp->exe_name);
 
return MAIN(argc, argv);
}
#endif /* SFX && MAIN */