	    PAGE    78,132
	    TITLE   "SLICE - Break file for multiple diskettes"

CSEG	    SEGMENT PARA PUBLIC 'CODE'
	    ASSUME  CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG

; ---------------------------------------------------------------------------
;   DTA structure for DOS "find matching" call
; ---------------------------------------------------------------------------
	    ORG     80H 		    ; dta offset
DTA	    DB	    21 dup (0)		    ; start of find file area
DTA_ATTR    DB	    0			    ; file attribute
DTA_TIME    DW	    0			    ; file time
DTA_DATE    DW	    0			    ; file date
DTA_LSIZ    DW	    0			    ; file lsw of size
DTA_HSIZ    DW	    0			    ; file msw of size
DTA_NAME    DB	    12 DUP (0)		    ; file name of file
DTA_LEN     EQU     $-DTA		    ; length of dta find entry

	    ORG     100H		    ; start of program area
START:	    JMP     MAIN		    ; go to the code

; ---------------------------------------------------------------------------
;   Common initialized work areas
; ---------------------------------------------------------------------------
ARG	    DW	    0			    ; addr of first argument
FLOPDRV     DB	    0,":\"                  ; output drive letter
DESTFILE    DB	    "            ",0        ; output file name
DESTEXT     DW	    0			    ; pointer to extension
DESTEXTC    DB	    "0"                     ; 1st character of extension
DESTNBR     DW	    1			    ; file extension counter
RSTFLAG     DB	    0			    ; slice/restore flag
CURRDIR     DB	    ".",0                   ; argument for current directory
IHANDLE     DW	    0			    ; input file handle
OHANDLE     DW	    0			    ; output file handle

; ---------------------------------------------------------------------------
;   Messages to user
; ---------------------------------------------------------------------------
HEADER_MSG  DB	    "SLICE   1.0 - (c) 1989 Ziff Communications Co.",0DH,0AH
	    DB	    "PC Magazine ",254," Bob Flanders & Michael Holmes",0AH
	    DB	    0DH,0AH
DOLLAR	    DB	    "$"
FILENF	    DB	    "File not found$"
NOCREATE    DB	    "Error opening output$"
NOROOM	    DB	    "Not enough room$"
WRONGDISK   DB	    "Wrong restore disk, insert number "
DISKNO	    DB	    "XX$"
DRVNR	    DB	    "Must be removable media$"
RDERROR     DB	    "Error reading input$"
WRTERROR    DB	    "Error writing output$"
FILEFND     DB	    "File exists$"
NEXTDISK    DB	    "Next diskette$"
HITANYKEY   DB	    ", Press any key ..",0DH,0AH,"$"
FORMAT	    DB	    0DH,0AH,"format:",09H,"$"
RSFORM	    DB	    "SPLICE   d:  d:[\path]",0DH,0AH,"$"
RESTORING   DB	    "Restoring: "
RESTFILE    DB	    12 DUP (" "),0DH,0AH,"$"

; ---------------------------------------------------------------------------
;   File ID Header
; ---------------------------------------------------------------------------
RSTLAST     DB	    0			    ; last file flag
RSTATTR     DB	    0			    ; file attributes
RSTTIME     DW	    0			    ; file time
RSTDATE     DW	    0			    ; file date
RSTLSIZ     DW	    0			    ; file lsw of size
RSTHSIZ     DW	    0			    ; file msw of size
RSTNAME     DB	    12 DUP (0)		    ; file name of file
RST_FFLEN   EQU     $-RSTATTR		    ; length to move from ff area
RSTSDTE     DD	    0			    ; date ..
RSTSTME     DD	    0			    ; ..and time of save
RST_LEN     EQU     $-RSTLAST		    ; length of our file header

; ---------------------------------------------------------------------------
;   MAIN - Mainline of program
; ---------------------------------------------------------------------------
MAIN	    PROC			    ; start of program
	    CMP     RSTFLAG, 0		    ; q. restoring?
	    JNZ     RESTORE		    ; a. goto restore section

	    CALL    INIT		    ; initialize program
	    CALL    PARMS		    ; check parameters
	    CALL    OPEN		    ; open the input file
	    CALL    SAVE		    ; copy/slice the file to output
	    JMP     SHORT MAIN10	    ; return to dos

RESTORE:    CALL    INIT		    ; perform restore setup
	    CALL    PARMS		    ; check parameters
	    CALL    ROPEN		    ; open the output file
	    CALL    RFILE		    ; restore the file

