;	PAGE	,132		       ;
;	SCCSID = @(#)sysconf.asm       0.0 86/10/20
;TITLE	BIOS SYSTEM INITIALIZATION
%warning out: ...SYSCONF

;==============================================================================
;REVISION HISTORY:
;AN000 - New for DOS Version 4.00 - J.K.
;AC000 - Changed for DOS Version 4.00 - J.K.
;AN00x - PTM number for DOS Version 4.00 - J.K.
;==============================================================================
;AN001; P132 Multiple character device installation problem.	   06/27/87 J.K.
;AN002; D24  MultiTrack= command added. 			   06/29/87 J.K.
;AN003; D41  REM command in CONFIG.SYS. 			   07/6/87  J.K.
;AN004; D184 Set DEVMARK for MEM command			   08/25/87 J.K.
;AN005; P568 CONFIG.SYS parsing error with FCBS=10,15		   08/31/87 J.K.
;AN006; P887 STACKS=0 does not show "ERROR in CONFIG.SYS..."	   09/09/87 J.K.
;AN007; D246, P976 Show "Bad command or parameters - ..." msg	   09/22/87 J.K.
;AN008; P1299 Set the second entry of DEVMARK for MEM command	   09/25/87 J.K.
;AN009; P1326 New Extended attribute				   09/28/87 J.K.
;AN010; P1820 New message SKL file				   10/20/87 J.K.
;AN011; P1970 AUTOTEST FCBS= command error msg inconsistent	   10/23/87 J.K.
;AN012; P2211 Setting the EA=7 for ANSI.SYS hangs the system	   11/02/87 J.K.
;AN013; P2342 REM not allowed after INSTALL command		   11/09/87 J.K.
;AN014; P2546 DEVICE= command still allowed after IFS=		   11/17/87 J.K.
;AN015; D358  New device driver INIT function package		   12/03/87 J.K.
;AN016; D285 Undo the extended error handling			   12/17/87 J.K.
;AN017; P3170 Do not call block device driver when drive # > 26    01/20/88 J.K.
;AN018; P3111 Take out the order dependency of the INSTALL=	   01/25/88 J.K.
;AN019; D479  New option to disable extended INT 16h function call 02/12/88 J.K.
;AN020; P3607 MEM does not give correct filename		   02/24/88 J.K.
;AN021; D493 Undo D358 & do not show error message for device driv 02/24/88 J.K.
;AN022; P3807 Single buffer unprotected - System hangs		   03/10/88 J.K.
;AN023; P3797 An INSTALL cmd right after Bad cmd is not executed   03/10/88 J.K.
;AN024; D503 Version change to 4.0 - IBMCACHE.SYS is an exception  03/15/88 J.K.
;AN025; D474 Change BUFFERS= /E option to /X for expanded memory   03/16/88 J.K.
;AN026; D506 Take out the order dependency of the IFS=		   03/28/88 J.K.
;AN027; P3957 Undo D503 - IBMCACHE.SYS version check problem	   03/30/88 J.K.
;AN028; P4086 Memory allocation error when loading share.exe	   03/31/88 J.K.
;AN029; D528 Install XMAEM.SYS first before everything else	   04/29/88 J.K.
;AN030; P4759 INT2f, INT 67h handlers for XMA			   05/11/88 J.K.
;AN031; P4889 Should check the validity of INT 67h call 	   05/17/88 G.A.
;AN032; P4934 P4759 INT 2fh number should be changed to 1Bh	   05/20/88 J.K.
;AN033; P5002 EMS w/single page allocated now works		   05/20/88 G.A.
;AN034; P5128 EMS INT 2FH HANDLER BUG				   06/24/88
;==============================================================================

TRUE	    EQU 0FFFFh
FALSE	    EQU 0
LF	equ	10
CR	equ	13
TAB	equ	 9
SEMICOLON equ	';'

IBMVER	   EQU	   TRUE
IBM	   EQU	   IBMVER
STACKSW    EQU	   TRUE 		;Include Switchable Hardware Stacks
IBMJAPVER  EQU	   FALSE		;If TRUE set KANJI true also
%iassign MSVER FALSE
ALTVECT    EQU	   FALSE		;Switch to build ALTVECT version
KANJI	   EQU	   FALSE

HAVE_INSTALL_CMD      equ     00000001b ;AN018; CONFIG.SYS has INSTALL= commands
HAS_INSTALLED	      equ     00000010b ;AN018; SYSINIT_BASE installed.

IS_IFS		      equ   00000001b	;IFS command?
NOT_IFS 	      equ   11111110b
;
;AN016; Undo the extended attribute handling
;;Extended attribute value
;EA_UNSPECIFIED 	 equ	 0	 ;AN009;
;EA_DEVICE_DRIVER	 equ	 6	 ;AN009;
;EA_IFS_DRIVER		 equ	 7	 ;AN009;

DEFAULT_FILENUM equ 8
;
	%IF	IBMJAPVER
NOEXEC	EQU	TRUE
	%ELSE
NOEXEC	EQU	FALSE
	%ENDIF

;DOSSIZE EQU	0A000H
;dossize equ	 0C000H 	;J.K. for the debugging version of IBMDOS.

[list -]
	%include "entryseg.nas"
	%include "msgroup.mac"
;	INCLUDE dossym.INC
	%include "smdossym.mac"	;J.K. Reduced version of DOSSYM.INC
	%include "devsym.mac"
	%include "ioctl.mac"
	%include "biostruc.mac"
	%include "smifssym.mac"	;AN000; Reduced version of IFSSYM.INC.
	%include "devmark.mac"	;AN004;
	%include "version.mac"
	%include "mzheader.mac"
	%include "lstruct.mac"
	%include "memsw.mac"
[list +]

	%IFN IBMJAPVER
	EXTRN	RE_INIT:FAR
	%ENDIF

;

;J.K. 6/29/87 External variable defined in IBMBIO module for Multi-track
MULTRK_ON	EQU	10000000B	;User spcified Mutitrack=on, or System turns
					; it on after handling CONFIG.SYS file as a
					; default value, if MulTrk_flag = MULTRK_OFF1.
MULTRK_OFF1	EQU	00000000B	;initial value. No "Multitrack=" command entered.
MULTRK_OFF2	EQU	00000001B	;User specified Multitrack=off.

section DOSENTRY
	EXTRN	MulTrk_flag:word	;AN002;
	extrn	KEYRD_Func:byte 	;AN019;
	extrn	KEYSTS_Func:byte	;AN019;
; (no prior section) ; CODE ends
;J.K. 6/29/87 End of Multi-track definition.

section SYSINITSEG PUBLIC class=INIT
section SYSINITSEG
	align 16, db 0

ASSUME	CS:SYSINITSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING

	extern alloc_initconfig, alloc_dpb_no_hma
	extern allocate_relocate_block
	extern allocate_temporary_block
	extern allocate_temporary_block.large_allow_error
	extern ParaRound, alloc_init
	extern sysinit_get_ds_dosbiodata

	EXTRN	BADOPM:BYTE,CRLFM:BYTE,BADCOM:BYTE,BADMEM:BYTE,BADBLOCK:BYTE
	EXTRN	BADSIZ_PRE:BYTE,BADLD_PRE:BYTE
;	 EXTRN	 BADSIZ_POST:BYTE,BADLD_POST:BYTE
	EXTRN	BADSTACK:BYTE,BADCOUNTRYCOM:BYTE
	EXTRN	SYSSIZE:BYTE,BADCOUNTRY:BYTE,INSUFMEMORY:BYTE
	extern config_overflow
	EXTRN	CONDEV:BYTE,AUXDEV:BYTE,PRNDEV:BYTE,COMMND:BYTE,CONFIG:BYTE
	EXTRN	Cntry_Drv:BYTE,Cntry_Root:BYTE,Cntry_Path:BYTE
	EXTRN	DeviceParameters:byte
	EXTRN	MEMORY_SIZE:word
	EXTRN	BUFFERS:word
	EXTRN	FILES:byte,NUM_CDS:byte
	EXTRN	DOSINFO:dword,ENTRY_POINT:dword
	EXTRN	FCBS:byte,KEEP:byte
	EXTRN	config_block:word,COMMAND_LINE:byte
	EXTRN	ZERO:byte,SEPCHR:byte
	EXTRN	COUNT:word,CHRPTR:word,CNTRYFILEHANDLE:word
	EXTRN	MEMLO:word,MEMHI:word,PRMBLK:word
	EXTRN	PACKET:byte,UNITCOUNT:byte,BREAK_ADDR:dword
	EXTRN	BPB_ADDR:dword,DRIVENUMBER:byte,SYSI_COUNTRY:dword
	extrn	Config_Size:word		;AN000;
	extrn	Install_Flag:word		;AN000;
	extrn	BadOrder:byte			;AN000;
	extrn	Errorcmd:byte			;AN000;
	extrn	LineCount:word			;AN000;
	extrn	ShowCount:byte			;AN000;
	extrn	Buffer_LineNum:word		;AN000;
	extrn	IFS_Flag:word			;AN000;
	extrn	IFS_RH:byte			;AN000;
	extrn	H_Buffers:word			;AN000;
	extrn	Buffer_Slash_X:byte		;AN000;AN025;
	extrn	Badparm:byte			;AN007;
	extrn	ConfigMsgFlag:Word		;AN015;
	extrn	Org_Count:Word			;AN018;
	extrn	Multi_Pass_Id:byte		;AN026;

	EXTRN	MEM_ERR:NEAR,SetDOSCountryInfo:NEAR
	EXTRN	PARAROUND:NEAR,TEMPCDS_after_block_device:NEAR
	EXTRN	Set_Country_Path:NEAR,Move_ASCIIZ:NEAR,DELIM:NEAR
	EXTRN	BADFIL:NEAR,ROUND:NEAR
	extrn	Do_Install_Exec:NEAR		;AN018;
	extrn	SetDevMark:NEAR 		;AN030;
	extern init2_SNextMCB

;AN016; Undo the extended attribute handling
;	 extrn	 Get_Ext_Attribute:near 	 ;AN009;

	%IF	STACKSW

; Internal Stack Parameters
	EntrySize		equ	8

	MinCount		equ	8
	DefaultCount		equ	9
	MaxCount		equ	64

	MinSize 		equ	32
	DefaultSize		equ	128
	MaxSize 		equ	512

	extrn  stack_count:word
	extrn  stack_size:word
	extrn  stack_addr:dword

	%ENDIF

	PUBLIC DOCONF
	PUBLIC GETCHR
	public Multi_Pass		;AN018;AN026;

	public	MultDeviceFlag
MultDeviceFlag	db	0		;AN001;
	public	DevMark_Addr
DevMark_Addr	dw	?		;AN004;Segment address for DEVMARK.
	public	SetDevMarkFlag
SetDevMarkFlag	    db	    0		;AN004;Flag used for DEVMARK

%ifndef BUF2
EMS_Stub_Installed  db	    0		;AN030;
%endif

Badparm_Ptr	label	dword
Badparm_Off	dw	0		;AN007;
Badparm_Seg	dw	0		;AN007;

	global devicehighflag, devicehighdata, devicehighafter, devicehighsd
	global deviceafter, shellhighflag
	global altah_option, configmsg.altah_message, configmsg.altah_message.error
	global devicefirstnewdpb, devicefirstnewdrive, deviceamountnew
	global cds_installed_last_unit_plus, cds_amount_wanted

country_block:	dw 0
CONFIG_used:	dw 0
checkdeviceflags:	dw 1
devicefilesizepara:	dw 0
devicehighsd:		dw 0
devicehighdata:		dw 0
devicehighsize:		dw 0
devicehighafter:	dw 0
deviceafter:		dw 0
devicelastdpb:		dd -1
devicefirstnewdpb:	dd -1
deviceamountnew:	db 0
devicefirstnewdrive:	db 0
cds_installed_last_unit_plus: db 0
cds_amount_wanted:	db 0
devicehighflag:		db 0
shellhighflag:		db 0
altah_option:		db 0
 global hidedosentry_option, hidedosdatafirst_option
hidedosentry_option:	db 0
hidedosdatafirst_option:db 0
	align 2, db 0
 global autobounce_both_options, autobouncehmachs_option, autobouncehmalba_option
autobounce_both_options:
autobouncehmachs_option:db -1
autobouncehmalba_option:db -1
 global enlargelma_option
enlargelma_option:	db -1
installasfirst_option:	db 0
installaslast_option:	db 0
 global preservecds_option
preservecds_option:	db -1
 global reinitcds_option
reinitcds_option:	db 0

 extern dosdata_relocate_first, dosdata_relocate_early

	struc COMPATOPTION
coSetOrClear:		resw 1
coPriorSegment:		resw 1		; 0 = sysinit, 1 = DOSDATA
coAlwaysClear:		resw 1
coNoMessage:		resw 1
coYesMessage:		resw 1
	endstruc

	align 2, db 0
compatoptionstable:
	istruc COMPATOPTION
at coSetOrClear,	dw altah_option
at coNoMessage,		dw configmsg.noaltah
at coYesMessage,	dw configmsg.altah
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw dosdata_relocate_first
at coNoMessage,		dw configmsg.nodosdatafirst
at coYesMessage,	dw configmsg.dosdatafirst
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw dosdata_relocate_early
at coNoMessage,		dw configmsg.nodosdataearly
at coYesMessage,	dw configmsg.dosdataearly
	iend

 extern config_bounce_hma_chs
 extern config_bounce_hma_lba
	istruc COMPATOPTION
at coSetOrClear,	dw config_bounce_hma_chs
at coPriorSegment,	dw 1
at coAlwaysClear,	dw autobouncehmachs_option
at coNoMessage,		dw configmsg.nobouncehmachs
at coYesMessage,	dw configmsg.bouncehmachs
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw autobouncehmachs_option
at coYesMessage,	dw configmsg.autobouncehmachs
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw config_bounce_hma_lba
at coPriorSegment,	dw 1
at coAlwaysClear,	dw autobouncehmalba_option
at coNoMessage,		dw configmsg.nobouncehmalba
at coYesMessage,	dw configmsg.bouncehmalba
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw autobouncehmalba_option
at coYesMessage,	dw configmsg.autobouncehmalba
	iend

 extern config_bounce_uma_chs
 extern config_bounce_uma_lba
	istruc COMPATOPTION
at coSetOrClear,	dw config_bounce_uma_chs
at coPriorSegment,	dw 1
at coNoMessage,		dw configmsg.nobounceumachs
at coYesMessage,	dw configmsg.bounceumachs
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw config_bounce_uma_lba
at coPriorSegment,	dw 1
at coNoMessage,		dw configmsg.nobounceumalba
at coYesMessage,	dw configmsg.bounceumalba
	iend

 extern config_bounce_any_chs
 extern config_bounce_any_lba
	istruc COMPATOPTION
at coSetOrClear,	dw config_bounce_any_chs
at coPriorSegment,	dw 1
at coNoMessage,		dw configmsg.nobounceanychs
at coYesMessage,	dw configmsg.bounceanychs
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw config_bounce_any_lba
at coPriorSegment,	dw 1
at coNoMessage,		dw configmsg.nobounceanylba
at coYesMessage,	dw configmsg.bounceanylba
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw hidedosentry_option
at coNoMessage,		dw configmsg.nohidedosentry
at coYesMessage,	dw configmsg.hidedosentry
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw hidedosdatafirst_option
at coNoMessage,		dw configmsg.nohidedosdatafirst
at coYesMessage,	dw configmsg.hidedosdatafirst
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw enlargelma_option
at coNoMessage,		dw configmsg.noenlargelma
at coYesMessage,	dw configmsg.enlargelma
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw enlargelma_option
	; ! yes and no reversed, protect first UMCB means no enlarge LMA
at coNoMessage,		dw configmsg.protectfirstumcb
at coYesMessage,	dw configmsg.noprotectfirstumcb
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw installasfirst_option
at coNoMessage,		dw configmsg.noinstallasfirst
at coYesMessage,	dw configmsg.installasfirst
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw installaslast_option
at coNoMessage,		dw configmsg.noinstallaslast
at coYesMessage,	dw configmsg.installaslast
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw preservecds_option
at coNoMessage,		dw configmsg.nopreservecds
at coYesMessage,	dw configmsg.preservecds
	iend
	istruc COMPATOPTION
at coSetOrClear,	dw reinitcds_option
at coNoMessage,		dw configmsg.noreinitcds
at coYesMessage,	dw configmsg.reinitcds
	iend

%ifdef LDOSMEM
 extern config_collect_all_mcbs
	istruc COMPATOPTION
at coSetOrClear,	dw config_collect_all_mcbs
at coPriorSegment,	dw 1
at coNoMessage,		dw configmsg.nocollectallmcbs
at coYesMessage,	dw configmsg.collectallmcbs
	iend
 extern config_collect_free_mcb
	istruc COMPATOPTION
at coSetOrClear,	dw config_collect_free_mcb
at coPriorSegment,	dw 1
at coNoMessage,		dw configmsg.nocollectfreemcb
at coYesMessage,	dw configmsg.collectfreemcb
	iend
%endif
.end:

configmsg:
.nodosdatafirst:	db "NO"
.dosdatafirst:		asciz "DOSDATAFIRST"
.nodosdataearly:	db "NO"
.dosdataearly:		asciz "DOSDATAEARLY"
.noaltah:		db "NO"
.altah:			asciz "ALTAH"
.nobouncehmachs:	db "NO"
.bouncehmachs:		asciz "BOUNCEHMACHS"
.nobouncehmalba:	db "NO"
.bouncehmalba:		asciz "BOUNCEHMALBA"
.autobouncehmachs:	asciz "AUTOBOUNCEHMACHS"
.autobouncehmalba:	asciz "AUTOBOUNCEHMALBA"
.nobounceumachs:	db "NO"
.bounceumachs:		asciz "BOUNCEUMACHS"
.nobounceumalba:	db "NO"
.bounceumalba:		asciz "BOUNCEUMALBA"
.nobounceanychs:	db "NO"
.bounceanychs:		asciz "BOUNCEANYCHS"
.nobounceanylba:	db "NO"
.bounceanylba:		asciz "BOUNCEANYLBA"
.nohidedosentry:	db "NO"
.hidedosentry:		asciz "HIDEDOSENTRY"
.nohidedosdatafirst:	db "NO"
.hidedosdatafirst:	asciz "HIDEDOSDATAFIRST"
.noenlargelma:		db "NO"
.enlargelma:		asciz "ENLARGELMA"
.noprotectfirstumcb:	db "NO"
.protectfirstumcb:	asciz "PROTECTFIRSTUMCB"
.noinstallasfirst:	db "NO"
.installasfirst:	asciz "INSTALLASFIRST"
.noinstallaslast:	db "NO"
.installaslast:		asciz "INSTALLASLAST"
.nopreservecds:		db "NO"
.preservecds:		asciz "PRESERVECDS"
.noreinitcds:		db "NO"
.reinitcds:		asciz "REINITCDS"
%ifdef LDOSMEM
.nocollectallmcbs:	db "NO"
.collectallmcbs:	asciz "COLLECTALLMCBS"
.nocollectfreemcb:	db "NO"
.collectfreemcb:	asciz "COLLECTFREEMCB"
%endif
.altah_message:		asciz "init: Applying ALTAH compatibility option.",13,10
.altah_message.error:	asciz "init: Error: ALTAH compatibility option failed!",13,10
 global configmsg.hidedosentry_message
 global configmsg.hidedosentry_error
.hidedosentry_message:	asciz "init: Hiding DOSENTRY MCB.",13,10
.hidedosentry_error:	asciz "init: Error: Hiding DOSENTRY MCB failed!",13,10
 global configmsg.hidedosdata_message
 global configmsg.hidedosdata_error
.hidedosdata_message:	asciz "init: Hiding DOSDATA first MCB.",13,10
.hidedosdata_error:	asciz "init: Error: Hiding DOSDATA first MCB failed!",13,10
 global .enlargelma_message
.enlargelma_message:	asciz "init: Enlarging Low Memory Area with new UMB.",13,10
.amisnumberinuse:	db "init: Error: Selected AMIS multiplex number "
.amisnumberinuse.num:	asciz "--h is already in use!",13,10

XMAEM_file	db	'XMAEM.SYS',0	;AN029;

;IBMCACHE_file	 db	 'IBMCACHE.SYS',0;AN024;AN026;To cope with the IBMCACHE.SYS
					; problem of DOS version checking.

;******************************************************************************
;Take care of Config.sys file.
;SYSTEM parser data and code.
;******************************************************************************
[list -]
	%include "psoption.mac"			;Parsing options for SYSCONF.
[list +]
;=== Push trace listing source: parse.nas
	%include "parse.nas"			;together with PSDATA.INC ; NASM included file
;=== Pop trace listing source
;Control block definitions for PARSER.
;---------------------------------------------------
; BUFFER = [n | n,m] {/E}

Buf_Parms	label	byte	;AN000;
	dw	Buf_Parmsx	;AN000;
	db	1		;AN000; An extra delimeter list
	db	1		;AN000; length is 1
	db	SEMICOLON	;AN000;

Buf_Parmsx	label	byte	;AN000;
	db	1,2		;AN000; Min 1, Max 2 positional
	dw	Buf_Pos1	;AN000;
	dw	Buf_Pos2	;AN000;
	db	1		;AN000; 1 switch
	dw	SW_X_Ctrl	;AN000;AN025; /X control
	db	0		;AN000; no keywords

Buf_Pos1	label	word	;AN000;
	dw	8000h		;AN000; Numeric value
	dw	0		;AN000; no function
	dw	Result_Val	;AN000; Result value buffer
	dw	Buf_Range_1	;AN000; value list
	db	0		;AN000; no switches/keywords

Buf_Range_1	label	byte	;AN000; value definition
	db	1		;AN000; range definition
	db	1		;AN000; 1 definition of range
	db	1		;AN000; item tag for this range
	dd	1,10000 	;AN000; from 1 to 10000

Buf_Pos2	label	word	;AN000;
	dw	8001h		;AN000; Numeric value, Optional
	dw	0		;AN000; no function
	dw	Result_Val	;AN000; Result value buffer
	dw	Buf_Range_2	;AN000; value list
	db	0		;AN000; no switches/keywords

Buf_Range_2	label	byte	;AN000; value definition
	db	1		;AN000; range definition
	db	1		;AN000; 1 definition of range
	db	1		;AN000; item tag for this range
	dd	0,8		;AN000; from 0 to 8.

SW_X_Ctrl	label	word	;AN000;AN025;
	dw	0		;AN000; no matching flag
	dw	0		;AN000; no function
	dw	Result_Val	;AN000; return value
	dw	NoVal		;AN000; no value definition
	db	1		;AN000; # of switches
Switch_X	label	byte	;AN000;AN025;
	db	'/X',0		;AN000;AN025;
;local variables
P_Buffers	dw     0	;AN000;
P_H_Buffers	dw     0	;AN000;
P_Buffer_Slash_X db    0	;AN000;AN025;
Buffer_Pre_Scan  db    0	;AN030;

;Common definitions -------------
NoVal	db	0		;AN000;

Result_Val	label	byte	;AN000;
	db	?		;AN000; type returned
	db	?		;AN000; item tag returned
	dw	?		;AN000; ES:offset of the switch defined
RV_Byte 	label	byte	;AN000;
RV_Dword	label	dword	;AN000;
	dd	?		;AN000; value if number, or seg:offset to string.
;--------------------------------

; BREAK = [ ON | OFF ]

Brk_Parms	label	byte	;AN000;
	dw	Brk_Parmsx	;AN000;
	db	1		;AN000; An extra delimeter list
	db	1		;AN000; length is 1
	db	SEMICOLON	;AN000;

Brk_Parmsx	label	byte	;AN000;
	db	1,1		;AN000; Min 1, Max 1 positional
	dw	Brk_Pos 	;AN000;
	db	0		;AN000; no switches
	db	0		;AN000; no keywords

Brk_Pos 	label	word	;AN000;
	dw	2000h		;AN000; Simple string
	dw	0		;AN000; No functions
	dw	Result_Val	;AN000;
	dw	On_Off_String	;AN000; ON,OFF string descriptions
	db	0		;AN000; no keyword/switch synonyms

On_Off_String	label	byte	;AN000;
	db	3		;AN000; signals that there is a string choice
	db	0		;AN000; no range definition
	db	0		;AN000; no numeric values choice
	db	2		;AN000; 2 strings for choice
	db	1		;AN000; the 1st string tag
	dw	On_String	;AN000;
	db	2		;AN000; the 2nd string tag
	dw	Off_String	;AN000;

On_String	db	"ON",0	;AN000;
Off_String	db	"OFF",0 ;AN000;
;local variable
P_Ctrl_Break	db	0	;AN000; local variable

;--------------------------------

; COUNTRY = n {m {path}}
; or
; COUNTRY = n,,path

Cntry_Parms	label	byte	;AN000;
	dw	Cntry_Parmsx	;AN000;
	db	1		;AN000; An extra delimeter list
	db	1		;AN000; length is 1
	db	SEMICOLON	;AN000;

Cntry_Parmsx	label	byte	;AN000;
	db	1,3		;AN000; Min 1, Max 3 positional
	dw	Cntry_Pos1	;AN000;
	dw	Cntry_Pos2	;AN000;
	dw	Cntry_Pos3	;AN000;
	db	0		;AN000; no switches
	db	0		;AN000; no keywords

Cntry_Pos1	label	word	;AN000; control definition for positional 1
	dw	8000h		;AN000; Numeric value
	dw	0		;AN000; no functions
	dw	Result_Val	;AN000;
	dw	Cntry_Codepage_Range  ;AN000; country id code range description
	db	0		;AN000; no switch/keyword synonyms

Cntry_Codepage_Range  label   byte  ;AN000;
	db	1		;AN000; # of value definitions
	db	1		;AN000; # of ranges
	db	1		;AN000; Tag for this range
	dd	1,999		;AN000;

Cntry_Pos2	label	word	;AN000; control definition for positional 2
	dw	8001h		;AN000; Numeric value, optional
	dw	0		;AN000; no functions
	dw	Result_Val	;AN000;
	dw	Cntry_Codepage_Range  ;AN000; code page range descriptions.
	db	0		;AN000; no switch/keyword synonyms

Cntry_Pos3	label	word	;AN000; control definition for positional 3
	dw	0201h		;AN000; File spec, optional
	dw	0		;AN000; No functions. Don't need to CAP.
	dw	Result_Val	;AN000;
	dw	NoVal		;AN000; no value list
	db	0		;AN000; no switch/keyword synonyms

;Local variables
P_Cntry_Code	dw	0	;AN000;
P_Code_Page	dw	0	;AN000;

;--------------------------------

; FILES = n

Files_Parms	label	byte	;AN000;
	dw	Files_Parmsx	;AN000;
	db	1		;AN000; An extra delimeter list
	db	1		;AN000; length is 1
	db	SEMICOLON	;AN000;

Files_Parmsx	label	byte	;AN000;
	db	1,1		;AN000; Min 1, Max 1 positional
	dw	Files_Pos	;AN000;
	db	0		;AN000; no switches
	db	0		;AN000; no keywords

Files_Pos	label	byte	;AN000;
	dw	8000h		;AN000; Numeric value
	dw	0		;AN000; no functions
	dw	Result_Val	;AN000;
	dw	Files_Range	;AN000; Files range description
	db	0		;AN000; no switch/keyword synonyms

Files_Range	label	byte	;AN000;
	db	1		;AN000; # of value definitions
	db	1		;AN000; # of ranges
	db	1		;AN000; Tag for this range
	dd	8,255		;AN000;
;local variable
P_Files db	0		;AN000;

;--------------------------------

; FCBS = n,m

FCBS_Parms	label	byte	;AN000;
	dw	FCBS_Parmsx	;AN000;
	db	1		;AN000; An extra delimeter list
	db	1		;AN000; length is 1
	db	SEMICOLON	;AN000;

FCBS_Parmsx	label	byte	;AN000;
	db	2,2		;AN000; Min 2, Max 2 positional
	dw	FCBS_Pos_1	;AN000;
	dw	FCBS_Pos_2	;AN000;
	db	0		;AN000; no switches
	db	0		;AN000; no keywords

FCBS_Pos_1	label	byte	;AN000;
	dw	8000h		;AN000; Numeric value
	dw	0		;AN000; no functions
	dw	Result_Val	;AN000;
	dw	FCBS_Range	;AN000; FCBS range descriptions
	db	0		;AN000; no switch/keyword synonyms

FCBS_Range	label	byte	;AN000;
	db	1		;AN000; # of value definitions
	db	1		;AN000; # of ranges
	db	1		;AN000; Tag for this range
	dd	1,255		;AN000;

FCBS_Pos_2	label	byte	;AN000;
	dw	8000h		;AN000; Numeric value
	dw	0		;AN000; no functions
	dw	Result_Val	;AN000;
	dw	FCBS_Keep_Range ;AN000; FCBS KEEP range descriptions
	db	0		;AN000; no switch/keyword synonyms

FCBS_Keep_Range label	byte	;AN000;
	db	1		;AN000; # of value definitions
	db	1		;AN000; # of ranges
	db	1		;AN000; Tag for this range
	dd	0,255		;AN000;

;local variable
P_Fcbs	db	0		;AN000;
P_Keep	db	0		;AN000;
;--------------------------------

; STACKS = n,m

STKS_Parms	label	byte	;AN000;
	dw	STKS_Parmsx	;AN000;
	db	1		;AN000; An extra delimeter list
	db	1		;AN000; length is 1
	db	SEMICOLON	;AN000;

STKS_Parmsx	label	byte	;AN000;
	db	2,2		;AN000; Min 2, Max 2 positional
	dw	STKS_Pos_1	;AN000;
	dw	STKS_Pos_2	;AN000;
	db	0		;AN000; no switches
	db	0		;AN000; no keywords

STKS_Pos_1	label	byte	;AN000;
	dw	8000h		;AN000; Numeric value
	dw	0		;AN000; no functions
	dw	Result_Val	;AN000;
	dw	STKS_Range	;AN000; number of stack range descriptions
	db	0		;AN000; no switch/keyword synonyms

STKS_Range	label	byte	;AN000;
	db	1		;AN000; # of value definitions
	db	1		;AN000; # of ranges
	db	1		;AN000; Tag for this range
	dd	0,64		;AN000;

STKS_Pos_2	label	byte	;AN000;
	dw	8000h		;AN000; Numeric value
	dw	0		;AN000; no functions
	dw	Result_Val	;AN000;
	dw	STK_SIZE_Range	;AN000; stack size range descriptions
	db	0		;AN000; no switch/keyword synonyms

STK_SIZE_Range label   byte	;AN000;
	db	1		;AN000; # of value definitions
	db	1		;AN000; # of ranges
	db	1		;AN000; Tag for this range
	dd	0,512		;AN000;
;local variables
P_Stack_Count	dw	0	;AN000;
P_Stack_Size	dw	0	;AN000;

;--------------------------------

; MULTITRACK = [ ON | OFF ]

MTrk_Parms	label	byte	;AN002;
	dw	MTrk_Parmsx	;AN002;
	db	1		;AN002; An extra delimeter list
	db	1		;AN002; length is 1
	db	SEMICOLON	;AN002;

MTrk_Parmsx	label	byte	;AN002;
	db	1,1		;AN002; Min 1, Max 1 positional
	dw	MTrk_Pos	;AN002;
	db	0		;AN002; no switches
	db	0		;AN002; no keywords

MTrk_Pos	label	word	;AN002;
	dw	2000h		;AN002; Simple string
	dw	0		;AN002; No functions
	dw	Result_Val	;AN002;
	dw	On_Off_String	;AN002; ON,OFF string descriptions
	db	0		;AN002; no keyword/switch synonyms

;local variables
P_Mtrk	db	0		;AN002;
;--------------------------------

; CPSW = [ ON | OFF ]

CPSW_Parms	label	byte	;AN002;
	dw	CPSW_Parmsx	;AN002;
	db	1		;AN002; An extra delimeter list
	db	1		;AN002; length is 1
	db	SEMICOLON	;AN002;

CPSW_Parmsx	label	byte	;AN002;
	db	1,1		;AN002; Min 1, Max 1 positional
	dw	CPSW_Pos	;AN002;
	db	0		;AN002; no switches
	db	0		;AN002; no keywords

CPSW_Pos	label	word	;AN002;
	dw	2000h		;AN002; Simple string
	dw	0		;AN002; No functions
	dw	Result_Val	;AN002;
	dw	On_Off_String	;AN002; ON,OFF string descriptions
	db	0		;AN002; no keyword/switch synonyms

;local variables
P_CPSW	db	0		;AN002;

;--------------------------------
; SWITCHES=/K

Swit_Parms	label	byte	;AN019;
	dw	Swit_Parmsx	;AN019;
	db	1		;AN019; An extra delimeter list
	db	1		;AN019; length is 1
	db	SEMICOLON	;AN019;

Swit_Parmsx	label	byte	;AN019;
	db	0,0		;AN019; No positionals
	db	1		;AN019; 1 switch for now.
	dw	Swit_K_Ctrl	;AN019; /K control
	db	0		;AN019; no keywords

Swit_K_Ctrl	label	word	;AN019;
	dw	0		;AN019; no matching flag
	dw	0		;AN019; no function
	dw	Result_Val	;AN019; return value
	dw	NoVal		;AN019; no value definition
	db	1		;AN019; # of switches
Swit_K		label	byte	;AN019;
	db	'/K',0		;AN019;
;local variables
P_Swit_K	db     0	;AN019;

no_config_file:		db 0

;******************************************************************************

%if 0
%macro debugnumber 1
	push ax
	mov ax, %1
	call display_debugnumber
	pop ax
%endmacro

display_debugnumber:
	pushf
	push bx
	push bp
	push ax
	mov ah, 0Eh
	mov bx, 7
	int 10h
	pop ax
	push ax
	xchg al, ah
	test al, al
	jz .nohigh
	mov ah, 0Eh
	mov bx, 7
	int 10h
.nohigh:
	pop ax
	pop bp
	pop bx
	popf
	retn
%else
%macro debugnumber 1
%endmacro
%endif

DOCONF:
 assume ds:nothing, es:nothing, ss:nothing
	debugnumber '0'
	PUSH	CS
	POP	DS
 ASSUME DS:SYSINITGROUP

CHAR_OPER equ Char_Oper	; NASM port equate
	MOV	AX,(CHAR_OPER << 8)	;GET SWITCH CHARACTER
	INT	21H
	MOV	[COMMAND_LINE+1],DL	; Set in default command line

extern CONFIG_pointers
	mov si, CONFIG_pointers - 2	; -> at command line name of prior
.loop:
	lodsw				; skip command line name
	lodsw				; skip function pointer
	inc ax				; is it -1 ?
	lodsw				; (load pointer)
	jz No_Config_sys		; yes, end -->
	test ax, ax			; pointer is zero ?
	jz .loop			; yes, load next -->
	mov bx, ax
	cmp byte [bx], 0		; pointer points at empty string ?
	je .loop			; yes, load next -->
	xchg dx, ax
OPEN equ Open	; NASM port equate
	MOV	AX,OPEN << 8		;OPEN FILE "CONFIG.SYS"
	STC				;IN CASE OF INT 24
	int 21h				; does open succeed ?
	jc .loop			; no, try next -->
	mov word [CONFIG_used], dx
	JMP	NOPROB			;PROBLEM WITH OPEN

No_Config_sys:				;AN028;
	not byte [no_config_file]
	xor ax, ax
	xor dx, dx			; = empty config
	jmp continue_no_file

ENDCONF:
	return


BADOP:	MOV	DX,OFFSET BADOPM	;WANT TO PRINT COMMAND ERROR "Unrecognized command..."
	invoke	PRINT
	call	Error_Line		;show "Error in CONFIG.SYS ..." .
	JMP	COFF

Badop_p 	proc	near		;AN000;
;Same thing as BADOP, but will make sure to set DS register back to SYSINITSEG
;and return back to the calller.
	push	cs
	pop	ds			;set ds to CONFIGSYS seg.
 assume ds:SYSINITGROUP
badopm equ BADOPM	; NASM port label
	mov	dx, offset badopm
	invoke	PRINT
	call	Error_Line
	ret
Badop_p 	endp

Badparm_p	proc	near		;AN007;
 assume ds:nothing, es:nothing, ss:nothing
;Show "Bad command or parameters - xxxxxx"
;In Badparm_seg, Badparm_off -> xxxxx
;
	cmp	byte [cs:Buffer_Pre_Scan], 1	;AN030; Pre scanning Buffers ... /X?
	je	BadParmp_Ret		;AN030;  then do not show any message.
	push	ds			;AN007;
	push	dx			;AN007;
	push	si			;AN007;

	push	cs			;AN007;
	pop	ds			;AN007;
 assume ds:SYSINITGROUP
	mov	dx, offset Badparm	;AN007;
	invoke	PRINT			;AN007;"Bad command or parameters - "
Badparm_ptr equ Badparm_Ptr	; NASM port label
	lds	si, [Badparm_ptr] 	;AN007;
 assume ds:nothing
Badparm_Prt:				;AN007;print "xxxx" until CR.
	mov	dl, byte ptr [si]	;AN007;
STD_CON_OUTPUT equ Std_Con_Output	; NASM port equate
	mov	ah,STD_CON_OUTPUT	;AN007;
	int	21h			;AN007;
	inc	si			;AN007;
	cmp	dl, CR			;AN007;
	jne	Badparm_Prt		;AN007;
	push	cs			;AN007;
	pop	ds			;AN007;
 assume ds:SYSINITGROUP
	mov	dx, offset CRLFM	;AN007;
	invoke	PRINT			;AN007;
	call	Error_Line		;AN007;
	pop	si			;AN007;
	pop	dx			;AN007;
	pop	ds			;AN007;
 assume ds:nothing
BadParmp_Ret:				;AN030;
	ret				;AN007;
Badparm_p	endp

NOPROB:					;GET FILE SIZE (NOTE < 64K!!)
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	MOV	BX,AX
	XOR	CX,CX
	XOR	DX,DX
LSEEK equ LSeek	; NASM port equate
	MOV	AX,(LSEEK << 8) | 2
	INT	21H

continue_no_file:
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	mov si, 64 * 1024 - 1 - 1 - 256	; maximum size
		; 1 = offset of end <= 0FFFFh
		; 1 = linebreak we'll append
		; 256 = maximum length of APPEND/PREPEND kernel command line names
	test dx, dx			; >= 64 KiB ?
	jnz .overflow			; yes -->
	cmp ax, si
	jbe .fine
.overflow:
	mov	dx, config_overflow
	invoke	PRINT
	mov ax, si
.fine:
	MOV	[COUNT],AX		; true file size to read

	add ax, 1
config_size equ Config_Size	; NASM port label
	mov	[config_size], ax	;save the size of config.sys file.

	rol byte [no_config_file], 1
	jc @F

	XOR	DX,DX
	MOV	AX,LSEEK << 8		;Reset pointer to beginning of file
	INT	21H

@@:
	push di
	push bx
	mov bx, .add
	call parse_configuration_command_line
	jmp @F

.add:
	add [config_size], cx		; add in PREPEND= / APPEND= line length
	retn

@@:
	pop bx
	pop di

	push di
	push bx

	MOV	AX,[config_size]
	mov si, alloc_initconfig
	call allocate_temporary_block
	MOV [config_block], es		; Config starts here. New CONBOT value.
	; CALL	TEMPCDS			; Finally get CDS to "safe" location
ASSUME	DS:NOTHING,ES:NOTHING

	 push cs
	 pop ds
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	MOV	DX,[config_block]
	MOV	ES,DX
 assume es:nothing
	XOR	DX,DX			; es:dx -> config buffer

	mov bx, .prepend
	call parse_configuration_command_line
	jmp @F

.prepend:
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	cmp di, nameprepend
	jne .retn
	sub si, cx
	xchg dx, di
	rep movsb
	mov byte [es:di - 1], 10	; LF
	xchg dx, di
.retn:
	retn

@@:
	pop bx
	pop di

	push es
	pop ds				; ds:dx -> where to read config file
 assume ds:nothing
	MOV	CX,[cs:COUNT]
	xor ax, ax			; NC, ax = 0
	jcxz @F
READ equ Read	; NASM port equate
	MOV	AH,READ
	STC				;IN CASE OF INT 24
	INT	21H			;Function request
@@:
	PUSHF
;
; Find the EOF mark in the file.  If present, then trim length.

	SaveReg <AX,DI,CX>
	xchg cx, ax			; cx = length actually read
	MOV	AL,1Ah			; eof mark
	MOV	DI,DX			; point ro buffer
	JCXZ	PutEOL			; no chars
	REPNZ	SCASB			; find end
	JNZ	PutEOL			; none found and count exahusted
;
; We found a 1A.  Back up
;
	DEC	DI			; backup past 1A
;
;  Just for the halibut, stick in an extra EOL
;
PutEOL:
	MOV	AL,LF
	STOSB				; ! LF only

	 push cs
	 pop ds
 assume ds:SYSINITGROUP
	mov dx, di
	push bx
	mov bx, .append
	call parse_configuration_command_line
	jmp @F

.append:
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	cmp di, nameappend
	jne .retn
	sub si, cx			; -> content
	xchg dx, di
	rep movsb			; store in buffer
	mov byte [es:di - 1], 10	; LF
	xchg dx, di
.retn:
	retn

@@:
	pop bx
	xchg dx, di			; di = size of configuration

Count equ COUNT	; NASM port label
	MOV	[Count],DI		; new count
;
; Restore registers
;
	RestoreReg  <CX,DI,AX>

ASSUME	DS:SYSINITSEG
	PUSH	AX
	rol byte [cs:no_config_file], 1
	jc @F
CLOSE equ Close	; NASM port equate
	MOV	AH,CLOSE
	INT	21H
@@:
	POP	AX
	POPF
	JC	CONFERR 		;IF NOT WE'VE GOT A PROBLEM
	CMP	CX,AX
	JZ	GETCOM			;COULDN'T READ THE FILE
CONFERR:
 assume ds:nothing, es:nothing, ss:nothing
	MOV	DX,[cs:CONFIG_used]	;WANT TO PRINT CONFIG ERROR
	CALL	BADFIL
ENDCONV:JMP	ENDCONF

extern nameprepend, nameappend, kernelcommandline, kernelcommandline.end

		; INP:	ds = cs
		;	ds:kernelcommandline -> contents
		;	word [kernelcommandline.end] -> end
		;	nameprepend, nameappend
		;	bx = callback near function
		; CHG:	ax, si, cx, di
		; Callback called with:
		; INP:	ds:si -> past name's content terminator
		;	cx = length of content including terminator
		;	es = unchanged
		;	dx = unchanged
		;	di = nameprepend or nameappend, whichever matched
		; CHG:	cx, ax
		; REM:	changes of dx passed back to caller
parse_configuration_command_line:
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	mov si, kernelcommandline
.loopcommand:
	db __TEST_IMM8		; skip inc
@@:
	inc si
	cmp byte [si], 32
	je @B
	cmp byte [si], 9
	je @B

	mov di, nameprepend	; -> first name
.loopname:
	push di
	push si
.comparename:
	lodsb
	cmp al, 0
	je .next
	cmp al, 'a'
	jb @F
	cmp al, 'z'
	ja @F
	sub al, 20h
@@:
	push es
	 push cs
	 pop es
 assume es:SYSINITGROUP
	scasb
	pop es
 assume es:nothing
	jne .next
	cmp byte [di], 0
	jne .comparename
	lodsb
	cmp al, 0
	je .found
	cmp al, 32
	je .found
	cmp al, 9
	je .found
	cmp al, '='
	je .found
.next:
	pop si
	pop di
	cmp di, nameprepend
	jne .donename
	mov di, nameappend
	jmp .loopname

@@:
	lodsb
.found:
	cmp al, 32
	je @B
	cmp al, 9
	je @B
	cmp al, '='
	jne @FF
@@:
	lodsb
@@:
	cmp al, 32
	je @BB
	cmp al, 9
	je @BB

	dec si			; -> content
	mov cx, si
.findlen:
	lodsb
	test al, al
	jnz .findlen
	neg cx
	add cx, si		; = length, including terminator
	pop di			; discard si
	pop di			; restore di
	call bx
	jmp .nextcommand
.donename:
@@:
	lodsb
	cmp al, 0
	jne @B
.nextcommand:
	cmp si, word [kernelcommandline.end]
	jb .loopcommand
	retn


 global get_config_size
get_config_size:
 assume ds:nothing, es:nothing, ss:nothing
	mov ax, [cs:Org_Count]
	mov cx, ax
	invoke ParaRound
	xchg bx, ax
	retn


Multi_Pass:				;AN018;AN026; called to execute IFS=,  INSTALL= commands
 assume ds:nothing, es:nothing, ss:nothing
	push	cs			;AN018;
	pop	ds			;AN018;
 assume ds:SYSINITGROUP
Multi_Pass_id equ Multi_Pass_Id	; NASM port label
	cmp	byte [Multi_Pass_id], 10	;J.K.
Endconv equ ENDCONV	; NASM port label
	jae	Endconv			;J.K. Do nothing. Just return.
	mov es, word [config_block]	; => config
 assume es:nothing
	mov	si, [Org_Count]		;AN018;
	mov	[Count], si		;AN018; set Count
	xor	si,si			;AN018;
Chrptr equ CHRPTR	; NASM port label
	mov	[Chrptr], si		;AN018; reset Chrptr, LineCount
	mov	[LineCount], si		;AN018;
GetChr equ GETCHR	; NASM port label
	call	GetChr			;AN018;
Conflp equ CONFLP	; NASM port label
	jmp	Conflp			;AN018;
	nop	; identicalise
GETCOM:
	invoke	ORGANIZE		;ORGANIZE THE FILE
	call get_config_size
	mov ah, 4Ah
	int 21h
	push ds
	mov ax, es
	dec ax
	mov ds, ax
 assume ds:MCB
	mov word [mcbOwner], 8
	pop ds
 assume ds:SYSINITGROUP
	CALL	GETCHR

CONFLP: JC	ENDCONV
	call	Reset_DOS_Version	;AN024;AN026; Still need to reset version even IBMDOS handles this through
					; function 4Bh call, since IBMDOS does not know when Load/Overlay call finishes.

%ifndef BUF2
%IFN BUFFERFLAG
EMS_Stub_handler equ EMS_Stub_Handler	; NASM port label
	call	EMS_Stub_handler	;AN030;
%ENDIF
%endif

	inc	word [LineCount]		;AN000; Increase LineCount.
	mov	byte [Buffer_Pre_Scan], 0	;AN030; Reset Buffer_Pre_Scan.
	mov	byte [MultDeviceFlag],0	;AN001; Reset MultDeviceFlag.
	mov	byte [SetDevMarkFlag],0	;AN004; Reset SetDevMarkFlag.
	and word [devicehighdata], 0
	cmp	al, LF			;AN000; LineFeed?
	je	Blank_Line		;AN000;  then ignore this line.
	MOV	AH,AL
	CALL	GETCHR
TryI equ TRYI	; NASM port label
	jnc	TryI			;AN000;
Multi_Pass_ID equ Multi_Pass_Id	; NASM port label
	cmp byte [Multi_Pass_ID], 0
	je Endconv
	cmp	byte [Multi_Pass_ID], 2	;AN026;
	jae	Endconv 		;AN026;Do not show Badop again for multi_pass.
	JMP	BADOP

COFF:	PUSH	CS
	POP	DS
 assume ds:SYSINITGROUP
	invoke	NEWLINE
	JMP	CONFLP
Blank_Line:				;AN000;
Getchr equ GETCHR	; NASM port label
	call	Getchr			;AN000;
	jmp	CONFLP			;AN000;

COFF_P:
	push	cs
	pop	ds


;J.K. 1/27/88 ;;;;;;;;;;;;;;;;;;
;To handle INSTALL= commands, we are going to use multi-pass.
;The first pass handles the other commands and only set Install_Flag when
;it finds any INSTALL command.	 The second pass will only handle the
;INSTALL= command.

;------------------------------------------------------------------------------
;INSTALL command
;------------------------------------------------------------------------------
TRYI:
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	cmp	byte [Multi_Pass_Id], -1
	je	Multi_Try_Compat
	cmp	byte [Multi_Pass_Id], 0		;AN029; the initial pass for XMAEM.SYS
	je	Multi_Try_XMAEM			;AN029;     and BUFFERS= ... /X pre scan.
	cmp	byte [Multi_Pass_Id], 2		;AN026; the second pass for IFS= ?
	je	Multi_Try_J			;AN026;
	cmp	byte [Multi_Pass_Id], 3		;AN026; the third pass for INSTALL= ?
	je	Multi_Try_I			;AN026;
	cmp	byte [Multi_Pass_Id], 4		; pass for INSTALLLAST= ?
	je	Multi_Try_I80
	cmp ah, 'i' | 80h			; INSTALLLASTHIGH= command ?
	je .install
	cmp ah, 'I' | 80h			; INSTALLLAST= command ?
	je .install
	cmp ah, '6'				; INSTALLMIDHIGH= command ?
	je .install
	cmp ah, '5'				; INSTALLMID= command ?
	je .install
	rol byte [installaslast_option], 1
	jc .notasfirst
	rol byte [installasfirst_option], 1
	jc TryB
.notasfirst:
	cmp ah, 'i'				; INSTALLHIGH= command ?
	je .install
	cmp	ah, 'I'				;AN018; INSTALL= command?
	jne	TryB				;AN018; the first pass is for normal operation.
.install:
	or	word [Install_Flag], HAVE_INSTALL_CMD	;AN018; Set the flag
coff equ COFF	; NASM port label
	jmp	coff				;AN018; and handles the next command

Multi_Try_Compat:
	cmp ah, '2'
	jne .not
	push ds
	push es
	push si
	 push es
	 pop ds
 assume ds:nothing
.loop:
	call skipcomma
	call iseol?
	je .done
	dec si
	 push cs
	 pop es
 assume es:SYSINITGROUP

	mov bx, compatoptionstable
.loop_table:
	xor cx, cx
	mov dx, [cs:bx + coNoMessage]
	test dx, dx
	jz @F
	call isstring?
	je .got_table
@@:
	not cx
	mov dx, [cs:bx + coYesMessage]
	call isstring?
	je .got_table
	add bx, COMPATOPTION_size
	cmp bx, compatoptionstable.end
	jb .loop_table

	pop si
	pop es
	pop ds
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	jmp BADOP

.got_table:
 assume es:SYSINITGROUP, ds:nothing, ss:nothing
	mov di, word [cs:bx + coAlwaysClear]
	test di, di
	jz @F
	mov byte [cs:di], 0
@@:
	testopt [cs:bx + coPriorSegment], 1
	mov bx, word [cs:bx + coSetOrClear]
	jnz .got_dosdata
	mov byte [cs:bx], cl
	jmp .loop

.got_dosdata:
	push ds
	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov byte [bx], cl
	pop ds
 assume ds:nothing
	jmp .loop

.done:
	pop si
	pop es
	pop ds
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	jmp Multi_Pass_Filter

.not:

Multi_Try_AMISNumber:
	cmp ah, '7'
	jne .not
	push ds
	push es
	push si
	 push es
	 pop ds
 assume ds:nothing
	call ldos_getnum
	jc .error
	test dh, dh
	jnz .error
@@:
	lodsb
	cmp al, 32
	je @B
	cmp al, 9
	je @B
	cmp al, 13
	je .done
	cmp al, 10
	je .done
	cmp al, 0
	je .done
.error:
	pop si
	pop es
	pop ds
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	jmp BADOP

 extern hexbyte, init2_disp_msg_asciz_cs_dx
.inuse:
	push cs
	pop es
 assume es:SYSINITGROUP
	mov di, configmsg.amisnumberinuse.num
	mov al, ah
	call hexbyte
	mov dx, configmsg.amisnumberinuse
	call init2_disp_msg_asciz_cs_dx
	jmp .skip

 extern i2D.amisnumber
.done:
 assume es:nothing
	mov si, DOSENTRY
	mov ds, si
 assume ds:DOSENTRYGROUP
	cmp byte [i2D.amisnumber], dl
	je .skip
	mov ah, dl
	mov al, 0
	int 2Dh
	test al, al
	jnz .inuse
	mov byte [i2D.amisnumber], ah
.skip:
	pop si
	pop es
	pop ds
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	jmp Multi_Pass_Filter

.not:
	jmp Multi_Pass_Filter

Multi_Try_XMAEM:				;AN029;
	cmp ah, 'd'
	je .devicehigh
	cmp	ah, 'D' 			;AN029; device= command?
	jne	Multi_Try_Buff			;AN029; no skip it.
.devicehigh:
	call	Chk_XMAEM			;AN029; is it for XMAEM.SYS?
Multi_Pass_FIlter equ Multi_Pass_Filter	; NASM port label
	jnz	Multi_Pass_FIlter		;AN029; no skip it.
	mov	byte ptr [es:si-1], 0FFh	;AN029; mark this command as a Null command for the next pass.
TryDJ equ TRYDJ	; NASM port label
	jmp	TryDJ				;AN029; execute this command.
Multi_Try_Buff: 				;AN030;
	cmp	ah, 'B' 			;AN030; Buffers= command?
	jne	Multi_Pass_Filter		;AN030;
	mov	byte [Buffer_Pre_Scan], 1		;AN030; Set Buffer_Pre_Scan
	jmp	TryB				;AN030; TryB will set P_Buffer_Slash_X to non-zero value.
	nop	; identicalise

Multi_Try_J:					;AN026;
	cmp	ah, 'J' 			;AN026; IFS= command?
	jne	Multi_Pass_Filter		;AN026; No. Ignore this.
GotJ equ GOTJ	; NASM port label
	jmp	GotJ				;AN026; Handles IFS= command.

Multi_Try_I80:
	rol byte [cs:installaslast_option], 1
	jnc .notinstall
	mov byte [cs:devicehighflag], 0
	cmp ah, 'i'
	jne @F
	not byte [cs:devicehighflag]
	mov ah, 'I'
@@:
	cmp ah, 'I'				; INSTALL= command?
	je ..@run_install

.notinstall:
	mov byte [cs:devicehighflag], 0
	cmp ah, 'i' | 80h
	jne @F
	not byte [cs:devicehighflag]
	mov ah, 'I' | 80h
@@:
	cmp	ah, 'I' | 80h			; INSTALLLAST= command?
	jmp ..@run_install

Multi_Try_I:					;AN026;
	mov byte [cs:devicehighflag], 0
	cmp ah, '6'
	jne @F
	not byte [cs:devicehighflag]
	mov ah, '5'
@@:
	cmp ah, '5'				; INSTALLMID= command ?
	je ..@run_install

	rol byte [cs:installaslast_option], 1
	jc Multi_Pass_Filter
	rol byte [cs:installasfirst_option], 1
	jc Multi_Pass_Filter

	mov byte [cs:devicehighflag], 0
	cmp ah, 'i'
	jne @F
	not byte [cs:devicehighflag]
	mov ah, 'I'
@@:
	cmp	ah, 'I' 			;AN026; INSTALL= command?
..@run_install:
	jne	Multi_Pass_Filter		;AN026; No. Ignore this.
	call	Do_Install_Exec 		;Install it.

extern init2_relocate_device

	push es
	mov ax, -1
	call init2_relocate_device
	pop es
 assume es:nothing

Coff equ COFF	; NASM port label
	jmp	Coff				;to handle next Install= command.

Multi_Pass_Filter:				;AN023;AN026;
	cmp	ah, 'Y' 			;AN023; Comment?
	je	Multi_Pass_Adjust		;AN023;
	cmp	ah, 'Z' 			;AN023; Bad command?
	je	Multi_Pass_Adjust		;AN023;
	cmp	ah, '0' 			;AN023; REM?
	jne	Multi_Pass_Coff 		;AN023; ignore the rest of the commands.
Multi_Pass_Adjust:				;AN023; These commands need to
	dec	word [Chrptr]				;AN023;  adjust chrptr, count
	inc	word [Count]				;AN023;  for NEWLINE proc.
Multi_Pass_Coff:				;AN023;
	jmp	Coff				;AN018; To handle next INSTALL= commands.

;------------------------------------------------------------------------------

Sysinit_Parse	proc
;Set up registers for SysParse
;In)	ES:SI -> command line in  CONFBOT
;	DI -> offset of the parse control defintion.
;
;Out)	Calls SYSPARSE.
;	Carry will set if Parse error.
;	*** The caller should check the EOL condition by looking at AX
;	*** after each call.
;	*** If no parameters are found, then AX will contain a error code.
;	*** If the caller needs to look at the SYNOMYM@ of the result,
;	***  the caller should use CS:@ instead of ES:@.
;	CX register should be set to 0 at the first time the caller calls this
;	 procedure.
;	AX - exit code
;	BL - TErminated delimeter code
;	CX - new positional ordinal
;	SI - set to pase scanned operand
;	DX - selected result buffer

	push	es			;save es,ds
	push	ds

	push	es
	pop	ds			;now DS:SI -> command line
 assume ds:nothing
	push	cs
	pop	es			;now ES:DI -> control definition
 assume es:SYSINITGROUP

	mov	[cs:Badparm_Seg],ds	;AN007;Save the pointer to the parm
	mov	[cs:Badparm_Off],si	;AN007; we are about to parse for Badparm msg.
	mov	dx, 0
	call	SysParse
