					;AN000;bgb
page	,132				;
TITLE	RECINIT.ASM - MS-DOS File/Disk Recovery Utility

;/*
; *                      Microsoft Confidential
; *                      Copyright (C) Microsoft Corporation 1991
; *                      All Rights Reserved.
; */

;*****************************************************************************
;*****************************************************************************
; Include files
;*****************************************************************************
;
 .xlist
	include pathmac.inc
 INCLUDE RECSEG.INC			;AN000;bgb
	INCLUDE DOSSYM.INC		;AN000;BGB
INCLUDE SYSCALL.INC			;AN000;BGB
INCLUDE RECEQU.INC			;AN000;BGB
INCLUDE RECMACRO.INC			;AN000;BGB
INCLUDE RECPARSE.INC			;AN000;BGB
 .list

;
;*****************************************************************************
; External Data Declarations
;*****************************************************************************
data	segment public para 'Data'	 ;an000;bgb
	EXTRN	movsi:word  ;move si pointer here for display of invalid parm	;an031;bgb
	extrn	command_line_buffer:byte ;AN000;bgb
	extrn	ExitStatus:Byte 	;AN000;bgb
	Extrn	FATTbl:byte
	Extrn	SubstErr:Byte
	Extrn	NotNetM:Byte
	Extrn	User_Drive:Byte 	;AN000;BGB
	Extrn	Baddrv:Byte
	Extrn	Drive_Letter_Msg:Byte	;AN000;BGB
	Extrn	Parse_Error_Msg:Byte
	extrn	options_msg:Byte
	extrn	MSG_OPTIONS_FIRST: ABS
	extrn	MSG_OPTIONS_LAST : ABS
	extrn	all_files_msg : byte
	extrn   whole_dsk_msg : byte
	extrn	bad_ver_msg : byte
	extrn	DO_ALL_FILES : ABS
	extrn	DO_WHOLE_DISK : ABS
	extrn	fname_buffer:byte	;AN000;BGB
	extrn	PSP_Segment:word	;AN000;bgb
	extrn	fatal_error:byte	;AN000;bgb
	extrn	found:byte		;AN000;bgb
	extrn	done:byte	       ;AN000;bgb
	extrn	bpb_buffer:byte        ;AN000;bgb
	extrn	data_start_low:word	;AN000;bgb
	extrn	data_start_high:word	 ;AN000;bgb
	extrn	driveletter:byte	      ;AN000;bgb
	extrn	drive:byte		;AN000;bgb
	extrn	transrc:byte		  ;AN000;bgb
	extrn	int_23_old_off:word	;AN000;bgb
	extrn	int_23_old_seg:word	;AN000;bgb
	extrn	int_24_old_off:word	;AN000;bgb
	extrn	int_24_old_seg:word	;AN000;bgb
	extrn	append:byte		 ;AN000;bgb
	extrn   display_interface: near
ifdef fsexec
	extrn	fat12_string:byte	;AN000;bgb
	extrn	fat16_string:byte	;AN000;bgb
	extrn	media_id_buffer:byte	;AN000;bgb
	extrn	fs_not_fat:byte 	;AN000;bgb				;an022;bgb
	extrn	FS_String_Buffer:Byte	;AN011;bgb				;an022;bgb
	extrn	FS_String_end:Byte   ;AN011;bgb 				;an022;bgb
endif
data	ends ;an000;bgb


code	segment public para 'CODE'	 ;an000;bgb
	pathlabl recinit
;*****************************************************************************
; recinit procedures
;*****************************************************************************
public	Main_Init, Init_Io, Preload_Messages, Parse_recover
public	Parse_good, Parse_err, Validate_Target_Drive
public	 Check_Target_Drive, Check_For_Network, Check_Translate_Drive
public	 Hook_interrupts, Clear_Append_X, RECOVER_IFS, Reset_Append_X
public	exitpgm 								;an026;bgb
;*****************************************************************************
; External Routine Declarations
;*****************************************************************************
;	Extrn	EXEC_FS_Recover:Near						;an022;bgb
	 Extrn	 SysLoadMsg:Near
	Extrn	SysDispMsg:Near
	Extrn	Main_Routine:Near
	Extrn	INT_23:Near
	Extrn	INT_24:Near

;*****************************************************************************
;Routine name:	MAIN_INIT
;*****************************************************************************
;
;description: Main routine for recover program
;
;Called Procedures: get_psp
;		    Init_IO
;		    Validate_Target_Drive
;		    Hook_Interrupts
;		    RECOVER_IFS (goes to main-routine)
;
;Input: None
;
;Output: None
;
;Change History: Created	5/8/87	       MT
;
;Psuedocode
;----------
;	get info from psp
;	Parse input and load messages (CALL Init_Input_Output)
;	IF no error
;	   Check target drive letter (CALL Validate_Target_Drive)
;	   IF no error
;	      Set up Control Break (CALL Hook_Interrupts)
;	      IF no error
;		 CALL RECOVER_IFS (goes to main routine)
;	      ENDIF
;	   ENDIF
;	ENDIF
;	Exit program
;*****************************************************************************
procedure Main_Init			;;AN000;
	xor	bp,bp
	Set_Data_Segment		;Set DS,ES to Data segment	;AN000;bgb
	call	get_psp
	mov	Fatal_Error,No		;Init the error flag		;AN000;
	call	Init_Io 		;Setup messages and parse	;AN000;
	cmp	Fatal_Error,Yes 	;Error occur?			;AN000;