MAIN10:     MOV     DX, OFFSET DOLLAR	    ; dx -> null message
	    CALL    DIE 		    ; .. say goodnight
MAIN	    ENDP

; ---------------------------------------------------------------------------
;   INIT - Handle initialization
; ---------------------------------------------------------------------------
INIT	    PROC
	    CLD 			    ; assure ascending
	    MOV     DX, OFFSET HEADER_MSG   ; dx -> header message
	    MOV     AH, 9		    ; ah = print ascii$ message
	    INT     21H 		    ; .. ask DOS to do it
	    RET 			    ; return to caller
INIT	    ENDP

; ---------------------------------------------------------------------------
;   ROPEN - open the file to restore
; ---------------------------------------------------------------------------
ROPEN	    PROC
	    MOV     DI, OFFSET ROPENFILE    ; di -> work area
	    MOV     SI, ARG		    ; si -> where to restore

ROPEN10:    MOVSB			    ; move a character

	    CMP     BYTE PTR [SI], 0	    ; q. end of parm?
	    JNE     ROPEN10		    ; a. yes .. continue

	    CMP     BYTE PTR [DI-1], "\"    ; q. last byte a back-slash?
	    JE	    ROPEN20		    ; a. yes .. continue

	    CMP     BYTE PTR [DI-1],":"     ; q. last byte a colon (drive)?
	    JE	    ROPEN20		    ; a. yes .. continue

	    MOV     AL, "\"                 ; end as directory
	    STOSB

ROPEN20:    MOV     SI, OFFSET RSTNAME	    ; si -> name of original file
	    MOV     BX, OFFSET RESTFILE     ; bx -> restore filename

ROPEN30:    LODSB			    ; al = char of filename
	    STOSB			    ; .. save it

	    OR	    AL, AL		    ; q. end of file name?
	    JZ	    ROPEN40		    ; a. yes .. continue

	    MOV     [BX], AL		    ; save in message
	    INC     BX			    ; bx -> next char
	    JMP     ROPEN30		    ; .. continue

ROPEN40:    MOV     AH, 4EH		    ; ah = find first
	    MOV     DX, OFFSET ROPENFILE    ; dx -> file to find
	    MOV     CX, 0FFH		    ; .. any attribute
	    INT     21H 		    ; q. file found?
	    JC	    ROPEN45		    ; a. no .. continue

	    MOV     DX, OFFSET FILEFND	    ; dx -> file already exists
	    CALL    DIE 		    ; .. push up some daisies

ROPEN45:    MOV     AH, 3CH		    ; ah = create function code
	    MOV     CL, RSTATTR 	    ; cx = original attributes
	    XOR     CH,CH		    ; .. upper byte off
	    INT     21H 		    ; issue DOS call
	    JNC     ROPEN50		    ; if no problems, continue

	    MOV     DX, OFFSET NOCREATE     ; dx -> create error message
	    CALL    DIE 		    ; .. go deep six

ROPEN50:    MOV     OHANDLE, AX 	    ; save the file handle

	    MOV     DX, OFFSET RESTORING    ; dx -> restore message
	    MOV     AH, 09H		    ; ah = print ascii$
	    INT     21H 		    ; .. tell the user

	    RET 			    ; return to caller
ROPEN	    ENDP

; ---------------------------------------------------------------------------
;   RFILE - restore file
; ---------------------------------------------------------------------------
RFILE	    PROC
	    CALL    NEXTFILE		    ; create a file name

RFILE10:    MOV     DX, OFFSET FLOPDRV	    ; dx -> file name
	    MOV     AX, 3D00H		    ; al = open for read
	    INT     21H 		    ; .. ask DOS to do it.
	    JNC     RFILE20		    ; ok .. continue

RFILE15:    MOV     DX, OFFSET WRONGDISK    ; dx -> wrong disk message
	    CALL    HITKEY		    ; .. display and wait
	    JMP     RFILE10		    ; .. and try again