D_P_NO_ERROR equ D_P_No_Error	; NASM port equate
	cmp	ax, D_P_NO_ERROR 	;no error
;	$IF	E,OR
	JE DD_LL1
	cmp	ax, D_P_RC_EOL		;or the end of line?
;	$IF	E
	JNE DD_IF1
DD_LL1:
		clc
;	$ELSE
	JMP SHORT DD_EN1
DD_IF1:
		stc
;	$ENDIF
DD_EN1:
	pop	ds
	pop	es			;restore es,ds
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	ret
Sysinit_Parse	endp

;------------------------------------------------------------------------------
; Buffer command
;------------------------------------------------------------------------------
;*******************************************************************************
;									       *
; Function: Parse the parameters of buffers= command.			       *
;									       *
; Input :								       *
;	ES:SI -> parameters in command line.				       *
; Output:								       *
;	Buffers set							       *
;	Buffer_Slash_X	flag set if /X option chosen.			       *
;	H_Buffers set if secondary buffer cache specified.		       *
;									       *
; Subroutines to be called:						       *
;	Sysinit_Parse							       *
; Logic:								       *
; {									       *
;	Set DI points to Buf_Parms;  /*Parse control definition*/	       *
;	Set DX,CX to 0; 						       *
;	Reset Buffer_Slash_X;						       *
;	While (End of command line)					       *
;	{ Sysinit_parse;						       *
;	  if (no error) then						       *
;	       if (Result_Val.D_P_SYNONYM_ptr == Slash_E) then /*Not a switch   *
;		    Buffer_Slash_X = 1					       *
;	       else if	 (CX == 1) then 	    /* first positional */     *
;			  Buffers = Result_Val.D_P_Picked_Val;		       *
;		    else  H_Buffers = Result_Val.D_P_Picked_Val; 	       *
;	  else	{Show Error message;Error Exit} 			       *
;	};								       *
;	If (Buffer_Slash_X is off & Buffers > 99) then Show_Error;	       *
; };									       *
;									       *
;*******************************************************************************
;TryB:	 CMP	 AH,'B' 		 ;BUFFER COMMAND?
;	 JNZ	 TRYC
;	 invoke  GETNUM
;	 JZ	 TryBBad		 ; Gotta have at least one
;	 CMP	 AX,100 		 ; check for max number
;	 JB	 SaveBuf
;TryBBad:JMP	 BadOp
;SaveBuf:
;	 MOV	 [BUFFERS],AX
;CoffJ1: JMP	 COFF