;	$IF	NE			;Nope, keep going		;AN000;
	JE $$IF1
	    call    Validate_Target_Drive ;Check drive letter		  ;AN000;
	    cmp     Fatal_Error,Yes	;Error occur?			;AN000;
;	    $IF     NE			;Nope, keep going		;AN000;
	    JE $$IF2
		call	Hook_Interrupts ;Set CNTRL -Break hook		;AN000;
		cmp	Fatal_Error,Yes ;Error occur?			;AN000;
;		$IF	NE		;Nope, keep going		;AN000;
		JE $$IF3
		    call    RECOVER_IFS ;RECOVER correct file system	 ;AN000;
;		$ENDIF			;				;AN000;
$$IF3:
;	    $ENDIF			;				;AN000;
$$IF2:
;	$ENDIF				;				;AN000;
$$IF1:
exitpgm: mov	 al,ExitStatus		 ;Get Errorlevel		 ;AN000;
	DOS_Call Exit			;Exit program			;AN000;
	int	20h			;If other exit fails		;AN000;

Main_Init endp				;				;AN000;

;*****************************************************************************
;Routine name: get_psp
;*****************************************************************************
;Description: get info from the psp area
;
;Called Procedures: get_drive
;
;Change History: Created	8/7/87	       bgb
;
;Input: none
;
;Output: psp_segment
;	 command_line_buffer
;
;Psuedocode
;----------
;	get addr of psp
;	move command line into data seg
;	get drive number of target
;	get addr of data seg
;	call get_drive
;	ret
;*****************************************************************************
Procedure get_psp			;;AN000;
	DOS_Call GetCurrentPSP		;Get PSP segment address	:AN000;bgb
	mov	PSP_Segment,bx		;Save it for later		;AN000;bgb
; get command line from psp							;AN000;bgb
	mov	cx,PSP_Segment		;point ds to data seg			;AN000;bgb
	mov	ds,cx			;  "   "   "   "    "                   ;AN000;bgb
	assume	ds:NOTHING,es:dg	;  "   "   "   "    "                   ;AN000;bgb
	mov	si,Command_Line_Parms	;ds:si --> old area in psp		;AN000;bgb
	LEA	di,command_line_buffer ; es:di -> new area in data
	mov	cx,128			; do for 128 bytes
	rep	movsb			; mov 1 byte until cx=0
; get the drive number of the target from the psp (0=default, a=1, b=2, c=3) ;AN000;bgb
	mov	bl,ds:[FCB1]	    ;Get target drive from FCB -74	    ;AN000;
	Set_Data_Segment	    ;Set DS,ES to Data segment		    ;AN000;bgb
	call	get_drive
	ret
get_psp   endp				;				;AN000;


;*****************************************************************************
;Routine name: get_drive
;*****************************************************************************
;Description: get drive letter from reg bl
;
;Change History: Created	8/7/87	       bgb
;
;Input: bl = drive num (default=0)
;
;Output: driveletter
;	 drive_letter_msg
;	 user_drive
;
;Psuedocode
;----------
;	IF drive-num = default
;	   get default drive number (a=1)
;	   convert to letter
;	ELSE
;	   convert to letter
;	ENDIF
;	move letter into data areas
;	ret
;*****************************************************************************
Procedure get_drive			;;AN000;
; convert drive number to drive letter
	    cmp     bl,0  ;a=1 b=2 c=3	;Is it default drive? 0=default ;AN000;
;	    $IF     E			;Yes, turn it into drive letter ;AN000;
	    JNE $$IF7
; get default drive number
		DOS_Call Get_Default_Drive ;Get default drive num in al    ;AN000;
					;a=0, b=1, c=2
		mov	drive,al	;					;AN000;bgb
;	    $ELSE			;Not default, A=1		;AN000;
	    JMP SHORT $$EN7
$$IF7:
; bl already contains the correct drive number - save it
		dec	bl		;a=0 b=1 c=2
		mov	drive,bl	;					;AN000;bgb
		mov	al,bl
;	    $ENDIF			; 74+40=b4
$$EN7:
	    add     al,"A"		;convert it to letter		;AN000;
	    mov     driveletter,al	;set up prompt msg			;AN000;bgb
	    mov     Drive_Letter_Msg,al ;Save it in message		;AN000;
	    mov     User_Drive,al	;Put it into path strings	;     ;
	ret
get_drive endp				;				;AN000;

;*****************************************************************************
;Routine name: Init_Io
;*****************************************************************************
;description: Initialize messages, Parse command line if FAT file system
;
;Called Procedures: Preload_Messages
;		   Parse_Recover
;
;Change History: Created	5/10/87 	MT
;
;Input: PSP command line at 81h and length at 80h
;
;Output: FS_Not_FAT = YES/NO
;	 Drive_Letter_Msg set up for any future messages that need it
;
;Psuedocode
;----------
;	Load messages (CALL Preload_Messages)
;	IF no fatal error
;	   Get file system type (12-bit fat, 16-bit fat, big fat, ifs)
;	   IF old-type-diskette, or
;	      dos4.00 12-bit fat, or
;	      dos4.00 16-bit fat, then
;	      Go handle FAT based Recover syntax's (Call Parse_Recover)
;	   ELSE
;	      FS_Not_FAT = YES
;	   ENDIF
;	ENDIF
;	ret
;*****************************************************************************
Procedure Init_IO			;;AN000;
; load the error messages from the system					;an022;bgb
	call	Preload_Messages	;Load up message retriever	;AN000;