RFILE20:    MOV     IHANDLE, AX 	    ; save file handle

	    MOV     BX, AX		    ; bx = handle
	    MOV     AH, 03FH		    ; ah = read file
	    MOV     CX, RST_LEN 	    ; cx = len to read
	    MOV     DX, OFFSET BUFFER	    ; dx -> buffer to read
	    INT     21H 		    ; read a buffer
	    JC	    RFILE35		    ; tell 'em we cant read it

	    MOV     SI, DX		    ; si -> buffer
	    MOV     DI, OFFSET RSTLAST	    ; di -> our header
	    MOVSB			    ; move last flag, setup for compare
	    MOV     CX, RST_LEN-1	    ; cx = bytes to check
       REPE CMPSB			    ; q. headers the same?
	    JE	    RFILE30		    ; a. yes .. continue

	    MOV     AH, 3EH		    ; ah = close file
	    INT     21H 		    ; close output file
	    JMP     RFILE15		    ; tell 'em

RFILE30:    MOV     AH, 03FH		    ; ah = read file
	    MOV     BX, IHANDLE 	    ; bx = handle of file to read
	    MOV     CX, BUFLEN		    ; cx = amount to read
	    MOV     DX, OFFSET BUFFER	    ; dx -> buffer
	    INT     21H 		    ; read, please
	    JNC     RFILE40		    ; if no error .. continue

RFILE35:    MOV     DX, OFFSET RDERROR	    ; dx -> read error message
	    CALL    DIE 		    ; ..and die gracefully

RFILE40:    MOV     CX, AX		    ; cx = bytes to write
	    JCXZ    RFILE80		    ; if finished .. exit loop

	    MOV     AH, 40H		    ; ax = write
	    MOV     BX, OHANDLE 	    ; bx = output file handle
	    INT     21H 		    ; write a buffer
	    JC	    RFILE50		    ; error .. die

	    CMP     AX, CX		    ; q. able to write it?
	    JE	    RFILE30		    ; a. no .. tell 'em

	    MOV     DI, OFFSET NOROOM	    ; di -> wontfit msg
	    JMP     SHORT RFILE60	    ; ..and exit gracefully

RFILE50:    MOV     DI, OFFSET WRTERROR     ; di -> write error message

RFILE60:    MOV     AH, 41H		    ; ah = delete function
	    MOV     DX, OFFSET ROPENFILE    ; dx -> filename
	    INT     21H 		    ; issue DOS call

	    MOV     DX, DI		    ; dx -> error message to give
	    CALL    DIE 		    ; ..make my day, punk!

RFILE80:    MOV     AH, 3EH		    ; ah = close file
	    INT     21H 		    ; close output file

	    CMP     RSTLAST, 0		    ; q. end of file
	    JNE     RFILE90		    ; a. no .. continue

	    MOV     DX, OFFSET NEXTDISK     ; dx -> next disk message
	    CALL    HITKEY		    ; display message and wait
	    JMP     RFILE		    ; .. get next file

RFILE90:    RET 			    ; else .. return to caller
RFILE	    ENDP

; ---------------------------------------------------------------------------
;   NEXTFILE - Build next filename
; ---------------------------------------------------------------------------
NEXTFILE    PROC
	    MOV     AX, DESTNBR 	    ; ax = current count
	    AAA 			    ; ax = almost ascii nbr
	    OR	    AX, 3030H		    ; ax = ascii values
	    XCHG    AL, AH		    ; swap bytes for store
	    MOV     BX, DESTEXT 	    ; bx -> 2nd char of extension
	    MOV     [BX], AX		    ; store rest of extension
	    MOV     WORD PTR DISKNO, AX     ; .. and in message
	    INC     DESTNBR		    ; increment for next time
	    RET 			    ; ..and return to caller
NEXTFILE    ENDP

; ---------------------------------------------------------------------------
;   HITKEY - Allow user to change diskettes; dx -> first message
; ---------------------------------------------------------------------------
HITKEY	    PROC
	    MOV     AH, 9H		    ; ah = print string
	    INT     21H 		    ; .. call dos to print message

	    MOV     DX, OFFSET HITANYKEY    ; dx -> prompt
	    INT     21H 		    ; issue prompt message

	    MOV     AX, 0C08H		    ; ax = clear buffer, wait for key
	    INT     21H 		    ; issue DOS call

	    OR	    AL, AL		    ; q. function key hit?
	    JNZ     HITKEY90		    ; a. no .. exit

	    MOV     AH, 08H		    ; ah = wait for key
	    INT     21H 		    ; issue DOS call

HITKEY90:   RET
HITKEY	    ENDP

; ---------------------------------------------------------------------------
;   PARMS - Parses the command line
; ---------------------------------------------------------------------------
PARMS	    PROC
	    CALL    UPCASE		    ; upper case the parm area
	    MOV     SI, 81H		    ; si -> parms area