TryB:
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	CMP	AH,'B'
	JNZ	TryC
	mov	byte [P_Buffer_Slash_X], 0	;AN000;AN025;
	mov	di, offset Buf_Parms	;AN000;
	xor	cx, cx			;AN000;
	mov	dx, cx			;AN000;

;	$SEARCH 			;AN000;
DD_DO4:
	    call   Sysinit_Parse	;AN000;
;	$EXITIF    C			;AN000; Parse Error,
	JNC DD_IF4
	    call   Badparm_p		;AN007;   and Show messages and end the search loop.
;	$ORELSE 			;AN000;
	JMP SHORT DD_SR4
DD_IF4:
	    cmp    ax, D_P_RC_EOL	;AN000; End of Line?
;	$LEAVE	   E			;AN000;  then jmp to $Endloop for semantic check.
	JE DD_EN4
D_P_SYNONYM_PTR equ D_P_SYNONYM_Ptr	; NASM port equate
	    cmp    word [Result_Val + D_P_SYNONYM_PTR], offset Switch_X ;AN000;AN025;
;	    $IF    E					      ;AN000;
	    JNE DD_IF8
		mov	byte [P_Buffer_Slash_X], 1		      ;AN000;AN025; set the flag
;	    $ELSE					      ;AN000;
	    JMP SHORT DD_EN8
DD_IF8:
D_P_PICKED_VAL equ D_P_Picked_Val	; NASM port equate
		mov	ax, word ptr [Result_Val + D_P_PICKED_VAL] ;AN000;
		cmp	cx, 1				      ;AN000;
;		$IF	E				      ;AN000;
		JNE DD_IF10
		    mov    [P_Buffers], ax		      ;AN000;
;		$ELSE					      ;AN000;
		JMP SHORT DD_EN10
DD_IF10:
		    mov    [P_H_Buffers], ax		      ;AN000;
;		$ENDIF					      ;AN000;
DD_EN10:
;	    $ENDIF					      ;AN000;
DD_EN8:
;	$ENDLOOP			;AN000;
	JMP SHORT DD_DO4
DD_EN4:
	    cmp     word [P_Buffers], 99	;AN000;
;	    $IF     A,AND		;AN000;
	    JNA DD_IF15
	    cmp     byte [P_Buffer_Slash_X], 0 ;AN000;AN025;
;	    $IF     E			;AN000;
	    JNE DD_IF15
		 call	Badparm_p	;AN000;
		 mov	word [P_H_Buffers], 0	;AN000;
;	    $ELSE			;AN000;
	    JMP SHORT DD_EN15
DD_IF15:
		 mov	ax, [P_Buffers]	;AN000; We don't have any problem.
Buffers equ BUFFERS	; NASM port label
		 mov	[Buffers], ax	;AN000; Now, let's set it really.
		 mov	ax, [P_H_Buffers] ;AN000;
		 mov	[H_Buffers], ax	;AN000;
		 mov	al, [P_Buffer_Slash_X]  ;AN000;AN025;
		 mov	[Buffer_Slash_X], al    ;AN000;AN025;
		 mov	ax, [LineCount]	      ;AN000;
		 mov	[Buffer_LineNum], ax    ;AN000; Save the line number for the future use.
;	    $ENDIF			;AN000;
DD_EN15:
;	$ENDSRCH			;AN000;
DD_SR4:
	jmp	Coff

;------------------------------------------------------------------------------
; Break command
;------------------------------------------------------------------------------
;*******************************************************************************
;									       *
; Function: Parse the parameters of Break = command.			       *
;									       *
; Input :								       *
;	ES:SI -> parameters in command line.				       *
; Output:								       *
;	Turn the Control-C check on or off.				       *
;									       *
; Subroutines to be called:						       *
;	Sysinit_Parse							       *
; Logic:								       *
; {									       *
;	Set DI to Brk_Parms;						       *
;	Set DX,CX to 0; 						       *
;	While (End of command line)					       *
;	{ Sysinit_Parse;						       *
;	  if (no error) then						       *
;	       if (Result_Val.D_P_Item_Tag == 1) then	  /*ON		 */    *
;		   Set P_Ctrl_Break, on;				       *
;	       else					  /*OFF 	 */    *
;		   Set P_Ctrl_Break, off;				       *
;	  else {Show message;Error_Exit};				       *
;	};								       *
;	If (no error) then						       *
;	   DOS function call to set Ctrl_Break check according to	       *
; };									       *
;									       *
;********************************************************************************
;TryC:	 CMP	 AH,'C'
;	 JZ	 GOTC
;	 JMP	 TRYDJ
;GOTC:
;	 CMP	 AL,'O' 		 ;FIRST LETTER OF "ON" or "OFF"
;	 JNZ	 TryCBad
;	 CALL	 GETCHR
;	 JC	 TryCBad
;	 CMP	 AL,'N' 		 ;SECOND LETTER OF "ON"
;	 JNZ	 TryCoff
;	 MOV	 AH,SET_CTRL_C_TRAPPING  ;TURN ON CONTROL-C CHECK
;	 MOV	 AL,1
;	 MOV	 DL,AL
;	 INT	 21H
;CoffJ2: JMP	 Coff
;TryCOff:CMP	 AL,'F'
;	 JNZ	 TryCBad		 ; Check for "OFF"
;	 CALL	 GetChr
;	 JC	 TryCBad
;	 CMP	 AL,'F'
;	 JZ	 COffJ2
;TryCBad:JMP	 BadOp
;
TryC:
	CMP	AH,'C'
TRYM equ TryM	; NASM port label
	JNZ	TRYM
	mov	di, offset Brk_Parms	;AN000;
	xor	cx,cx			;AN000;
	mov	dx,cx			;AN000;
;	$SEARCH 			;AN000;
DD_DO19:
	    call   Sysinit_Parse	;AN000;
;	$EXITIF    C			;AN000; Parse error
	JNC DD_IF19
	    call   Badparm_p		;AN007;  Show message and end the serach loop.
;	$ORELSE 			;AN000;
	JMP SHORT DD_SR19
DD_IF19:
	    cmp    ax, D_P_RC_EOL	;AN000; End of Line?
;	$LEAVE	   E			;AN000;  then end the $ENDLOOP
	JE DD_EN19
D_P_ITEM_TAG equ D_P_Item_Tag	; NASM port equate
	    cmp    byte [Result_Val + D_P_ITEM_TAG], 1	 ;AN000;
;	    $IF    E				 ;AN000;
	    JNE DD_IF23
	       mov    byte [P_Ctrl_Break], 1		 ;AN000; Turn it on
;	    $ELSE				 ;AN000;
	    JMP SHORT DD_EN23
DD_IF23:
	       mov    byte [P_Ctrl_Break], 0		 ;AN000; Turn it off
;	    $ENDIF				 ;AN000;
DD_EN23:
;	$ENDLOOP			   ;AN000; we actually set the ctrl break
	JMP SHORT DD_DO19
DD_EN19:
SET_CTRL_C_TRAPPING equ Set_CTRL_C_Trapping	; NASM port equate
	    mov    ah, SET_CTRL_C_TRAPPING ;AN000; if we don't have any parse error.
	    mov    al, 1		   ;AN000;
	    mov    dl, [P_Ctrl_Break]	   ;AN000;
	    Int    21h			   ;AN000;
;	$ENDSRCH			   ;AN000;
DD_SR19:
	jmp	Coff

;------------------------------------------------------------------------------
; MultiTrack command
;------------------------------------------------------------------------------
;*******************************************************************************
;									       *
; Function: Parse the parameters of MultiTrack= command.		       *
;									       *
; Input :								       *
;	ES:SI -> parameters in command line.				       *
; Output:								       *
;	Turn MulTrk_Flag on or off.					       *
;									       *
; Subroutines to be called:						       *
;	Sysinit_Parse							       *
; Logic:								       *
; {									       *
;	Set DI to Brk_Parms;						       *
;	Set DX,CX to 0; 						       *
;	While (End of command line)					       *
;	{ Sysinit_Parse;						       *
;	  if (no error) then						       *
;	       if (Result_Val.D_P_Item_Tag == 1) then	  /*ON		 */    *
;		   Set P_Mtrk, on;					       *
;	       else					  /*OFF 	 */    *
;		   Set P_Mtrk, off;					       *
;	  else {Show message;Error_Exit};				       *
;	};								       *
;	If (no error) then						       *
;	   DOS function call to set MulTrk_Flag according to P_Mtrk.	       *
;									       *
; };									       *
;									       *
;********************************************************************************
TryM:					;AN002;
	CMP	AH,'M'			;AN002;
TRYW equ TryW	; NASM port label
	JNZ	TRYW			;AN002;
Mtrk_Parms equ MTrk_Parms	; NASM port label
	mov	di, offset Mtrk_Parms	;AN002;
	xor	cx,cx			;AN002;
	mov	dx,cx			;AN002;
;	$SEARCH 			;AN002;
DD_DO28:
	    call   Sysinit_Parse	;AN002;
;	$EXITIF    C			;AN002; Parse error
	JNC DD_IF28
	    call   Badparm_p		;AN007;  Show message and end the serach loop.
;	$ORELSE 			;AN002;
	JMP SHORT DD_SR28
DD_IF28:
	    cmp    ax, D_P_RC_EOL	;AN002; End of Line?
;	$LEAVE	   E			;AN002;  then end the $ENDLOOP
	JE DD_EN28
	    cmp    byte [Result_Val + D_P_ITEM_TAG], 1	 ;AN002;
;	    $IF    E				 ;AN002;
	    JNE DD_IF32
	       mov    byte [P_Mtrk], 1 		 ;AN002; Turn it on temporarily.
;	    $ELSE				 ;AN002;
	    JMP SHORT DD_EN32
DD_IF32:
	       mov    byte [P_Mtrk], 0 		 ;AN002; Turn it off temporarily.
;	    $ENDIF				 ;AN002;
DD_EN32:
;	$ENDLOOP			;AN002; we actually set the MulTrk_Flag here.
	JMP SHORT DD_DO28
DD_EN28:
	    push   ds			;AN002;
	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
	    cmp    byte [cs:P_Mtrk], 0		;AN002;
;	    $IF    E			;AN002;
	    JNE DD_IF36
MulTrk_Flag equ MulTrk_flag	; NASM port label
	       mov    word [MulTrk_Flag], MULTRK_OFF2	  ;AN002; 0001h
;	    $ELSE				  ;AN002;
	    JMP SHORT DD_EN36
DD_IF36:
	       mov    word [MulTrk_Flag], MULTRK_ON	  ;AN002; 8000h
;	    $ENDIF			;AN002;
DD_EN36:
	    pop    ds			;AN002;
 assume ds:SYSINITGROUP
;	$ENDSRCH			;AN002;
DD_SR28:
	jmp	Coff			;AN002;

