;=============================================================================
;FILE:    MAKEHOG.ASM
;
;DESC:    Makes a Descent .HOG file from .MSN file info
;
;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 makehog.asm
;         link /cp:1 starts makehog,splithog,,sas;
;
;         This source code is placed into the public domain.
;
; Version 1.0, 03/25/95:  Initial release
;=============================================================================



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

READWRITEBUFR  equ  63 * 1024
SPACE          equ  " "
TAB            equ  9
HIGHBLANK      equ  255
CARRIAGERETURN equ  13
LINEFEED       equ  10
COMMA          equ  ","
NULL           equ  0

.codeseg	lib

.extrn    start:auto, exit:auto, exit_ok:auto
.extrn    arg_count:auto
.extrn    arg_next:auto
.extrn    close_h:auto
.extrn    clr_region:auto
.extrn    console_init:auto
.extrn    cput_str:auto
.extrn    getfsize_h:auto
.extrn    get_version:auto
.extrn    goto_xy:auto
.extrn    hget_str:auto
.extrn    openex_h:auto
.extrn    open_h:auto
.extrn    read_h:auto
.extrn    set_dta:auto
.extrn    str_len:auto
.extrn    str_pbrk:auto
.extrn    str_upr:auto
.extrn    word_to_asc:auto
.extrn    write_h:auto

.ends


.dataseg

.extrn    e_code:word

RDLSize        dword     0
MSNHandle      word      0                   ; handle of mission file
HogHandle      word      0                   ; handle of HOG file
RDLHandle      word      0                   ; handle of RDL file
MemSeg         word      0                   ; read/write buffer segment
ScratchBuffer  byte      130 dup(0)
ScratchLength  word      $ - offset ScratchBuffer - 1
HogFileName    byte      15 dup(0)
HogHeader      byte      "DHF"
HogHdrLength   word      $ - offset HogHeader
RDLBuffer      byte      13 dup(0)
RDLBufrLength  word      $ - offset RDLBuffer
EndChars       byte      SPACE, TAB, HIGHBLANK, CARRIAGERETURN, LINEFEED
               byte      COMMA, NULL
CrLf           byte      13,10,0
SignOn         byte      "MAKEHOG.EXE   ver 1.0    by Bob Clarke",13,10
               byte      "Read registered Descent mission (.MSN) file and"
               byte      13,10,"creates a .HOG file of the same name."
               byte      13,10,10,"Press a key to begin, ESC to exit.",13,10,0
DTA            FBUF      <>        ; disk transfer area
WorkingWith    byte      "Working with ",0
CreatingMsg    byte      "Creating ",0

; error messages

ErrorCodeMsg   byte      "Error code:      ",0
NeedMSNName    byte      "Provide the name of the mission file (.MSN) "
               byte      "on the command line,",13,10
               byte      "as in MAKEHOG MYGAME.MSN ",13,10,0
NoMSNFile      byte      "Failure opening .MSN file.",13,10,0
MemAllocError  byte      "Error allocating read/write buffer.",13,10,0
HogCreateError byte      "Error creating new .HOG file.",13,10,0
HdrWriteError  byte      "Error writing .HOG header bytes.",13,10,0
LineReadError  byte      "Error reading .MSN line.",13,10,0
NoEndInSight   byte      "Can't find end of RDL file name, "
               byte      "possible invalid .MSN file format.",13,10,0
NoOpenRDL      byte      "Error opening RDL file: ",0
HogWriteError  byte      "Error writing to .HOG file.",13,10,0
RDLReadError   byte      "Error reading from RDL file.",13,10,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
          .call clr_region
          xor  ax,ax
          .call goto_xy
          mov  si,offset SignOn
          .call cput_str
          xor  ah,ah
          int  16h
          cmp  al,27
          jne  @F
          ret                      ; violate a principle of multiple returns
                                   ; since we know the AllDone code will do
                                   ; nothing anyway

@@:       mov  di,offset DTA
          .call set_dta

; read the command line, looking for the .MSN file name

          .call arg_count
          or   cx,cx
          jnz  @F
          mov  si,offset NeedMSNName
          .call cput_str
          jmp  AllDone

@@:       mov  si,offset ScratchBuffer
          .call arg_next

; look for the .MSN file

          mov  al,O_RDONLY+O_DENYNO
          .call openex_h
          jnc  @F
          mov  si,offset NoMSNFile
          .call cput_str
ErrorCodeDisplay:
          call ErrorOut
          jmp  AllDone

@@:       mov  [MSNHandle],bx

; create the .HOG file by first constructing the name, then create

          mov  si,offset ScratchBuffer
          mov  di,offset HogFileName
HogLoop1: lodsb
          stosb
          cmp  al,"."
          je   HogLoop1Out
          or   al,al               ; shouldn't happen
          jnz  HogLoop1