PARMS10:    LODSB			    ; get parameter character

	    CMP     AL, 0DH		    ; q. end of line?
	    JE	    PARMS50		    ; a. yes .. exit
	    CMP     AL, " "                 ; q. blank?
	    JNA     PARMS10		    ; a. yes .. skip
	    CALL    ARGCHK		    ; set the argument
	    JC	    PARMSERR		    ; .. die on an error

PARMS30:    LODSB			    ; get next character
	    CMP     AL, 0DH		    ; q. end of line?
	    JE	    PARMS50		    ; a. yes .. process
	    CMP     AL, " "                 ; q. end of PARMS?
	    JA	    PARMS30		    ; a. no .. next char

	    MOV     BYTE PTR [SI-1], 0	    ; end the parameter
	    JMP     PARMS10		    ; .. look for next

PARMS50:    MOV     BYTE PTR [SI-1], 0	    ; end the parameter

	    CMP     ARG, 0		    ; q. PARMS 1 available?
	    JNE     PARMS60		    ; a. no .. error

	    CMP     RSTFLAG, 0		    ; q. restoring?
	    JE	    PARMSERR		    ; a. no .. error

	    MOV     ARG, OFFSET CURRDIR     ; arg -> current directory

PARMS60:    CMP     FLOPDRV, 0		    ; q. Drive given?
	    JE	    PARMSERR		    ; a. no .. error also

	    RET 			    ; .. else .. return to caller

PARMSERR:   MOV     DX, OFFSET FORMAT	    ; dx -> format message
	    MOV     AH, 09H		    ; ah = print ascii$
	    INT     21H 		    ; hey DOS .. print it!

	    MOV     DX, OFFSET RSFORM	    ; dx -> restore format

	    CMP     RSTFLAG, 0		    ; q. restore?
	    JNZ     PARMSERR1		    ; a. yes .. die now

	    MOV     DX, OFFSET SPFORM	    ; dx -> slice format

PARMSERR1:  CALL    DIE 		    ; .. play taps
PARMS	    ENDP

; ---------------------------------------------------------------------------
;   ARGCHK - Setup pointers to command line args; si -> 2nd char in arg
;	     Exit: ARG or FLOPDRV filled in; Carry set if > 2 args
; ---------------------------------------------------------------------------
ARGCHK	    PROC
	    LEA     BX, [SI-1]		    ; bx -> argument

	    CMP     RSTFLAG, 0		    ; q. restoring?
	    JE	    ARG05		    ; a. no .. continue

	    CMP     FLOPDRV, 0		    ; q. drive filled in?
	    JE	    ARG20		    ; a. no .. fill it in

ARG05:	    CMP     ARG, 0		    ; q. ARG filled in?
	    JNE     ARG10		    ; a. yes .. check 2
	    MOV     ARG, BX		    ; save ARG pointer
	    JMP     SHORT ARG90 	    ; .. exit ok!

ARG10:	    CMP     FLOPDRV, 0		    ; q. drive filled in?
	    JE	    ARG20		    ; a. no .. fill it in
	    STC 			    ; else .. error
	    RET 			    ; .. and return to caller

ARG20:	    MOV     FLOPDRV, AL 	    ; save drive
	    MOV     SPLICEDRV, AL	    ; .. in file and program names

	    MOV     BL, AL		    ; bl = drive letter
	    SUB     BL, "@"                 ; bl = drive number
	    MOV     AX, 4408H		    ; ax = ioctl, removable?
	    INT     21H 		    ; issue DOS call

	    OR	    AL, AL		    ; q. removable media drive?
	    JZ	    ARG90		    ; a. yes .. return

	    MOV     DX, OFFSET DRVNR	    ; dx -> error message
	    CALL    DIE 		    ; issue non-removable message

ARG90:	    CLC 			    ; show no error
	    RET 			    ; return to caller
ARGCHK	    ENDP

; ---------------------------------------------------------------------------
;   UPCASE - Convert command line arguments to uppercase
; ---------------------------------------------------------------------------
UPCASE	    PROC
	    PUSH    SI			    ; save caller regs
	    PUSH    DI
	    MOV     SI, 81H		    ; si -> start of parm area
	    MOV     DI, SI		    ; .. same for di
	    CLD 			    ; .. assure ascending