;------------------------------------------------------------------------------
; CPSW command
;------------------------------------------------------------------------------
;*******************************************************************************
;									       *
; Function: Parse the parameters of CPSW= command.			       *
;									       *
; Input :								       *
;	ES:SI -> parameters in command line.				       *
; Output:								       *
;	Turn CPSW on or off.						       *
;									       *
; Subroutines to be called:						       *
;	Sysinit_Parse							       *
; Logic:								       *
; {									       *
;	Set DI to CPSW_Parms;						       *
;	Set DX,CX to 0; 						       *
;	While (End of command line)					       *
;	{ Sysinit_Parse;						       *
;	  if (no error) then						       *
;	       if (Result_Val.D_P_Item_Tag == 1) then	  /*ON		 */    *
;		   Set P_CPSW, on;					       *
;	       else					  /*OFF 	 */    *
;		   Set P_CPSW, off;					       *
;	  else {Show message;Error_Exit};				       *
;	};								       *
;	If (no error) then						       *
;	   DOS function call to set CPSW according to P_CPSW.		       *
; };									       *
;									       *
;********************************************************************************
TryW:					;AN002;
	CMP	AH,'W'			;AN002;
	JNZ	TRYDJ			;AN002;
	mov	di, offset CPSW_Parms	;AN002;
	xor	cx,cx			;AN002;
	mov	dx,cx			;AN002;
;	$SEARCH 			;AN002;
DD_DO40:
	    call   Sysinit_Parse	;AN002;
;	$EXITIF    C			;AN002; Parse error
	JNC DD_IF40
	    call   Badparm_p		;AN007;  Show message and end the serach loop.
;	$ORELSE 			;AN002;
	JMP SHORT DD_SR40
DD_IF40:
	    cmp    ax, D_P_RC_EOL	;AN002; End of Line?
;	$LEAVE	   E			;AN002;  then end the $ENDLOOP
	JE DD_EN40
	    cmp    byte [Result_Val + D_P_ITEM_TAG], 1	 ;AN002;
;	    $IF    E				 ;AN002;
	    JNE DD_IF44
	       mov    byte [P_CPSW], 1 		 ;AN002; Turn it on temporarily.
;	    $ELSE				 ;AN002;
	    JMP SHORT DD_EN44
DD_IF44:
	       mov    byte [P_CPSW], 0 		 ;AN002; Turn it off temporarily.
;	    $ENDIF				 ;AN002;
DD_EN44:
;	$ENDLOOP			;AN002; we actually set the MulTrk_Flag here.
	JMP SHORT DD_DO40
DD_EN40:
	    mov    ah, SET_CTRL_C_TRAPPING ;AN000; The same function number as Ctrl_Break
	    mov    al, 4		   ;AN000; Set CPSW state function
	    mov    dl, [P_CPSW]		   ;AN000; 0=off, 1=on
	    Int    21h			   ;AN000;
;	$ENDSRCH			;AN002;
DD_SR40:
	jmp	Coff			;AN002;

;------------------------------------------------------------------------------
; Device command
;------------------------------------------------------------------------------
TRYDJ:
	mov byte [cs:devicehighflag], 0
	cmp ah, '4'
	jne @F
	not byte [cs:devicehighflag]
	mov ah, '3'
@@:
	cmp ah, '3'			; INSTALLFIRST= command?
	je ..@run_install

	rol byte [cs:installaslast_option], 1
	jc .notinstall			; INSTALLASLAST overrides INSTALLASFIRST
	rol byte [cs:installasfirst_option], 1
	jnc .notinstall			; not INSTALLASFIRST -->
	mov byte [cs:devicehighflag], 0
	cmp ah, 'i'
	jne @F
	not byte [cs:devicehighflag]
	mov ah, 'I'
@@:
	cmp ah, 'I'			; INSTALL= command?
	je ..@run_install

.notinstall:

Try_CheckDevice:
	cmp ah, '8'
	jne .not
	push ds
	push es
	push si
	 push es
	 pop ds
 assume ds:nothing
	 push cs
	 pop es
 assume es:SYSINITGROUP

	mov dx, On_String
	call isstring?
	je .on
	mov dx, Off_String
	call isstring?
	je .off
	xor bx, bx
	lodsb
	cmp al, '+'
	je @F
	inc bx
	cmp al, '-'
	je @F
	inc bx
	dec si
@@:
	call ldos_getnum
		; OUT:	NC if success,
		;	 dx = number
		;	 bl = 0 if +, 1 if -, 2 else
	jc .error
	jmp @F

.on:
	mov dx, 1
	mov bl, 0
	jmp @F

.off:
	mov dx, 1
	mov bl, 1
@@:
	lodsb
	cmp al, 32
	je @B
	cmp al, 9
	je @B
	cmp al, 13
	je .done
	cmp al, 10
	je .done
	cmp al, 0
	je .done
.error:
	pop si
	pop es
	pop ds
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	jmp BADOP

.done:
 assume es:nothing
	pop si
	pop es
	pop ds
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	cmp bl, 1
	jb .or
	je .clr
.set:
	mov word [checkdeviceflags], dx
	jmp .end
.or:
	or word [checkdeviceflags], dx
	jmp .end
.clr:
	not dx
	and word [checkdeviceflags], dx
.end:
	jmp COFF
.not:

Try_EarlyLastdrive:
	cmp ah, '9'
	jne .not
	push ds
	push es
	push si
	 push es
	 pop ds
 assume ds:nothing
	 push cs
	 pop es
 assume es:SYSINITGROUP
	lodsw
	cmp ah, ':'
	je .trydrive
	cmp ah, 32
	je .trydrive
	cmp ah, 9
	je .trydrive
	cmp ah, 13
	je .trydrive
	cmp ah, 10
	je .trydrive
	cmp ah, 0
	jne .number
.trydrive:
	call capitalise
	cmp al, 'A'
	jb .number
	cmp al, '`'		; CDS limit
	ja .number
	sub al, 'A' - 1
	mov bl, 2
	cmp ah, ':'
	je @F
	dec si
@@:
	xchg dx, ax
	jmp .got

.number:
	dec si
	xor bx, bx
	cmp al, '+'
	je @F
	inc bx
	cmp al, '-'
	je @F
	inc bx
	dec si
@@:
	call ldos_getnum
		; OUT:	NC if success,
		;	 dx = number
		;	 bl = 0 if +, 1 if -, 2 else
	jc .error
	cmp dx, 32		; CDS limit
	ja .error
.got:
@@:
	lodsb
	cmp al, 32
	je @B
	cmp al, 9
	je @B
	cmp al, 13
	je .done
	cmp al, 10
	je .done
	cmp al, 0
	je .done
.error:
	pop si
	pop es
	pop ds
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	jmp BADOP

.done:
 assume es:nothing
	LES	DI,[ss:DOSINFO]
 assume es:DOSGROUP
	mov al, [es:di + SYSI_NCDS]
	mov ah, al

	cmp bl, 1
	jb .plus
	je .minus
.set:
	mov ah, dl
	jmp .common

.plus:
	add ah, dl
	jc .max
	cmp ah, 32		; CDS limit
	jna .common
.max:
	mov ah, 32		; CDS limit
	jmp .common

.minus:
	sub ah, dl
	jnc .common
.min:
	mov ah, 0
.common:
  extern cds_last_used, alloc_initcds, free_temp_cds, tempcds_block
  extern FOOSTRNG, FOOSET
	xchg dx, ax		; dh = desired
	call cds_last_used
	inc bh			; = minimum
	cmp bh, dh
	jae @F
	mov bh, dh		; max(bh, dh)
@@:
	LES	DI,[ss:DOSINFO]
 assume es:DOSGROUP
	mov bl, [es:di + SYSI_NCDS]
	cmp bh, bl
	jnb @F
	mov bl, bh			; how many to preserve: min(bl, bh)
@@:
	mov al, curdir_list_struc_size
	mul bl
	push bx				; stack = how many entries in old CDS
	push ax				; stack = how much to preserve in bytes

	xor cx, cx
	mov cl, bh
	mov byte [es:di + SYSI_NCDS], cl	; update amount CDS entries
	mov al, curdir_list_struc_size
	mul cl				; ax = how much to allocate in bytes

	push cx
	push es
	push di
	mov si, alloc_initcds
	call allocate_temporary_block
 assume es:nothing
	pop si
	pop ds				; -> DOSINFO
 assume ds:DOSGROUP
	pop bx				; bl = how many entries in new CDS
	pop cx				; = how much to preserve in bytes

	push ds
	push si
	lds si, [si + SYSI_CDS]		; -> old CDS
 assume ds:CDS
	mov dx, di			; es:dx -> new CDS
	rep movsb			; preserve old
	pop si
	pop ds
 assume ds:DOSGROUP
	call free_temp_cds		; free old
	mov word [cs:tempcds_block], es	; => temp CDS
	pop ax				; al = how many entries in old CDS
	MOV	WORD PTR [si + SYSI_CDS + 2], es
	mov	WORD PTR [si + SYSI_CDS], dx
					; -> new temp CDS
	sub bl, al			; = additional amount
	ja @F
	xor bx, bx			; just run for the init: verbose line,
					;  do not add any drives
@@:
	add al, "A"			; prior amount + "A"
	mov byte [ss:FOOSTRNG], al	; first letter of additional table

	xor cx, cx
	mov cl, bl			; cx = additional amount of CDS entries
	mov si, -1			; no DPBs for additional table
	call FOOSET			; init additional table
	pop si
	pop es
	pop ds
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	jmp COFF

.not:
Try_Device:
	debugnumber 'DJ'
	mov byte [cs:devicehighflag], 0
	and	word [cs:IFS_Flag], NOT_IFS	;AN000; Reset the flag
	cmp ah, 'd'
	je GOTDJ_devicehigh
	CMP	AH,'D'
	JZ	GOTDJ
	CMP	AH,'J'
	jz	GOTJ
	JMP	TRYQ
GOTJ:					;AN000; IFS= command.
	or	word [cs:IFS_Flag], IS_IFS	;AN000; set the flag.
	cmp	byte [Multi_Pass_Id], 2	;second pass?
	je	GOTDJ			;then proceed
	jmp	Coff			;else ignore this until the second pass.

;	 jmp	 GOTDJ_Cont
;GOTD:
;	 test	 [cs:IFS_Flag], HAD_IFS  ;AN000; Cannot have DEVICE= command after IFS= command.
;	 jz	 GOTDJ_Cont		 ;AN000;
;	 call	 Incorrect_Order	 ;AN000; Display "Incorrect order ..." msg.
;	 jmp	 COFF			 ;AN000;

GOTDJ_devicehigh:
	not byte [cs:devicehighflag]
GOTDJ:
	debugnumber 'gt'
	MOV	BX,CS			;DEVICE= or IFS= command.
	MOV	DS,BX
 assume ds:SYSINITGROUP

	MOV	WORD PTR [BPB_ADDR],SI
	MOV	WORD PTR [BPB_ADDR+2],ES

;J.K. In case it is for IFS=, then set the parameter pointer.
ifs_rh equ IFS_RH	; NASM port label
	mov	word ptr [ifs_rh + IFSR_PARMS@], SI   ;AN000; for IFS
	mov	word ptr [ifs_rh + IFSR_PARMS@+2], ES ;AN000;

; We are going to open the cdevice driver and size it as is done
;  in LDFIL. The reason we must do this is that EXEC does NO checking
;  for us. We must make sure there is room to load the device without
;  trashing SYSINIT. This code is not
;  perfect (for instance .EXE device drivers are possible) because
;  it does its sizing based on the assumption that the file being loaded
;  is a .COM file. It is close enough to correctness to be usable.

	PUSH	ES
	POP	DS
ASSUME	DS:NOTHING
	MOV	DX,SI			;DS:DX POINTS TO FILE NAME

	MOV	AX,OPEN << 8		;OPEN THE FILE
	STC				;IN CASE OF INT 24
	INT	21H
	JC	BADLDRESET
	MOV	BX,AX			;Handle in BX
	push ds
	PUSH	DX			; Save pointer to name

	mov di, sp			; -> original stack
	push ss
	pop ds
	mov cx, exeOverlayNum
	sub sp, cx			; -> space for MZ header
	mov dx, sp			; -> buffer
	mov ah, 3Fh
	int 21h				; read header
	jc .closebad
	cmp ax, cx			; full header read ?
	jne .flat			; no, must be a flat file -->
	pop ax				; exeSignature
	cmp ax, "MZ"			; sign match ?
	je .mz
	cmp ax, "ZM"
	jne .flat			; no -->
.mz:
	pop ax				; exeExtraBytes
	pop ax				; exePages
	mov cl, 9 - 4			; log2(512) - log2(16)
	shl ax, cl			; (some sources report this is mod 1 MiB)
	pop dx				; exeRelocItems
	pop dx				; exeHeaderSize
	sub ax, dx			; image size in paragraphs
	jbe .closebad
	jmp .got

.flat:
	XOR	CX,CX
	XOR	DX,DX
	MOV	AX,(LSEEK << 8) | 2	; seek to EOF
	STC				;IN CASE OF INT 24
	INT	21H			; Get file size in DX:AX
	jc .closebad

    ; Convert size in DX:AX to para in AX
	ADD	AX,15			; Round up size for conversion to para
	ADC	DX,0
	jc .err				; rounded up is 4 GiB ? -->
	mov cx, 4
@@:
	shr dx, 1
	rcr ax, 1
	loop @B
	test dx, dx			; >= 1 MiB ?
	jnz .err			; -->
	cmp ax, -16			; allow for some increment
	jb .got				; if fine -->
.err:
	mov sp, di
	jmp MEM_ERRJY

.closebad:
	mov sp, di
	MOV	AH,CLOSE		; Close file
	INT	21H
	POP	DX			; Clean stack
	pop dx				; discard ds
	STC				; Close may clear carry
	JMP	BADLDRESET
.got:
	mov sp, di
	push cs
	pop ds
 assume ds:SYSINITGROUP
	mov word [devicefilesizepara], ax

retry_devicehigh_oom:
	mov dx, word [devicefilesizepara]
;	rol byte [devicehighflag], 1
;	jnc .low1
.high1:

	push bx				; preserve handle
	mov ax, 5800h
	int 21h
	push ax
	mov ax, 5801h
	mov bx, 0140h			; ignore UMB link, UMA only, first fit
	rol byte [devicehighflag], 1
	jc @F
	mov bx, 0110h			; ignore UMB link, LMA only, first fit
@@:
	int 21h

	mov bx, dx
	inc bx				; space for SD sub-MCB
	mov ah, 48h
	int 21h
	jnc @F

	pop bx
	mov ax, 5801h
	int 21h
	pop bx				; handle

	rol byte [devicehighflag], 1	; already tried LMA ?
	jnc .oom			; yes -->
	not byte [devicehighflag]	; toggle back to try LMA
	jmp retry_devicehigh_oom

.oom:
	jmp MEM_ERR

@@:
	mov dx, ax
	pop bx
	mov ax, 5801h
	int 21h

	push es
	push si

	mov es, dx
 assume es:nothing
	mov ah, 4Ah
	mov bx, -1
	int 21h			; grow to largest size

		; recreate stack frame of init2_relocate_device
	lframe 0
	lvar word, umb_first_umcb
	lvar word, umb_last_umcb
	lvar word, last_mcb
	lenter
	lvar word, flags
	 push ax
	lvar word, first_mcb
	mov ah, 52h
	int 21h
 assume es:nothing
	 push word [es:bx - 2]
	lvar word, first_umcb
	mov ax, 1261h
	int 2Fh
	 push ax

	dec dx

	xor si, si
	push si			; loop detection counter word
	mov si, 20h		; "LMA then UMA" (+ first fit)
	push si
	mov si, sp		; ss:si -> area flags and strategy word

	xor ax, ax		; = 0 = get first UMCB
.search_umb:
	mov word [bp + ?last_mcb], ax
	call init2_SNextMCB
	jc .no_sd_merge		; chain corrupted
	jnz .no_sd_merge	; end reached

	cmp ax, dx
	jne .search_umb

	mov ax, word [bp + ?last_mcb]
	mov ds, ax
 assume ds:MCB
	cmp word [di + mcbOwner], 8
	jne .no_sd_merge
	cmp word [di + mcbName], "SD"
	jne .no_sd_merge
	cmp byte [di + mcbName + 2], 0
	jne .no_sd_merge

		; ax => SD MCB immediately before ours
.sd_merge:
	mov es, dx		; => new MCB (to become sub MCB)
 assume es:MCB
	mov bx, [es:di + mcbSize]
				; get size
	inc bx			; count MCB itself
	add word [di + mcbSize], bx
				; grow SD MCB
	jmp .merge_common

.no_sd_merge:
	mov ds, dx		; => new MCB (to become SD MCB)
 assume ds:MCB
	mov ax, dx
	mov word [di + mcbOwner], 8
	mov word [di + mcbName], "SD"
	mov word [di + mcbName + 2], di
	inc dx
	mov es, dx		; => new sub MCB
 assume es:nothing
	mov bx, [di + mcbSize]
	dec bx
	mov word [es:di + mcbSize], bx
	mov word [es:di + mcbReserved], di
	mov word [es:di + mcbReserved + 2], di
				; clear reserved fields
.merge_common:
		; ax => SD MCB, we are at the tail end
		; es => sub-MCB we're creating
		; di = 0
		; dx = es
	mov byte [es:di + mcbSignature], DEVMARK_DEVICE
				; set devmark
	inc dx
	mov word [es:di + mcbOwner], dx
				; set owner
	mov word [es:di + mcbName], di
	mov word [es:di + mcbName + 2], di
	mov word [es:di + mcbName + 4], di
	mov word [es:di + mcbName + 6], di
				; clear name for a bit
	mov bx, word [es:di + mcbSize]
				; bx = size
		; ax => SD MCB, we are at the tail end
		; es => sub-MCB we've created
		; di = 0
		; dx => data block to use
		; bx = size of sub-MCB

	lleave
	push cs
	pop ds
 assume ds:SYSINITGROUP, es:nothing
	mov word [devicehighsd], ax
	mov word [devicehighdata], dx
	mov word [devicehighsize], bx
	add bx, dx
	mov word [devicehighafter], bx

	push es
	pop ds				; ds => sub-MCB
 assume ds:nothing

	pop si
	pop es				; es:si -> filename
 assume es:nothing

	push es
	push si
	call get_device_mcb_name
	pop si
	pop es
 assume es:nothing

	xchg ax, dx			; ax => memory block
	pop bx				; handle
	jmp .common1

%if 0
.low1:
	CALL	ROUND
;J.K. Set up the DEVMARK entries here for MEM command.
;J.K. Only the DEVMARK_ID and DEVMARK_FILENAME will be set.
;J.K. DEVMARK_SIZE should be set after a successful process of this file.
	call	Set_DevMark		;AN004;
	inc	word [MEMHI] 		;AN004;Size of DEVMARK is a paragraph!!
					;Don't forget decrease MEMHI
					; with an unsuccessful process of this file!!.
	MOV	AX,[MEMHI]
%endif

.common1:
	push cs
	pop ds
 assume ds:SYSINITGROUP, es:nothing
	and	WORD PTR [ENTRY_POINT], 0
	MOV	WORD PTR [ENTRY_POINT+2],AX	;SET ENTRY POINT

	MOV	[PRMBLK],AX		;SET LOAD OFFSET
	MOV	[PRMBLK + 2],AX		;SET LOAD OFFSET

%if 1
	jmp OKLDX
%else
	rol byte [devicehighflag], 1
	jc OKLDX			; already know for devicehigh -->
	MOV	CX,ax			; CX:0 is xaddr
	ADD	CX, [devicefilesizepara]; New device will take up to here
	JC	MEM_ERRJY		; WOW!!!!
	CMP	CX, [ALLOCLIM]
	JB	OKLDX
%endif

MEM_ERRJY:
	JMP	MEM_ERR

OKLDX:
	POP	DX			; Recover name pointer
	pop ds
 assume ds:nothing
	MOV	AH,CLOSE		; Close file
	INT	21H
	push cs
	pop es
 assume es:SYSINITGROUP
	MOV	BX,OFFSET PRMBLK	;ES:BX POINTS TO PARAMETERS
	MOV	AL,3
EXEC equ Exec	; NASM port equate
	MOV	AH,EXEC
	STC				;IN CASE OF INT 24
	INT	21H			;LOAD IN THE DEVICE DRIVER
	mov word [cs:devicelastdpb], -1
	mov word [cs:devicefirstnewdpb], -1
	mov byte [cs:deviceamountnew], 0

BADLDRESET:
	PUSH	DS
	POP	ES			;ES:SI BACK TO CONFIG.SYS
 assume es:nothing
	PUSH	CS
	POP	DS			;DS BACK TO SYSINIT
 ASSUME DS:SYSINITGROUP
	JNC	GOODLD_first
BADBRK:
 assume ds:nothing, es:nothing, ss:nothing
	test	byte [cs:SetDevMarkFlag],SETBRKDONE ;AN004;If already Set_Break is done,
	jnz	Skip0_ResetMEMHI	;AN004; then do not
	; dec	word [cs:MEMHI]		   ;AN004;Adjust MEMHI by a paragrah of DEVMARK.
	call release_device_memory
Skip0_ResetMEMHI:
	cmp	byte ptr [es:si], CR	;file name is CR? (Somebody entered "device=" without filename)
	jne	BADBRK_1
	jmp	BADOP			;show "Unrecognized command in CONFIG.SYS"
BADBRK_1:
	invoke	BADLOAD
	JMP	COFF

GOODLD_first:
	testopt [cs:checkdeviceflags], 1
	jz .nocheck
	push ds
	mov ds, word [cs:ENTRY_POINT + 2]
 assume ds:nothing
		; The first word is not checked in order to allow
		;  loading dual-mode .COM executables, which need
		;  a short jump in the first two bytes.
		; Dual-mode MZ .EXE executables may also want to
		;  provide a "zero entrypoint" here, though it is
		;  not required to make a dual-mode .EXE file.
	cmp word [2], -1		; check that second word = 0FFFFh
	jne .bad
	mov dx, word [cs:devicefilesizepara]
	cmp dx, 1000h
	jae .good
	shl dx, 1
	shl dx, 1
	shl dx, 1
	shl dx, 1			; to byte offset
	cmp word [6], dx		; check strategy entry low enough
	jae .bad
	cmp word [8], dx		; check interrupt entry low enough
	jae .bad
		; The interrupt entrypoint dvc_int is only chained to
		;  after the strategy. If the file is compressed
		;  then the interrupt may point behind the packed
		;  data, and it may become initialised in time.
		; Therefore we do not check for the interrupt entry.
		; Update: Added CHECKDEVICE commanf if this check
		;  would really need to be bypassed.
.good:
	db __TEST_IMM8			; skip stc, NC
.bad:
	stc

	pop ds
 assume ds:nothing
	jc BADBRK
.nocheck:

GOODLD:
	mov byte [cs:cds_installed_last_unit_plus], 0
;J.K. If it is IFS=, then we should set IFS_DOSCALL@ field in IFSHEADER.
	test	word [cs:IFS_Flag], IS_IFS		;AN000;
	jz	Skip_IFSHEADER_Set		;AN000;
	push	es				;AN000;
	push	di				;AN000;
	push	ds				;AN000;
	mov	bx, word ptr [cs:ENTRY_POINT+2] ;AN000;
	mov	ds, bx				;AN000; DS:0 will be the header
 assume ds:nothing
DosInfo equ DOSINFO	; NASM port label
	les	di, [cs:DosInfo]		;AN000;
 assume es:DOSGROUP
	mov	bx, word ptr [es:di + SYSI_IFS_DOSCALL@]	 ;AN000;
	mov	word ptr [IFS_DOSCALL@], bx		 ;AN000;
	mov	bx, word ptr [es:di + SYSI_IFS_DOSCALL@ + 2] ;AN000;
	mov	word ptr [IFS_DOSCALL@ + 2], bx	 ;AN000;
	pop	ds				;AN000;
 assume ds:nothing
	pop	di				;AN000;
	pop	es				;AN000;
 assume ds:nothing, es:nothing
