;=============================================================================
;FILE:    SPLITHOG.ASM
;
;DESC:    Splits a Descent .HOG file into separate files
;
;NOTES:   Uses Spontaneous Assembly 3.0.  Can be modified to not use it
;         at all....
;
;         Built with MASM 6.1 and Spontaneous Assembly 3.0.
;         Use the /cp:1 link option for automatic memory footprint reduction
;         at load time:
;
;         ml /c splithog.asm
;         link /cp:1 starts splithog,splithog,,sas;
;
;         This source code is placed into the public domain.
;
; Version 1.0, 03/25/95:  Initial release
;         1.1, 04/06/95:  Added ESC checking
;=============================================================================


_model    equ  <small>
include		MODEL.INC
include        CONSOLE.INC
include        FILECNTL.INC
include        FILEIO.INC
include        IMATH.INC

READWRITEBUFR  equ  63 * 1024
NAMELENGTH     equ  13


.codeseg	lib

.extrn    start:auto, exit:auto, exit_ok:auto
.extrn    console_init:auto
.extrn    get_version:auto
.extrn    clr_region:auto
.extrn    goto_xy:auto
.extrn    openex_h:auto
.extrn    cput_str:auto
.extrn    lseekb_h:auto
.extrn    read_h:auto
.extrn    create_h:auto
.extrn    write_h:auto
.extrn    word_to_asc:auto
.extrn    dword_to_dec:auto
.extrn    arg_count:auto
.extrn    arg_next:auto
.extrn    str_len:auto

.ends


.dataseg

.extrn    e_code:word

SizeOfCreate   dword     0              ; bytes in file to be created
MemSeg         word      0              ; read/write buffer segment
HogHandle      word      0              ; handle of HOG file
NewHandle      word      0              ; handle of FileToCreate file
LogHandle      word      0              ; handle of results log file
BigHogFile     byte      "DESCENT.HOG",0,0,0
FileToCreate   byte      13 dup(0),0
CrLf           byte      13,10,0
ScratchBuffer  byte      130 dup(0)     ; oversized buffer in case user
                                        ; really screws up command line
Spaces1        byte      6 dup(" "),0
Spaces2        byte      17 dup(" ")
LogFile        byte      13 dup(0)      ; name of results log file
ModulesOf      byte      13,10,"Modules of file ",0
ColonAndEnd    byte      ":",13,10,"(file name, size in bytes)",13,10,10,0
ResultsAlsoIn  byte      13,10,"Results logged to file ",0
PressESC       byte      "SPLITHOG.EXE  1.1   by Bob Clarke",13,10
               byte      "Splits Registered Descent HOG file into components"
               byte      13,10,10
               byte      "You may press ESC to interrupt program run."
               byte      13,10,"Press a key to begin.",13,10,10,0
Interrupted    byte      13,10,"*** Processing interrupted by user ***",13,10,0


; Error messages

MemAllocError  byte      "Error allocating read/write buffer.",13,10,0
NoHogOpen      byte      "Can't open .HOG file.", 13,10,0
ErrorCodeMsg   byte      "Error code:      ",0
Overflow       byte      "Overflow subtracting word from dword!",13,10,0
HogReadError   byte      "Error reading HOG file.",13,10,0
HogWriteError  byte      "Error writing to new file.",13,10,0
CreateError    byte      "Error creating ",0
LogWriteError  byte      "Error writing to log file.",13,10,0
LogCreateError byte      "Error creating log results file.",0

.ends


IF NOT __TINY__
.stackseg
.public		stack_start
.label		stack_start	word
		db	1024 dup(?)	;define a 1024 byte stack
.ends
ENDIF


;=============================================================================
;FUNC:	MAIN
;
;DESC:	Main body of program.
;
;IN:      DX        segment address of PSP
;
;ASUMS:   DS,ES     @DATASEG  (same as @CODESEG in TINY model)
;         SS        @STACKSEG (same as @CODESEG in TINY model)
;=============================================================================

.codeseg

IF __TINY__
assume		cs:@codeseg, ds:@dataseg, es:@dataseg, ss:@dataseg
ELSE
assume		cs:@codeseg, ds:@dataseg, es:@dataseg, ss:@stackseg
ENDIF

.public		main
.proc		main		auto

          cld
          .call console_init
          .call get_version             ;; init for use of file sharing flags


; read the command line, looking for a .HOG file name

          .call arg_count
          or   cx,cx
          jz   UseDescentHog

          mov  si,offset ScratchBuffer
          .call arg_next
          mov  di,offset BigHogFile
          mov  cx,13
          rep  movsb

; clear the screen and home the cursor