ifdef fsexec									;an022;bgb
	mov	FS_Not_FAT,No							;an022;bgb
	cmp	Fatal_Error,YES 	;Quit?				;AN000; ;an022;bgb
;	$IF	NE			;Nope, keep going		;AN000; ;an022;bgb
	JE $$IF10
; get file system type from ioctl						;an022;bgb
	    mov     al,generic_ioctl	 ;al=0d (get media id)			;AN000;;an030;bgb
	    xor     bx,bx		;use default drive		;AN009;b;an022;bgbgb
	    mov     ch,Rawio		;8 = disk io				;an030;bgb;an022;bgb
	    mov     cl,Get_Media_Id	;66h					;an030;bgb
	    lea     dx,Media_ID_Buffer ;Point at buffer 	       ;AN000;	;an022;bgb
	    DOS_Call IOCtl		;Do function call ah=44 	;AN000; ;an022;bgb
; is it DOS 3.3 or below?			;carry flag means old dos	;an022;bgb
;	    $IF     C,OR		;Old style diskette, OR 	;AN000; ;an022;bgb
	    JC $$LL11
; is it a new-12 bit fat?							;an022;bgb
	       lea     si,FAT12_String ;Check for FAT_12 string        ;AN000;	;an022;bgb
	       lea     di,Media_ID_Buffer.Media_ID_File_System ;	    ;AN0;an022;bgb00;
	       mov     cx,Len_FS_ID_String ;Length of compare		   ;AN00;an022;bgb0;
	       repe    cmpsb		   ;Find it?			   ;AN00;an022;bgb0;
;	    $IF     E,OR		;Nope, keep going		;AN000; ;an022;bgb
	    JE $$LL11
; is it a new 16-bit fat?							;an022;bgb
	       lea     si,FAT16_String ;Check for FAT_16 string        ;AN000;	;an022;bgb
	       lea     di,Media_ID_Buffer.Media_ID_File_System ;	    ;AN0;an022;bgb00;
	       mov     cx,Len_FS_ID_String ;Length of compare		   ;AN00;an022;bgb0;
	       repe    cmpsb		   ;Do compare			   ;AN00;an022;bgb0;
;	    $IF     E			; is it new 16-bit fat? 	;AN000; ;an022;bgb
	    JNE $$IF11
$$LL11:
endif										;an022;bgb
; file system is fat based, continue (old or new)				;an022;bgb
		call	Parse_Recover	;Yes, go sort out syntax		;an022;bgb
;										;an022;bgb
; non-fat based system								;an022;bgb
ifdef fsexec									;an022;bgb
;	    $ELSE			;We got FS other than FAT	;AN000; ;an022;bgb
	    JMP SHORT $$EN11
$$IF11:
		mov	FS_Not_FAT,Yes	;Indicate exec file system	;AN000; ;an022;bgb
		mov	cx,8							;an022;bgb;an011;bgb
		lea	si,Media_ID_Buffer.Media_ID_File_System ;get file system;an022;bgb ;an011;bgb
		lea	di,fs_string_buffer ;put it here			;an022;bgb;an011;bgb
		rep	movsb							;an022;bgb;an011;bgb
		lea	di,fs_string_buffer ;point to beginning again		;an022;bgb;an011;bgb
;		$DO	COMPLEX 	;search th string until eol found	;an022;bgb;an011;bgb
		JMP SHORT $$SD13
$$DO13:
		    inc     di		;next char				;an022;bgb;an011;bgb
;		$STRTDO 		;start loop here			;an022;bgb;an011;bgb
$$SD13:
		    cmp     byte ptr [di],' '	 ;end of string ?		;an022;bgb	   ;an011;bgb
;		$ENDDO	E		;end loop when eol found		;an022;bgb;an011;bgb
		JNE $$DO13
		lea	si,fs_string_end ;get end of string - rec.exe		;an022;bgb;an011;bgb
		mov	cx,8		; 8 more chars				;an022;bgb;an011;bgb
		rep	movsb		;move it in				;an022;bgb;an011;bgb
;	    $ENDIF			; fat based file system 	;AN000; ;an022;bgb
$$EN11:
;	$ENDIF				; no error from msg retreiver	   ;AN00;an022;bgb0;
$$IF10:
endif										;an022;bgb
	ret				;				;AN000;
Init_Io 	  endp			;				;AN000;

;*****************************************************************************
;Routine name: Preload_Messages
;*****************************************************************************
;Description: Preload messages using common message retriever routines.
;
;Called Procedures: SysLoadMsg
;
;Change History: Created	5/1/87	       MT
;
;Input: Fatal_Error = NO
;
;Output: Fatal_Error = YES/NO
;
;Psuedocode
;----------
;	Preload All messages (Call SysLoadMsg)
;	IF error
;	   Display SysLoadMsg error message
;	   Fatal_Error = YES
;	ENDIF
;	ret
;*****************************************************************************
Procedure Preload_Messages		;;AN000;						 ;
	call	SysLoadMsg		;Preload the messages		;AN000;
;	$IF	C			;Error? 			;AN000;
	JNC $$IF18
	    lea	    dx, bad_ver_msg
	    call    display_interface