Skip_IFSHEADER_Set:				;AN000;
	SaveReg <ES,SI> 		;INITIALIZE THE DEVICE
;	 call	 Chk_IBMCACHE		 ;AN024 IBMCACHE.SYS problem.;AN026;IBMDOS will handles this thru 4Bh call.
.Restore:MOV	BL,[ES:SI]		;   while ((c=*p) != 0)
	test	BL,BL
	JZ	.Got
	INC	SI			;	p++;
	JMP	.Restore
.Got:	MOV	BYTE PTR [ES:SI],' '	;   *p = ' ';
	SaveReg <ES,SI>
	PUSH	CS
	POP	ES
 assume es:SYSINITGROUP

	test	word [cs:IFS_Flag], IS_IFS	;AN000;
	jz	Got_Device_Com		;AN000;
	mov	bx, IFS_CALL@		;AN000; offset from the start of IFSHEADER
	call	sysinit_CallIFS		;AN000;
	jmp	short End_Init_Call
Got_Device_Com:
	push	ds			;AN017;
	push	si			;AN017;
	lds	si, [cs:ENTRY_POINT]	;AN017; Peeks the header attribute
 assume ds:nothing
	test	word ptr [si + SDEVATT], DEVTYP  ;AN017;Block device driver?
	jnz	Got_Device_Com_Cont		  ;AN017;No.
	lds	si, [cs:DOSINFO]	;AN017; DS:SI -> SYS_VAR
 assume ds:DOSGROUP
	cmp	byte [si + SYSI_NUMIO], 32	;AN017; No more than 26 drive number (CDS limit)
	jb	Got_Device_Com_Cont	;AN017;
	pop	si			;AN017;
	pop	ds			;AN017;
 assume ds:nothing
	pop	si			;AN017;clear the stack
	pop	es			;AN017;
 assume es:nothing
	jmp	BadNumBlock		;AN017;
Got_Device_Com_Cont:			;AN017;
	pop	si			;AN017;
	pop	ds			;AN017;
 assume ds:nothing

	rol byte [cs:MultDeviceFlag], 1
	jc .keepbreak
	mov ax, word [cs:devicehighafter]
%if 0
	rol byte [cs:devicehighflag], 1
	jc .common3
.low3:
alloclim equ ALLOCLIM	; NASM port label
	mov ax, [cs:alloclim]
%endif
.common3:

	push ds
	push si
	push ax
	rol byte [cs:reinitcds_option], 1
	jnc .find
	lds si, [cs:DOSINFO]
	mov bh, [si + SYSI_NUMIO]
	jmp @F
.find:
	mov al, byte [cs:cds_installed_last_unit_plus]
 extern cds_first_unused
	call cds_first_unused
@@:
DriveNumber equ DRIVENUMBER	; NASM port label
	mov byte [cs:DriveNumber], bh
	mov [cs:devicefirstnewdrive], bh
	pop ax
	pop si
	pop ds

Break_addr equ BREAK_ADDR	; NASM port label
	and word ptr [cs:Break_addr], 0
	mov word ptr [cs:Break_addr+2], ax
	mov word [cs:deviceafter], ax
.keepbreak:
	MOV	BX,SDEVSTRAT
	invoke	CALLDEV			;   CallDev (SDevStrat);
 assume ds:nothing, es:nothing
	MOV	BX,SDEVINT
	invoke	CALLDEV			;   CallDev (SDevInt);
 assume ds:nothing, es:nothing
	debugnumber 'rt'
End_Init_Call:
	RestoreReg  <SI,DS>
 assume ds:nothing
	MOV	BYTE PTR [SI],0		;   *p = 0;

	PUSH	CS
	POP	DS
 assume ds:SYSINITGROUP

	test	word [IFS_Flag], IS_IFS	;AN000;
	jz	Was_Device_Com		;AN000;
	cmp	byte [ifs_rh + IFSR_RETCODE], 0 ;AN000; Was a success ?
Erase_Dev_do equ ERASE_DEV_do	; NASM port label
	jne	Erase_Dev_do		;AN000;
	pop	si			;AN000; restore es:si to clean up the
	pop	es			;AN000; stack for Set_Break call.
 assume es:nothing
Entry_Point equ ENTRY_POINT	; NASM port label
	mov	ax, word ptr [Entry_Point+2]	   ;AN000; Get the loaded segment
	add	ax, word ptr [ifs_rh + IFSR_RESSIZE] ;AN000;
	and	word ptr [Break_addr], 0	   ;AN000;
	mov	word ptr [Break_addr+2], ax	   ;AN000;
	invoke	Set_Break		;AN000; Will also check the memory size too.
	push	es			;AN000; Save it again, in case, for Erase_Dev_Do.
	push	si			;AN000;
	jc	Erase_Dev_do		;AN000;
Link_IFS:				;AN000;
dosinfo equ DOSINFO	; NASM port label
	les	di, [cs:dosinfo]	;AN000;
 assume es:DOSGROUP
	mov	cx, word ptr [es:di + SYSI_IFS]	;AN000; save old pointer
	mov	dx, word ptr [es:di + SYSI_IFS+2] ;AN000;
	lds	si, [cs:Entry_Point]		;AN000;
 assume ds:nothing
	mov	word ptr [es:di + SYSI_IFS],si	;AN000;
	mov	word ptr [es:di + SYSI_IFS+2], ds ;AN000;
	mov	word ptr [si], cx		;AN000; We don't permit multiple IFSs.
	mov	word ptr [si+2], dx		;AN000;
	pop	si			;AN000; Restore es:si for the next command.
	pop	es			;AN000;
 assume es:nothing
;	 mov	 [cs:IFS_Flag], HAD_IFS  ;AN014; Set the flag.
	jmp	COFF			;AN000;

ERASE_DEV_do:				;AC000;; Modified to show message "Error in CONFIG.SYS..."
	pop	si
	pop	es
 assume es:nothing
	push	cs
	pop	ds
 assume ds:SYSINITGROUP

	test	byte [SetDevMarkFlag],SETBRKDONE ;AN004;If already Set_Break is done,
	jnz	Skip1_ResetMEMHI	;AN004; then do not
	; dec	word [MEMHI] 		;AN004;Adjust MEMHI by a paragrah of DEVMARK.
	call release_device_memory
Skip1_ResetMEMHI:
	cmp	word [ConfigMsgFlag], 0	;AN015;
	je	No_Error_Line_Msg	;AN015;
	call	Error_Line		;AN021; No "Error in CONFIG.SYS" msg for device driver. DCR D493
No_Error_Line_Msg:			;AN015;
	JMP	COFF_relocate

release_device_memory:
	push ds
	 push cs
	 pop ds
 assume ds:SYSINITGROUP
	; rol byte [devicehighflag], 1
	; jnc .low2
.high2:
	push es
	push ax
	push bx

	mov ax, word [devicehighsd]
	inc ax				; => SD MCB's data
	mov bx, word [devicehighdata]
	test bx, bx
	jz .ret
	dec bx				; => sub-MCB
	mov es, ax
 assume es:nothing
	sub bx, ax			; = size of SD to keep
	jz @F				; if to free -->
	mov ah, 4Ah
	int 21h				; shrink SD MCB, cannot fail
	mov ax, es
	dec ax
	mov es, ax			; => SD MCB
 assume es:MCB
	mov word [es:mcbOwner], 8	; reset owner changed by 21.4A
	jmp @FF
@@:
	mov ah, 49h
	int 21h				; free SD MCB
@@:
.ret:
	pop bx
	pop ax
	pop es
 assume es:nothing
	pop ds
 assume ds:nothing
	retn
%if 0
.low2:
	dec word [MEMHI]		; Adjust MEMHI by a paragraph of DEVMARK.
	pop ds
	retn
%endif

Was_Device_Com:				;AN000;
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
break_addr equ BREAK_ADDR	; NASM port label
	mov ax, word ptr [break_addr]
	call ParaRound
	add ax, word ptr [break_addr + 2]
	jc .bad
	cmp ax, word [deviceafter]
	jbe BREAKOK
.bad:
	POP	SI
	POP	ES
 assume es:nothing
	JMP	BADBRK

BREAKOK:
	mov word [deviceafter], ax	; for multi device drivers
	LDS	DX,[ENTRY_POINT]	;SET DS:DX TO HEADER
 assume ds:nothing
	MOV	SI,DX
	ADD	SI,SDEVATT		;DS:SI POINTS TO ATTRIBUTES
	LES	DI,[CS:DOSINFO] 	;ES:DI POINT TO DOS INFO
 assume es:DOSGROUP
	MOV	AX,[SI]		;GET ATTRIBUTES
	TEST	AX,DEVTYP		;TEST IF BLOCK DEV
	JZ	ISBLOCK
	invoke	Set_Break		; Go ahead and alloc mem for device
	jc	Erase_Dev_do		;device driver's Init routien failed.
	TEST	AX,ISCIN		;IS IT A CONSOLE IN?
	JZ	TRYCLK
	MOV	WORD PTR [ES:DI + SYSI_CON],DX
	MOV	WORD PTR [ES:DI + SYSI_CON+2],DS

TRYCLK: TEST	AX,ISCLOCK		;IS IT A CLOCK DEVICE?
	JZ	GOLINK
	MOV	WORD PTR [ES:DI+SYSI_CLOCK],DX
	MOV	WORD PTR [ES:DI+SYSI_CLOCK+2],DS
GOLINK: JMP	LINKIT

ISBLOCK:
	MOV	AL,[CS:UNITCOUNT]	;IF NO UNITS FOUND, erase the device
	test al, al
	jz	Erase_Dev_do
;	 JNZ	 PERDRV
;	 MOV	 AX, -1
;	 JMP	 ENDDEV

PERDRV:
	mov ah, 0
	MOV	CX,AX
	mov dh, 0
	push ds
	push si
	push ax
	rol byte [cs:reinitcds_option], 1
	jnc .find
	lds si, [cs:DOSINFO]
	mov bh, [si + SYSI_NUMIO]
	jmp @F
.find:
	mov al, byte [cs:cds_installed_last_unit_plus]
 extern cds_first_unused
	call cds_first_unused
@@:
	pop ax
	pop si
	pop ds
	mov dl, bh
	MOV	AH,DL
	ADD	AH,AL			; Check for too many devices
	jc BadNumBlock
	CMP	AH,32			; 'A' - 'Z' is 26 devices (CDS limit)
	JBE	OK_BLOCK
BadNumBlock:				;AN017;
	PUSH	CS
	POP	DS
 assume ds:SYSINITGROUP
	MOV	DX,OFFSET BADBLOCK
	invoke	PRINT
	JMP	ERASE_DEV_do

OK_BLOCK:
 assume ds:nothing
	invoke	SET_BREAK		; Alloc the device
	ADD	[ES:DI + SYSI_NUMIO],AL	;UPDATE THE AMOUNT
	LDS	BX,[CS:BPB_ADDR]	;POINT TO BPB ARRAY
 assume ds:nothing
sysconf_PERUNIT:
	LES	BP,[CS:DOSINFO]
 assume es:DOSGROUP
	LES	BP,[ES:BP + SYSI_DPB]	;GET FIRST DPB
 assume es:DPB

DPB_NEXT_DPB equ dpb_next_dpb	; NASM port equate
SCANDPB:CMP	WORD PTR [ES:BP + DPB_NEXT_DPB],-1
	JZ	FOUNDPB
	LES	BP,[ES:BP + DPB_NEXT_DPB]
	JMP	SCANDPB
FOUNDPB:
	push dx
	push bx
	push cx

	push ds
	push si
	push es
	push di

	les di, [cs:devicelastdpb]
 assume es:nothing
	cmp di, -1
	jne .try_extend
.alloc:
	mov ax, DPBSIZ
	mov si, alloc_dpb_no_hma
	call allocate_relocate_block
	jmp @F

.try_extend:
	add di, DPBSIZ
@@:
	mov word [cs:devicelastdpb], di
	mov word [cs:devicelastdpb + 2], es

	cmp word [cs:devicefirstnewdpb], -1
	jne .gotfirst
	mov word [cs:devicefirstnewdpb], di
	mov word [cs:devicefirstnewdpb + 2], es
.gotfirst:

	lea cx, [di + 15]
	shr cx, 1
	shr cx, 1
	shr cx, 1
	shr cx, 1		; old size (must succeed)

	lea bx, [di + DPBSIZ + 15]
	shr bx, 1
	shr bx, 1
	shr bx, 1
	shr bx, 1		; new size
	mov ah, 4Ah
	int 21h			; can we have it ?
	jnc .extended		; yes -->
	mov bx, cx
	mov ah, 4Ah
	int 21h			; restore to old size
	mov ax, es
	dec ax
	mov es, ax
 assume es:MCB
	mov word [es:mcbOwner], 8	; reset owner
	jmp .alloc

.extended:
	mov ax, es
	dec ax
	mov es, ax
 assume es:MCB
	mov word [es:mcbOwner], 8	; reset owner

	pop	di			;AN004;
	pop	es			;AN004;
 assume es:DPB
	pop	si			;AN004;
	pop	ds			;AN004;
 assume ds:nothing, es:DPB

	pop cx
	pop bx
	pop dx

	MOV	AX,[cs:devicelastdpb]
	MOV	WORD PTR [ES:BP + DPB_NEXT_DPB],AX
	MOV	AX,[cs:devicelastdpb + 2]
	MOV	WORD PTR [ES:BP + DPB_NEXT_DPB+2],AX
	LES	BP,[cs:devicelastdpb]
	or	WORD PTR [ES:BP + DPB_NEXT_DPB],-1
DPB_FIRST_ACCESS equ dpb_first_access	; NASM port equate
	MOV	byte [ES:BP + DPB_FIRST_ACCESS],-1
 assume es:DPB

	MOV	SI,[BX]			;DS:SI POINTS TO BPB
	INC	BX
	INC	BX			;POINT TO NEXT GUY
	push ds
	push si
	push ax
	push bx
	mov al, byte [cs:cds_installed_last_unit_plus]
	rol byte [cs:reinitcds_option], 1
	jnc .find
	lds si, [cs:DOSINFO]
	mov bh, al
	cmp byte [cs:deviceamountnew], 0
	jne @F
	mov bh, [cs:devicefirstnewdrive]
	jmp @F
.find:
 extern cds_first_unused
	call cds_first_unused
@@:
	mov dl, bh
	inc bh
	mov byte [cs:cds_installed_last_unit_plus], bh
	cmp bh, 32			; CDS limit
	ja BadNumBlock_2
	inc byte [cs:deviceamountnew]
	mov byte [cs:cds_amount_wanted], bh
	pop bx
	pop ax
	pop si
	pop ds
DPB_DRIVE equ dpb_drive	; NASM port equate
	MOV	WORD PTR [ES:BP + DPB_DRIVE],DX
SETDPB equ SetDPB	; NASM port equate
	MOV	AH,SETDPB		;HIDDEN SYSTEM CALL
	INT	21H
DPB_SECTOR_SIZE equ dpb_sector_size	; NASM port equate
	MOV	AX,[ES:BP + DPB_SECTOR_SIZE]
	PUSH	ES
	LES	DI,[CS:DOSINFO] 	;ES:DI POINT TO DOS INFO
 assume es:DOSGROUP
	CMP	AX,[ES:DI + SYSI_MAXSEC]
	POP	ES
 assume es:DPB
	ja	Bad_BPB_Size_Sector
	PUSH	DS
	PUSH	DX
	LDS	DX,[CS:ENTRY_POINT]
 assume ds:nothing
DPB_DRIVER_ADDR equ dpb_driver_addr	; NASM port equate
	MOV	WORD PTR [ES:BP + DPB_DRIVER_ADDR],DX
	MOV	WORD PTR [ES:BP + DPB_DRIVER_ADDR+2],DS
	POP	DX
	POP	DS
 assume ds:nothing
	INC	DX
	INC	DH
	LOOP	j_sysconf_PERUNIT
@@:
	PUSH	CS
	POP	DS
 assume ds:SYSINITGROUP
	CALL	TEMPCDS_after_block_device
					; Set CDS for new drives
	jmp LINKIT

BadNumBlock_2:
	pop bx
	pop ax
	pop si
	pop ds
	PUSH	CS
	POP	DS
 assume ds:SYSINITGROUP
	MOV	DX,OFFSET BADBLOCK
	invoke	PRINT

	cmp byte [deviceamountnew], 0
	jbe ERASE_DEV_do
	jmp @B


j_sysconf_PERUNIT:
	jmp sysconf_PERUNIT

LINKIT:
	LES	DI,[CS:DOSINFO] 	;ES:DI = DOS TABLE
 assume es:DOSGROUP
	MOV	CX,WORD PTR [ES:DI + SYSI_DEV]	;DX:CX = HEAD OF LIST
	MOV	DX,WORD PTR [ES:DI + SYSI_DEV+2]

	LDS	SI,[CS:ENTRY_POINT]	;DS:SI = DEVICE LOCATION
 assume ds:nothing
	MOV	WORD PTR [ES:DI + SYSI_DEV],SI	;SET HEAD OF LIST IN DOS
	MOV	WORD PTR [ES:DI + SYSI_DEV+2],DS
	MOV	AX,[SI]		;GET POINTER TO NEXT DEVICE
	MOV	WORD PTR [CS:ENTRY_POINT],AX	;AND SAVE IT

	MOV	WORD PTR [SI],CX	;LINK IN THE DRIVER
	MOV	WORD PTR [SI+2],DX
ENDDEV:
	POP	SI
	POP	ES
 assume es:nothing
	INC	AX			;AX = FFFF (no more devs if YES)?
	JZ	COFFJ3
	mov	byte [cs:MultDeviceFlag], -1	;AN001; Possibly multiple device driver.
	JMP	GOODLD			;OTHERWISE PRETEND WE LOADED IT IN
COFFJ3:
	mov	byte [cs:MultDeviceFlag], 0	;AN001; Reset the flag

COFF_relocate:
	and word [cs:ConfigMsgFlag], 0	; Set the default value again.
	push es
	mov ax, -1
	call init2_relocate_device
	pop es
 assume es:nothing
	JMP	COFF

Bad_BPB_Size_Sector:
	POP	SI
	POP	ES
 assume es:nothing
	MOV	DX,OFFSET BADSIZ_PRE
;	 MOV	 BX,OFFSET BADSIZ_POST
	mov	bx, offset CRLFM	;AN???;
	invoke	PRNERR
%if 0		; flag is never clear here
	test	byte [SetDevMarkFlag],SETBRKDONE ;AN004;If already Set_Break is done,
	jnz	Skip2_ResetMEMHI	;AN004; then do not
	; dec	word [MEMHI] 		;AN004;Adjust MEMHI by a paragrah of DEVMARK.
	call release_device_memory
Skip2_ResetMEMHI:
%endif
	JMP	COFF


;------------------------------------------------------------------------------
; Country command
; J.K. The syntax is:
;	COUNTRY=country id {,codepage {,path}}
;	COUNTRY=country id {,,path}	:Default CODEPAGE ID in DOS
;------------------------------------------------------------------------------
TRYQ:
	CMP	AH,'Q'
	JZ	TRYQ_CONT
	JMP	TRYF
TRYQ_CONT:

;	 invoke  GETNUM
;	 JZ	 TryQBad		 ; 0 is never a valid code, or number is
;					 ;   bad
;	 MOV	 BX,AX			 ; Country code in BX
;
;					 ;J.K. 5/26/86
;	 MOV	 DX,0			 ; assume no code page id
;
;	 invoke  skip_delim		 ;skip the delimeters after the first num
;	 jc	 TryQ_Def_File		 ;no more characters left? then use default file
;	 cmp	 al, CR 		 ;
;	 je	 TryQ_Def_File
;	 cmp	 al, LF
;	 jne	 TRYQ_YES_EXTENDED
;	 inc	 [COUNT]		 ;This is for NEWLINE routine in COFF.
;	 dec	 [CHRPTR]
;COFFJ41:
;	 JMP	 TryQ_Def_File		 ;O.K. no code page, no path specified. Use default path.
;
;TRYQ_YES_EXTENDED:
;	 cmp	 al, ','		 ;was the second comma?
;	 jne	 TryQ_GETNUM
;	 invoke  skip_delim		 ;Yes, skip ',' and other possible delim
;	 jmp	 short TRYQ_PATH	 ;and No code page id entered.
;TRYQ_GETNUM:
;	 invoke  GETNUM
;	 jc	 TryQBadCOM		 ;"Country=xxx,path" will not be accepted.
;;	 jc	 TRYQ_PATH		 ;Codepage is not specified. No code page.
;;					 ;At this point, AL already contain the
;;					 ;first char of the PATH.
;	 jz	 TryQBad		 ;codepage=0 entered. Error
;	 mov	 DX, AX 		 ;save code page in DX
;	 invoke  skip_delim		 ;move CHRPTR to the path string
;	 jc	 TryQ_Def_File		 ;no more char? then use default filename
;	 cmp	 al, CR
;	 je	 TryQ_Def_File
;	 cmp	 al, LF
;	 jne	 TryQ_PATH		 ;path entered.
;	 inc	 [COUNT]
;	 dec	 [CHRPTR]
;TryQ_Def_File:
;	 push	 dx			 ;save code page
;	 mov	 cs:CNTRY_DRV, 0	 ;flag that the default path has been used!!!
;	 mov	 dx, offset CNTRY_ROOT	 ;the default path
;	 jmp	 TRYQ_OPEN
;
;TryQBad:				 ;"Invalid country code or code page"
;	STC
;	MOV	DX,OFFSET BADCOUNTRY
;	 jmp	 TryQChkErr
;
;TryQBadCOM:				 ;Error in COUNTRY command
;	 STC
;	 MOV	 DX,OFFSET BADCOUNTRYCOM
;	 jmp	 TryQChkErr
;
;TRYQ_PATH:				 ;DS - sysinitseg, ES - CONFBOT,
;	 mov	 CX, [COUNT]		 ;AL - the first char of path
;	 inc	 CX			 ;BX - country id, DX - codepage id, 0 = No code page
;	 mov	 DI, SI
;TRYQ_PATH_LOOP:			 ;find the end of path to put 0 after that.
;	 mov	 AL, byte ptr [ES:DI]
;	 call	 delim
;	 jz	 TRYQ_PATH_END
;	 cmp	 al, 13
;	 jz	 TRYQ_PATH_END
;	 inc	 DI
;	 jmp	 short TRYQ_PATH_LOOP
;TryQBad_Brg:jmp short TryQBad
;TRYQ_PATH_END:
;	 mov	 byte ptr [es:di], 0	 ;make it a ASCIIZ string. (Organize did not handle this string)
;	 push	 ds			 ;switch ds,es
;	 push	 es
;	 pop	 ds
;	 pop	 es
;
;	 mov	 di, offset  CNTRY_DRV	 ;move the user specified path to CNTRY_DRV
;	 call	 Move_ASCIIZ
;
;	 push	 ds			 ;restore ds,es
;	 push	 es
;	 pop	 ds
;	 pop	 es
;
;;	  call	  Set_Country_Path	  ;set CNTRY_DRV
;
;	 push	 dx			 ;save DX
;	 mov	 dx, offset CNTRY_DRV	 ;Now DS:DX -> CNTRY_DRV

 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	mov	byte [Cntry_Drv], 0		;AN000; Reset the drive,path to default value.
	mov	word [P_Code_Page],0		;AN000;
	mov	di, offset Cntry_Parms	;AN000;
	xor	cx,cx			;AN000;
	mov	dx,cx			;AN000;