UseDescentHog:
          .call clr_region
          xor  ax,ax
          .call goto_xy
          mov  si,offset PressESC
          .call cput_str
          xor  ah,ah
          int  16h

; allocate read/write buffer

          mov  ah,48h
          mov  bx,READWRITEBUFR shr 4
          int  21h
          jnc  GotMem
          mov  [e_code],ax
          mov  si,offset MemAllocError
          .call cput_str
          call ErrorOut
          jmp  NoRelease
GotMem:   mov  [MemSeg],ax

; open .HOG file

          mov  si,offset BigHogFile
          mov  al,O_RDONLY+O_DENYNO
          .call openex_h
          jnc  @F
          mov  si,offset NoHogOpen
          .call cput_str
          jmp  AllDone

Oops:     call ErrorOut
          jmp  AllDone

; create the log file

@@:       mov  [HogHandle],bx
          mov  si,offset BigHogFile
          mov  di,offset LogFile
LogLoop:  lodsb
          stosb
          cmp  al,"."
          je   LoopOut
          or   al,al               ; shouldn't happen...
          jnz  LogLoop
LoopOut:  mov  ax,"OL"
          stosw
          mov  al,"G"
          stosb
          xor  al,al
          stosb
          mov  si,offset LogFile
          mov  ax,FA_NORM
          .call create_h
          jnc  @F
          mov  si,offset LogCreateError
          .call cput_str
          jmp  short Oops
@@:       mov  [LogHandle],bx

; write header to log file

          mov  si,offset ModulesOf
          .call str_len
          .call write_h
          jnc  @F
LogWErr:  mov  si,offset LogWriteError
          .call cput_str
          jmp  short Oops

@@:       mov  si,offset BigHogFile
          .call str_len
          .call write_h
          jc   LogWErr
          mov  si,offset ColonAndEnd
          .call str_len
          .call write_h
          jc   LogWErr

; move past 3-byte header in .HOG file

          mov  dx,0
          mov  ax,3
          mov  bx,[HogHandle]
          .call lseekb_h
          jc   Oops

; start loop that reads file name, creates file, transfers bytes, closes file

; get the name of the file

BigLoop:  mov  ah,1
          int  16h                 ; check for key waiting
          jz   NoKey
          cmp  al,27               ; ESC?
          jne  NoKey
          mov  si,offset Interrupted
          .call cput_str
          jmp  AllDone

NoKey:    mov  si,offset FileToCreate
          mov  cx,NAMELENGTH
          mov  bx,[HogHandle]
          .call read_h
          ja   AllDone             ; all done
          je   @F                  ; read was okay...
          mov  si,offset HogReadError  ;read failed
          .call cput_str
          jmp  Oops

; create the new file

@@:       mov  ax,FA_NORM          ; normal file attributes
          .call create_h           ; destroys earlier BX
          jnc  @F
          mov  si,offset CreateError
          .call cput_str
          mov  si,offset FileToCreate
          .call cput_str
          mov  si,offset CrLf
          .call cput_str
          jmp  Oops
@@:       mov  [NewHandle],bx

; display the file being written

          mov  si,offset FileToCreate
          .call cput_str
          mov  si,offset Spaces1
          .call cput_str

; read the length of the file

          mov  si,offset SizeOfCreate
          mov  cx,4
          mov  bx,[HogHandle]
          .call read_h
          ja   AllDone             ; shouldn't happen...
          je   SizeToCRT
          mov  si,offset HogReadError
          .call cput_str
          jmp  Oops

; dislay the number of bytes in the file

SizeToCRT:
          lodsw                    ; low-order
          mov  dx,ax
          lodsw                    ; high-order
          xchg dx,ax
          mov  si,offset ScratchBuffer
          .call dword_to_dec
          .call cput_str
          mov  si,offset CrLf
          .call cput_str

; write file info to log file

          call LogWrite
          jc   AllDone

; read as many bytes as told by the file length just read, and place into
; the newly created file

; compare what has been read to what we need to read

HogCompare:
          mov  dx,word ptr [SizeOfCreate+2]
          mov  ax,word ptr [SizeOfCreate]
          mov  bx,ax
          or   bx,dx               ; if 0, all done with this new file
          jnz  @F

; close the output file, get the next one

          mov  ah,3eh
          mov  bx,[NewHandle]
          int  21h
          mov  [NewHandle],0
          jmp  BigLoop

@@:       mov  cx,READWRITEBUFR
          .cmp_dw dx,ax,cx

; JB  if dword (DX:AX) < word (CX)
; JBE if dword <= word
; JE  if dword = word
; JAE if dword >= word
; JA  if dword > word