;	    call    SysDispMsg		;Display preload msg		;AN000;
	    mov     Fatal_Error, YES	;Indicate error exit		;AN000;
;	$ENDIF				;				;AN000;
$$IF18:
	ret				;				;AN000;

Preload_Messages endp			;				;AN000;

;*****************************************************************************
;Routine name: Parse_Command_Line
;*****************************************************************************
;Description: Parse the command line. Check for errors, and display error and
;		 exit program if found. Use parse error messages except in case
;		 of no parameters, which has its own message
;
;Called Procedures: Message (macro)
;		    SysParse
;		    parse_good
;		    parse_err
;
;Change History: Created	5/1/87	       MT
;
;Input: Fatal_Error = NO
;
;Output: Fatal_Error = YES/NO
;	 PARSE-ADDR
;	 DRIVELETTER
;	 PARSE-ADDR
;
;Psuedocode
;----------
;    set up regs to call sysparse
;DO UNTIL error=yes or return(ax)=finish(-1)
;    call sysparse
;    IF ax=good return(0)
;	   call parse-good
;    ELSE
;	   call parse-err
;    ENDIF
;ENDLOOP
;ret
;
;A. normal proc ==  1- ax=good 0
;		    2- ax=done -1
;B. no parm	==  1- ax=error 2
;
;C. too many	==  1- ax=good 0
;		    2- ax=error 1
;D. syntax	==  1- ax=error 9
;*****************************************************************************
Procedure Parse_recover 		;					;AN000;bgb
	push	ds			; save ds				;AN000;bgb
; set up to call sysparse							;AN000;bgb
	set_data_segment		;ds,es point to data seg
	LEA	si,command_line_buffer ;ds:si -> cmd line
	LEA	di,parms_input_block   ;es:di--> parms input block	   ;AN000;bgb
	xor	cx,cx			;cx = 0 				;AN000;bgb
	xor	dx,dx			;dx = 0 				;AN000;bgb
	mov	done,no
; call sysparse until error or end of cmd line					;AN000;bgb
;	$DO				;AN000;bgb
$$DO20:
	    call    SysParse		;go parse				;AN000;bgb
	    cmp     ax,$p_rc_eol	; -1 end of command line?		   ;AN000;bgb
;	    $LEAVE  E			; yes - done				    ;AN000;bgb
	    JE $$EN20
	    cmp     ax,$p_no_error	; good return code ??? (0)		;AN000;bgb
;	    $IF     E			; yes					;AN000;bgb
	    JNE $$IF22
		call	parse_good	; go get it				;AN000;bgb
;	    $ELSE			; ax not= good				;AN000;bgb
	    JMP SHORT $$EN22
$$IF22:
		call	parse_err	; check for error			;AN000;bgb
;	    $ENDIF			; eol					;AN000;bgb
$$EN22:
	    cmp     Fatal_Error,YES	;Can we continue?			    ;AN000;bgb
;	    $LEAVE  E			    ;NO 				    ;AN000;bgb
	    JE $$EN20
;	$ENDDO				;					;AN000;bgb
	JMP SHORT $$DO20
$$EN20:
	pop	ds			;					;AN000;bgb
	ret				;					;AN000;bgb
					;					;AN000;bgb
Parse_recover endp			;					;AN000;bgb
					;					;AN000;bgb
					;AN000;bgb
;*****************************************************************************
;Routine name: parse_good
;*****************************************************************************
;
;Description: when the ax register returned by sysparse indicates and error,
;	      this procedure is called.  it then determines which error
;	      occurred, and calls parse_message to display the msg.
;
;Called Procedures: parse_message (macro)
;
;Change History: Created	7/23/87 	bgb
;
;Input:
;
;Output: Fatal_Error = YES/NO
;
;Psuedocode
;----------
;
;	  found=yes
;	  IF data=drive
;	       save drive number and letter
;	  ELSE
;	       IF data=filespec
;		    save filespec
;	       ELSE
;		    call parse-msg
;	       ENDIF
;	  ENDIF
;*****************************************************************************
;
Procedure Parse_good			;				;AN000;bgb

	; See if the /? options help switch was given.
	; If so, display the options help message,
	; and set up for a quick exit.

PG_Check_?:
	cmp	[PARSE_SYN], offset SwOptions_Syn
	jne	PG_Check_?_done
	call	Display_options		; display the options hlp msg
	mov	[Fatal_Error], YES	; flag that we are done
	mov	[ExitStatus], 0		; no error to return
	jmp	short Parse_good_exit	; bail out now
PG_Check_?_done:

	cmp	parse_type,$p_drive  ; 6 if data=drive ;AN000;bgb
;	$IF	E			; not eol, good syntax, drive entered ;AN000;bgb
	JNE $$IF27
	    mov     bl,byte ptr parse_addr ;AN000;bgb
	    dec     bl			;Make drive 0 based		;AN000;bgb
	    mov     drive,bl		;AN000;bgb
	    add     bl,'A'		;make it character		;AN000;bgb
	    mov     driveletter,bl	;save into drive letter 	;AN000;bgb
;	$ELSE				; no - filespec entered 	;AN000;bgb
	JMP SHORT $$EN27
$$IF27:
	    cmp     parse_type,$p_file_spec ; 5 if data = filespec ;AN000;bgb