;	$SEARCH 			;AN000;
DD_DO49:
	    call   Sysinit_Parse	;AN000;
;	$EXITIF    C			;AN000; Parse error, check the error code and
	JNC DD_IF49
	    call   Cntry_Error		;AN000;  Show message and end the serach loop.
	    mov    word [P_Cntry_Code], -1	;AN000; Signals that parse error.
;	$ORELSE 			;AN000;
	JMP SHORT DD_SR49
DD_IF49:
	    cmp    ax, D_P_RC_EOL	;AN000; End of Line?
;	$LEAVE	   E			;AN000;  then end the $SEARCH LOOP
	JE DD_EN49
D_P_NUMBER equ D_P_Number	; NASM port equate
D_P_TYPE equ D_P_Type	; NASM port equate
	    cmp    byte [Result_Val + D_P_TYPE], D_P_NUMBER		;AN000; Numeric?
;	    $IF    E						;AN000;
	    JNE DD_IF53
		   mov	  ax, word ptr [Result_Val + D_P_PICKED_VAL] ;AN000;
		   cmp	    cx, 1				;AN000;
;		   $IF	 E					;AN000;
		   JNE DD_IF54
			 mov   [P_Cntry_Code], ax 		;AN000;
;		   $ELSE					;AN000;
		   JMP SHORT DD_EN54
DD_IF54:
			 mov   [P_Code_Page], ax			;AN000;
;		   $ENDIF					;AN000;
DD_EN54:
;	    $ELSE				;AN000; Path entered.
	    JMP SHORT DD_EN53
DD_IF53:
		   push ds			;AN000;
		   push es			;AN000;
		   push si			;AN000;
		   push di			;AN000;
		   push cs			;AN000;
		   pop	es			;AN000;
 assume es:SYSINITGROUP
		   lds	si, [RV_Dword]		;AN000; Move the path to known place.
 assume ds:nothing
CNTRY_Drv equ Cntry_Drv	; NASM port label
		   mov	di, offset CNTRY_Drv	;AN000; access with es
		   call Move_ASCIIZ		;AN000;
		   pop	di			;AN000;
		   pop	si			;AN000;
		   pop	es			;AN000;
		   pop	ds			;AN000;
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
;	    $ENDIF				;AN000;
DD_EN53:
;	$ENDLOOP
	JMP SHORT DD_DO49
DD_EN49:
;	$ENDSRCH				;AN000;
DD_SR49:
	cmp	word [P_Cntry_Code], -1		;AN000; Had a parse error?
	jne	TRYQ_OPEN			;AN000;
	jmp	Coff				;AN000;

TryQBad:				;"Invalid country code or code page"
       STC
       MOV     DX,OFFSET BADCOUNTRY
       jmp     TryQChkErr

TRYQ_OPEN:
	cmp	byte [CNTRY_Drv], 0		;AC000;
	je	TRYQ_Def		;AC000;
	mov	dx, offset CNTRY_Drv	;AC000;
	jmp	TryQ_Openit		;AC000;
	nop	; identicalise
TRYQ_Def:				;AC000;
CNTRY_Root equ Cntry_Root	; NASM port label
	mov	dx, offset CNTRY_Root	;AC000;
TryQ_Openit:
	mov	ax, 3d00h		;open a file
	stc
	int	21h
	jc	TryQFileBad		;open failure

CntryFileHandle equ CNTRYFILEHANDLE	; NASM port label
	mov	[cs:CntryFileHandle], ax	;save file handle
	mov	bx, ax
	mov	ax, [cs:P_Cntry_Code]	   ;AN000;
	mov	dx, [cs:P_Code_Page]	   ;AN000; Now, AX=country id, bx=filehandle
;	 xchg	 ax, bx 		 ;now, AX = country id, BX = file handle

	push ax
	push bx
	push dx
	push ds
	push es
	mov si, alloc_init
	mov ax, 2048			;I need 2K buffer to handle COUNTRY.SYS
	xor dx, dx
	call allocate_temporary_block.large_allow_error
	mov cx, es
	pop es
	pop ds
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	pop dx
	pop bx
	pop ax
	jc TryQMemory			;cannot allocate the buffer for country.sys
	mov word [cs:country_block], cx

CNTRY_DRV equ Cntry_Drv	; NASM port label
	mov	si, offset CNTRY_DRV	;DS:SI -> CNTRY_DRV
	cmp	byte ptr [si],0 	;default path?
	jne	TRYQ_Set_for_DOS
	inc	si
	inc	si			;DS:SI -> CNTRY_ROOT
TRYQ_Set_for_DOS:
SYSI_Country equ SYSI_COUNTRY	; NASM port label
	les	di, [cs:SYSI_Country]	;ES:DI -> country info tab in DOS
 assume es:DOSGROUP
	push	di			;save di
	add	di, ccPath_CountrySys
MOVE_ASCIIZ equ Move_ASCIIZ	; NASM port label
	call	MOVE_ASCIIZ		;Set the path to COUNTRY.SYS in DOS.
	pop	di			;ES:DI -> country info tab again.
	mov cx, word [cs:country_block]
	mov	ds, cx
 assume ds:nothing
	xor	si, si			;DS:SI -> 2K buffer to be used.
	call	SetDOSCountryInfo	;now do the job!!!
TryQchkERR equ TryQChkErr	; NASM port label
	jnc	TryQchkERR		;read error or could not find country,code page combination
	cmp	cx, -1			;Could not find matching country_id,code page?
	je	TryQBad 		;then "Invalid country code or code page"
TryQFileBad:
	push	cs			;AN000;
	pop	es			;AN000;
 assume es:SYSINITGROUP
	cmp	byte [cs:CNTRY_DRV],0		;Is the default file used?
	je	TryQDefBad
;	 mov	 si, [cs:CONFBOT]
;	 mov	 es, si
;	 mov	 si, [cs:CHRPTR]
;	 dec	 si			 ;ES:SI -> path in CONFBOT
	mov	si, offset CNTRY_Drv
	jmp	short TryQBADLOAD
TryQDefBad:				;Default file has been used.
;	 push	 cs
;	 pop	 es
CNTRY_ROOT equ Cntry_Root	; NASM port label
	mov	si, offset CNTRY_ROOT	;ES:SI -> \COUNTRY.SYS in SYSINIT_SEG
TryQBADLOAD:
	call	BADLOAD 		;DS will be restored to SYSINIT_SEG
	mov	cx, [cs:config_block]
	mov	es, cx			;Restore ES -> CONFBOT.
 assume es:nothing
	jmp	short CoffJ4
TryQMemory:
	stc
	MOV	DX,OFFSET INSUFMEMORY
TryQChkErr:
	mov	cx, [cs:config_block]
	mov	es, cx			;restore ES -> CONFBOT seg
 assume es:nothing
	push	cs
	pop	ds			;retore DS to SYSINIT_SEG
 assume ds:SYSINITGROUP
	jnc	CoffJ4			;if no error, then exit
	invoke	PRINT			;else show error message
	call	Error_Line		;AN000;
CoffJ4:
	xor ax, ax
	xchg ax, word [country_block]
	test ax, ax
	jz @F
	push es
	mov es, ax
 assume es:nothing
	mov ah, 49h
	int 21h
	pop es
 assume es:nothing
@@:
	mov	bx, [CntryFileHandle]
	mov	ah, 3eh
	int	21h			;close a file. Don't care even if it fails.
	JMP	COFF

Cntry_Error	proc	near
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
;Function: Show "Invalid country code or code page" messages, or
;		"Error in COUNTRY command" depending on the error code
;		in AX returned by SYSPARSE;
;In:	AX - error code
;	DS - Sysinitseg
;	ES - CONFBOT
;Out:	Show message.  DX destroyed.

D_P_OUT_OF_RANGE equ D_P_Out_Of_Range	; NASM port equate
	cmp	ax, D_P_OUT_OF_RANGE
;	$IF	E
	JNE DD_IF61
BadCountry equ BADCOUNTRY	; NASM port label
	     mov	dx, offset BadCountry ;"Invalid country code or code page"
;	$ELSE
	JMP SHORT DD_EN61
DD_IF61:
BadCountryCom equ BADCOUNTRYCOM	; NASM port label
	     mov	dx, offset BadCountryCom ;"Error in CONTRY command"
;	$ENDIF
DD_EN61:
	invoke	Print
	call	Error_Line
	ret
Cntry_Error	endp

;------------------------------------------------------------------------------
; Files command
;------------------------------------------------------------------------------
;*******************************************************************************
; Function: Parse the parameters of FILES= command.			       *
;									       *
; Input :								       *
;	ES:SI -> parameters in command line.				       *
; Output:								       *
;	Variable FILES set.						       *
;									       *
; Subroutines to be called:						       *
;	Sysinit_Parse							       *
; Logic:								       *
; {									       *
;	Set DI points to FILES_Parms;					       *
;	Set DX,CX to 0; 						       *
;	While (End of command line)					       *
;	{ Sysinit_parse;						       *
;	  if (no error) then						       *
;	     Files = Result_Val.D_P_Picked_Val				       *
;	  else								       *
;	     Error Exit;						       *
;	};								       *
; };									       *
;									       *
;*******************************************************************************
TRYF:
	CMP	AH,'F'
	JNZ	TRYL

;	 invoke  GETNUM
;	 CMP	 AX,5			 ;j.k. change it to 8!!!!!!!!
;	 JB	 TryFBad		 ; Gotta have at least 5
;	 CMP	 AX,256
;	 JAE	 TryFBad		 ; Has to be a byte
;	 MOV	 [FILES],AL
;CoffJ5: JMP	 COFF
;TryFBad:JMP	 BadOp

	mov	di, offset Files_Parms	;AN000;
	xor	cx, cx			;AN000;
	mov	dx, cx			;AN000;

;	$SEARCH 			;AN000;
DD_DO64:
	    call   Sysinit_Parse	;AN000;
;	$EXITIF    C			;AN000; Parse Error,
	JNC DD_IF64
	    call   Badparm_p		;AN007;   and Show messages and end the search loop.
;	$ORELSE 			;AN000;
	JMP SHORT DD_SR64
DD_IF64:
	    cmp    ax, D_P_RC_EOL	;AN000; End of Line?
;	$LEAVE	   E			;AN000;  then end the $ENDLOOP
	JE DD_EN64
	    mov    al, byte ptr [Result_Val + D_P_PICKED_VAL] ;AN000;
	    mov    [P_Files], al		;AN000; Save it temporarily
;	$ENDLOOP			;AN000;
	JMP SHORT DD_DO64
DD_EN64:
	    mov    al, [P_Files]		;AN000;
Files equ FILES	; NASM port label
	    mov    [Files], al		;AN000; No error. Really set the value now.
;	$ENDSRCH			;AN000;
DD_SR64:
	jmp	Coff

;------------------------------------------------------------------------------
; LastDrive command
;------------------------------------------------------------------------------
;*******************************************************************************
; Function: Parse the parameters of LASTDRIVE= command. 		       *
;									       *
; Input :								       *
;	ES:SI -> parameters in command line.				       *
; Output:								       *
;	Set the variable NUM_CDS.					       *
;									       *
; Subroutines to be called:						       *
;	Sysinit_Parse							       *
; Logic:								       *
; {									       *
;	Set DI points to LDRV_Parms;					       *
;	Set DX,CX to 0; 						       *
;	While (End of command line)					       *
;	{ Sysinit_Parse;						       *
;	  if (no error) then						       *
;	     Set NUM_CDS to the returned value; 			       *
;	  else	/*Error exit*/						       *
;	     Error Exit;						       *
;	};								       *
; };									       *
;									       *
;*******************************************************************************
TRYL:
	CMP	AH,'L'
	JNZ	TRYP
	push ds
	push es
	push si
	 push es
	 pop ds
 assume ds:nothing
	 push cs
	 pop es
 assume es:SYSINITGROUP
	lodsw
	cmp ah, ':'
	je .trydrive
	cmp ah, 32
	je .trydrive
	cmp ah, 9
	je .trydrive
	cmp ah, 13
	je .trydrive
	cmp ah, 10
	je .trydrive
	cmp ah, 0
	jne .number
.trydrive:
	call capitalise
	cmp al, 'A'
	jb .number
	cmp al, '`'		; CDS limit
	ja .number
	sub al, 'A' - 1
	mov bl, 2
	cmp ah, ':'
	je @F
	dec si
@@:
	xchg dx, ax
	jmp .got

.number:
	dec si
	xor bx, bx
	; cmp al, '+'
	; je @F
	inc bx
	; cmp al, '-'
	; je @F
	inc bx
	dec si
@@:
	call ldos_getnum
		; OUT:	NC if success,
		;	 dx = number
		;	 bl = 0 if +, 1 if -, 2 else
	jc .error
	cmp dx, 32		; CDS limit
	ja .error
.got:
@@:
	lodsb
	cmp al, 32
	je @B
	cmp al, 9
	je @B
	cmp al, 13
	je .done
	cmp al, 10
	je .done
	cmp al, 0
	je .done
.error:
	pop si
	pop es
	pop ds
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	jmp BADOP

.done:
 assume es:nothing
	LES	DI,[ss:DOSINFO]
 assume es:DOSGROUP
	mov al, [es:di + SYSI_NCDS]
	mov ah, al

	cmp bl, 1
	jb .plus
	je .minus
.set:
	mov ah, dl
	jmp .common

.plus:
	add ah, dl
	jc .max
	cmp ah, 32		; CDS limit
	jna .common
.max:
	mov ah, 32		; CDS limit
	jmp .common

.minus:
	sub ah, dl
	jnc .common
.min:
	mov ah, 0
.common:
	mov byte [cs:NUM_CDS], ah

	pop si
	pop es
	pop ds
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	jmp COFF

;-------------------------------------------------------------------------------
; Setting Drive Parameters
;-------------------------------------------------------------------------------
TRYP:
	CMP	AH,'P'
	JNZ	TRYK
	invoke	PARSELINE
	JC	TryPBad
	invoke	SETPARMS
	INVOKE	sysinit_DIDDLEBACK
	jc	TryPBad
	JMP	COFF
Badop equ BADOP	; NASM port label
TryPBad:jmp	Badop
;-------------------------------------------------------------------------------
; Setting Internal Stack Parameters
; STACKS=M,N where
;	M is the number of stacks (range 8 to 64, default 9)
;	N is the stack size (range 32 to 512 bytes, default 128)
; J.K. 5/5/86: STACKS=0,0 implies no stack installation.
;	Any combinations that are not within the specified limits will
;	result in "Unrecognized command" error.
;-------------------------------------------------------------------------------
;*******************************************************************************
;									       *
; Function: Parse the parameters of STACKS= command.			       *
;	    The minimum value for "number of stacks" and "stack size" is       *
;	    8 and 32 each.  In the definition of SYSPARSE value list, they     *
;	    are set to 0.  This is for accepting the exceptional case of       *
;	    STACKS=0,0 case (,which means do not install the stack.)	       *
;	    So, after SYSPARSE is done, we have to check if the entered        *
;	    values (STACK_COUNT, STACK_SIZE) are within the actual range,      *
;	    (or if "0,0" pair has been entered.)			       *
; Input :								       *
;	ES:SI -> parameters in command line.				       *
; Output:								       *
;	Set the variables STACK_COUNT, STACK_SIZE.			       *
;									       *
; Subroutines to be called:						       *
;	Sysinit_Parse							       *
; Logic:								       *
; {									       *
;	Set DI points to STKS_Parms;					       *
;	Set DX,CX to 0; 						       *
;	While (End of command line)					       *
;	{ Sysinit_Parse;						       *
;	  if (no error) then						       *
;	     { if (CX == 1) then /* first positional = stack count */	       *
;		   P_Stack_Count = Result_Val.D_P_Picked_Val;		       *
;	       if (CX == 2) then /* second positional = stack size */	       *
;		   P_Stack_Size = Result_Val.D_P_Picked_Val;		       *
;	     }								       *
;	  else	/*Error exit*/						       *
;	     Error Exit;						       *
;	};								       *
;	Here check P_STACK_COUNT,P_STACK_SIZE if it meets the condition;       *
;	If O.K., then set Stack_Count, Stack_Size;			       *
;	 else Error_Exit;						       *
; };									       *
;*******************************************************************************
TRYK:
	CMP	AH,'K'
	JE	Do_TryK
	jmp	TRYS

		%IF	STACKSW

;	 MOV	 SepChr,','
;	 INVOKE  GetNum 		 ; Get number of stacks
;	 MOV	 SepChr,0
;	 cmp	 ax, 0			 ;J.K. 5/5/86
;	 je	 TRYK_0 		 ;J.K. Let's accept 0.
;	 CMP	 AX, MinCount		 ; 8 <= Number of Stacks <= 64
;	 JB	 TryKBad
;	 CMP	 AX, MaxCount
;	 JA	 TryKBad
;TRYK_0:
;	 MOV	 [STACK_COUNT], AX
;
; Skip delimiters after the first number.
;
;	 invoke  Skip_delim		 ;J.K.
;	 JC	 TryKBad
;
;	 INVOKE  GetNum 		 ; Get size of individual stack
;	 JC	 TryKBad		 ; Number bad
;
;	 cmp	 ax, 0			 ;J.K. 5/5/86
;	 je	 TRYK_SIZE0		 ;J.K. 5/5/86. Accept 0
;
;	 CMP	 AX, MinSize		 ; 32 <= Stack Size <= 512
;	 JB	 TryKBad
;	 CMP	 AX, MaxSize
;	 JA	 TryKBad
;TRYK_SIZE0:
;	 MOV	 [STACK_SIZE], AX
;	 cmp	 ax,0
;	 je	 TRYK_BOTH0
;TRYK_OK:
;	 mov	 word ptr [stack_addr], -1 ;set the flag that the user entered stacks= command.
;	JMP	COFF
;TRYK_BOTH0:
;	 cmp	 [STACK_COUNT],0	 ;stack_size = 0. Stack_Count = 0 too?
;	 je	 TRYK_OK		 ;yes. accepted.
;TryKBad:
;	 MOV	 DX, OFFSET BADSTACK	 ;J.K. 5/26/86 "Invalid stack parameter"
;	 invoke  PRINT
;	 JMP	 COFF

Do_TryK:
	mov	di, offset STKS_Parms	;AN000;
	xor	cx, cx			;AN000;
	mov	dx, cx			;AN000;

;	$SEARCH 			;AN000;
DD_DO76:
	    call   Sysinit_Parse	;AN000;
;	$EXITIF    C			;AN000; Parse Error,
	JNC DD_IF76
BadStack equ BADSTACK	; NASM port label
	    mov    dx, offset BadStack	;AN000; "Invalid stack parameter"
	    call   Print		;AN000;   and Show messages and end the search loop.
	    call   Error_Line		;AN006;
;	$ORELSE 			;AN000;
	JMP SHORT DD_SR76
DD_IF76:
	    cmp    ax, D_P_RC_EOL	;AN000; End of Line?
;	$LEAVE	   E			;AN000;  then end the $ENDLOOP
	JE DD_EN76
	    mov    ax, word ptr [Result_Val + D_P_PICKED_VAL]   ;AN000;
	    cmp    cx, 1				   ;AN000;
;	    $IF    E					   ;AN000;
	    JNE DD_IF80
		 mov   [P_Stack_Count], ax		   ;AN000;
;	    $ELSE					   ;AN000;
	    JMP SHORT DD_EN80
DD_IF80:
		 mov   [P_Stack_Size], ax 		   ;AN000;
;	    $ENDIF					   ;AN000;
DD_EN80:
;	$ENDLOOP					   ;AN000;
	JMP SHORT DD_DO76
DD_EN76:
	    cmp    word [P_Stack_Count], 0			   ;AN000;
;	    $IF    NE					   ;AN000;
	    JE DD_IF84
MINCOUNT equ MinCount	; NASM port equate
		 cmp	word [P_Stack_Count], MINCOUNT 	   ;AN000;
;		 $IF	B,OR				   ;AN000;
		 JB DD_LL85
MINSIZE equ MinSize	; NASM port equate
		 cmp	word [P_Stack_Size], MINSIZE		   ;AN000;
;		 $IF	B				   ;AN000;
		 JNB DD_IF85
DD_LL85:
			mov  word [P_Stack_Count], -1		   ;AN000; Invalid
;		 $ENDIF 				   ;AN000;
DD_IF85:
;	    $ELSE					   ;AN000;
	    JMP SHORT DD_EN84
DD_IF84:
		 cmp	word [P_Stack_Size], 0 		   ;AN000;
;		 $IF	NE				   ;AN000;
		 JE DD_IF88
			mov  word [P_Stack_Count], -1		   ;AN000; Invalid
;		 $ENDIF 				   ;AN000;
DD_IF88:
;	    $ENDIF					   ;AN000;
DD_EN84:
	    cmp  word [P_Stack_Count], -1			   ;AN000; Invalid?
;	    $IF  E					   ;AN000;
	    JNE DD_IF91
Stack_Count equ stack_count	; NASM port label
DEFAULTCOUNT equ DefaultCount	; NASM port equate
		 mov	word [Stack_Count], DEFAULTCOUNT	   ;AN000;Reset to default value.
Stack_Size equ stack_size	; NASM port label
DEFAULTSIZE equ DefaultSize	; NASM port equate
		 mov	word [Stack_Size], DEFAULTSIZE 	   ;AN000;
STACK_ADDR equ stack_addr	; NASM port label
		 mov	word [STACK_ADDR], 0		   ;AN000;
		 mov	dx, offset BadStack		   ;AN000;
		 call	Print				   ;AN000;
		 call	Error_Line			   ;AN006;
;	    $ELSE					   ;AN000;
	    JMP SHORT DD_EN91
DD_IF91:
		 mov	ax, [P_Stack_Count]		   ;AN000;
		 mov	[Stack_Count], ax 		   ;AN000;
		 mov	ax, [P_Stack_Size]		   ;AN000;
		 mov	[Stack_Size], ax			   ;AN000;
Stack_Addr equ stack_addr	; NASM port label
		 mov	word [Stack_Addr], -1 	   ;AN000;STACKS= been accepted.
;	    $ENDIF					   ;AN000;
DD_EN91:
;	$ENDSRCH					   ;AN000;
DD_SR76:
	jmp	Coff
		%ENDIF
;------------------------------------------------------------------------------
; Switch command		;No longer supported.
;------------------------------------------------------------------------------
;TRYW:
;	 CMP	 AH,'W'
;	 JNZ	 TRYA
;	 JMP	 BadOp			 ; no longer implemented
;	MOV	DL,AL
;	MOV	AX,(CHAR_OPER SHL 8) OR 1      ;SET SWITCH CHARACTER
;	MOV	[COMMAND_LINE+1],DL
;	INT	21H
;	JMP	COFF
;------------------------------------------------------------------------------
; Availdev command		;No longer supported.
;------------------------------------------------------------------------------
;TRYA:
;	 CMP	 AH,'A'
;	 JNZ	 TRYS
;	 JMP	 BadOp			 ; NO LONGER IMPLEMENTED
;	CMP	AL,'F'			;FIRST LETTER OF "FALSE"
;	JNZ	COFFJ7
;	MOV	AX,(CHAR_OPER SHL 8) OR 3 ;TURN ON "/DEV" PREFIX
;	XOR	DL,DL
;	INT	21H
;COFFJ7: JMP	 COFF

;------------------------------------------------------------------------------
; shell command
;------------------------------------------------------------------------------
TRYS:
	cmp ah, 's'
	jne @F
	mov byte [cs:shellhighflag], -1
	jmp .shell
@@:
	CMP	AH,'S'
	JNZ	TRYX
	mov byte [cs:shellhighflag], 0