; If what we need to read is >= READWRITEBUFR, read a full buffer, else
; read what's left.
; Since DX = 0 if DX:AX <= READWRITEBUFR, AX is amount for the read operation

          ja   FullRead
          mov  word ptr [SizeOfCreate],0
          mov  word ptr [SizeOfCreate+2],0
          mov  cx,ax
          jmp  short DoTheRead

; subtract the amount we're about to read from what is left to read

FullRead: .sub_dw dx,ax,cx
          jnc  NoOverflow          ; there should be no overflow...

; error, close all and exit

          mov  si,offset Overflow
          .call cput_str
          jmp  short AllDone

NoOverflow:
          mov  word ptr [SizeOfCreate+2],dx
          mov  word ptr [SizeOfCreate],ax

; read from the source file, write it to the target file

DoTheRead:
          mov  bx,[HogHandle]
          xor  si,si
          push ds
          mov  ds,[MemSeg]
          .call read_h
          pop  ds
          ja   AllDone             ; already at EOF (shouldn't happen...)
          je   ReadOkay
          mov  si,offset HogReadError
          .call cput_str
          jmp  Oops
ReadOkay: mov  bx,[NewHandle]
          push ds
          mov  ds,[MemSeg]
          .call write_h
          pop  ds
          jae  HogCompare          ; okay, get more
          mov  si,offset HogWriteError
          .call cput_str
          jmp  Oops


; release any allocated memory

AllDone:  mov  ax,[MemSeg]
          or   ax,ax
          jz   NoRelease
          mov  es,ax
          mov  ah,49h
          int  21h
NoRelease:
          mov  bx,[NewHandle]
          or   bx,bx
          jz   @F
          mov  ah,3eh
          int  21h
@@:       mov  bx,[HogHandle]
          or   bx,bx
          jz   @F
          mov  ah,3eh
          int  21h
@@:       mov  bx,[LogHandle]
          or   bx,bx
          jz   @F
          mov  ah,3eh
          int  21h
          mov  si,offset ResultsAlsoIn
          .call cput_str
          mov  si,offset LogFile
          .call cput_str
          mov  si,offset CrLf
          .call cput_str
@@:       ret

.endp		main



;=============================================================================
;FUNC:    ErrorOut
;
;DESC:    Displays DOS error code message
;
;IN:      nothing
;
;OUT:     nothing
;
;=============================================================================

.public        ErrorOut
.proc          ErrorOut     auto uses ax bx si

          mov  ax,[e_code]
          mov  bl,10
          mov  si,offset ErrorCodeMsg+12
          .call word_to_asc
          mov  si,offset ErrorCodeMsg
          .call cput_str
          ret

.endp          ErrorOut



;=============================================================================
;FUNC:    LogWrite
;
;DESC:    Write HOG module info to log file
;
;IN:      nothing
;
;OUT:     CF set if error, else CF clear
;
;=============================================================================

.public        LogWrite
.proc          LogWrite  auto uses ax bx cx dx si

          mov  bx,[LogHandle]
          mov  si,offset FileToCreate
          .call str_len
          .call write_h
          jc   LWError
          mov  dx,17
          sub  dx,cx
          xchg dx,cx
          mov  si,offset Spaces2
          .call write_h
          jc   LWError
          mov  si,offset ScratchBuffer
          .call str_len
          .call write_h
          jc   LWError
          mov  si,offset CrLf
          mov  cx,2
          .call write_h
          jc   LWError
          ret

LWError:  mov  si,offset LogWriteError
          .call cput_str
          call ErrorOut
          stc
          ret

.endp          LogWrite


.ends


;=============================================================================
; Stack normalization and memory management initialization labels
;
; NOTE: These declarations must remain after the declaration of the stack
; and anything in the stack segment. These labels define the end of the
; stack and the program, which is where the near and far heaps are placed
; by default. These declarations do not affect the size of the program and
; may be left here even if the stack is not normalized and the heaps are
; not used.
;=============================================================================

.public		nheap_default, fheap_default
IF NOT __TINY__
.stackseg
  IF __SMALL__ OR __MEDIUM__
.public		stack_end		;used by START to normalize stack
.label		stack_end	word	;must be defined past entire stack
  ENDIF
.label		nheap_default	word	;used by the near heap
.label		fheap_default	word	;used by the far heap
.ends
ELSE
_BSSEND		segment	byte public 'STACK'
.label		nheap_default	word	;used by the near heap
.label		fheap_default	word	;used by the far heap
_BSSEND		ends
% @codeseg	group	_BSSEND
ENDIF


		end	start		;specify START as starting address