UPCASE10:   LODSB			    ; al = char
	    CMP     AL, 0DH		    ; q. end of line?
	    JE	    UPCASE90		    ; a. yes .. end of line!
	    CMP     AL, "a"                 ; q. is it below 'a'?
	    JB	    UPCASE20		    ; a. yes .. continue
	    CMP     AL, "z"                 ; q. is it above 'z'?
	    JA	    UPCASE20		    ; a. yes .. continue
	    SUB     AL, 20H		    ; set to upper case

UPCASE20:   STOSB			    ; save the byte
	    JMP     UPCASE10		    ; .. and continue

UPCASE90:   POP     DI			    ; restore caller regs
	    POP     SI
	    RET 			    ; .. and return to caller
UPCASE	    ENDP

; ---------------------------------------------------------------------------
;   DIE - Display an error message and return to DOS; dx -> ascii$ error msg
; ---------------------------------------------------------------------------
DIE	    PROC
	    MOV     AH, 9H		    ; ah = print string
	    INT     21H 		    ; .. call dos to print error

	    MOV     BX, IHANDLE 	    ; bx = input file handle
	    OR	    BX, BX		    ; q. file opened?
	    JZ	    DIE90		    ; a. no .. try output file

	    MOV     AH, 3EH		    ; ah = close file
	    INT     21H 		    ; .. ask DOS to do it

DIE90:	    MOV     BX, OHANDLE 	    ; bx = output file handle
	    OR	    BX, BX		    ; q. file opened?
	    JZ	    DIE95		    ; a. no .. just exit

	    MOV     AH, 3EH		    ; ah = close file
	    INT     21H 		    ; .. ask DOS to do it

DIE95:	    MOV     AX, 4C00H		    ; ax = exit
	    INT     21H 		    ; .. terminate routine
DIE	    ENDP


RESTLIMIT   EQU     $			    ; only need up to here


; ---------------------------------------------------------------------------
;   Slice only areas and messages
; ---------------------------------------------------------------------------
SPFORM	    DB	    "SLICE     [d:\path\]filename[.ext] "
	    DB	    " d:",0DH,0AH,0AH,"$"
ZEROLEN     DB	    "Input file empty",0DH,0AH,"$"
NOCOM	    DB	    "Program won't fit",0DH,0AH,"$"
SPLICEDRV   DB	    "x:\"
SPLICE	    DB	    "SPLICE.COM",0

; ---------------------------------------------------------------------------
;   OPEN - Opens next file to process; Carry indicates file would not open.
; ---------------------------------------------------------------------------
OPEN	    PROC
	    MOV     DX, ARG		    ; dx -> file name
	    MOV     AX, 3D00H		    ; al = open for read
	    INT     21H 		    ; .. ask DOS to do it.
	    JC	    OPEN05		    ; ok .. continue

	    MOV     IHANDLE, AX 	    ; save file handle

	    MOV     AH, 4EH		    ; ah = find first
	    MOV     DX, ARG		    ; dx -> file to find
	    XOR     CX, CX		    ; cx = search attribute
	    INT     21H 		    ; q. find first file ok?
	    JNC     OPEN10		    ; a. yes .. continue

OPEN05:     MOV     DX, OFFSET FILENF	    ; dx -> file not found
	    CALL    DIE 		    ; .. gasp your final breath

OPEN10:     MOV     AX, DS:DTA_LSIZ	    ; ax = lsw of size
	    OR	    AX, DS:DTA_HSIZ	    ; q. any data?
	    JNZ     OPEN90		    ; a. yes ..continue

	    MOV     DX, OFFSET ZEROLEN	    ; dx -> file contains no data
	    CALL    DIE 		    ; .. dearly beloved ...

OPEN90:     RET
OPEN	    ENDP

; ---------------------------------------------------------------------------
;   SAVE - Handle building slice files on destination
; ---------------------------------------------------------------------------
SAVE	    PROC
	    CALL    BLD_RESTORE 	    ; build restore program

SAVE10:     MOV     AH, 03FH		    ; ah = read file
	    MOV     BX, IHANDLE 	    ; bx = handle of file to read
	    MOV     CX, BUFLEN		    ; cx = amount to read
	    MOV     DX, OFFSET BUFFER	    ; dx -> buffer
	    INT     21H 		    ; read, please
	    JNC     SAVE20		    ; if no error .. continue

	    MOV     DX, OFFSET RDERROR	    ; dx -> read error message
	    CALL    DIE 		    ; ..and die gracefully