;	    $IF     E			; was file spec entered       ;AN000;bgb
	    JNE $$IF29
;		    push    si		; save input offset reg 		;AN000;bgb
;		    push    ds		; save input seg reg			;AN000;bgb
;		    push    cx		; save count				;AN000;bgb
;		    push    es		; save other seg reg			;AN000;bgb
;		    mov     cx,ds	;es points to data			;AN000;bgb
;		    mov     es,cx	;es points to data			;AN000;bgb
;		    mov     si,word ptr parse_addr ;get offset to filespec   ;AN000;bgb
;		    mov     ds,word ptr parse_addr+2 ;get segment to filespec	;AN000;bgb
;		    mov     cx,128	; mov 128 bytes 			;AN000;bgb
;		    rep     movs es:fname_buffer,ds:[si] ;move it		    ;AN000;bgb
;		    pop     es		; save other seg reg			;AN000;bgb
;		    pop     cx		; save other seg reg			;AN000;bgb
;		    pop     ds		; save other seg reg			;AN000;bgb
;		    pop     si		; save other seg reg			;AN000;bgb
;	    $ELSE			; no, no drive or filespec    ;AN000;bgb
	    JMP SHORT $$EN29
$$IF29:
		mov	ax,$p_syntax	;tell user bad syntax	   ;AN000;bgb
		parse_message		;display msg		   ;AN000;bgb
		mov Fatal_Error,YES ;Indicate death!  ;AN000;bgb
;	    $ENDIF			; was drive entered ?		;AN000;bgb
$$EN29:
;	$ENDIF				;if data=drive		      ;AN000;bgb
$$EN27:
Parse_good_exit:
	ret				;					;aN000;bgb
					;AN000;bgb
parse_good endp 			;				;AN000;bgb

					;AN000;bgb
;*****************************************************************************
;Routine name: parse_err
;*****************************************************************************
;
;Description: when the ax register returned by sysparse indicates and error,
;	      this procedure is called.  it then determines which error
;	      occurred, and calls parse_message to display the msg.
;
;Called Procedures: parse_message (macro)
;
;Change History: Created	7/23/87 	bgb
;
;Input:
;
;Output: Fatal_Error = YES/NO
;
;Psuedocode
;----------
;
;	  IF ax=done	   (end of cmd line?) -1
;	       IF found=no (eol, but no parameters listed)
;		    call parse-msg
;	       ENDIF
;	  ELSE		   (error other than eol)
;	       call parse-msg
;	  ENDIF
;*****************************************************************************
;
Procedure Parse_err			;					;AN000;bgb
	mov Fatal_Error,YES ;Indicate death!  ;AN000;bgb			;AN000;bgb
	cmp ax,$P_Op_Missing		; 2 = no parameters ?			;AN000;bgb
;	$IF E				;					;AN000;bgb
	JNE $$IF33
	    message baddrv		; yes (invalid drive or filename)	;AN000;bgb
;	$ELSE									;AN000;bgb
	JMP SHORT $$EN33
$$IF33:
	   mov	   byte ptr [si],00	;zero terminate display string	;an031;bgb
	   dec	   si			;look at previous char			;an031;bgb
nextsi:
public nextsi
	   dec	   si			;look at previous char			;an031;bgb
	   cmp	   byte ptr [si],' '	;find parm separator			;an031;bgb
	   jnz	   nextsi		;loop until begin of parm found
	   mov	   movsi,si		;mov si into display parms		;an031;bgb
	    parse_message		;no- display parse message ;AN000;bgb	;AN000;bgb
;	$ENDIF									;AN000;bgb
$$EN33:
	ret				;					;AN000;bgb
parse_err endp				;					;AN000;bgb


;*****************************************************************************
;Routine name: Display_options
;*****************************************************************************
;
;Description: Display the options help message on standard output.
;
;Called Procedures: 
;
;Change History: Created	4/26/90 	c-PaulB
;
;Input:  No value passed.
;
;Output: No value returned.
;        Options help message is output.
;
;Psuedocode
;----------
;
;	  IF ax=done	   (end of cmd line?) -1
;	       IF found=no (eol, but no parameters listed)
;		    call parse-msg
;	       ENDIF
;	  ELSE		   (error other than eol)
;	       call parse-msg
;	  ENDIF
;*****************************************************************************
;
Procedure Display_options

DO_loop:
	Message	options_msg
	cmp	word ptr[options_msg], MSG_OPTIONS_LAST	; last line of msg?
	je	DO_done			; done if so
	inc	word ptr[options_msg]	;  else bump message number
	jmp	short DO_loop		;  and keep going
DO_done:
	ret

Display_options endp


;*****************************************************************************
;Routine name: Validate_Target_Drive
;*****************************************************************************
;
;Description: Control routine for validating the specified format target drive.
;	      If any of the called routines find an error, they will print
;	      message and terminate program, without returning to this routine
;
;Called Procedures: Check_Target_Drive
;		    Check_For_Network
;		    Check_Translate_Drive
;
;Change History: Created	5/1/87	       MT
;
;Input: Fatal_Error = NO
;
;Output: Fatal_Error = YES/NO
;
;Psuedocode
;----------
;
;	CALL Check_Target_Drive
;	IF !Fatal_Error
;	   CALL Check_For_Network
;	   IF !Fatal_Error
;	      CALL Check_Translate_Drive
;	   ENDIF
;	ENDIF
;	ret
;*****************************************************************************
;
Procedure Validate_Target_Drive 	;				;AN000;
	call	Check_For_Network	;See if Network drive letter	;AN000;
	cmp	Fatal_Error,YES 	;Can we continue?		;AN000;
