	title	snip
;++
;
; Program to snip data off of the beginning and/or end of a file.
;
; It seems it's not so easy to make unlabeled tapes these days...
;
; By John Wilson.
;
; 11/26/95	JMBW	Created.
;
;--
	.radix	8
;
lf=	12
cr=	15
;
bufl=	32768d			;length of file I/O buffer
;
code	segment
	assume	cs:code
	org	100h
;
start:	cld
	mov	dx,offset banner ;say hellow
	mov	ah,09h		;func=print
	int	21h
	mov	dx,offset nomem	;assume no memory
	cmp	sp,offset pdl	;make sure we have enough memory
	jb	error1
getfn:	; get filename
	mov	dx,offset prmpt1 ;point at prompt
	call	getln		;get a line
	jcxz	getfn		;loop if none
	mov	dx,si		;copy ptr
	add	si,cx		;pt at end
	mov	byte ptr [si],0	;mark it
	mov	ax,3D02h	;func=open for R/W
	int	21h
	mov	dx,offset opnerr ;[assume open error]
	jc	error1
	mov	ds:handle,ax	;save handle
	; get # bytes to chop off at begn
	mov	dx,offset prmpt2 ;point at prompt
	call	getno		;get a number
	mov	ds:stacnt,ax	;save
	mov	ds:stacnt+2,dx
	; get # bytes to chop off at end
	mov	dx,offset prmpt3 ;point at prompt
	call	getno		;get a number
	mov	ds:endcnt,ax	;save
	mov	ds:endcnt+2,dx
	; find length of file
	xor	dx,dx		;offset=0000:0000
	xor	cx,cx
	mov	bx,ds:handle	;get handle
	mov	ax,4202h	;func=seek to EOF+0000:0000
	int	21h
	jnc	savlen
serr1:	mov	dx,offset sekerr ;seek failed
error1:	; bomb, dx=error msg
	mov	ah,09h		;func=print
	int	21h
	mov	ax,4C01h	;func=bomb
	int	21h
savlen:	; dx:ax=length of file
	sub	ax,ds:stacnt	;subtract off starting count
	sbb	dx,ds:stacnt+2
	jc	bdcnt
	sub	ax,ds:endcnt	;subtract off ending count
	sbb	dx,ds:endcnt+2
	jc	bdcnt
	mov	ds:flen,ax	;save
	mov	ds:flen+2,dx
	mov	bx,ds:stacnt	;see if there was any starting count
	or	bx,ds:stacnt+2
	jz	trunc1		;no
	mov	ds:fcnt,ax	;init counter
	mov	ds:fcnt+2,dx
	jmp	short copy1	;into loop
bdcnt:	mov	dx,offset badcnt ;pt at msg
	jmp	short error1
trunc1:	jmp	trunc2
copy1:	; seek to position for next read
	mov	dx,ds:stacnt	;get starting posn
	mov	cx,ds:stacnt+2
	mov	bx,ds:handle	;handle
	mov	ax,4200h	;func=seek from BOF
	int	21h
	jc	serr1		;seek error
	; read next bufferload
	mov	dx,offset buf	;pt at buf
	mov	cx,bufl		;length of buf
	cmp	ds:fcnt+2,0	;do we have at least 64KB left?
	jnz	copy2
	cmp	ds:fcnt,cx	;got at least that much?
	ja	copy2
	mov	cx,ds:fcnt	;no, take what there is
copy2:	mov	ah,3Fh		;func=read
	int	21h
	mov	dx,offset rderr	;[assume error]
	jc	error1
	cmp	ax,cx		;get what we wanted?
	jne	error1		;we should have
	; seek to position for next write
	push	cx		;save
	mov	dx,ds:wpos	;get posn
	mov	cx,ds:wpos+2
	mov	ax,4200h	;func=seek from BOF
	int	21h
	jc	serr2		;error
	pop	cx		;restore
	; write next bufferload
	mov	dx,offset buf	;pt at buf
	mov	ah,40h		;func=write
	int	21h
	mov	dx,offset wrerr	;[assume error]
	jc	error2
	cmp	ax,cx		;wrote it all?
	jne	error2		;we should have
	; update positions
	add	ds:wpos,ax	;write posn
	adc	ds:wpos+2,0
	add	ds:stacnt,ax	;read posn
	adc	ds:stacnt+2,0
	sub	ds:fcnt,ax	;count it off
	sbb	ds:fcnt+2,0
	mov	ax,ds:fcnt	;anything left?
	or	ax,ds:fcnt+2
	jnz	copy1		;loop if so