SAVE20:     CALL    WRITE		    ; ..and write out a buffer full
	    JC	    SAVE90		    ; if finished .. exit loop
	    JMP     SAVE10		    ; else .. get next buffer

SAVE90:     RET 			    ; return to caller
SAVE	    ENDP

; ---------------------------------------------------------------------------
;   BLD_RESTORE - Build the restore program
; ---------------------------------------------------------------------------
BLD_RESTORE PROC
	    MOV     AH, 2AH		    ; ah = get date function call
	    INT     21H 		    ; issue DOS call

	    MOV     WORD PTR RSTSDTE, CX    ; save year
	    MOV     WORD PTR RSTSDTE+2, DX  ; ..and month and day

	    MOV     AH, 2CH		    ; ah = get time function call
	    INT     21H 		    ; issue DOS call

	    MOV     WORD PTR RSTSTME, CX    ; save hours and minutes
	    MOV     WORD PTR RSTSTME+2, DX  ; ..and seconds and hundredths

	    MOV     SI, OFFSET DTA_ATTR     ; si -> source string
	    MOV     DI, OFFSET RSTATTR	    ; di -> save area
	    MOV     CX, RST_FFLEN	    ; cx = length to move
	REP MOVSB			    ; copy string

	    MOV     DI, OFFSET HEADER_MSG   ; di -> program name
	    MOV     SI, OFFSET SPLICE	    ; si -> restore program name
	    MOV     CX, 7		    ; cx = length
	REP MOVSB			    ; .. setup program name

	    MOV     SI, OFFSET DTA_NAME     ; si -> source file name
	    MOV     DI, OFFSET DESTFILE     ; di -> work file name
	    MOV     CX, 8		    ; cx = length to move

BLD_REST10: LODSB			    ; al = char from filename

	    CMP     AL, "."                 ; q. end of filename?
	    JE	    BLD_REST30		    ; a. yes .. exit loop
	    OR	    AL, AL		    ; q. end of string?
	    JZ	    BLD_REST20		    ; a. yes .. exit loop

	    STOSB			    ; save character
	    LOOP    BLD_REST10		    ; ..and loop till end of string

BLD_REST20: MOV     AL, "."                 ; assure file separator char
BLD_REST30: STOSB			    ; save the separator

	    MOV     DESTEXT, DI 	    ; save pointer to file extension

	    CMP     BYTE PTR [SI-1], "."    ; q. was extension found?
	    JNE     BLD_REST32		    ; a. no .. allow default

	    LODSB			    ; get 1st char after extenstion
	    MOV     DESTEXTC, AL	    ; ..and save for later

BLD_REST32: MOV     RSTFLAG, 1		    ; set restore flag

	    MOV     AL, DESTEXTC	    ; al = 1st char of extension
	    MOV     DI, DESTEXT 	    ; di -> position in filename
	    STOSB			    ; save 1st character
	    MOV     DESTEXT, DI 	    ; save pointer to 2nd char

BLD_REST35: MOV     DX, OFFSET SPLICEDRV    ; dx -> SPLICE program name
	    CALL    CREATE		    ; create the new file

	    PUSH    WORD PTR FLOPDRV	    ; save drive parameter
	    PUSH    ARG 		    ; .. and ARG
	    MOV     FLOPDRV, 0		    ; zero ..
	    MOV     ARG, 0		    ; .. them out

	    MOV     AH, 40H		    ; ah = write function code
	    MOV     CX, OFFSET RESTLIMIT    ; cx = length to move
	    MOV     DX, OFFSET START	    ; dx -> start of program
	    SUB     CX, DX		    ; .. forget the PSP
	    INT     21H 		    ; issue DOS call

	    POP     ARG 		    ; restore ..
	    POP     WORD PTR FLOPDRV	    ; .. parameters
	    JC	    BLD_REST40		    ; if ok, continue

	    CMP     AX, CX		    ; q. all of pgm get out?
	    JE	    BLD_REST50		    ; a. yes .. continue

BLD_REST40: MOV     AH, 3EH		    ; ah = close function
	    INT     21H 		    ; close file

	    CALL    DELETE		    ; delete output file
	    MOV     DX, OFFSET NOCOM	    ; dx -> no room at the inn
	    CALL    HITKEY		    ; ..issue message
	    JMP     BLD_REST35		    ; ..and try with a new diskette

