Leaked source code of windows server 2003
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

;/*
; * 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;