;	$IF	NE			;Yep				;AN000;
	JE $$IF36
	    call    Check_Translate_Drive ;See if Subst, Assigned   ;AN000;
	    call    Check_Target_Drive	;See if valid drive letter	;AN000;
;	$ENDIF				;- Fatal_Error passed back	;AN000;
$$IF36:
	ret				;				;AN000;

Validate_Target_Drive endp		;				;AN000;

;*****************************************************************************
;Routine name: Check_Target_Drive
;*****************************************************************************
;
;Description: Check to see if valid DOS drive by checking if drive is
;	      removable. If error, the drive is invalid. Save default
;	      drive info. Also get target drive BPB information, and compute
;	      the start of the data area
;
;Called Procedures: Message (macro)
;
;Change History: Created	5/1/87	       MT
;
;Input: Fatal_Error = NO
;
;Output: Fatal_Error = YES/NO
;	 User_Drive = default drive
;
;Psuedocode
;----------
;
;	Get default drive
;	See if drive LOCAL     (INT 21h, AX=4409h IOCtl)
;	IF error - drive invalid
;	   Display Invalid drive message
;	   Fatal_Error= YES
;	ENDIF
;	Get BPB of target drive (Generic IOCtl Get Device parameters)
;	Compute start of data area
;	ret
;*****************************************************************************
;
Procedure Check_Target_Drive		;				;AN000;
	mov	al,0Dh			;Get BPB information		;AN000;
	mov	cx,0860h		; "  "	 "  "			;AN000;
;;;;;;;;mov	bl,byte ptr parse_addr	; "  "	 "  " ;AN000;
	mov	bl,drive		;drive number	 ;A=0,B=1		;AN000;bgb
	inc	bl			;a=1					;AN000;bgb
	lea	dx,BPB_Buffer	 ; "  "   "  "			 ;AN000;
	DOS_Call IOCtl			; "  "	 "  "			;AN000;
	xor	cx,cx			;Find # sectors used by FAT's   ;AN000;
	mov	cl,BPB_Buffer.NumberOfFATs ; "  "   "  "		   ;AN000;
	mov	ax,BPB_Buffer.SectorsPerFAT ; "  "   "  "		    ;AN000;
	mul	cx			; "  "	 "  "			;AN000;
	push	dx			;Save results			;AN000;
	push	ax			;     "  "			;AN000;
	mov	ax,BPB_Buffer.RootEntries ;Find number of sectors in root ;AN000;
	mov	cl,Dir_Entries_Per_Sector ; by dividing RootEntries	  ;AN000;
	div	cl			; by (512/32)			;AN000;
	pop	bx			;Get low sectors per FAT back	;AN000;
	pop	dx			;Get high part			;AN000;
	add	ax,bx			;Add to get FAT+Dir sectors	;AN000;
	adc	dx,bp ;zero		;High part			;AN000;
	add	ax,ReservedSectors	;Add in Boot record sectors	;AN000;
	adc	dx,bp ;zero		;to get start of data (DX:AX)	;AN000;
	mov	Data_Start_Low,ax	;Save it			;AN000;
	mov	Data_Start_High,dx	;				;AN000;
	ret				;And we're outa here            ;AN000;
Check_Target_Drive endp 		;				;AN000;

;*****************************************************************************
;Routine name: Check_For_Network
;*****************************************************************************
;
;Description: See if target drive isn't local, or if it is a shared drive. If
;	      so, exit with error message. The IOCtl call is not checked for
;	      an error because it is called previously in another routine, and
;	      invalid drive is the only error it can generate. That condition
;	      would not get this far
;
;Called Procedures: Message (macro)
;
;Change History: Created	5/1/87	       MT
;
;Input: Drive
;	   Fatal_Error = NO
;
;Output: Fatal_Error = YES/NO
;
;Psuedocode
;----------
;	See if drive is local (INT 21h, AX=4409 IOCtl)
;	IF not local
;	   Display network message
;	   Fatal_ERROR = YES
;	ELSE
;	   IF  8000h bit set on return
;	      Display assign message
;	      Fatal_Error = YES
;	   ENDIF
;	ENDIF
;	ret
;*****************************************************************************
;
Procedure Check_For_Network		;				;AN000;
; is device local?  int 21, ah=44, al=9
	mov	bl,drive		;drive number	 ;A=0,B=1		;AN000;bgb
	inc	bl			;drive number	 ;A=1,B=2 for IOCtl call;AN000;bgb
	mov	al,09h			;See if drive is local			;AC000;bgb
	DOS_Call IOCtl			;-this will fail if bad drive	;AC000;
;	$IF	C			;CarrY means invalid drive	   ;AC000;
	JNC $$IF38
	    Message BadDrv		;Print message			;AC000;
	    mov     Fatal_Error,Yes	;Indicate error 		;AN000;
;	$ELSE
	JMP SHORT $$EN38
$$IF38:
	    test    dx,Net_Check	;if (x & 1200H)(redir or shared);     ;
;	    $IF     NZ			;Found a net drive		;AC000;
	    JZ $$IF40
		Message NotNetM 	;Tell 'em                       ;AC000;
		mov	Fatal_Error,Yes ;Indicate bad stuff		;AN000;