trunc2:	; truncate file to size
	mov	dx,ds:flen	;get final length
	mov	cx,ds:flen+2
	mov	bx,ds:handle	;file handle
	mov	ax,4200h	;func=seek from BOF
	int	21h
	jc	serr2		;seek error
	mov	dx,offset buf	;not like it matters
	xor	cx,cx		;count=0
	mov	ah,40h		;func=write
	int	21h
	mov	dx,offset wrerr	;[assume error]
	jc	error2
	mov	ah,3Eh		;func=close
	int	21h
	int	20h		;later
serr2:	jmp	serr1		;couldn't reach
error2:	jmp	error1
;+
;
; Get a decimal number from the keyboard.
;
; bx	prompt
; dx:ax	return number
;
;-
getno:	call	getln		;get a line
	xor	bx,bx		;init
	xor	dx,dx
	jcxz	getno2		;nothing, keep the 0
getno1:	lodsb			;get a char
	sub	al,'0'		;convert
	cmp	al,9d		;digit?
	ja	getno3		;no
	cbw			;ah=0
	mov	di,ax		;save
	mov	ax,10d		;high word *10.
	mul	dx
	xchg	ax,bx		;save result, get low word
	mov	dx,10d		;low word *10.
	mul	dx
	add	ax,di		;add in new digit
	adc	dx,bx		;handle carry from both
	mov	bx,ax		;move out of the way
	loop	getno1		;loop
getno2:	mov	ax,bx		;copy
	ret
getno3:	mov	dx,offset badnum ;bad number
	jmp	error1		;handle it
;+
;
; Get a line from the keyboard, squish out blanks.
;
; bx	pointer to prompt
; si,cx	return addr,length of the line
;
;-
getln:	mov	ah,09h		;func=print
	int	21h
	mov	dx,offset lbuf	;get a line
	mov	ah,0Ah		;func=line input
	int	21h
	mov	dl,lf		;echo LF
	mov	ah,02h		;func=conout
	int	21h
	mov	si,offset lbuf+1 ;point at length
	lodsb			;fetch it
	cbw			;ah=0
	mov	cx,ax		;copy
	jcxz	getln3		;nothing
	mov	di,si		;copy ptr
	mov	dx,si		;twice
getln1:	lodsb			;get a byte
	cmp	al,' '		;blank or ctrl char?
	jbe	getln2		;yes
	 stosb			;save
getln2:	loop	getln1		;loop
	mov	si,dx		;pt at begn of buf
	mov	cx,di		;pt at end
	sub	cx,si		;find length
getln3:	ret
;
	subttl	pure data
banner	db	'This program removes bytes from the beginning and/or end of a'
	db	'file.',cr,lf,lf,'$'
prmpt1	db	'File name: $'
prmpt2	db	'Number of bytes to remove from beginning <0>: $'
prmpt3	db	'Number of bytes to remove from end <0>: $'
;
nomem	db	'?Insufficient memory',cr,lf,'$'
opnerr	db	'?Error opening file',cr,lf,'$'
badnum	db	'?Bad digit',cr,lf,'$'
sekerr	db	'?File seek error',cr,lf,'$'
badcnt	db	'?File is too short to snip off that much',cr,lf,'$'
rderr	db	'?Read error',cr,lf,'$'
wrerr	db	'?Write error',cr,lf,'$'
;
	subttl	impure data
;
wpos	dw	0,0		;file position for writing
;
lbuf	db	80d,?,80d dup(?) ;buffer for input line
	db	1 dup(?)	;guard byte for NUL at end of long filename
;
	subttl	pure storage
;
handle	dw	1 dup(?)	;file handle
stacnt	dw	2 dup(?)	;# bytes to remove at start
endcnt	dw	2 dup(?)	;# bytes to remove at end
flen	dw	2 dup(?)	;file length after truncation
fcnt	dw	2 dup(?)	;amount of file left to copy
;
buf	db	bufl dup(?)	;file buffer, must all fit in <64KB
;
	dw	100h dup(?)	;minimum stack
pdl	label	word		;SP must be here or higher
;
code	ends
	end	start