BLD_REST50: MOV     AH, 3EH		    ; ah = close file
	    INT     21H 		    ; .. ask DOS to do it

	    RET 			    ; return to caller
BLD_RESTORE ENDP

; ---------------------------------------------------------------------------
;   WRITE - Write a file segment; ax = nbr of bytes to write (0 if EOF)
;			    Exit: Carry set if EOF processing complete
; ---------------------------------------------------------------------------
WRITE	    PROC
	    MOV     BX, OHANDLE 	    ; bx = handle number
	    MOV     CX, AX		    ; q. anything to write?
	    JCXZ    WRITE50		    ; a. no .. EOF request

	    MOV     DX, OFFSET BUFFER	    ; dx -> start of buffer
	    OR	    BX, BX		    ; q. handle open?
	    JNZ     WRITE40		    ; a. yes .. continue

WRITE05:    PUSH    CX			    ; save length
	    PUSH    DX			    ; ..and buffer address
	    CALL    NEXTFILE		    ; build extension for next file

WRITE10:    MOV     DX, OFFSET FLOPDRV	    ; dx -> file to create
	    CALL    CREATE		    ; open new file

	    MOV     OHANDLE, BX 	    ; save file handle
	    MOV     CX, RST_LEN 	    ; cx = length of header
	    CALL    HOWMUCH		    ; update remaining disk space
	    MOV     AH, 40H		    ; ah = write file function
	    MOV     DX, OFFSET RSTLAST	    ; dx -> our file header
	    INT     21H 		    ; issue DOS call
	    JNC     WRITE20		    ; if no error .. continue

	    MOV     DX, OFFSET WRTERROR     ; dx -> error message
	    CALL    DIE 		    ; ..then display and die

WRITE20:    CMP     AX, CX		    ; q. write out all of header?
	    JE	    WRITE30		    ; a. yes .. continue

	    MOV     AH, 3EH		    ; ah = close function
	    INT     21H 		    ; issue DOS call

	    CALL    DELETE		    ; delete new file

	    MOV     DX, OFFSET NOROOM	    ; dx -> next disk message
	    CALL    HITKEY		    ; issue message and wait
	    JMP     WRITE10		    ; ..try to get next file

WRITE30:    POP     DX			    ; restore registers
	    POP     CX			    ;

WRITE40:    CALL    HOWMUCH		    ; get how much to write

	    MOV     AH, 40H		    ; ah = write file
	    INT     21H 		    ; issue DOS call
	    JNC     WRITE45		    ; die on any error

	    MOV     DX, OFFSET WRTERROR     ; dx -> general error msg
	    CALL    DIE 		    ; issue msg and terminate

WRITE45:    ADD     DX, AX		    ; dx -> next buffer address
	    MOV     CX, DI		    ; cx = remainder of bytes to write
	    JCXZ    WRITE48		    ; if no more, exit

	    PUSH    DX			    ; save buffer address
	    MOV     AH, 3EH		    ; ah = close function
	    INT     21H 		    ; issue DOS call

	    MOV     DX, OFFSET NEXTDISK     ; dx -> next disk message
	    CALL    HITKEY		    ; display message and wait
	    POP     DX			    ; .. restore buffer address
	    JMP     WRITE05		    ; ..then get next file

WRITE48:    CLC 			    ; clear carry for caller
	    RET 			    ; ..and return


WRITE50:    OR	    BX, BX		    ; q. handle open?
	    JZ	    WRITE60		    ; a. no .. continue

	    MOV     AX, 4200H		    ; ah = position file
	    XOR     CX, CX		    ; cx = file position
	    XOR     DX, DX		    ; dx = msb of file position
	    INT     21H 		    ; position to top of file

	    MOV     RSTLAST, 1		    ; set flag
	    MOV     AH, 40H		    ; ah = write function
	    MOV     CX, 1		    ; cx = length
	    MOV     DX, OFFSET RSTLAST	    ; dx -> buffer
	    INT     21H 		    ; write eof marker in header

	    MOV     AH, 3EH		    ; ah = close function
	    INT     21H 		    ; issue DOS call

WRITE60:    STC 			    ; set carry flag
	    RET 			    ; ..and return to caller
WRITE	    ENDP