;	    $ELSE			;Local drive, now check assign	;AN000;
	    JMP SHORT $$EN40
$$IF40:
		test	dx,Assign_Check ;8000h bit is bad news		;     ;
;		$IF	NZ		;Found it			;AC000;
		JZ $$IF42
		    Message SubstErr	;Tell error			;AC000;
		    mov     Fatal_Error,Yes ;Indicate bad stuff 	    ;AN000;
;		$ENDIF			;				;AN000;
$$IF42:
;	    $ENDIF			;				;AN000;
$$EN40:
;	$ENDIF				;				;AN000;
$$EN38:
	ret				;				;AN000;

Check_For_Network endp			;				;AN000;

;*****************************************************************************
;Routine name: Check_Translate_Drive
;*****************************************************************************
;
;Description: Do a name translate call on the drive letter to see if it is
;	      assigned by SUBST or ASSIGN
;
;Called Procedures: Message (macro)
;
;Change History: Created	5/1/87	       MT
;
;Input: Drive_Letter_Msg has drive string
;	   Fatal_Error = NO
;
;Output: Fatal_Error = YES/NO
;
;Psuedocode
;----------
;	Put drive letter in ASCIIZ string "d:\",0
;	Do name translate call (INT 21)
;	IF drive not same
;	   Display assigned message
;	   Fatal_Error = YES
;	ENDIF
;	ret
;*****************************************************************************
;
Procedure Check_Translate_Drive 	;				;AN000;
	mov	al,Drive_Letter_Msg	;Get target drive letter into	;AN000;
	mov	TranSrc,al		; "d:\",0 string		;AN000;
	lea	si,TranSrc	 ;Point to translate string	 ;AN000;
	push	ds			;Set ES=DS (Data segment)	;     ;
	pop	es			;     "  "	"  "		;     ;
	lea	di,FatTbl	 ;Point at output buffer	 ;     ;
	DOS_Call xNameTrans		;Get real path			;AC000;
;	$IF	NC								;an017;bgb
	JC $$IF46
	    mov     bl,byte ptr [TranSrc]   ;Get drive letter from path     ;	  ;
	    cmp     bl,byte ptr [Fattbl]    ;Did drive letter change?	    ;	  ;
;	    $IF     NE			    ;If not the same, it be bad     ;AC000;
	    JE $$IF47
		Message SubstErr	    ;Tell user			    ;AC000;
		mov	Fatal_Error,Yes     ;Setup error flag		    ;AN000;
;	    $ENDIF			    ;				    ;AN000;
$$IF47:
;	$ELSE									;an017;bgb
	JMP SHORT $$EN46
$$IF46:
	    mov     Fatal_Error,Yes	;Setup error flag		;AN000; ;an017;bgb
	    mov     bx,1							;an017;bgb
	    mov     cx,bp ;zero 						;an017;bgb
	    mov     dx,0100h							;an017;bgb
	    call    sysdispmsg							;an017;bgb
;	$ENDIF				;				;AN000; ;an017;bgb
$$EN46:
	ret				;				;AN000;

Check_Translate_Drive endp		;				;AN000;

;*****************************************************************************
;Routine name: Hook_Interrupts
;*****************************************************************************
;
;Description: Change the interrupt handler for INT 13h to point to the
;	      ControlC_Handler routine
;
;Called Procedures: None
;
;Change History: Created	4/21/87 	MT
;
;Input: None
;
;Output: None
;
;Psuedocode
;----------
;
;	Point at ControlC_Handler routine
;	Set interrupt handler (INT 21h, AX=2523h)
;	ret
;*****************************************************************************
;
 Procedure Hook_Interrupts		 ;				 ;AN000;
	mov	al,23h
	DOS_Call Get_Interrupt_Vector	;Get the INT 23h handler	;AC000;
	mov	word ptr INT_23_Old_Off,bx ;
	mov	bx,es			;				;AN000;
	mov	word ptr INT_23_Old_Seg,bx ;				   ;AN000;
	mov	al,23h			;Specify CNTRL handler		;     ;
	lea	dx, INT_23	 ;Point at it			 ;     ;
	push	ds			;Save data seg			;     ;
	push	cs			;Point to code segment		;     ;
	pop	ds			;				;     ;
	DOS_Call Set_Interrupt_Vector	;Set the INT 23h handler	;AC000;
	pop	ds			;Get Data degment back		;     ;
	mov	al,24h			;
	DOS_Call Get_Interrupt_Vector	;Get the INT 24h handler	;AC000;
	mov	word ptr INT_24_Old_Off,bx ;Save it
	mov	bx,es			;				;AN000;
	mov	word ptr INT_24_Old_Seg,bx ;
	mov	al,24h			;Specify handler		 ;     ;
	lea	dx, INT_24	 ;Point at it			 ;     ;
	push	ds			;Save data seg			;     ;
	push	cs			;Point to code segment		;     ;
	pop	ds			;				;     ;
	DOS_Call Set_Interrupt_Vector	;Set the INT 23h handler	;AC000;
	pop	ds			;Get Data degment back		;     ;
	ret				;				;AN000;

 Hook_Interrupts endp			 ;				 ;AN000;