.shell:
	MOV	byte [COMMAND_LINE+1],0
	MOV	DI,OFFSET COMMND
	jmp @F
STORESHELL:
	CALL	GETCHR
@@:
	test al, al
	JZ	GETSHPARMS
	CMP	AL," "
	JB	ENDSH
	MOV	[DI],AL
	INC	DI
	JMP	STORESHELL

ENDSH:
	MOV	BYTE PTR [DI],0
	CALL	GETCHR
	CMP	AL,LF
	JNZ	CONV
	CALL	GETCHR
CONV:	JMP	CONFLP

GETSHPARMS:
	MOV	BYTE PTR [DI],0
	MOV	DI,OFFSET COMMAND_LINE+1
PARMLOOP:
	CALL	GETCHR
	CMP	AL," "
	JB	ENDSH
	MOV	[DI],AL
	INC	DI
	JMP	PARMLOOP

;------------------------------------------------------------------------------
; FCBS Command
;------------------------------------------------------------------------------
;*******************************************************************************
; Function: Parse the parameters of FCBS= command.			       *
;									       *
; Input :								       *
;	ES:SI -> parameters in command line.				       *
; Output:								       *
;	Set the variables FCBS, KEEP.					       *
;									       *
; Subroutines to be called:						       *
;	Sysinit_Parse							       *
; Logic:								       *
; {									       *
;	Set DI points to FCBS_Parms;					       *
;	Set DX,CX to 0; 						       *
;	While (End of command line)					       *
;	{ SYSPARSE;							       *
;	  if (no error) then						       *
;	     { if (CX == 1) then /* first positional = FCBS */		       *
;		   FCBS = Result_Val.D_P_Picked_Val;			       *
;	       if (CX == 2) then /* second positional = KEEP */ 	       *
;		   KEEP = Result_Val.D_P_Picked_Val;			       *
;	     }								       *
;	  else	/*Error exit*/						       *
;	     Error Exit;						       *
;	};								       *
; };									       *
;*******************************************************************************
TRYX:
	CMP	AH,'X'
	JNZ	TRYY
;	 invoke  GETNUM
;	 JZ	 TryXBad		 ; gotta have at least one
;	 CMP	 AX,256
;	 JAE	 TryXBad		 ; Can't be more than 8 bits worth
;	 MOV	 [FCBS],AL
;
; Skip delimiters after the first number including ","
;
;	 invoke  Skip_delim		 ;J.K.
;	 jc	 tryxbad
;	 invoke  GetNum
;	 JC	 TryXBad		 ; Number bad (Zero is OK here)
;	 CMP	 AX,256
;	 JAE	 TryXBad
;	 CMP	 AL,FCBS
;	 JA	 TryXBad
;	 MOV	 Keep,AL
;	 JMP	 COFF
;TryXBad:JMP	 BadOp

	mov	di, offset FCBS_Parms	;AN000;
	xor	cx, cx			;AN000;
	mov	dx, cx			;AN000;

;	$SEARCH 			;AN000;
DD_DO95:
	    call   Sysinit_Parse	;AN000;
;	$EXITIF    C			;AN000; Parse Error,
	JNC DD_IF95
	    call   Badparm_p		;AN007;   and Show messages and end the search loop.
;	$ORELSE 			;AN000;
	JMP SHORT DD_SR95
DD_IF95:
	    cmp    ax, D_P_RC_EOL	;AN000; End of Line?
;	$LEAVE	   E			;AN000;  then end the $ENDLOOP
	JE DD_EN95
	    mov    al, byte ptr [Result_Val + D_P_PICKED_VAL]  ;AN000;
	    cmp    cx, 1		;AN000; The first positional?
;	    $IF    E			;AN000;
	    JNE DD_IF99
		mov   [P_Fcbs], al	;AN000;
;	    $ELSE			;AN000;
	    JMP SHORT DD_EN99
DD_IF99:
		mov   [P_Keep], al	;AN000;
;	    $ENDIF			;AN000;
DD_EN99:
;	$ENDLOOP			;AN000;
	JMP SHORT DD_DO95
DD_EN95:
	    mov    al, [P_Fcbs]		;AN005;make sure P_Fcbs >= P_Keep
	    cmp    al, [P_Keep]		;AN005;
;	    $IF    B			;AN005;
	    JNB DD_IF103
;		 call  Badop_p		 ;AN005;
		call  Badparm_p 	;AN011;show "Bad parameter -" msg.
		mov   byte [P_Keep], 0 	;AN005;
;	    $ELSE			;AN005;
	    JMP SHORT DD_EN103
DD_IF103:
Fcbs equ FCBS	; NASM port label
		mov    [Fcbs], al 	    ;AN000; No error. Really set the value now.
		mov    al, [P_Keep]	    ;AN000;
Keep equ KEEP	; NASM port label
		mov    [Keep], al 	    ;AN000;
;	    $ENDIF			;AN005;
DD_EN103:
;	$ENDSRCH			;AN000;
DD_SR95:
	jmp	Coff

;------------------------------------------------------------------------------
; Comment= Do nothing. Just decrese CHRPTR, and increase COUNT for correct
;		line number
;------------------------------------------------------------------------------
TRYY:					;AN000;
	cmp	ah, 'Y' 		;AN000;
	jne	Try0			;AN000;
DoNothing:
	dec	word [CHRPTR]			;AN000;
	inc	word [COUNT]			;AN000;
	jmp	COFF			;AN000;

;------------------------------------------------------------------------------
; REM command
;------------------------------------------------------------------------------
Try0:					;AN003;do nothing with this line.
	cmp	ah, '0' 		;AN003;
	je	DoNothing		;AN003;

;------------------------------------------------------------------------------
; SWITCHES command
;------------------------------------------------------------------------------
;*******************************************************************************
;									       *
; Function: Parse the option switches specified.			       *
; Note - This command is intended for the future use also.  When we need to    *
; to set system data flag, use this command.				       *
;									       *
; Input :								       *
;	ES:SI -> parameters in command line.				       *
; Output:								       *
;	P_Swit_K set if /K option chosen.				       *
;									       *
; Subroutines to be called:						       *
;	Sysinit_Parse							       *
; Logic:								       *
; {									       *
;	Set DI points to Swit_Parms;  /*Parse control definition*/	       *
;	Set DX,CX to 0; 						       *
;	While (End of command line)					       *
;	{ Sysinit_parse;						       *
;	  if (no error) then						       *
;	       if (Result_Val.D_P_SYNONYM_ptr == Swit_K) then		       *
;		    P_Swit_K = 1					       *
;	       endif							       *
;	  else {Show Error message;Error Exit}				       *
;	};								       *
; };									       *
;									       *
;*******************************************************************************

	cmp	ah, '1' 		;AN019;Switches= command entered?
Tryz equ TRYZ	; NASM port label
	jne	Tryz			;AN019;

	mov	di, offset Swit_Parms	;AN019;
	xor	cx, cx			;AN019;
	mov	dx, cx			;AN019;

;	$SEARCH 			;AN019;
DD_DO107:
	    call   Sysinit_Parse	;AN019;
;	$EXITIF    C			;AN019; Parse Error,
	JNC DD_IF107
	    call   Badparm_p		;AN019;   and Show messages and end the search loop.
;	$ORELSE 			;AN019;
	JMP SHORT DD_SR107
DD_IF107:
	    cmp    ax, D_P_RC_EOL	;AN019; End of Line?
;	$LEAVE	   E			;AN019;  then jmp to $Endloop for semantic check.
	JE DD_EN107
	    cmp    word [Result_Val + D_P_SYNONYM_PTR], offset Swit_K   ;AN019;
;	    $IF    E					      ;AN019;
	    JNE DD_IF111
		mov	byte [P_Swit_K], 1			      ;AN019; set the flag
;	    $ENDIF					      ;AN019;
DD_IF111:
;	$ENDLOOP			;AN019;
	JMP SHORT DD_DO107
DD_EN107:
	    cmp    byte [P_Swit_K], 1		;AN019;If /K entered,
	    push   ds			;AN019;
	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
;	    $IF    E			;AN019;
	    JNE DD_IF114
	       mov    byte [KEYRD_Func], 0	;AN019;Use the conventional keyboard functions
	       mov    byte [KEYSTS_Func], 1	;AN019;
;	    $ENDIF			;AN019;
DD_IF114:
	    pop    ds			;AN019;
 assume ds:SYSINITGROUP			;AN019;
;	$ENDSRCH			;AN019;
DD_SR107:
	jmp	Coff			;AN019;

;------------------------------------------------------------------------------
; Bogus command
;------------------------------------------------------------------------------
TRYZ:
	cmp ah, '2'
	je TryFF
	cmp ah, '7'
	je TryFF
	cmp ah, '8'
	je TryFF
	cmp ah, '9'
	je TryFF
	cmp	ah, 0FFh		;AN029;
	je	TryFF			;AN029;
	dec	word [CHRPTR]
	inc	word [COUNT]
	JMP	BADOP

;------------------------------------------------------------------------------
; Null command
;------------------------------------------------------------------------------
TryFF:					;AN029;Skip this command.
	jmp	DoNothing		;AN029;

GETCHR:
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	PUSH	CX
	MOV	CX,[COUNT]
	JCXZ	NOCHAR
	MOV	SI,[CHRPTR]
	MOV	AL,[ES:SI]
	DEC	word [COUNT]
	INC	word [CHRPTR]
	CLC
GET_RET:
	POP	CX
	return
NOCHAR: STC
	JMP	SHORT GET_RET

Incorrect_Order proc	near		;AN000;
;Show "Incorrect order in CONFIG.SYS ..." message.
BADORDER equ BadOrder	; NASM port label
	mov	dx, offset BADORDER	;AN000;
print equ Print	; NASM port label
	call	print			;AN000;
	call	ShowLineNum		;AN000;
	ret				;AN000;
Incorrect_Order endp			;AN000;
;
	public	Error_Line
Error_Line	proc	near		;AN000;
;Show "Error in CONFIG.SYS ..." message.
	push	cs			;AN000;
	pop	ds			;AN000;
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
ErrorCmd equ Errorcmd	; NASM port label
	mov	dx, offset ErrorCmd	;AN000; access with ds
	call	print			;AN000;
	call	ShowLineNum		;AN000;
	ret				;AN000;
Error_Line	endp			;AN000;
;
ShowLineNum	proc	near		;AN000;
;J.K. Convert the binary LineCount to Decimal ASCII string in ShowCount
;and Display Showcount at the current curser position.
;In.) LineCount
;
;Out) the number is printed.
	push	es			;AN000;
	push	ds			;AN000;
	push	di			;AN000;

	push	cs			;AN000;
	pop	es			;AN000; es=cs
 assume es:SYSINITGROUP
	push	cs			;AN000;
	pop	ds			;AN000;
 assume ds:SYSINITGROUP, es:SYSINITGROUP, ss:nothing

;	 mov	 ax, '  '
;	 mov	 di, offset ShowCount	 ;clean it up.
;	 stosw
;	 stosw
;	 stosb				 ;lenght of ShowCount is 5.
;	 dec	 di			 ;let DI points to the least significant ASCII field.

	mov	di, offset ShowCount+4	;AN000; DI -> the least significant decimal field.
	mov	cx, 10			;AN000; decimal devide factor
	mov	ax, [cs:LineCount]	;AN000;
SLN_Loop:				;AN000;
	cmp	ax, 10			;AN000; < 10?
	jb	SLN_Last		;AN000;
	xor	dx,dx			;AN000;
	div	cx			;AN000;
	or	dl, 30h 		;AN000; add "0" (= 30h) to make it an ascii.
	mov	[di],dl 		;AN000;
	dec	di			;AN000;
	jmp	SLN_Loop		;AN000;
SLN_Last:				;AN000;
	or	al, 30h 		;AN000;
	mov	[di],al 		;AN000;
	mov	dx, di			;AN000;
	call	print			;AN000; show it.
	pop	di			;AN000;
	pop	ds			;AN000;
	pop	es			;AN000;
 assume ds:nothing, es:nothing
	ret				;AN000;
ShowLineNum	endp			;AN000;


sysinit_CallIFS proc	near			;AN000;
;*******************************************************************************
; Function: Interface to IFS call. This procedure will call IFS_CALL@	       *
;									       *
; Input :								       *
;	    Entry_Point - Segment:Offset of loaded IFS. 		       *
;	    BX = IFS_CALL@ (offset of IFS_CALL@ from the IFS header)	       *
;	    ES = Segment of IFS request header				       *
;	    IFS_Packet - IFS Request packet				       *
;									       *
; Output:   Nothing							       *
;*******************************************************************************
	push	ax				;AN000;
	mov	ds, word ptr [cs:Entry_Point+2] ;AN000;
 assume ds:nothing
	add	bx, word ptr [cs:Entry_Point]	;AN000; [DS:BX] = Real IFS_CALL@ addr.
	mov	ax, [bx]			;AN000; save it
	push	word ptr [cs:Entry_Point]	;AN000; save Entry point offset
	mov	word ptr [cs:Entry_Point], ax	;AN000; set for the call
	mov	bx, offset IFS_RH		;AN000; Now, ES:BX -> Request packet
	call	far [cs:Entry_Point]		;AN000; Far call
	pop	word ptr [cs:Entry_Point]	;AN000; Restore Entry point offset
	pop	ax				;AN000;
	ret					;AN000;
sysinit_CallIFS endp


%if 0
Set_DevMark	proc	near			;AN004;
;*******************************************************************************
; Function: Set a paragraph of informations infront of a Device file or        *
;	    an IFS file to be loaded for MEM command.			       *
;	    The structure is:						       *
;	      DEVMARK_ID	byte "D" for device, "I" for IFS	       *
;	      DEVMARK_SIZE	size in para for the device loaded	       *
;	      DEVMARK_FILENAME	11 bytes. Filename			       *
;									       *
; Input :								       *
;	    [MEMHI] = address to set up DEVMARK.			       *
;	    [MEMLO] = 0 						       *
;	    ES:SI -> pointer to [drive][path]filename,0 		       *
;	    [IFS_Flag] = IS_IFS bit set if IFS= command.		       *
;									       *
; Output:   DEVMARK_ID, DEVMARK_FILENAME set				       *
;	    [cs:DevMark_addr] set.					       *
;	    AX, CX register destroyed.					       *
;*******************************************************************************
	push	ds			;AN004;
	push	si			;AN004;
	push	es			;AN004;
	push	di			;AN004;

	mov	di, [cs:MEMHI]		;AN004;
	mov	ds, di			;AN004;
	assume	ds:nothing		;AN004;
	mov	[cs:DevMark_Addr], di	;AN004; save the DEVMARK address for the future.
	test	word [cs:IFS_Flag], IS_IFS	;AN004;
	jnz	SDVMK_IFS		;AN004;
	mov	al, DEVMARK_DEVICE	;AN004; ='D'
	jmp	short SDVMK_ID		;AN004;
SDVMK_IFS:
	mov	al, DEVMARK_IFS 	;AN004; ='I'
SDVMK_ID:				;AN004;
	mov	[DEVMARK_ID], al	;AN004;
	inc	di			;AN008;
	mov	[DEVMARK_SEG], di	;AN008;
	call get_device_mcb_name
	pop	di			;AN004;
	pop	es			;AN004;
	pop	si			;AN004;
	pop	ds			;AN004;
	ret				;AN004;
Set_DevMark	endp			;AN004;
%endif

		; INP:	es:si -> pathname
		;	ds => sub-MCB
		; CHG:	si, di, ds, es, cx, ax
get_device_mcb_name:
	xor	al,al			;AN004;
	push	si			;AN004;
	pop	di			;AN004; now es:si = es:di = [path]filename,0
	mov	cx, 128 		;AN004; Maximum 128 char
	repnz	scasb			;AN004; find 0
	dec	di			;AN020; Now es:di-> 0
SDVMK_Backward: 			;AN004; find the pointer to the start of the filename.
	mov	al, byte ptr [es:di]	;AN004;;AN020;We do this by check es:di backward until
	cmp	al, '\' 		;AN004;;AN020; DI = SI or DI -> '\' or DI -> ':'.
	je	SDVMK_GotFile		;AN004;;AN020;
	cmp	al, ':' 		;AN004;
	je	SDVMK_GotFile		;AN004;
	cmp	di, si			;AN004;
	je	SDVMK_FilePtr		;AN004;
	dec	di			;AN004;
SDVMK_BackWard equ SDVMK_Backward	; NASM port label
	jmp	SDVMK_BackWard		;AN004;
SDVMK_GotFile:				;AN004;
	inc	di			;AN004;
SDVMK_FilePtr:				;AN004; now es:di -> start of file name
	push	di			;AN004;
	pop	si			;AN004; save di to si.
	push	ds			;AN004; switch es, ds
	push	es			;AN004;
	pop	ds			;AN004;
	pop	es			;AN004; now, ds:si -> start of filename
 assume es:nothing, ds:nothing
	mov	di, DEVMARK_FILENAME	;AN004;
	push	di			;AN004;
	mov	al, ' ' 		;AN004;
	mov	cx, 8			;AN004;
	rep	stosb			;AN004; Clean up Memory.
	pop	di			;AN004;
	mov	cx, 8			;AN004; Max 8 char. only
SDVMK_Loop:				;AN004;
	lodsb				;AN004;
	cmp	al, '.' 		;AN004;
	je	SDVMK_Done		;AN004;
	cmp	al, 0			;AN004;
	je	SDVMK_Done		;AN004;
	stosb				;AN004;
	loop	SDVMK_Loop		;AN004;
SDVMK_Done:				;AN004;
	retn

Chk_XMAEM	proc	near		;AN029;
;Function: Check XMAEM.SYS file name.
;In: ES:SI -> path, filename, 0
;out: if XMAEM.SYS, then zero flag set.

	push	es			;AN029;
	push	si			;AN029;
	push	ds			;AN029;
	push	di			;AN029;
	push	cx			;AN029;
	mov	di, si			;AN029;save current starting pointer
CX_Cmp: 				;AN029;
	cmp	byte ptr [es:si], 0	;AN029;
	je	CX_Endfile		;AN029;
	inc	si			;AN029;
	jmp	CX_Cmp			;AN029;
CX_Endfile:				;AN029;
	dec	si			;AN029;
	cmp	byte ptr [es:si], '\'	;AN029;
	je	CX_Got_Tail		;AN029;
	cmp	byte ptr [es:si], ':'	;AN029;
	je	CX_Got_Tail		;AN029;
	cmp	di, si			;AN029;
	je	CX_Got_Tail0		;AN029;
	jmp	CX_Endfile		;AN029;
CX_Got_Tail:				;AN029;
	inc	si			;AN029;
CX_Got_Tail0:				;AN029;
	push	cs			;AN029;
	pop	ds			;AN029;
 assume ds:SYSINITGROUP
	push	si			;AN029;
	pop	di			;AN029;now es:di -> filename,0
	mov	cx, 9			;AN029;
XMAEM_File equ XMAEM_file	; NASM port label
	mov	si, offset XMAEM_File	;AN029;ds:si -> XMAEM.SYS,0
	repe	cmpsb			;AN029;
CX_Ret: 				;AN029;
	pop	cx			;AN029;
	pop	di			;AN029;
	pop	ds			;AN029;
 assume ds:nothing
	pop	si			;AN029;
	pop	es			;AN029;
 assume es:nothing
	ret				;AN029;
Chk_XMAEM	endp

;Chk_IBMCACHE	 proc	 near		 ;AN024;AN026; Don't need this any more.
					 ; IBMDOS is going to handle this through 4Bh call.
;Function: IBMCACHE.SYS does not handle a DOS version 4.0 or above.
;	   So, this procedure will check if the device driver is IBMCACHE.SYS.
;	   If it is, through new INT 2fh interface "Set/Restore DOS version"
;		AX=122Fh
;		DX= 0 ; reset
;		    otherwise ; DH = minor version, DL = major version
;		INT 2fh
;In: ES:SI -> path, filename, 0
;out: if IBMCACHE.SYS, then DOS version changed to 4.00 temporarily.
;     Reset_Dos_Version proc will later reset it back to current DOS version 4.0.

;	 push	 es			 ;AN024;
;	 push	 si			 ;AN024;
;	 push	 ds			 ;AN024;
;	 push	 di			 ;AN024;
;	 push	 cx			 ;AN024;
;	 mov	 di, si 		 ;AN024;save current starting pointer
;CIC_Cmp:				 ;AN024;
;	 cmp	 byte ptr [es:si], 0	 ;AN024;
;	 je	 CIC_Endfile		 ;AN024;
;	 inc	 si			 ;AN024;
;	 jmp	 CIC_Cmp		 ;AN024;
;CIC_Endfile:				 ;AN024;
;	 dec	 si			 ;AN024;
;	 cmp	 byte ptr [es:si], '\'	 ;AN024;
;	 je	 CIC_Got_Tail		 ;AN024;
;	 cmp	 byte ptr [es:si], ':'	 ;AN024;
;	 je	 CIC_Got_Tail		 ;AN024;
;	 cmp	 di, si 		 ;AN024;
;	 je	 CIC_Got_Tail0		 ;AN024;
;	 jmp	 CIC_Endfile		 ;AN024;
;CIC_Got_Tail:				 ;AN024;
;	 inc	 si			 ;AN024;
;CIC_Got_Tail0: 			 ;AN024;
;	 push	 cs			 ;AN024;
;	 pop	 ds			 ;AN024;
;	 push	 si			 ;AN024;
;	 pop	 di			 ;AN024;now es:di -> filename,0
;	 mov	 cx, 12 		 ;AN024;
;	 mov	 si, offset IBMCACHE_File ;AN024;ds:si -> IBMCACHE.SYS,0
;	 repe	 cmpsb			 ;AN024;
;	 jnz	 CIC_ret		 ;AN024;
;	 mov	 ax, 122Fh		 ;AN024;Change DOS version to
;	 mov	 dx, 2803h		 ;AN024; DOS 3.4 temporarily.
;	 int	 2fh			 ;AN024;
;CIC_Ret:				 ;AN024;
;	 pop	 cx			 ;AN024;
;	 pop	 di			 ;AN024;
;	 pop	 ds			 ;AN024;
;	 pop	 si			 ;AN024;
;	 pop	 es			 ;AN024;
;	 ret				 ;AN024;
;Chk_IBMCACHE	 endp
;

Reset_DOS_Version	proc	near	;AN024;
;Function: issue AX=122Fh, DX=0, INT 2fh to restore the DOS version.
	push	ax			;AN024;
	push	dx			;AN024;
	mov	ax, 122Fh		;AN024;
	mov	dx, 0			;AN024;
	int	2fh			;AN024;
	pop	dx			;AN024;
	pop	ax			;AN024;
	ret				;AN024;
Reset_DOS_Version	endp


%ifndef BUF2
;Int 2F EMS handler + Int 67h handler for EMS
;=========================================================================
; Int_2F_EMS		- This routine provides support for VDISK,
;			  FASTOPEN, and BUFFERS to determine the physical
;			  EMS pages available for their usage.
;
;	Inputs	: AH - Function code (18h) to return available phys. page
;		  DI - FEh (Signals to return useable page for VDISK & FASTOPEN)
;		       FFh (Signals to return useable page for BUFFERS)
;
;		  AL = 0 is for installation check. - J.K.
;
;	Outputs : ES - Segment value for physical page
;		  DI - Physical Page number
;		  AH - Non-zero (physical page not available)
;		       Zero (valid physical page data returned)
;
;		  For installation check, AL = 0FFh for being present. - J.K.
;		  For the other functions, AX = 0 for successful op.
;					   AX = -1 for an error.
;
;	Date	: 5/5/88
;	Release : DOS 4.0
;=========================================================================