HogLoop1Out:
          mov  ax,"OH"
          stosw
          mov  al,"G"
          stosb
          xor  al,al
          stosb
          mov  si,offset CreatingMsg
          .call cput_str
          mov  si,offset HogFileName
          .call str_upr
          .call cput_str
          mov  si,offset CrLf
          .call cput_str
          mov  si,offset HogFileName
          mov  ax,O_RDWR+O_DENYRW+O_CREAT+O_TRUNC
          .call open_h
          jnc  @F
          mov  si,offset HogCreateError
          .call cput_str
          jmp  short ErrorCodeDisplay

@@:       mov  [HogHandle],bx

; build the .HOG file header

          mov  si,offset HogHeader
          mov  cx,[HogHdrLength]
          .call write_h
          jae  @F
          mov  si,offset HdrWriteError
          .call cput_str
          jmp  short ErrorCodeDisplay

; allocate read/write buffer

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

@@:       mov  [MemSeg],ax

; begin loop of reading MSN file lines, looking for RDL file names,
; moving RDL info to HOG file

RDLLoop:  mov  bx,[MSNHandle]
          mov  si,offset ScratchBuffer
          mov  cx,[ScratchLength]
          .call hget_str                ; get line from .MSN file
          ja   AllDone
          je   LineRead
          mov  si,offset LineReadError
          .call cput_str
          jmp  ErrorCodeDisplay
LineRead: .call str_len
          mov  ax,12                    ; maximum file name length
          cmp  cx,ax
          jb   @F
          xchg cx,ax
@@:       mov  al,"."                   ; look for "." in file name
          mov  di,si
          repne scasb
          jnz  RDLLoop                  ; if not found, can't be a line
                                        ; containing an .RDL name

; mark the end of the file name

          mov  si,offset ScratchBuffer
          mov  di,offset EndChars       ; list of characters that could
                                        ; signal the end of a string
          .call str_pbrk
          jc   @F                       ; if char not found, name is
                                        ; already null-terminated
          mov  di,si
          xor  al,al
          stosb

; display the name of the RDL file being worked

@@:       mov  si,offset WorkingWith
          .call cput_str
          mov  si,offset ScratchBuffer
          .call cput_str
          mov  si,offset CrLf
          .call cput_str

; look for the RDL file, open it

          mov  si,offset ScratchBuffer
          mov  al,O_RDONLY+O_DENYNO
          .call openex_h
          jnc  @F
          mov  si,offset NoOpenRDL
          .call cput_str
          mov  si,offset ScratchBuffer
          .call cput_str
          mov  si,offset CrLf
          .call cput_str
          jmp  ErrorCodeDisplay

; RDL is open, get size and transfer info to .HOG file

@@:       mov  [RDLHandle],bx
          .call getfsize_h
          mov  di,offset RDLSize
          stosw                         ; store low word
          xchg dx,ax
          stosw                         ; store high word

; clear name buffer

          mov  di,offset RDLBuffer
          push di
          mov  cx,[RDLBufrLength]
          xor  al,al
          rep  stosb
          pop  di

; move name to buffer

          mov  si,offset ScratchBuffer
          .call str_len
          mov  di,offset RDLBuffer
          rep  movsb

; write name to .HOG file

          mov  cx,[RDLBufrLength]
          mov  bx,[HogHandle]
          mov  si,offset RDLBuffer
          .call write_h
          jnc  @F
HWriteErr:
          mov  si,offset HogWriteError
          .call cput_str
          jmp  ErrorCodeDisplay

; write RDL size to .HOG file

@@:       mov  si,offset RDLSize
          mov  cx,4
          .call write_h
          jc   HWriteErr

; transfer RDL file info to HOG file

ReadWriteLoop:
          xor  si,si
          mov  cx,READWRITEBUFR
          mov  bx,[RDLHandle]
          push ds
          mov  ds,[MemSeg]
          .call read_h
          pop  ds
          ja   NoMoreRDL           ; CX = 0, all done
          jc   ReadRDLError
          xor  si,si
          mov  bx,[HogHandle]
          push ds
          mov  ds,[MemSeg]
          .call write_h
          pop  ds
          jc   HWriteErr
          jmp  short ReadWriteLoop

NoMoreRDL:
          mov  bx,[RDLHandle]
          .call close_h
          mov  [RDLHandle],0
          jmp  RDLLoop             ; go get another RDL file

ReadRDLError:
          mov  si,offset RDLReadError
          .call cput_str
          jmp  ErrorCodeDisplay

; clean up and go home

AllDone:  mov  bx,[HogHandle]
          or   bx,bx
          jz   @F
          .call close_h
@@:       mov  bx,[MSNHandle]
          or   bx,bx
          jz   @F
          .call close_h
@@:       mov  bx,[RDLHandle]
          or   bx,bx
          jz   @F
          .call close_h
@@:       mov  ax,[MemSeg]
          or   ax,ax
          jz   @F
          mov  es,ax
          mov  ah,49h
          int  21h
@@:       ret            ;exit to DOS with ERRORLEVEL=0
.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

.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