;*****************************************************************************
;Routine name: Hook_CNTRL_C
;*****************************************************************************
;
;Description: Change the interrupt handler for INT 13h to point to the
;	      ControlC_Handler routine
;
;Called Procedures: None
;
;Change History: Created	4/21/87 	MT
;
;Input: None
;
;Output: None
;
;Psuedocode
;----------
;
;	Point at ControlC_Handler routine
;	Set interrupt handler (INT 21h, AX=2523h)
;	ret
;*****************************************************************************
;
;rocedure Hook_CNTRL_C				;				;AN000;
;	mov	al,23H				;Specify CNTRL handler		;     ;
;	mov	dx, offset ControlC_Handler	;Point at it			;     ;
;	push	ds				;Save data seg			;     ;
;	push	cs				;Point to code segment		;     ;
;	pop	ds				;				;     ;
;	DOS_Call Set_Interrupt_Vector		;Set the INT 23h handler	;AC000;
;	pop	ds				;Get Data degment back		;     ;
;	ret					;				;AN000;
;ook_CNTRL_C endp				;				;AN000;
;
;ontrolC_Handler:
;	set_data_segment
;;;;;;; Message msgInterrupt			;				;AC000;
;;;;;;;;mov	ExitStatus, ExitCtrlC
;	jmp	ExitPgm
;*****************************************************************************
;Routine name: Clear_Append_X
;*****************************************************************************
;
;Description: Determine if Append /XA is turned on thru INT 2Fh, and shut
;	      off for life of RECOVER if it is.
;
;Called Procedures: None
;
;
;Change History: Created	5/13/87 	MT
;
;Input: None
;
;Output: APPEND = YES/NO
;
;Psuedocode
;----------
;
;	Append = NO
;	See if APPEND /X is present (INT 2Fh, AX=0B706h)
;	IF present
;	   Turn append /X off (INT 2Fh, AX=B707h, BX = 0)
;	   Append = YES
;	ENDIF
;	ret
;*****************************************************************************
;
Procedure Clear_Append_X		;				 ;AN000;
	mov	Append,NO		;Init the Append /X flag	;AN000;
	mov	ax,Append_X		;Is Append /X there?		;AN000;
	int	Multiplex		; "  "	   "  " 		;AN000;
	cmp	bx,Append_X_Set 	;Was it turned on?		;AN000;
;	$IF	E			;Yep				;AN000;
	JNE $$IF51
	    mov     Append,YES		;Indicate that it was on	;AN000;
	    mov     ax,Set_Append_X	;Turn Append /X off		;AN000;
	    xor     bx,bx ;Append_Off	    ; "  "    "  "		    ;AN000;
	    int     Multiplex		; "  "	  "  "			;AN000;
;	$ENDIF				;				;AN000;
$$IF51:
	ret				;				;AN000;

Clear_Append_X endp			;				;AN000;


;*****************************************************************************
;Routine name: RECOVER_IFS
;*****************************************************************************
;
;description:
;
;Called Procedures: Main_Routine
;		   EXEC_FS_RECOVER
;
;Change History: Created	5/8/87	       MT
;
;Input: FS_Not_FAT = Yes/No
;
;Output: None
;
;Psuedocode
;----------
;
;	IF File system other than FAT
;	   Go call file system specific RECOVER (CALL EXEC_FS_RECOVER)
;	ELSE
;	   Do FAT based RECOVER (CALL Main_Routine)
;	ENDIF
;	ret
;*****************************************************************************
;
Procedure RECOVER_IFS			;				;AN000;
ifdef fsexec									;an022;bgb
;	cmp	FS_Not_Fat,YES		;Is the target FS a FAT?	;AN000; ;an022;bgb
;	$IF	E			;No, so need to exec the	;AN000; ;an022;bgb
;	    call    EXEC_FS_RECOVER	; file system specific prog.	;AN000; ;an022;bgb
;	$ELSE				;It's a FAT                     ;AN000; ;an022;bgb
endif										;an022;bgb
	    call    clear_append_x	;BGB
	    call    Main_Routine	;Use canned code!		;AN000;
	    call    reset_append_x	;BGB
ifdef fsexec									;an022;bgb
;	$ENDIF				;				;AN000; ;an022;bgb
endif										;an022;bgb
	ret				;				;AN000;

RECOVER_IFS endp			;				;AN000;

;*****************************************************************************
;Routine name: Reset_Append_X
;*****************************************************************************
;
;description: If APPEND /XA was on originally, turn it back on
;
;Called Procedures: None
;
;
;Change History: Created	5/13/87 	MT
;
;Input: None
;
;Output: APPEND = YES/NO
;
;Psuedocode
;----------
;
;	IF APPEND = YES
;	   Turn append /X on (INT 2Fh, AX=B707h, BX = 1)
;	ENDIF
;	ret
;*****************************************************************************
;
Procedure Reset_Append_X		;				;AN000;
	cmp	Append,Yes		;Was Append /X on to start with?;AN000;
;	$IF	E			;Yep				;AN000;
	JNE $$IF53
	    mov     ax,Set_Append_X	;Turn Append /X off		;AN000;
	    mov     bx,Append_On	; "  "	  "  "			;AN000;
	    int     Multiplex		; "  "	  "  "			;AN000;
;	$ENDIF				;				;AN000;
$$IF53:
	ret				;				;AN000;

Reset_Append_X endp			;				;AN000;

	pathlabl recinit
code	ends
	end main_init ;AC000;bgb