; ---------------------------------------------------------------------------
;   HOWMUCH - Calculate how much to write; cx = requested amount to write
;				     Exit: cx = nbr of bytes which will fit
;					   di = remainder
; ---------------------------------------------------------------------------
HOWMUCH     PROC
	    PUSH    DX			    ; save registers

	    MOV     AX, WORD PTR AVAIL	    ; get howmuch is available
	    MOV     DX, WORD PTR AVAIL+2    ; . . . .
	    MOV     DI, 0		    ; assume everything will fit

	    OR	    DX, DX		    ; q. more than 64k?
	    JNZ     HOWMUCH80		    ; a. no .. must be less than 64k

	    CMP     CX, AX		    ; q. enough room left?
	    JNA     HOWMUCH80		    ; a. yes .. use it all

	    MOV     DI, CX		    ; di = nbr requested
	    SUB     DI, AX		    ; di = remainder
	    MOV     CX, AX		    ; cx = nbr to write

HOWMUCH80:  SUB     AX, CX		    ; ax = new available
	    SBB     DX, 0		    ; dx:ax = new available
	    MOV     WORD PTR AVAIL, AX	    ; store for later
	    MOV     WORD PTR AVAIL+2, DX    ; . . . .

HOWMUCH90:  POP     DX			    ; restore registers
	    RET 			    ; ..and return
HOWMUCH     ENDP

; ---------------------------------------------------------------------------
;   CREATE - Create new file; dx -> file to open
;			Exit: bx = handle of opened file
; ---------------------------------------------------------------------------
CREATE	    PROC
	    MOV     BP, DX		    ; save file name pointer

CREATE10:   MOV     AH, 36H		    ; ah = get drive info
	    MOV     DL, FLOPDRV 	    ; dl = drive letter
	    SUB     DL, "@"                 ; dl = drive number
	    INT     21H 		    ; get free space

	    CMP     AX, -1		    ; q. drive ok?
	    JE	    CREATE15		    ; a. no .. next disk

	    OR	    BX, BX		    ; q. any clusters available?
	    JNZ     CREATE18		    ; a. yes .. build new file

CREATE15:   MOV     DX, OFFSET NOROOM	    ; dx -> no room at inn message
	    CALL    HITKEY		    ; get new diskette
	    JMP     CREATE10		    ; ..try again

CREATE18:   MUL     BX			    ; dx:ax = nbr of sectors available
	    MUL     CX			    ; dx:ax = nbr of bytes available
	    MOV     WORD PTR AVAIL, AX	    ; store howmuch is available
	    MOV     WORD PTR AVAIL+2, DX    ; . . . .

	    MOV     AH, 4EH		    ; ah = find first function code
	    MOV     CX, 0FFH		    ; cx = any attributes
	    MOV     DX, BP		    ; dx -> filename
	    INT     21H 		    ; issue DOS call
	    JC	    CREATE20		    ; if not available, create it

	    MOV     DX, OFFSET FILEFND	    ; dx -> file found message
	    CALL    HITKEY		    ; let user change diskette
	    JMP     CREATE10		    ; ..then try again

CREATE20:   MOV     AH, 3CH		    ; ah = create function code
	    XOR     CX, CX		    ; cx = no (special) attributes
	    INT     21H 		    ; issue DOS call
	    JNC     CREATE90		    ; if problems, exit

	    MOV     DX, OFFSET NOCREATE     ; dx -> create error message
	    CALL    DIE 		    ; ..and die

CREATE90:   MOV     BX, AX		    ; bx = handle
	    RET 			    ; ..and return to caller
CREATE	    ENDP

; ---------------------------------------------------------------------------
;   DELETE - Delete a file
; ---------------------------------------------------------------------------
DELETE	    PROC
	    MOV     AH, 41H		    ; ah = delete function
	    MOV     DX, OFFSET FLOPDRV	    ; dx -> filename
	    INT     21H 		    ; issue DOS call

	    RET 			    ; ..and return
DELETE	    ENDP

; ---------------------------------------------------------------------------
;   Uninitialized data areas
; ---------------------------------------------------------------------------
UDATA	    EQU     $			    ; start of unitialized data
ROPENFILE   EQU     BYTE PTR UDATA	    ; word area for ropen
AVAIL	    EQU     DWORD PTR ROPENFILE+65  ; available output space
BUFFER	    EQU     BYTE PTR AVAIL+4	    ; file buffer
BUFLEN	    EQU     32*1024		    ; length of buffer

CSEG	    ENDS			    ; end of code segment
	    END     START
