You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1180 lines
30 KiB
1180 lines
30 KiB
;/*
|
|
; * Microsoft Confidential
|
|
; * Copyright (C) Microsoft Corporation 1991
|
|
; * All Rights Reserved.
|
|
; */
|
|
|
|
Title E2BINIT(EXE2BIN)
|
|
|
|
;*****************************************************************************
|
|
; Loader for EXE files under 86-DOS
|
|
; VER 1.5
|
|
; 05/21/82 Added rev number
|
|
; VER 1.6
|
|
; 07/01/82 A little less choosy about size matches
|
|
; VER 2.0 M.A.U
|
|
; 10/08/82 Modified to use new 2.0 system calls for file i/o
|
|
; Ver 2.1 M.A.U
|
|
; 10/27/82 Added the DOS version check
|
|
; Ver 2.2 MZ
|
|
; 8/30/83 Fixed command line parsing
|
|
; Ver 2.3 EE
|
|
; 10-12-83 More fixes to command line parsing
|
|
; Ver 2.4 NP
|
|
; 10/17/83 Use Printf for messages
|
|
; Ver 2.5 MZ Fix LOCATE sss D: problem
|
|
; 04/09/87 Add PARSER and MESSAGE RETRIEVER
|
|
; Ver 4.00 DRM
|
|
;
|
|
; M001 MD 12/27/90 Removed special checks for ambiguous
|
|
; file names
|
|
;*****************************************************************************
|
|
|
|
|
|
INCLUDE SYSMSG.INC
|
|
MSG_UTILNAME <EXE2BIN> ;AN000;
|
|
|
|
subttl Main Code Area ;AN000;
|
|
page
|
|
|
|
|
|
; The following switch allows use with the "old linker", which put a version
|
|
; number where the new linker puts the number of bytes used in the last page.
|
|
; If enabled, this will cause a test for 0004 at this location (the old linker
|
|
; version number), and if equal, change it to 200H so all of the last page
|
|
; will be used.
|
|
|
|
OLDLINK EQU 0 ;1 to enable, 0 to disable
|
|
|
|
CODE SEGMENT PARA PUBLIC 'CODE' ;AN000;
|
|
CODE ENDS ;AN000;
|
|
DATA SEGMENT PARA PUBLIC 'DATA' ;AN000;
|
|
DATA ENDS ;AN000;
|
|
STACK SEGMENT PARA PUBLIC 'STACK' ;AN000;
|
|
STACK ENDS ;AN000;
|
|
ZLOAD SEGMENT PARA PUBLIC 'ZLOAD' ;AN000;
|
|
ZLOAD ENDS ;AN000;
|
|
|
|
DATA SEGMENT PARA PUBLIC 'DATA' ;AN000;
|
|
|
|
MSG_SERVICES <MSGDATA> ;AN000;
|
|
|
|
Command_Line_Buffer db 128 dup(0) ;AN000;
|
|
Command_Line_Length equ $ - Command_Line_Buffer ;AN000;
|
|
|
|
Fatal_Error db 0 ;AN000;
|
|
|
|
Command_Line db NO
|
|
|
|
|
|
|
|
rev db "2.4"
|
|
|
|
|
|
file1_ext db ".EXE",00h
|
|
file2_ext db ".BIN",00h
|
|
|
|
per11 db 0 ;AN000;
|
|
per2 db 0
|
|
per22 db 0 ;AN000;
|
|
|
|
update equ 0 ;AN000;
|
|
noupdate equ -1 ;AN000;
|
|
|
|
file1 db (64+13) dup(?)
|
|
fnptr dw offset file1 ; Ptr to filename in file1
|
|
handle1 dw 1 dup(?)
|
|
|
|
file2 db (64+13) dup(?)
|
|
f2cspot dw offset file2 ; Ptr to spot in file2, file1 maybe added
|
|
|
|
name2_given db 1 ;1-> atleast the file2 name is present
|
|
ext2_given db 0 ;1-> full file2 spec given
|
|
file2_given db 0 ; is TRUE if user specified atleast a
|
|
; drive, or path (or full name)
|
|
handle2 dw 1 dup(?)
|
|
|
|
dma_buf db 80h dup(0) ; DMA transfer buffer
|
|
|
|
INBUF DB 5,0
|
|
DB 5 DUP(?)
|
|
|
|
;The following locations must be defined for storing the header:
|
|
|
|
RUNVAR LABEL BYTE ;Start of RUN variables
|
|
RELPT DW ?
|
|
LASTP LABEL WORD
|
|
RELSEG DW ?
|
|
SIZ LABEL WORD ;Share these locations
|
|
PAGES DW ?
|
|
RELCNT DW ?
|
|
HEADSIZ DW ?
|
|
DW ?
|
|
LOADLOW DW ?
|
|
INITSS DW ?
|
|
INITSP DW ?
|
|
DW ?
|
|
INITIP DW ?
|
|
INITCS DW ?
|
|
RELTAB DW ?
|
|
RUNVARSIZ EQU $-RUNVAR
|
|
|
|
DBCS_Vector_Off dw 0 ;AN000;
|
|
DBCS_Vector_Seg dw 0 ;AN000;
|
|
|
|
parse_ptr DW ?
|
|
|
|
DATA ENDS
|
|
|
|
|
|
STACK SEGMENT PARA PUBLIC 'STACK'
|
|
DB (362 - 80h) + 80H DUP (?) ; (362 - 80h) is IBMs ROM requirement
|
|
; (New - Old) == size of growth
|
|
STACK ENDS
|
|
;
|
|
|
|
|
|
|
|
ZLOAD SEGMENT PARA PUBLIC 'ZLOAD'
|
|
db ?
|
|
ZLOAD ENDS
|
|
LOAD EQU ZLOAD
|
|
;
|
|
|
|
|
|
|
|
;
|
|
;*****************************************************************************
|
|
; Include files
|
|
;*****************************************************************************
|
|
;
|
|
|
|
.xlist
|
|
INCLUDE DOSSYM.INC ; also versiona.inc ;AN000;
|
|
INCLUDE SYSCALL.INC ;AN000;
|
|
INCLUDE E2BMACRO.INC ;AN000;
|
|
INCLUDE E2BEQU.INC ;AN000;
|
|
INCLUDE E2BTABLE.INC ;AN000;
|
|
INCLUDE E2BPARSE.INC ;AN000;
|
|
include version.inc
|
|
.list
|
|
|
|
|
|
|
|
CODE SEGMENT PARA PUBLIC 'CODE'
|
|
assume cs:CODE,ds:DATA,es:NOTHING,SS:STACK ;AN000;
|
|
|
|
psp_ptr dw 1 dup(?) ;AN000;
|
|
;
|
|
;*****************************************************************************
|
|
; SysDisplayMsg Declarations
|
|
;*****************************************************************************
|
|
;
|
|
.xlist
|
|
MSG_SERVICES <LOADmsg> ;AN000;
|
|
MSG_SERVICES <DISPLAYmsg,CHARmsg> ;AN000;
|
|
MSG_SERVICES <EXE2BIN.CLA,EXE2BIN.CLB> ;AN000;
|
|
MSG_SERVICES <EXE2BIN.CL1,EXE2BIN.CL2> ;AN000;
|
|
MSG_SERVICES <EXE2BIN.CTL> ;AN000;
|
|
|
|
|
|
.list
|
|
|
|
;
|
|
;*****************************************************************************
|
|
; External Routine Declarations
|
|
;*****************************************************************************
|
|
;
|
|
|
|
public SysDispMsg ;AN000;
|
|
public SysLoadMsg ;AN000;
|
|
|
|
|
|
;*****************************************************************************
|
|
;Routine name: Main_Init
|
|
;*****************************************************************************
|
|
;
|
|
;Description: Main control routine for init section
|
|
;
|
|
;Called Procedures: Message (macro)
|
|
; Check_DOS_Version
|
|
; Init_Input_Output
|
|
; Validate_Target_Drive
|
|
; Hook_CNTRL_C
|
|
;
|
|
;Input: None
|
|
;
|
|
;Output: None
|
|
;
|
|
;Change History: Created 6/22/87 DM
|
|
;
|
|
;*****************************************************************************
|
|
|
|
procedure Main_Init near ; ;AN000;
|
|
|
|
ASSUME DS:NOTHING ; THIS IS WHAT dos GIVES YOU ;AN000;
|
|
ASSUME ES:NOTHING ;AN000;
|
|
|
|
PUSH DS ;AN000;
|
|
mov psp_ptr,ds ;AN000;
|
|
XOR AX,AX ;AN000;
|
|
PUSH AX ;Push return address to DS:0 ;AN000;
|
|
|
|
MOV AX,SEG DATA ;SET UP ADDRESSABILITY TO ;AN000;
|
|
MOV DS,AX ; THE DATA SEGMENT ;AN000;
|
|
ASSUME DS:DATA ;TELL ASSEMBLER WHAT I JUST DID ;AN000;
|
|
|
|
mov Fatal_Error,No ;Init the error flag ;AN000;
|
|
call Init_Input_Output ;Setup messages and parse ;AN000;
|
|
cmp Fatal_Error,Yes ;Error occur? ;AN000;
|
|
; $IF NE ;Nope, keep going ;AN000;
|
|
JE $$IF1
|
|
call LOCATE ;Go do the real program ;AN000;
|
|
; $ENDIF ;AN000;
|
|
$$IF1:
|
|
xor al,al ;AN000;
|
|
Dos_call Exit ;AN000;
|
|
int 20h ;If other exit fails ;AN000;
|
|
|
|
Main_Init endp ;AN000;
|
|
|
|
;*****************************************************************************
|
|
;Routine name: Init_Input_Output
|
|
;*****************************************************************************
|
|
;
|
|
;Description: Initialize messages, Parse command line, allocate memory as
|
|
; needed. If there is a /FS switch, go handle it first as
|
|
; syntax of IFS format may be different from FAT format.
|
|
;
|
|
;Called Procedures: Preload_Messages
|
|
; Parse_For_FS_Switch
|
|
; Parse_Command_Line
|
|
; Interpret_Parse
|
|
;
|
|
;Change History: Created 6/22/87 DM
|
|
;
|
|
;Input: PSP command line at 81h and length at 80h
|
|
; Fatal_Error = No
|
|
;
|
|
;Output: Fatal_Error = YES/NO
|
|
;
|
|
;*****************************************************************************
|
|
|
|
procedure Init_Input_Output near ;AN000;
|
|
|
|
call Preload_Messages ;Load up message retriever ;AN000;
|
|
cmp Fatal_Error,YES ;Quit? ;AN000;
|
|
; $IF NE ;Nope, keep going ;AN000;
|
|
JE $$IF3
|
|
call Parse_Command_Line ;Parse in command line input ;AN000;
|
|
; $ENDIF ;AN000;
|
|
$$IF3:
|
|
ret ;AN000;
|
|
|
|
Init_Input_Output endp ;AN000;
|
|
|
|
;*****************************************************************************
|
|
;Routine name: Preload_Messages
|
|
;*****************************************************************************
|
|
;
|
|
;Description: Preload messages using common message retriever routines.
|
|
;
|
|
;Called Procedures: SysLoadMsg
|
|
;
|
|
;
|
|
;Change History: Created 6/22/87 DM
|
|
;
|
|
;Input: Fatal_Error = NO
|
|
;
|
|
;Output: Fatal_Error = YES/NO
|
|
;
|
|
;*****************************************************************************
|
|
|
|
procedure Preload_Messages near ;AN000;
|
|
|
|
call SYSLOADMSG ;Preload the messages ;AN000;
|
|
; $IF C ;Error? ;AN000;
|
|
JNC $$IF5
|
|
call SYSDISPMSG ;AN000;
|
|
mov fatal_error, YES ;AN000;
|
|
; $ENDIF ;AN000;
|
|
$$IF5:
|
|
ret ;AN000;
|
|
Preload_Messages endp ;AN000;
|
|
|
|
|
|
;*****************************************************************************
|
|
;Routine name: Parse_Command_Line
|
|
;*****************************************************************************
|
|
;
|
|
;Description: Parses command line.
|
|
;
|
|
;Called Procedures: Message (macro)
|
|
; Sysparse
|
|
;
|
|
;Change History: Created 6/22/87 DM
|
|
;
|
|
;Input: Fatal_Error = NO
|
|
;
|
|
;Output: Fatal_Error = YES/NO
|
|
;
|
|
;*****************************************************************************
|
|
|
|
|
|
Procedure Parse_Command_Line ;AN000;
|
|
|
|
push ds ;AN000;
|
|
mov ds,psp_ptr ;AN000;
|
|
ASSUME DS:NOTHING ;AN000;
|
|
mov si,Command_Line_Parms ;AN000;
|
|
mov ax,seg command_line_table ;AN000;
|
|
push es ;AN000;
|
|
mov es,ax ;AN000;
|
|
ASSUME ES:NOTHING ;AN000;
|
|
mov di,offset Command_Line_Table ;AN000;
|
|
xor cx,cx ;AN000;
|
|
|
|
PUBLIC MainParseLoop
|
|
MainParseLoop:
|
|
|
|
; $DO ;AN000;
|
|
$$DO7:
|
|
xor dx,dx ;AN000;
|
|
mov es:parse_ptr,si
|
|
call Sysparse ;AN000;
|
|
cmp ax,No_Error ;AN000;
|
|
|
|
; $IF E ;AN000;
|
|
JNE $$IF8
|
|
|
|
; Check if /? switch entered.
|
|
; If so, display the options help message
|
|
; and set for exit.
|
|
;
|
|
; This gives the user the info they want,
|
|
; without all the other possible error messages.
|
|
;
|
|
; 4/18/90 c-PaulB
|
|
|
|
cmp es:[sw_synonym1], offset sw1_s1 ; /?
|
|
jne CheckSW1Done ; skip this if not
|
|
call DisplayOptions ; else display msg
|
|
mov es:[Fatal_Error], YES ; set flag to stop
|
|
jmp ParseCLExit ; and bail out now
|
|
CheckSW1Done:
|
|
|
|
push ax ;AN000;
|
|
push bx ;AN000;
|
|
push ds ;AN000;
|
|
push es ;AN000;
|
|
push si ;AN000;
|
|
push di ;AN000;
|
|
|
|
cmp cx,1 ;AN000;
|
|
|
|
; $IF E ;AN000;
|
|
JNE $$IF9
|
|
|
|
mov ax,seg rb_string1_off ;AN000;
|
|
mov ds,ax ;AN000;
|
|
ASSUME DS:NOTHING ;AN000;
|
|
mov si,offset rb_string1_off ;AN000;
|
|
mov ax,ds:[si] ;AN000;
|
|
mov bx,ax ;AN000;
|
|
|
|
|
|
mov ax,ds:[si+2] ;AN000;
|
|
mov ds,ax ;AN000;
|
|
ASSUME DS:NOTHING ;AN000;
|
|
mov si,bx ;AN000;
|
|
|
|
mov ax,seg file1 ;AN000;
|
|
mov es,ax ;AN000;
|
|
ASSUME ES:NOTHING ;AN000;
|
|
mov di,offset file1 ;AN000;
|
|
call copyfs ;AN000;
|
|
|
|
; $ELSE ;AN000;
|
|
JMP SHORT $$EN9
|
|
$$IF9:
|
|
|
|
mov ax,seg rb_string2_off ;AN000;
|
|
mov ds,ax ;AN000;
|
|
ASSUME DS:NOTHING ;AN000;
|
|
mov si,offset rb_string2_off ;AN000;
|
|
mov ax,ds:[si] ;AN000;
|
|
mov bx,ax ;AN000;
|
|
|
|
|
|
mov ax,ds:[si+2] ;AN000;
|
|
mov ds,ax ;AN000;
|
|
ASSUME DS:NOTHING ;AN000;
|
|
mov si,bx ;AN000;
|
|
|
|
mov ax,seg file2 ;AN000;
|
|
mov es,ax ;AN000;
|
|
ASSUME ES:NOTHING ;AN000;
|
|
mov di,offset file2 ;AN000;
|
|
call copyfs ;AN000;
|
|
|
|
; $ENDIF ;AN000;
|
|
$$EN9:
|
|
|
|
pop di ;AN000;
|
|
pop si ;AN000;
|
|
pop es ;AN000;
|
|
ASSUME ES:NOTHING ;AN000;
|
|
pop ds ;AN000;
|
|
ASSUME DS:NOTHING ;AN000;
|
|
pop bx ;AN000;
|
|
pop ax ;AN000;
|
|
|
|
; $ENDIF ;AN000;
|
|
$$IF8:
|
|
|
|
cmp ax,No_Error ;AN000;
|
|
|
|
; $ENDDO NE ;AN000;
|
|
JE $$DO7
|
|
|
|
cmp ax,End_of_Parse ;Check for parse error ;AN000;
|
|
; $IF NE ;AN000;
|
|
JE $$IF14
|
|
push ax ;AN001;
|
|
mov ax,es:parse_ptr ;AN001;
|
|
mov es:parsoff,ax ;AN001;
|
|
mov es:parseg,ds ;AN001;
|
|
mov byte ptr ds:[si],0 ;AN001;
|
|
pop ax ;AN001;
|
|
parse_message ;Must enter file name ;AN000;
|
|
mov es:Fatal_Error,YES ;Indicate death! ;AN000;
|
|
; $ENDIF ;AN000;
|
|
$$IF14:
|
|
ParseCLExit:
|
|
pop es ;AN000;
|
|
ASSUME ES:NOTHING ;AN000;
|
|
pop ds ;AN000;
|
|
ASSUME DS:DATA ;AN000;
|
|
|
|
ret ;AN000;
|
|
|
|
Parse_Command_Line endp ;AN000;
|
|
|
|
;*****************************************************************************
|
|
;Routine name: Parse_Command_Line
|
|
;*****************************************************************************
|
|
;
|
|
;Description: Displays options help message lines.
|
|
;
|
|
;Called Procedures: Display_Interface
|
|
;
|
|
;Change History: Created 5/2/90 c-PaulB
|
|
;
|
|
;Input: No value passed.
|
|
;
|
|
;Output: No value returned.
|
|
;
|
|
;*****************************************************************************
|
|
|
|
|
|
Procedure DisplayOptions
|
|
|
|
mov dx, offset msgOptions ; get options msg
|
|
DO_Loop:
|
|
call Display_Interface ; and show it
|
|
cmp word ptr es:[msgOptions], MSG_OPTIONS_LAST ; last msg?
|
|
je DO_Done ; done if so
|
|
inc word ptr es:[msgOptions] ; else get next msg
|
|
jmp short DO_Loop ; and go do it
|
|
DO_Done:
|
|
ret
|
|
|
|
DisplayOptions endp
|
|
|
|
;*****************************************************************************
|
|
|
|
INCLUDE PARSE.ASM
|
|
|
|
;*****************************************************************************
|
|
|
|
|
|
procedure LOCATE near
|
|
|
|
push ds ;AN000;
|
|
ASSUME ES:NOTHING ; THIS IS THE WAY IT GETS HERE! ;AN000;
|
|
mov ax,es ; ES -> PSP ;AN000;
|
|
mov ds,ax ; DS -> PSP ;AN000;
|
|
ASSUME DS:NOTHING ;AN000;
|
|
|
|
MOV SI,offset file1
|
|
MOV BX,SEG DATA
|
|
MOV ES,BX
|
|
assume es:data ;AN000;
|
|
|
|
MOV BX,WORD PTR DS:[2] ;Get size of memory
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
|
|
;
|
|
; The rules for the arguments are:
|
|
; File 1:
|
|
; If no extention is present, .EXE is used.
|
|
; File 2:
|
|
; If no drive is present in file2, use the one from file1
|
|
; If no path is specified, then use current dir
|
|
; If no filename is specified, use the filename from file1
|
|
; If no extention is present in file2, .BIN is used
|
|
;
|
|
|
|
|
|
;----- Get the first file name
|
|
push ds ;AN000;
|
|
push es ;AN000;
|
|
ASSUME ES:DATA ;AN000;
|
|
pop ds ;AN000;
|
|
ASSUME DS:DATA ;AN000;
|
|
|
|
sj01:
|
|
mov si,offset file1 ; d = file1;
|
|
mov per11,0 ; assume no extension on file1;AC000;
|
|
|
|
;******************************************************************************
|
|
|
|
sj0:
|
|
lodsb ; while (!IsBlank(c=*p++)) {
|
|
cmp al,0
|
|
JE SJ2
|
|
call dbcs_check ; see if a dbcs character ;AN000;
|
|
jc dbcs_1 ; dbcs character, go load another char ;AN000;
|
|
cmp al,'\' ; if (c == '\\' || c == ':') {
|
|
jnz sj05
|
|
mov per11,update ;AC000;
|
|
mov fnptr,si ; fnptr = ptr to slash
|
|
sj05:
|
|
cmp al,':' ; if (c == '\\' || c == ':') {
|
|
jnz checkper1
|
|
mov per11,update ;AC000;
|
|
mov fnptr,si ; fnptr = ptr to slash
|
|
checkper1:
|
|
cmp al,'.' ; if (c == '.')
|
|
jne sj0 ; ;M001
|
|
mov per11,noupdate ; set file1 to have extension ;AN000;
|
|
jmp short sj0 ; ;M001
|
|
;M001 - code removed
|
|
dbcs_1: ; ;AN000;
|
|
lodsb ; load another character and got to ;AN000;
|
|
jmp short sj0 ; the start again. ;AN000;
|
|
|
|
;******************************************************************************
|
|
|
|
sj2:
|
|
get_second:
|
|
;----- Get the second file name
|
|
; Initially we assume that user has not given any file2 spec. Then if we find
|
|
; that user has entered something, then file2_given is made to TRUE;
|
|
; Once file2_given is TRUE, then we assume that user has given atleast a name
|
|
; i.e. name2_given = 1 but ext2_given = 0;
|
|
; if we find that user has given just a drive: then name2_given is made to FALSE
|
|
; The logic then simplifies to :
|
|
; if (!file2_given)
|
|
; copy file1 and add .BIN ext and try to open
|
|
; else { /* file2 given */
|
|
; if (!name2_given)
|
|
; copy name from file1 and .BIN as extn ; try to open
|
|
; else { /* name2 also given */
|
|
; do find_first
|
|
; if (file_not_found)
|
|
; add extn .BIN if needed and try to open
|
|
; else if (it is subdir) {
|
|
; add '\' to it;
|
|
; add the file1 name and .BIN
|
|
; go for file open
|
|
; }
|
|
; } /* else name2 given*/
|
|
; } /* else file2 given */
|
|
|
|
MOV SI,offset file1
|
|
mov di,offset file2 ; d = file2
|
|
|
|
;******************************************************************************
|
|
|
|
sj3:
|
|
cmp word ptr [di],00 ; check to see if first character of
|
|
je sj32 ; file2 is a null. ;AN000;
|
|
mov file2_given,1 ; user has given atleast a partial
|
|
; spec for file2
|
|
mov si,offset file2 ; set pointer to file2
|
|
|
|
;******************************************************************************
|
|
|
|
sj31:
|
|
lodsb ; If file2 first character is not a
|
|
mov f2cspot,si
|
|
cmp al,0 ; null, this loop will check to see
|
|
JZ maycopy ; the file has an extension assigned;AN000;
|
|
call dbcs_check ; to it. If not it will set per2 to ;AN000;
|
|
jc dbcs_2 ; go load another byte ;AN000;
|
|
cmp al,'\'
|
|
jnz checkper6
|
|
cmp byte ptr [si],0 ; end of file2 spec ?
|
|
jne sj31 ; no, go get next char
|
|
mov name2_given,0 ; copy from file1
|
|
checkper6:
|
|
cmp al,':' ; if (c == '\\' || c == ':') {
|
|
jnz checkper4
|
|
cmp byte ptr [si],0 ; end of file2 spec ?
|
|
jne sj31 ; no, go get next char
|
|
mov name2_given,0 ; no name; copy from file1
|
|
checkper4: ; there is an extension already.
|
|
cmp al,'.' ;
|
|
jne sj31 ; M001
|
|
mov ext2_given,1 ; M001 - code removed
|
|
jmp short sj31 ; M001
|
|
; M001 - code removed
|
|
dbcs_2: ;
|
|
lodsb ;load another character and got to ;AN000;
|
|
jmp short sj31 ;the start again. ;AN000;
|
|
|
|
;******************************************************************************
|
|
|
|
; we get here only if user specified something - a drive, just a name or
|
|
; even the full spec
|
|
; check if we have to copy the name
|
|
|
|
maycopy:
|
|
cmp name2_given,1 ; did the user give a name
|
|
je sj5 ; yes, go check for the existence
|
|
|
|
dec f2cspot
|
|
mov di,f2cspot
|
|
|
|
sj32:
|
|
; There is no second filename so
|
|
mov si,fnptr ;AN000;
|
|
|
|
;******************************************************************************
|
|
|
|
copy1to2: ;AN000;
|
|
lodsb ; This loop is executed when there is ;AN000;
|
|
cmp al,0 ; no file2 specified on the command ;AN000;
|
|
JZ SJ5 ; line. It will copy the file1 name ;AN000;
|
|
call dbcs_check ; check for dbcs character ;AN000;
|
|
jc dbcs_3 ; got a dbcs character, go copy. ;AN000;
|
|
cmp al,'.' ; extension. The defult extension ;AN000;
|
|
je sj5 ; of .BIN will be added in check_ext. ;AN000;
|
|
stosb ;AN000;
|
|
jmp short copy1to2 ;AN000;
|
|
dbcs_3:
|
|
stosb ; Got a dbcs character. Copy ;AN000;
|
|
lodsb ; two characters and then go to ;AN000;
|
|
stosb ; next character in filename. ;AN000;
|
|
jmp short copy1to2 ;AN000; ;AN000;
|
|
|
|
;******************************************************************************
|
|
|
|
sj5:
|
|
; mov byte ptr es:[di],00h ; *d = 0;
|
|
cmp file2_given,1 ; if the user specified some path
|
|
jne check_ext ; we need to check it; else
|
|
cmp name2_given,1 ; add .BIN and try to open file2
|
|
jne check_ext ; (at this point we have the name)
|
|
mov ah,Set_DMA ; Use find_first to see if file2 is
|
|
mov dx,offset dma_buf ; a directory. If it isn't, go to
|
|
int 21h ; set f2cspot to point to the spot
|
|
mov ah,Find_First ; right after the backslash, and
|
|
mov dx,offset file2 ; fall through to no_second so that
|
|
mov cx,-1 ; file1's name will be added to file2.
|
|
int 21h
|
|
jc check_ext
|
|
test dma_buf+21,00010000b
|
|
jNZ DoDirectory
|
|
jmp short Check_Ext
|
|
DoDirectory:
|
|
mov AL,'\'
|
|
mov di,f2cspot
|
|
dec di
|
|
stosb
|
|
inc f2cspot
|
|
mov name2_given,0 ; so that we will copy file1.ext to
|
|
mov ext2_given,0 ; file2; we also have to copy ext
|
|
jmp maycopy ;
|
|
|
|
|
|
;----- Check that files have an extension, otherwise set default
|
|
check_ext:
|
|
cmp per11,noupdate ; if (ext2_given == NULL) { ;AC000;
|
|
jz file1_ok
|
|
mov di,offset file1 ; d = file1;
|
|
mov si,offset file1_ext ; s = ".EXE";
|
|
call strcat ; strcat (d, s);
|
|
file1_ok: ; }
|
|
cmp ext2_given,1 ; if (ext2_given == NULL) { ;AC000;
|
|
je file2_ok
|
|
mov di,offset file2 ; d = file2;
|
|
mov si,offset file2_ext ; s = ".BIN";
|
|
call strcat ; strcat (d, s);
|
|
jmp short file2_ok ; }
|
|
|
|
;-----------------------------------------------------------------------;
|
|
file2_ok:
|
|
mov dx,offset file1
|
|
mov ax,(open SHL 8) + 0 ;for reading only
|
|
INT 21H ;Open input file
|
|
jc bad_file
|
|
mov [handle1],ax
|
|
jmp short exeload
|
|
|
|
bad_file:
|
|
jmp DosError
|
|
|
|
BADEXE:
|
|
pop ds
|
|
ASSUME DS:nothing ;AN000;
|
|
MESSAGE msgNoConvert ;AC000;
|
|
jmp getout ;AN000;
|
|
|
|
ReadError:
|
|
jmp DosError
|
|
|
|
EXELOAD:
|
|
ASSUME DS:DATA ;AN000;
|
|
MOV DX,OFFSET RUNVAR ;Read header in here
|
|
MOV CX,RUNVARSIZ ;Amount of header info we need
|
|
push bx
|
|
mov bx,[handle1]
|
|
MOV AH,read
|
|
INT 21H ;Read in header
|
|
pop bx
|
|
jc ReadError
|
|
CMP [RELPT],5A4DH ;Check signature word
|
|
JNZ BADEXE
|
|
MOV AX,[HEADSIZ] ;size of header in paragraphs
|
|
ADD AX,31 ;Round up first
|
|
CMP AX,1000H ;Must not be >=64K
|
|
JAE TOOBIG
|
|
AND AX,NOT 31
|
|
MOV CL,4
|
|
SHL AX,CL ;Header size in bytes
|
|
|
|
push dx
|
|
push cx
|
|
push ax
|
|
push bx
|
|
mov dx,ax
|
|
xor cx,cx
|
|
mov al,0
|
|
mov bx,[handle1]
|
|
mov ah,lseek
|
|
int 21h
|
|
jc LseekError
|
|
pop bx
|
|
pop ax
|
|
pop cx
|
|
pop dx
|
|
|
|
XCHG AL,AH
|
|
SHR AX,1 ;Convert to pages
|
|
MOV DX,[PAGES] ;Total size of file in 512-byte pages
|
|
SUB DX,AX ;Size of program in pages
|
|
CMP DX,80H ;Fit in 64K? (128 * 512 = 64k)
|
|
JAE TOOBIG
|
|
XCHG DH,DL
|
|
SHL DX,1 ;Convert pages to bytes
|
|
MOV AX,[LASTP] ;Get count of bytes in last page
|
|
OR AX,AX ;If zero, use all of last page
|
|
JZ WHOLEP
|
|
|
|
IF OLDLINK
|
|
CMP AX,4 ;Produced by old linker?
|
|
JZ WHOLEP ;If so, use all of last page too
|
|
ENDIF
|
|
|
|
SUB DX,200H ;Subtract last page
|
|
ADD DX,AX ;Add in byte count for last page
|
|
WHOLEP:
|
|
MOV [SIZ],DX
|
|
ADD DX,15
|
|
SHR DX,CL ;Convert bytes to paragraphs
|
|
MOV BP,SEG LOAD
|
|
ADD DX,BP ;Size + start = minimum memory (paragr.)
|
|
CMP DX,BX ;Enough memory?
|
|
JA TOOBIG
|
|
MOV AX,[INITSS]
|
|
OR AX,[INITSP]
|
|
OR AX,[INITCS]
|
|
JMP short ERRORNZ
|
|
|
|
TOOBIG:
|
|
pop ds
|
|
ASSUME DS:NOTHING ;AN000;
|
|
MESSAGE msgOutOfMemory ;AN000;
|
|
jmp getout ;AN000;
|
|
|
|
LseekError:
|
|
jmp DosError
|
|
|
|
|
|
ERRORNZ:
|
|
ASSUME DS:DATA ;AN000;
|
|
jz xj
|
|
JMP BADEXE ;AC000; For ptm P475;
|
|
xj: MOV AX,[INITIP]
|
|
OR AX,AX ;If IP=0, do binary fix
|
|
JZ BINFIX
|
|
CMP AX,100H ;COM file must be set up for CS:100
|
|
JNZ ERRORNZ
|
|
|
|
push dx
|
|
push cx
|
|
push ax
|
|
push bx
|
|
mov dx,100h ;chop off first 100h
|
|
xor cx,cx
|
|
mov al,1 ;seek from current position
|
|
mov bx,[handle1]
|
|
mov ah,lseek
|
|
int 21h
|
|
jc LseekError
|
|
pop bx
|
|
pop ax
|
|
pop cx
|
|
pop dx
|
|
|
|
SUB [SIZ],AX ;And count decreased size
|
|
CMP [RELCNT],0 ;Must have no fixups
|
|
JNZ ERRORNZ
|
|
BINFIX:
|
|
XOR BX,BX ;Initialize fixup segment
|
|
;See if segment fixups needed
|
|
CMP [RELCNT],0
|
|
JZ LOADEXE
|
|
GETSEG:
|
|
pop ds
|
|
ASSUME DS:NOTHING ;AN000;
|
|
MESSAGE msgFixUp ;AN000;
|
|
PUSH DS
|
|
PUSH ES
|
|
POP DS
|
|
ASSUME DS:DATA ;AN000;
|
|
MOV AH,STD_CON_STRING_INPUT
|
|
MOV DX,OFFSET INBUF
|
|
INT 21H ;Get user response
|
|
MOV SI,OFFSET INBUF+2
|
|
;;dcl;; MOV BYTE PTR [SI-1],0 ;Any digits?
|
|
cmp BYTE PTR [SI-1],0 ;Any digits? ;AC000;
|
|
JZ GETSEG
|
|
DIGLP:
|
|
LODSB
|
|
SUB AL,"0"
|
|
JC DIGERR
|
|
CMP AL,10
|
|
JB HAVDIG
|
|
AND AL,5FH ;Convert to upper case
|
|
SUB AL,7
|
|
CMP AL,10
|
|
JB DIGERR
|
|
CMP AL,10H
|
|
JAE DIGERR
|
|
HAVDIG:
|
|
SHL BX,1
|
|
SHL BX,1
|
|
SHL BX,1
|
|
SHL BX,1
|
|
OR BL,AL
|
|
JMP DIGLP
|
|
|
|
DIGERR:
|
|
CMP BYTE PTR [SI-1],0DH ;Is last char. a CR?
|
|
JNZ GETSEG
|
|
LOADEXE:
|
|
XCHG BX,BP ;BX has LOAD, BP has fixup
|
|
|
|
MOV CX,[SIZ]
|
|
MOV AH,read
|
|
push di
|
|
mov di,[handle1]
|
|
PUSH DS
|
|
MOV DS,BX
|
|
ASSUME DS:NOTHING ;AN000;
|
|
XOR DX,DX
|
|
push bx
|
|
mov bx,di
|
|
INT 21H ;Read in up to 64K
|
|
pop bx
|
|
POP DS
|
|
ASSUME DS:DATA ;AN000;
|
|
pop di
|
|
Jnc HAVEXE ;Did we get it all?
|
|
|
|
jmp DosError
|
|
|
|
LseekError2:
|
|
jmp DosError
|
|
|
|
HAVEXE:
|
|
ASSUME DS:DATA ;AN000;
|
|
CMP [RELCNT],0 ;Any fixups to do?
|
|
JZ STORE
|
|
MOV AX,[RELTAB] ;Get position of table
|
|
|
|
push dx
|
|
push cx
|
|
push ax
|
|
push bx
|
|
mov dx,ax
|
|
xor cx,cx
|
|
mov al,0
|
|
mov bx,[handle1]
|
|
mov ah,lseek
|
|
int 21h
|
|
jc LseekError2
|
|
pop bx
|
|
pop ax
|
|
pop cx
|
|
pop dx
|
|
|
|
MOV DX,OFFSET RELPT ;4-byte buffer for relocation address
|
|
RELOC:
|
|
MOV DX,OFFSET RELPT ;4-byte buffer for relocation address
|
|
MOV CX,4
|
|
MOV AH,read
|
|
push bx
|
|
mov bx,[handle1]
|
|
INT 21H ;Read in one relocation pointer
|
|
pop bx
|
|
Jnc RDCMP
|
|
jmp short DosError
|
|
RDCMP:
|
|
MOV DI,[RELPT] ;Get offset of relocation pointer
|
|
MOV AX,[RELSEG] ;Get segment
|
|
ADD AX,BX ;Bias segment with actual load segment
|
|
MOV ES,AX
|
|
ASSUME ES:NOTHING ;AN000;
|
|
ADD ES:[DI],BP ;Relocate
|
|
DEC [RELCNT] ;Count off
|
|
JNZ RELOC
|
|
STORE:
|
|
MOV AH,CREAT
|
|
MOV DX,OFFSET file2
|
|
xor cx,cx
|
|
INT 21H
|
|
Jc MKERR
|
|
mov [handle2],ax
|
|
MOV CX,[SIZ]
|
|
MOV AH,write
|
|
push di
|
|
mov di,[handle2]
|
|
PUSH DS
|
|
MOV DS,BX
|
|
ASSUME DS:NOTHING ;AN000;
|
|
XOR DX,DX ;Address 0 in segment
|
|
push bx
|
|
mov bx,di
|
|
INT 21H
|
|
pop bx
|
|
POP DS
|
|
ASSUME DS:DATA ;AN000;
|
|
pop di
|
|
Jc WRTERR ;Must be zero if more to come
|
|
cmp AX,CX
|
|
jnz NOROOM
|
|
MOV AH,CLOSE
|
|
push bx
|
|
mov bx,[handle2]
|
|
INT 21H
|
|
jc CloseError
|
|
pop bx
|
|
pop ds
|
|
pop ds
|
|
ASSUME DS:NOTHING ;AN000;
|
|
|
|
RET
|
|
|
|
;*******************************************************************************
|
|
|
|
NOROOM: ; ;AN000;
|
|
ASSUME DS:DATA ;AN000;
|
|
MOV AH,CLOSE ; Close the file here ;AN000;
|
|
push bx ; ;AN000;
|
|
mov bx,[handle2] ; ;AN000;
|
|
INT 21H ; ;AN000;
|
|
jc CloseError ; If error let extend messages get it;AN000;
|
|
pop bx ; ;AN000;
|
|
mov ah,UNLINK ; Delete the file because it did ;AN000;
|
|
MOV DX,OFFSET file2 ; not get written correctly. ;AN000;
|
|
INT 21H ; ;AN000;
|
|
jc CloseError ; If error let extend messages get it;AN000;
|
|
pop ds ; ;AN000;
|
|
ASSUME DS:NOTHING ; ;AN000;
|
|
message msgNoDiskSpace ; Put out insufficient disk space ;AN000;
|
|
jmp short getout ; message ;AN000;
|
|
RET ; return to main_init ;AN000;
|
|
|
|
;*******************************************************************************
|
|
|
|
WRTERR: ;AN000;
|
|
MKERR: ;AN000;
|
|
CloseError: ;AN000;
|
|
|
|
public DosError ;AN000;
|
|
DosError: ;AN000;
|
|
mov es:FileNameSegment,ds ; save for opens, creates, ;AN000;
|
|
mov es:FileNameOffset,dx ;AN000;
|
|
|
|
mov bx,0 ; get the extended error code ;AN000;
|
|
mov ah,059h ;AN000;
|
|
int 21h ;AN000;
|
|
|
|
mov si,offset ds:Sublist_msg_exterror ;AC001;
|
|
extend_message ;AN001;
|
|
pop ds ;AN001;
|
|
|
|
getout: ;AN000;
|
|
pop ds ;AN000;
|
|
ASSUME DS:NOTHING ;AN000;
|
|
|
|
ret ;AN000;
|
|
|
|
|
|
LOCATE ENDP
|
|
|
|
;----- concatenate two strings
|
|
strcat proc near ; while (*d)
|
|
cmp byte ptr [di],0
|
|
jz atend
|
|
inc di ; d++;
|
|
jmp strcat
|
|
atend: ; while (*d++ = *s++)
|
|
lodsb
|
|
stosb
|
|
or al,al ; ;
|
|
jnz atend
|
|
ret
|
|
strcat endp
|
|
|
|
;----- Find the first non-ignorable char, return carry if CR found
|
|
kill_bl proc near
|
|
cld
|
|
sj10: ; while ( *p != 13 &&
|
|
lodsb
|
|
CMP AL,13 ; IsBlank (*p++))
|
|
JZ BreakOut
|
|
CALL IsBlank
|
|
JZ SJ10 ; ;
|
|
BreakOut:
|
|
dec si ; p--;
|
|
cmp al,0dh ; return *p == 13;
|
|
clc
|
|
jne sj11
|
|
stc
|
|
sj11:
|
|
ret
|
|
kill_bl endp
|
|
|
|
IsBlank proc near
|
|
cmp al,00 ;AN000;
|
|
retz ;AN000;
|
|
cmp al,13
|
|
retz
|
|
cmp al,' ' ; space
|
|
retz
|
|
cmp al,9 ; tab
|
|
retz
|
|
cmp al,',' ; comma
|
|
retz
|
|
cmp al,';' ; semicolon
|
|
retz
|
|
cmp al,'+' ; plus
|
|
retz
|
|
cmp al,10 ; line feed
|
|
retz
|
|
cmp al,'=' ; equal sign
|
|
return
|
|
IsBlank Endp
|
|
|
|
|
|
procedure copyfs near
|
|
|
|
push ax ;AN000;
|
|
|
|
; $do ; while we have filespec ;AN000;
|
|
$$DO16:
|
|
lodsb ; move byte to al ;AN000;
|
|
cmp al,0 ; see if we are at ;AN000;
|
|
; the end of the
|
|
; filespec
|
|
; $leave e ; exit while loop ;AN000;
|
|
JE $$EN16
|
|
stosb ; move byte to path_name ;AN000;
|
|
; $enddo ; end do while ;AN000;
|
|
JMP SHORT $$DO16
|
|
$$EN16:
|
|
stosb ;AN000;
|
|
pop ax ;AN000;
|
|
|
|
ret ;AN000;
|
|
copyfs endp ;AN000;
|
|
|
|
|
|
procedure dbcs_check near
|
|
|
|
push ds ;Save registers ;AC000;
|
|
push si ; " " " " ;AC000;
|
|
push ax ; " " " " ;AC000;
|
|
push ds ; " " " " ;AC000;
|
|
pop es ;Establish addressability;AC000;
|
|
cmp byte ptr es:DBCS_VECTOR,Yes ;Have we set this yet? ;AC000;
|
|
push ax ;Save input character ;AC000;
|
|
; $IF NE ;Nope ;AN000;
|
|
JE $$IF19
|
|
mov al,0 ;Get DBCS environment vectors;AC000;
|
|
DOS_Call Hongeul ; " " " " ;AC000;
|
|
mov byte ptr es:DBCS_VECTOR,YES ;Indicate we've got vector;AC000;
|
|
mov es:DBCS_Vector_Off,si ;Save the vector ;AC000;
|
|
mov ax,ds ; ;AC000;
|
|
mov es:DBCS_Vector_Seg,ax ; ;AC000;
|
|
; $ENDIF ; for next time in ;AC000;
|
|
$$IF19:
|
|
pop ax ;Restore input character;AC000;
|
|
mov si,es:DBCS_Vector_Seg ;Get saved vector pointer;AC000;
|
|
mov ds,si ; ;AC000;
|
|
mov si,es:DBCS_Vector_Off ; ;AC000;
|
|
; $SEARCH ;Check all the vectors ;AC000;
|
|
$$DO21:
|
|
cmp word ptr ds:[si],End_Of_Vector ;End of vector table? ;AC000;
|
|
; $LEAVE E ;Yes, done ;AC000;
|
|
JE $$EN21
|
|
cmp al,ds:[si] ;See if char is in vector;AC000;
|
|
; $EXITIF AE,AND ;If >= to lower, and ;AC000;
|
|
JNAE $$IF21
|
|
cmp al,ds:[si+1] ; =< than higher range ;AC000;
|
|
; $EXITIF BE ; then DBCS character ;AC000;
|
|
JNBE $$IF21
|
|
stc ;Set CY to indicate DBCS;AC000;
|
|
; $ORELSE ;Not in range, check next;AC000;
|
|
JMP SHORT $$SR21
|
|
$$IF21:
|
|
add si,DBCS_Vector_Size ;Get next DBCS vector ;AC000;
|
|
; $ENDLOOP ;We didn't find DBCS chaR;AC000;
|
|
JMP SHORT $$DO21
|
|
$$EN21:
|
|
clc ;Clear CY for exit ;AC000;
|
|
; $ENDSRCH ; ;AC000;
|
|
$$SR21:
|
|
pop ax ;Restore registers ;AC000;
|
|
pop si ; " " " " ;AC000;
|
|
pop ds ;Restore data segment ;AC000;
|
|
ret ; ;AC000;
|
|
|
|
ret ;AN000;
|
|
dbcs_check endp ;AN000;
|
|
|
|
|
|
|
|
CODE ends
|
|
|
|
|
|
end main_init ;AC000;
|
|
|
|
|