;Int_2F_Handler  proc			 ;traps Int_2f and checks for EMS	 ;an000; dms;

EMS_STUB_START label byte		;AN030;J.K.
;Dummy DEVICE HEADER for other dummy	;AN031; Symphony assumes int 67h handler seg as a device driver!
	DD	-1			;AN031;becomes pointer to next device header
	DW	0C040H			;AN031;attribute (character device)
	DW	0000			;AN031;pointer to harzard area. System will hang.
	DW	0000			;AN031;pointer to harzard area. System will hang.
	DB	'EMMXXXX0'		;AN031;device name

INTV2F	equ $-EMS_STUB_START		;AN030;J.K.pointer to old 2Fh handler		  ;an000; dms;
IntV2FO DW	?			;AN030;;offset				       ;an000; dms;
IntV2FS DW	?			;AN030;;segment 			       ;an000; dms;

OLDINT67_VECTOR equ $-EMS_STUB_START	;AN030;J.K.
OldInt67	dd	?		;AN030;; save pointer to old INT 67 handler here

%IF	BUFFERFLAG

LOCKFLAG	equ $-EMS_STUB_START
LOCK_FLAG	db  ?

%ELSE

EMSPAGE_CNT	equ	$-EMS_STUB_START ;AN030;J.K.
EMSPageCount	dw	?		;AN030;; save count of EMS mappable pages here

EMSReservedArray_X label word		;AN030;;J.K. For initialization routine
EMSRESERVEDARRAY equ $-EMS_STUB_START	;AN030;;J.K.
		 dw	0ffffh,0ffffh	;AN030;; array of reserved pages
		 dw	0ffffh,0ffffh	;AN030;; phys_page_segment, phys_page_number * 2 entries
MappableArray_X label  word		;AN030;;J.K. for initialization routine
MAPPABLEARRAY	equ  $-EMS_STUB_START	;AN030;;J.K.
		dw	64 dup (0,0)	;AN030;; table to get addresses from old INT 67 handler

%ENDIF
					; 64 entries * 2 words
NEWEMS2F_OFF	equ	$-EMS_STUB_START;AN030;
Int_2F_EMS:				;AN030;;J.K. Name changed.
	cmp	ah,1Bh			;AN030;;AN032;2Fh trap for Mappable Phys. Add. Array ;an000; dms;
	je	Int_2F_EMS_MINE 	;AN030;;This one we want		       ;an000; dms;

IntV2F equ INTV2F	; NASM port equate
	jmp	far [cs:IntV2F]	;AN030;;go to old interrupt handler	       ;an000; dms;

Int_2F_EMS_MINE:			;AN030;
	or	al, al			;AN030;;J.K. Installation check?
	jnz	Int_2F_5800_Func	;AN030;;J.K.
	mov	al, 0FFh		;AN030;;J.K. Yes, I am here!
	iret				;AN030;;J.K.

Int_2F_5800_Func:			;AN030;

%IF	BUFFERFLAG
;	int	3
	cmp	di, 80h
	jne	st_flag
	mov	byte [cs:LOCKFLAG], 0
Int_2f_5800_Good_Exit equ Int_2F_5800_Good_Exit	; NASM port label
	jmp	Int_2f_5800_Good_Exit
	nop	; identicalise
st_flag:
	cmp	di, 81h
Int_2f_5800_Err_Exit equ Int_2F_5800_Err_Exit	; NASM port label
	jne	Int_2f_5800_Err_Exit
	mov	byte [cs:LOCKFLAG], 1
	jmp	Int_2f_5800_Good_Exit
	nop	; identicalise
%ELSE

	push	si			;AN030;;				       ;an000; dms;

;	 mov	 si,offset EMSReservedArray ;point to array containing pages	 ;an000; dms;
	mov	si, EMSRESERVEDARRAY	;AN030;;J.K.

	cmp	di,0feh 		;AN030;;VDISK or FASTOPEN request?	       ;an000; dms;
	jne	Int_2F_5800_Buff_Ck	;AN030;;no - check for buffers		       ;an000; dms;

	cmp	word ptr [cs:si],0ffffh  ;AN030;;valid entry?				;an000; dms;
	je	Int_2F_5800_Err_Exit	;AN030;;no - exit			       ;an000; dms;

	mov	es,word ptr [cs:si]	;AN030;;get segment value		       ;an000; dms;
	mov	di,word ptr [cs:si+2]	;AN030;;get physical page value 	       ;an000; dms;
	jmp	Int_2F_5800_Good_Exit	;AN030;;exit routine			       ;an000; dms;

Int_2F_5800_Buff_Ck:			;AN030;

	cmp	di,0ffh 		;AN030;;BUFFERS request?		       ;an000; dms;
	jne	Int_2F_5800_Err_Exit	;AN030;;no - exit with error		       ;an000; dms;

	add	si,4			;AN030;;point to second element in array       ;an000; dms;

	cmp	word ptr [cs:si],0ffffh  ;AN034;;valid entry?				;an000; dms;
	je	Int_2F_5800_Err_Exit	;AN034;;no - exit			       ;an000; dms;

	mov	es,word ptr [cs:si]	;AN030;;get segment value		       ;an000; dms;
	mov	di,word ptr [cs:si+2]	;AN030;;get physical page value 	       ;an000; dms;

%ENDIF

Int_2F_5800_Good_Exit:			;AN030;

	xor	ax,ax			;AN030;;signal good return		       ;an000; dms;
	jmp	Int_2F_Exit		;AN030;;exit routine			       ;an000; dms;
	nop	; identicalise

Int_2F_5800_Err_Exit:			;AN030;

	mov	ax,0ffffh		 ;AN030;;signal error				;an000; dms;

Int_2F_Exit:				;AN030;


%IFN BUFFERFLAG
	pop	si			;AN030;;restore regs			       ;an000; dms;
%ENDIF
	iret				;AN030;;return to caller		       ;an000; dms;



;-------------------------------------------------------------------
;
;	INT 67h Filter
;
;	This routine filters INT 67's looking for AH=58h.  When initialized,
;	the original INT 67 handler is called and the mappable address array
;	is changed to "reserve" two pages for DOS use.	This new array is
;	then returned to the calling program when INT 67 AH=58h is found.
;
;	Information about the two pages "reserved" for DOS is returned
;	via an unpublished INT 2Fh interface.
;
;	5/10/88 for DOS 4.0.
;-------------------------------------------------------------------

%IFN BUFFERFLAG

GetMappableArray equ	58h		; INT 67 function code for Get Mappable Array
GetPageFrame	equ	41h		; function code for getting the page frame address
null		equ	0		; zero value
I67Error8F	equ	8fh		;AN031;; invalid sub-function error

%ENDIF

;-------------------------------------------------------------------
NEW67_OFFSET	equ	$-EMS_STUB_START	;J.K.
Int67Filter:				;AN030;

%IF	BUFFERFLAG
;	int	3
	cmp	byte [cs:LOCKFLAG], 1
	jne	PassThru
	mov	ah, 80h
	stc
	iret
%ELSE
GETMAPPABLEARRAY equ GetMappableArray	; NASM port equate
	cmp	ah,GETMAPPABLEARRAY	;AN030;; is this the INT 67 call we are interested in?
	jne	PassThru		;AN030;; no, pass it to old INT 67 handler
					;AN030;; yes ...
	cmp	al,0			;AN031;; AL=0 return count and table
	je	I67Fcn0

	cmp	al,1			;AN031;; AL=1 return count only
	jne	I67Error		;AN031;; otherwise, error


;	return count of mappable pages

	sti				;AN031;; turn interrupts on

	mov	cx,word ptr [cs:EMSPAGE_CNT]    ;AN031;J.K. get number of mappable pages in fake table
	xor	ah,ah			;AN031;; good return code
	iret

;	return invalid sub-function code

I67Error:
	sti				;AN031;; turn interrupts on
	mov	ah,I67Error8F		;AN031;; invalid sub-function error
	iret


I67Fcn0:				;AN031

;	copy the fake table to user's buffer

	sti				;AN030;; turn interrupts on

	push	ds			;AN030; save some regs
	push	di			;AN030;
	push	si			;AN030;

	mov	cx,word ptr [cs:EMSPAGE_CNT]    ;AN030;J.K. get number of mappable pages in fake table
	shl	cx,1			;AN030;; count * 2 = number of words to copy

	push	cs			;AN030;; point DS:SI to fake table
	pop	ds			;AN030;
;	 lea	 si,MappableArray
	mov	si, MAPPABLEARRAY	;AN030;;J.K.

	rep	movsw			;AN030;; copy CX words from DS:SI to ES:DI

	xor	ah,ah			;AN030;; good return code
	mov	cx,word ptr [cs:EMSPAGE_CNT] ;AN030;; page count returned to user in CX


	pop	si			;AN030;; restore some regs
	pop	di			;AN030;
	pop	ds			;AN030;

	iret				;AN030;; end of INT 67 filter routine

%ENDIF

;-------------------------------------------------------------------
;
;	PassThru - send request to old INT 67 handler
;
;-------------------------------------------------------------------

PassThru:
OldINT67_VECTOR equ OLDINT67_VECTOR	; NASM port equate
	jmp	far [cs:OldINT67_VECTOR] ;AN030;;J.K. jump to old INT 67 handler
					; (IRET will return to calling program)


EMS_STUB_END	label	byte		;AN030;
;-------------------------------------------------------------------

%IFN BUFFERFLAG
;-------------------------------------------------------------------
;
;	Int67FilterInit - This routine is called to initialize the INT 67
;	filter. It should be called as soon as possible after installation.
;
;-------------------------------------------------------------------

Int67FilterInit:			;AN030;
	push	es			;AN030;; save caller's ES:DI
	push	di			;AN030;

	push	cs			;AN030;; make ES:DI point to our array
	pop	es			;AN030;
	mov	di,offset MappableArray_X   ;AN030;

;	 call	 dword ptr cs:OldInt67	    ; get mappable array from EMS DD

	mov	ah, GetMappableArray	;AN030;
	xor	al,al			;AN030;
	int 67h 			;AN030;;J.K.


;------------------------
; scan table looking for highest phys_page_number

	xor	ax,ax			;AN030;;

	cmp	cx,0			;AN033;; are the any pages left?
	je	NoMoreEMSPages		;AN033;; no, don't bother looking any more

	call	GetHighestPage		;AN030;; get highest entry from table

	mov	[cs:EMSReservedArray_X+4],bx   ;AN030;; phys_page_segment
	mov	[cs:EMSReservedArray_X+6],ax   ;AN030;; phys_page_number

	cmp	cx,0			;AN033;; are the any pages left?
	je	NoMoreEMSPages		;AN033;; no, don't bother looking any more

	call	GetHighestPage		;AN030;; get next highest entry from table

	mov	[cs:EMSReservedArray_X+0],bx   ;AN030;; phys_page_segment
	mov	[cs:EMSReservedArray_X+2],ax   ;AN030;; phys_page_number

NoMoreEMSPages: 			;AN033;;
	mov	[cs:EMSPageCount],cx 	;AN030;; save new page count for INT 67 filter

	pop	di
	pop	es
	ret				;AN030;; return to calling program


;	page
;-------------------------------------------------------------------
;
;	GetHighestPage - returns highest physical page number in AX
;	and segment for it in BX.  A -1 means no valid page found.
;
;-------------------------------------------------------------------
GetHighestPage:

	xor	ax,ax			;AN030;; zero candidate register
	mov	bx,ax			;AN030;; zero pointer to candidate page

	push	cx			;AN030;; save count
	push	dx			;AN030;
	push	di			;AN030;; save pointer

PageScanLoop:				;AN030;
	cmp	ax,[ES:di+2]		;AN030;; get phys_page_number
	ja	LookAtNextPage		;AN030;; this one is lower than the one we are holding

	cmp	word [es:di], 0a000h 	; Only reserve pages in memory above 640K..
	jb	LookAtNextPage		; fix for ps2emm and m20emm with motherboard
					; disabled. 7/25/88. HKN.

	mov	ax,[ES:di+2]		;AN030;; this one is higher, make it new candidate
	mov	bx,di			;AN030;; pointer to new candidate page, used to zero
					; it later so we don't get the same one again
	mov	dx,cx			;AN030;; save count where we found candidate

LookAtNextPage: 			;AN030;
	add	di,4			;AN030;; point to next entry in mappable table

	loop	PageScanLoop		;AN030;; look at next entry

	cmp	bx,null 		;AN030;; did we find any pages?
	jne	FoundOne		;AN030;; yes, exit

	jmp	ReturnError		;AN030;

;------------------------
FoundOne:				;AN030;
	cmp	ax,3			;AN030;; could the one we found be part of a page frame
NotFrame equ Notframe	; NASM port label
	ja	NotFrame		;AN030;; no, carry on

;	yes, find out if it is part of frame

	push	ax			;AN030;; save physical page number
	push	bx			;an030;; dms; bx destroyed by call
	mov	ah,GetPageFrame 	;AN030;; function code to get page frame ...
;	 call	 dword ptr cs:OldInt67	    ; ... from the EMS DD
	int	67h			;AN030;;J.K.
	or	ah,ah			;an030;;dms; error?
	pop	bx			;an030;;dms; restore bx
	pop	ax			;AN030;; restore phys page number
	jnz	NotFrame		;AN030;; no frame available, carry on

;	there is a frame, this page is part of frame, so return -1's

ReturnError:				;AN030;
	mov	ax,0ffffh		;AN030;; indicate failure
	mov	bx,ax			;AN030;; ax and bx = -1

	pop	di			;AN030;; restore pointer
	pop	dx
	pop	cx			;AN030;; restore count

	jmp	GHPExit 		;AN030;




;------------------------
;	Found a page, and it is not part of a page frame, so re-pack table
;	and return info.  The entry we "reserve" for DOS must be removed
;	from the table and the other entries moved up to repack the table.
;	The count must be reduced by 1 to reflect this change.

Notframe:				;AN030;

	mov	di,bx			;AN030;; make ES:DI point to highest page table entry

	mov	bx,[ES:di]		;AN030;; get segment address of page

	mov	cx,dx			;AN030;; get count from candidate page

	push ax 			;AN030;
PackLoop:				;AN030;
	mov	ax, [es:di+4]		;AN030;
	mov	[es:di+0], ax		;AN030;
	mov	ax, [es:di+6]		;AN030;
	mov	[es:di+2], ax		;AN030;
	add	di, 4			;AN030;
	loop	PackLoop		;AN030;; do it until done
	pop  ax 			;AN030;

	pop	di			;AN030;; restore pointer
	pop	dx			;AN030;
	pop	cx			;AN030;; restore count

	sub	cx,1			;AN030;; reduce count by one, one less page in table now

GHPExit:				;AN030;

	ret				;AN030;; return to caller

%ENDIF

;=========================================================================
; EMS_Install_Check	: THIS MODULE DETERMINES WHETHER OR NOT EMS IS
;			  INSTALLED FOR THIS SESSION.
;
;	INPUTS		: NONE
;
;	OUTPUTS 	: ES:BX - FRAME ARRAY
;			  CY	- EMS NOT AVAILABLE
;			  NC	- EMS AVAILABLE
;
;	Date	: 5/6/88
;=========================================================================

EMS_Install_Check	proc	near	;AN030;; check if EMS is installed	       ;an000; dms;

	push	ax			;AN030;; save regs			       ;an000; dms;

	push	ds			;AN030;; save ds			       ;an000; dms;
	xor	ax,ax			;AN030;; set ax to 0			       ;an000; dms;
	mov	ds,ax			;AN030;; set ds to 0			       ;an000; dms;
	cmp	word ptr [067h*4+0],0 ;AN030;; see if int 67h is there	       ;an000; dms;
	pop	ds			;AN030;; restore ds			       ;an000; dms;
	je	EMS_Install_Ck_Err_Exit ;AN030;; exit routine - EMS not loaded	       ;an000; dms;

	mov	ah,40h			;AN030;; Get Status function		       ;an000; dms;
	xor	al,al			;AN030;; clear al			       ;an000; dms;
	int	67h			;AN030;;				       ;an000; dms;
	or	ah,ah			;AN030;; EMS installed? 		       ;an000; dms;
	jnz	EMS_Install_Ck_Err_Exit ;AN030;; exit routine - EMS not loaded	       ;an000; dms;

	mov	ah,46h			;AN030;; Get Version number		       ;an000; dms;
	xor	al,al			;AN030;; clear al			       ;an000; dms;
	int	67h			;AN030;;				       ;an000; dms;
	cmp	al,40h			;AN030;; Version 4.0?			       ;an000; dms;
	jb	EMS_Install_Ck_Err_Exit ;AN030;; exit routine - wrong EMS loaded       ;an000; dms;

	clc				;AN030;; signal EMS loaded		       ;an000; dms;
	jmp	EMS_Install_Ck_Exit	;AN030;; exit routine			       ;an000; dms;
	nop	; identicalise

EMS_Install_Ck_Err_Exit:		;AN030;

	stc				;AN030;; signal EMS not loaded		       ;an000; dms;

EMS_Install_Ck_Exit:			;AN030;

	pop	ax			;AN030;; restore regs			       ;an000; dms;

	ret				;AN030;; return to caller		       ;an000; dms;

EMS_Install_Check	endp		;					;an000; dms;

EMS_Stub_Handler	proc	near	;AN030;
;At the request of Architecture Group, this logic is implemented.
;Function: If (Buffer_Slash_X <> 0 and EMS_Stub_Installed == 0),
;	    then { call Chk_EMS;
;		   if EMS is there, then install EMS_Stub dynamically
;		    and initialize it.}
;      Note: EMS_Stub consists of INT 2fh EMS handler and INT 67h handler.
;	   When EMS_Stub is installed, EMS_Stub_Installed will be set to 1.

	push	es			;AN030;
	push	si			;AN030;
	push	ds			;AN030;
	push	di			;AN030;
	push	ax			;AN030;
	push	cx			;AN030;
	cmp	byte [cs:EMS_Stub_Installed], 0	;AN030;
	je	EMS_Stub_X		;AN030;
	jmp short EMS_SH_Ret		;AN030;
	nop	; identicalise
EMS_Stub_X:				;AN030;
	cmp	byte [cs:Buffer_Slash_X], 0	;AN030;
	je     EMS_SH_Ret		;AN030;
	call	EMS_Install_Check	;AN030;
	jc	EMS_SH_Ret		;AN030;
;Install EMS_Stub.			;AN030;
EMS_Stub_Do:
	push	es			;AN030;
	xor	ax,ax			;AN030;save current Int 2fh, 67h vectors.
	mov	es, ax			;AN030;
	mov	ax, word ptr [es:2fh*4] ;AN030;
	mov	[cs:IntV2FO], ax		;AN030;
	mov	ax, word ptr [es:2fh*4+2]	;AN030;
	mov	[cs:IntV2FS], ax			;AN030;
	mov	ax, word ptr [es:67h*4] 	;AN030;
	mov	word ptr [cs:OldInt67], ax	;AN030;
	mov	ax, word ptr [es:67h*4+2]	;AN030;
	mov	word ptr [cs:OldInt67+2], ax	;AN030;
	pop	es				;AN030;

%IFN BUFFERFLAG
;initalize tables in INT 67h handler
	call	Int67FilterInit 		;AN030;
	cmp	ax, 0ffffh			; if the page found was part of a lim 4.0 page frame
EMS_SH_ret equ EMS_SH_Ret	; NASM port label
	je	EMS_SH_ret			;	do not install stub.  7/24/88. HKN
%ENDIF
Round equ ROUND	; NASM port label
	call	Round				;AN030;
	mov	ax, DEVMARK_EMS_STUB		;AN030;
	call	SetDevMark			;AN030;
memhi equ MEMHI	; NASM port label
	mov	ax, [cs:memhi]			;AN030;
	mov	es, ax				;AN030;
	assume	es:nothing			;AN030;
	xor	di, di				;AN030;
	push	cs				;AN030;
	pop	ds				;AN030;
	mov	cx, offset EMS_STUB_END 	;AN030;
	mov	si, offset EMS_STUB_START	;AN030;
	sub	cx, si				;AN030;cx = size in byte
memlo equ MEMLO	; NASM port label
	mov	[cs:memlo], cx			;AN030;
	rep	movsb				;AN030;
	or	byte [cs:SetDevMarkFlag], FOR_DEVMARK	;AN030;set the devmark_size for MEM command.
	call	Round				;AN030;and get the next [memhi] avaiable.
	mov	byte [cs:EMS_Stub_Installed], 1		;AN030;

	xor	ax, ax				;AN030;
	mov	ds, ax				;AN030;
	cli					;AN030;
	mov	word ptr [2Fh*4],NEWEMS2F_OFF;AN030;set the new int 2fh, 67h vectors.
	mov	word ptr [2Fh*4+2], es	;AN030;
	mov	word ptr [67h*4],NEW67_OFFSET;AN030;
	mov	word ptr [67h*4+2], es	;AN030;
	sti					;AN030;
EMS_SH_Ret:					;AN030;
	pop	cx				;AN030;
	pop	ax				;AN030;
	pop	di				;AN030;
	pop	ds				;AN030;
	pop	si				;AN030;
	pop	es				;AN030;
	ret					;AN030;

EMS_Stub_Handler	endp			;AN030;
%endif	; BUF2


 global ldos_getnum_far
 extern ldos_getnum
ldos_getnum_far:
	call ldos_getnum
	retf

 global isstring?, skipcomma, skipcomm0, skipwhite, skipwh0
skipcomma:
	lodsb
skipcomm0:
	call skipwh0
	cmp al, ','
	je skipwhite
	retn

skipwhite:
	lodsb
skipwh0:
	cmp al, 32
	je skipwhite
	cmp al, 9
	je skipwhite
	retn


		; Check for given string (cap-insensitive)
		;
		; INP:	ds:si -> input string to check (either cap),
		;	 terminated by CR (13), NUL, semicolon, space,
		;	 tab, dot, comma, equals, colon, [, ], (, or )
		;	es:dx -> ASCIZ string to check (all-caps)
		; OUT:	Iff string matches,
		;	 ZR, NC
		;	 si -> at separator that terminates the keyword
		;	else,
		;	 NZ, CY
		;	 si = input si
		; CHG:	dx, al
isstring?:
	push si
	xchg dx, di
.loop:
	lodsb
	call capitalise
	scasb
	jne .mismatch
	test al, al		; NC
	jne .loop
				; ZR
	jmp .matched_zr_nc

.mismatch:
	call iseol?
	je .checkend
	cmp al, 32
	je .checkend
	cmp al, 9
	je .checkend
	cmp al, '.'
	je .checkend
	cmp al, ','
	je .checkend
	cmp al, '='
	je .checkend
	cmp al, ':'
	je .checkend
	cmp al, '['
	je .checkend
	cmp al, ']'
	je .checkend
	cmp al, '('
	je .checkend
	cmp al, ')'
	je .checkend
.ret_nz:	; NZ
	pop si
	stc			; CY
.ret:
	xchg dx, di
	retn

.checkend:
	cmp byte [es:di - 1], 0
	jne .ret_nz
				; ZR, NC
.matched_zr_nc:	; ZR, NC
	pop di			; (discard)
	lea si, [si - 1]	; -> separator (preserve ZR)
	jmp .ret


capitalise:
	cmp al, 'a'
	jb .ret
	cmp al, 'z'
	ja .ret
	and al, ~ 20h
.ret:
	retn

iseol?:
	cmp al, ';'
	je .ret
.notsemicolon:
	cmp al, 13
	je .ret
	cmp al, 10
	je .ret
	cmp al, 0
.ret:
	retn


; (no prior section) ; SYSINITSEG	ENDS
	END

