; FILENAME: AH.ASM
P386
IDEAL
JUMPS
LOCALS @_


include	'useful.inc'

;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
segment code
        org     100h
        assume cs:code, ds:code, es:nothing, ss:code
start:
        jmp     main


	KB_PAGE_UP              = 4900h
	KB_PAGE_DOWN            = 5100h
	KB_ESCAPE               = 011Bh
	KB_TAB			= 0F09h
	KB_SHIFT_TAB		= 0F00h
	KB_ENTER		= 1C0Dh
	KB_INSERT               = 5200h
	KB_HOME			= 4700h

	KB_F11			= 8500h

	KB_CTRL_F10		= 6700h
	SHORTCUT_HOTKEY         = KB_CTRL_F10
	KB_SOFTWARE_INTR 	= 16h

	KB_ALT_PLUS		= 8300h

	PASTE_HOTKEY		= KB_ALT_PLUS

        REM	   -- The Ctrl+S in Pascal and C/C++ is move left
	REM		Ctrl+D Ctrl+E and Ctrl+X are right, up, down
	REM	        respectively
	KB_CTRL_S		= 13h
	KB_CTRL_X		= 18h
	KB_CTRL_E		= 05h
	KB_CTRL_D		= 04h

        UP			= KB_CTRL_E
	DOWN			= KB_CTRL_X
	LEFT			= KB_CTRL_S
	RIGHT			= KB_CTRL_D

	REM -- this special symbol is use in pasting an example
	HOME			= 3

;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
        label   dosBusyFlagAddr dword
                dosBusyFlagOfs  dw ?
                dosBusyFlagSeg  dw ?

	REM	-- prev address of keyboard interrupt 16h
	label   preAHAddr      	dword
		preAHOffset     dw ?
		preAHSegment    dw ?

	initialMCBSegment	dw ?
        mcbAsciiNameLength      dw ?

        struc   langNameList
                len     dw ?
                desc    db 8 dup(NULL)
	ends

	WIN_X1   	  = 7
	WIN_Y1            = 3
	WIN_X2   	  = 73
	WIN_Y2   	  = 21
	WIN_FGCOLOR       = YELLOW
	WIN_BGCOLOR       = CYAN
	WIN_TITLEFGCOLOR  = WHITE
	WIN_TITLEBGCOLOR  = RED

	WIN_RELATED_FGCOLOR = BLACK
	WIN_RELATED_BGCOLOR = CYAN
	SHADOW_COLOR      = ( BLACK shl 4 ) or LIGHTGRAY


        cursorRowLoopVar        db ?
        cursorColLoopVar        db ?


        REM                     -- 4000 is 80x25 = 2000 chars + another 2000
        REM                             for the chars' attribute
        SCREEN_BUFFER_SIZE      = 4000
        helpWinBackSave         db SCREEN_BUFFER_SIZE dup(?)

        label   prevCursorPos   word
                prevCursorCol   db ?
                prevCursorRow   db ?


	pascalLang	langNameList< 5, 'TURBO' >
			langNameList< 2, 'TP' >
			langNameList< 3, 'TPX' >
			langNameList< 2, 'BP' >
			langNameList< 3, 'BPX' >
			langNameList< 6, 'PASCAL' >
                        db NULL

	ccplusLang      langNameList< 2, 'TC' >
			langNameList< 3, 'TCX' >
			langNameList< 2, 'BC' >
			langNameList< 3, 'BCX' >
			langNameList< 2, 'QC' >
			langNameList< 3, 'QCX' >
			langNameList< 1, 'C' >
                        db NULL




        langToDetect    dw ?


	helpFilename    db 'augment.hlp', NULL
	helpFilenameFullPath	db DOS_MAXPATHLEN dup(?)
	helpFileHandle  dw ?





        buffer          db ?
	bytesRead       dw ?



	struc	topicLink
		column		db ?
		row		db ?
		stringLength	db ?
		description	db 60 dup(?)
	ends

	REM			-- this is the index to the related topics
	relatedTopicIndex	dw ?
	relatedTopics		topicLink 70 dup(?)
	relatedTopicsCount      dw ?


	topicPageCount          dw ?
	topicCurrentPage	dw ?

	struc   topicPageFileLoc
		label 	dataDWord 	dword
			dataLoWord	dw ?
			dataHiWord  	dw ?
	ends

        topicFirstPageLoc	topicPageFileLoc <>
	topicPageLocList	topicPageFileLoc 15 dup(<>)



        REM     -- use for determining if the lines we read
        REM         already exceeds MAX_LINE_IN_A_PAGE
        lineCountTheFile        db ?

        REM     -- use for determining if the lines display in screen
        REM         already exceeds MAX_LINE_IN_A_PAGE
        lineCountTheScreen      dw ?

	MAX_LINE_IN_PAGE      = WIN_Y2 - WIN_Y1 - 2

	MAX_COLUMN_IN_PAGE    = 80

	BEEP			= 7

        keywordAtCursorLen      db ?
        keywordAtCursor         db 80 dup(?)
        keywordFromFileLen      db ?
        keywordFromFile         db 80 dup(?)


	clipboardLength		dw 0
	clipboardBuffer		db 10000 dup(?)
	clipboardLinesCount	dw ?


	ptrToText	        dw ?
	endingInsertOffset	dw ?

	stuffing		db FALSE


	dta			db 256 dup(?)

	prevDTASeg		dw ?
	prevDTAOffs		dw ?

;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
        proc    isLanguageInMem?
                push    ax
                push    bx
                push    cx
                push    ds
                push    si
                push    es
                push    di


        @_firstMCB:
		push	[cs:initialMCBSegment]
		pop	es

                push    cs
                pop     ds

;............................................................................
        @_traverseMCB:

                mov     bx, [cs:langToDetect]

	@_loopLang:

                mov     di, 0
                mov     cx, 8
        @_findMCBAsciiNameLength:
                inc     di
                cmp     [(mcb es:di).asciiName], NULL
                loopne  @_findMCBAsciiNameLength

                mov     [cs:mcbAsciiNameLength], di

                mov     cx, [(langNameList cs:bx).len]

                REM     -- if not same string length scan the
                REM        next language name
                cmp     cx, [cs:mcbAsciiNameLength]
                        ohNo    @_scanNextLanguageName

                lea     di, [es:mcb.asciiName]
                lea     si, [(langNameList cs:bx).desc]


                cld
                repe    cmpsb
                        ohYes   @_found


        @_scanNextLanguageName:

                add     bx, size langNameList
                cmp     [(langNameList cs:bx).desc], NULL
                        ohYes   @_stopScanningLang

		jmp     @_loopLang

        @_stopScanningLang:

	@_scanTheNextMCB:

                cmp     [es:mcb.linkIndicator], 'Z'
                je      @_notFound

                mov     ax, es
                inc     ax

                add     ax, [es:mcb.paragraphLen]
                mov     es, ax

                jmp     @_traverseMCB

;............................................................................
        @_found:
                ste
                jmp     @_finish

;............................................................................
        @_notFound:
                cle
                jmp     @_finish

        @_finish:

                pop     di
                pop     es
                pop     si
                pop     ds
                pop     cx
                pop     bx
                pop     ax

		ret
        endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
        proc    isPascalInMem?
        REM     Input(s):
        REM        langToDetect -- pass here to offset of name list of
        REM                        the language
        REM     Output(s):
        REM        Equality/Zero Flag -- if present in memory
;............................................................................
                mov     [cs:langToDetect], offset pascalLang
                call    isLanguageInMem?
                ret
        endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
        proc    isCCPlusplusInMem?
        REM     Input(s):
        REM        langToDetect -- pass here to offset of name list of
        REM                        the language
        REM     Output(s):
        REM        Equality/Zero Flag -- if present in memory
;............................................................................
                mov     [cs:langToDetect], offset ccplusLang
                call    isLanguageInMem?
                ret
        endp




;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
        proc    whatIsTheKeyword?
        REM     Purpose:
        REM             See if there is a word at the current cursor
        REM             position
        REM
        REM     Output Registers:
        REM             Equality clear if there is no keyword at cursor
	REM             Equality set if there is a keyword at cursor
        REM
        REM     Output Variables:
	REM             keywordAtCursor: data type = Pascal-like string
;............................................................................

                mov     ah, BIOS_GET_CURSOR_POS
                mov     bh, 0
                int     10h
                mov     [cs:prevCursorPos], dx
                mov     cx, dx

                mov     ah, BIOS_READ_CHAR_AT_POS
                mov     bh, 0
                int     10h


		cmp     al, '.'
			je      @_hasKeyword

                cmp     al, '0'
                        jl      @_checkCharAtLeft

		REM	-- the number 9 character
		REM	   precedes the colon character so
		REM	   it is just safe to do this kind
		REM	   of comparison
		cmp     al, ':'
                        jle     @_hasKeyword

                cmp     al, 'A'
                        jl      @_checkCharAtLeft

                cmp     al, 'Z'
                        jle     @_hasKeyword

                cmp     al, '_'
                        je      @_hasKeyword


                cmp     al, 'a'
                        jl      @_checkCharAtLeft

                cmp     al, 'z'
                        jle     @_hasKeyword

		jmp   	@_checkCharAtLeft

;............................................................................
        @_checkCharAtLeft:

                REM     -- now try if the character at the left
                REM        is also valid
                dec     cl
                mov     dx, cx
                mov     ah, BIOS_SET_CURSOR_POS
                mov     bh, 0
                int     10h

                mov     ah, BIOS_READ_CHAR_AT_POS
                mov     bh, 0
		int     10h

                cmp     al, '.'
			je      @_hasKeyword

                cmp     al, '0'
                        jl      @_noKeyword

		REM	-- the number 9 character
		REM	   precedes the colon character so
		REM	   it is just safe to do this kind
		REM	   of comparison
		cmp     al, ':'
                        jle     @_hasKeyword

                cmp     al, 'A'
                        jl      @_noKeyword

                cmp     al, 'Z'
                        jle     @_hasKeyword

                cmp     al, '_'
                        je      @_hasKeyword


                cmp     al, 'a'
                        jl      @_noKeyword

                cmp     al, 'z'
                        jle     @_hasKeyword


		jmp     @_noKeyword

;............................................................................
	@_hasKeyword:
                mov     dx, cx
                mov     ah, BIOS_SET_CURSOR_POS
                mov     bh, 0
                int     10h

                REM     -- loop until no more valid char

        @_loopWhileValidChar:
                REM     -- this loop will go the beginning of the string

                mov     ah, BIOS_READ_CHAR_AT_POS
                mov     bh, 0
		int     10h

                cmp     al, '.'
			je      @_checkNextChar

                cmp     al, '0'
                        jl      @_noMoreValid

		REM	-- the number 9 character
		REM	   precedes the colon character so
		REM	   it is just safe to do this kind
		REM	   of comparison
		cmp     al, ':'
                        jle     @_checkNextChar

                cmp     al, 'A'
                        jl      @_noMoreValid

                cmp     al, 'Z'
                        jle     @_checkNextChar

                cmp     al, '_'
                        je      @_checkNextChar


                cmp     al, 'a'
                        jl      @_noMoreValid

                cmp     al, 'z'
                        jle     @_checkNextChar


        @_checkNextChar:

                dec     cl
                mov     dx, cx
                mov     ah, BIOS_SET_CURSOR_POS
                mov     bh, 0
                int     10h

                jmp     @_loopWhileValidChar


;............................................................................
        @_noMoreValid:
                REM     -- go to valid character
                inc     cl

                mov     dx, cx
                mov     ah, BIOS_SET_CURSOR_POS
                mov     bh, 0
                int     10h

                REM     -- it is customary to use CX as a counter
                REM        but since we use CX as a row and column,
                REM        we had to find another register to store
                REM        the length of the string
                REM        in this case we had to choose DI register

                REM     -- length of string is 0 tentatively
                mov     di, 0
                mov     si, offset keywordAtCursor

                mov     ah, BIOS_READ_CHAR_AT_POS
                mov     bh, 0
		int     10h

                jmp     @_collectNow

;............................................................................
	@_collectNow:
                REM     -- collect chararacters


                mov     [byte cs:si], al

                REM     -- increment keyword length
                inc     di
                inc     si

                mov     ah, BIOS_SET_CURSOR_POS
                mov     bh, 0
                inc     cl
                mov     dx, cx
                int     10h

                mov     ah, BIOS_READ_CHAR_AT_POS
                mov     bh, 0
		int     10h

		cmp     al, '.'
			je      @_collectNow

		cmp     al, '0'
			jl      @_stopCollecting

		REM	-- the number 9 character
		REM	   precedes the colon character so
		REM	   it is just safe to do this kind
		REM	   of comparison
		cmp     al, ':'
			jle     @_collectNow

		cmp     al, 'A'
			jl      @_stopCollecting

		cmp     al, 'Z'
			jle     @_collectNow

		cmp     al, '_'
			je      @_collectNow


		cmp     al, 'a'
			jl      @_stopCollecting

		cmp     al, 'z'
			jle     @_collectNow

		jmp	@_stopCollecting

	@_stopCollecting:

                REM     -- finish collecting save the string length
                REM        and restore the previous cursor position

		mov     dx, di
		mov     [cs:keywordAtCursorLen], dl

                mov     ah, BIOS_SET_CURSOR_POS
                mov     bh, 0
                mov     dx, [cs:prevCursorPos]
                int     10h

                ste
                ret

;............................................................................
        @_noKeyword:

                mov     ah, BIOS_SET_CURSOR_POS
                mov     bh, 0
                mov     dx, [cs:prevCursorPos]
                int     10h

                cle
                ret
        endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
        proc    preserveBackground

                REM     -- save first the background
                mov     ah, BIOS_GET_CURSOR_POS
                mov     bh, 0
                int     10h
                mov     [cs:prevCursorPos], dx

                REM     -- B800h is the segment address of the
                REM           CGA, VGA system
                push    0B800h
                pop     ds
                mov     si, 0

                push    cs
                pop     es
                mov     di, offset helpWinBackSave

                mov     cx, SCREEN_BUFFER_SIZE
                cld
                rep     movsb

                ret
        endp

;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
        proc    restoreBackground

                push    cs
                pop     ds
                mov     si, offset helpWinBackSave


                push    0B800h
                pop     es
                mov     di, 0

                cld
                mov     cx, SCREEN_BUFFER_SIZE
                rep     movsb

                mov     ah, BIOS_SET_CURSOR_POS
                mov     bh, 0
                mov     dx, [cs:prevCursorPos]
                int     10h

                ret
        endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
        proc    showWindow

                push    cs
                pop     ds

                mov     ah, BIOS_SCROLL_WIN_UP
                mov     al, WIN_Y2
                sub     al, WIN_Y1
                inc     al
                mov     bh, WIN_BGCOLOR
                shl     bh, 4
                or      bh, WIN_FGCOLOR
                mov     ch, WIN_Y1
                mov     cl, WIN_X1
                mov     dh, WIN_Y2
                mov     dl, WIN_X2
                int     10h


                mov     ah, BIOS_SET_CURSOR_POS
                mov     bh, 0
                mov     dl, WIN_X1
                mov     dh, WIN_Y1
                int     10h

                mov     ah, BIOS_WRITE_CHAR_ATTR
                mov     al, ' '
                mov     bh, 0
                mov     bl, WIN_TITLEBGCOLOR
                shl     bl, 4
                or      bl, WIN_TITLEFGCOLOR
                mov     cx, 0
                mov     cl, WIN_X2
                sub     cl, WIN_X1
                inc     cx
                int     10h

                puts    ' Augmented Help for C/C++ and Pascal '


                mov     al, WIN_Y1
                inc     al
                mov     [cs:cursorRowLoopVar], al

        @_loopSide:
                mov     al, WIN_Y2
                inc     al
                cmp     [cs:cursorRowLoopVar], al
                        jg      @_finishWithSide

                mov     ah, BIOS_SET_CURSOR_POS
                mov     bh, 0
                mov     dh, [cs:cursorRowLoopVar]
                mov     dl, WIN_X2
                inc     dl
                int     10h

                mov     ah, BIOS_READ_CHAR_ATTR
                mov     bh, 0
                int     10h

                REM     -- now let us put a shadow
                mov     bl, SHADOW_COLOR
                mov     ah, BIOS_WRITE_CHAR_ATTR
                mov     bh, 0
                mov     cx, 1
                int     10h

                mov     ah, BIOS_SET_CURSOR_POS
                mov     bh, 0
                mov     dh, [cs:cursorRowLoopVar]
                mov     dl, WIN_X2
                add     dl, 2
                int     10h
                
                mov     ah, BIOS_READ_CHAR_ATTR
                mov     bh, 0
                int     10h

                REM     -- now let us put a shadow
                mov     bl, SHADOW_COLOR
                mov     ah, BIOS_WRITE_CHAR_ATTR
                mov     bh, 0
                mov     cx, 1
                int     10h

                inc     [cs:cursorRowLoopVar]
                jmp     @_loopSide

        @_finishWithSide:


                mov     al, WIN_X1
                add     al, 2
                mov     [cs:cursorColLoopVar], al

        @_loopBottom:
                mov     al, WIN_X2
                add     al, 2
                cmp     [cs:cursorColLoopVar], al
                        je      @_finishWithBottom

                mov     ah, BIOS_SET_CURSOR_POS
                mov     bh, 0
                mov     dh, WIN_Y2
                inc     dh
                mov     dl, [cs:cursorColLoopVar]
                int     10h

                mov     ah, BIOS_READ_CHAR_ATTR
                mov     bh, 0
                int     10h

                REM     -- now let us put a shadow
                mov     bl, SHADOW_COLOR
                mov     ah, BIOS_WRITE_CHAR_ATTR
                mov     bh, 0
                mov     cx, 1
                int     10h

                inc     [cs:cursorColLoopVar]
                jmp     @_loopBottom

        @_finishWithBottom:

                ret
	endp

;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
	proc	getCurrentFilePointer
	REM	Input Register(s):
	REM		BX -- file handle
	REM	Output Register(s):
	REM		DX:AX -- new file pointer location
;............................................................................
		push	bx
		push	cx
		mov	ah, DOS_FILE_MOVE_PTR
		mov	al, DOS_FILE_CURRENT
		mov	cx, 0
		mov	dx, 0
		int	21h
		pop	cx
		pop	bx
		ret
	endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
	proc    displayTheChar
		TAB 	= 9

		push    ax
		push    bx
		push	cx
		push	dx

		cmp     [buffer], TAB
			ohYes	@_displayTab


		

		mov	ah, BIOS_READ_CHAR_ATTR
		mov	bh, 0
		int 	10h

		mov	bl, ah
		mov	ah, BIOS_WRITE_CHAR_ATTR
		mov	al, [buffer]
		mov	bh, 0
		mov	cx, 1
		int	10h

                mov	ah, BIOS_GET_CURSOR_POS
		mov 	bh, 0
		int	10h

		inc	dl

		mov	ah, BIOS_SET_CURSOR_POS
		mov	bh, 0
		int	10h

		jmp	@_finish

	@_displayTab:
		mov	cx, 8
	@_displaySpace:
		push	cx

		mov	ah, BIOS_READ_CHAR_ATTR
		mov	bh, 0
		int 	10h

		mov	bl, ah
		mov	ah, BIOS_WRITE_CHAR_ATTR
		mov	al, ' '
		mov	bh, 0
		mov	cx, 1
		int	10h


                mov	ah, BIOS_GET_CURSOR_POS
		mov 	bh, 0
		int	10h

		inc	dl

		mov	ah, BIOS_SET_CURSOR_POS
		mov	bh, 0
		int	10h

		pop	cx
		loop	@_displaySpace
		jmp	@_finish

	@_finish:
		pop	dx
		pop	cx
		pop     bx
		pop     ax
		ret
	endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
	REM	Input(s):
	REM		BX = offset of topic link
	proc	unfocusHighlight

		pusha

		mov	di, bx

		lea	si, [(relatedTopics+bx).description]

                mov	ch, 0
		mov	cl, [(relatedTopics+bx).stringLength]

		mov	ah, BIOS_SET_CURSOR_POS
		mov	bh, 0
		mov	dl, [(relatedTopics+di).column]
		mov	dh, [(relatedTopics+di).row]
		int	10h

		lodsb

		cld
	@_displayHighlightedRelated:

                push	cx
		push	bx

		mov	ah, BIOS_WRITE_CHAR_ATTR
		mov	cx, 1
		mov	bl, WIN_RELATED_BGCOLOR
		shl	bl, 4
		or	bl, WIN_RELATED_FGCOLOR
		int	10h

                mov	ah, BIOS_SET_CURSOR_POS
		mov	bh, 0
		inc	dl
		int	10h

		pop	bx
		pop	cx

		lodsb
		loop	@_displayHighlightedRelated

		popa

		ret
	endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
	REM	Input(s):
	REM		BX = offset of topic link
	proc	focusHighlight


		pusha

		mov	di, bx

		lea	si, [(relatedTopics+bx).description]

                mov	ch, 0
		mov	cl, [(relatedTopics+bx).stringLength]

		mov	ah, BIOS_SET_CURSOR_POS
		mov	bh, 0
		mov	dl, [(relatedTopics+di).column]
		mov	dh, [(relatedTopics+di).row]
		int	10h

		lodsb

		cld
	@_displayHighlightedRelated:

                push	cx
		push	bx

		mov	ah, BIOS_WRITE_CHAR_ATTR
		mov	cx, 1
		mov	bl, WIN_RELATED_FGCOLOR
		shl	bl, 4
		or	bl, WIN_RELATED_BGCOLOR
		int	10h

                mov	ah, BIOS_SET_CURSOR_POS
		mov	bh, 0
		inc	dl
		int	10h

		pop	bx
		pop	cx

		lodsb
		loop	@_displayHighlightedRelated

		popa

		ret
	endp



;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
        proc    displayTopic
                REM                     -- this is letter T
                TOPIC_MARKER            = 20

		REM                     -- this is letter S
		SAMPLE_MARKER           = 19

                REM                     -- this is letter X
		END_OF_TOPIC_MARKER     = 24


		REM                     -- this is letter A
		RELATED_TOPIC_MARKER    = 1

		REM                     -- this is Ctrl+Z
		EOF_OF_TEXT             = 26

		REM			-- this is the carriage return
		NEXTLINE_MARKER         = 0Dh
;............................................................................


                REM     -- we will concentrate more on our data segment
                REM          so we must point DS segment to our code
                REM          segment, so we can just avoid
		REM          the numerous segment override prefix,
                REM        just in case you are a beginning assembly
                REM          programmer, segment override prefix is
		REM          like this: mov [cs:helpFileHandle], where
                REM          you always explicit places a segment
                REM          prefix( cs, ds, es, ss ).  at the beginning
                REM          of every variable
		REM        the following two instructions will prevent
                REM          tedious typing of segment prefix
                push    cs
                pop     ds

		mov	ah, DOS_GET_DTA
		int	21h

		push	es
		pop	[prevDTASeg]

		push	bx
		pop	[prevDTAOffs]


		mov	ah, DOS_SET_DTA
		mov	dx, offset dta
		int	21h


		BUG	-- this following lines are missing from
		BUG        the distributed disketee causing an
		BUG	   a very serious error which when
		BUG	   the 'augment.hlp' file is missing,
		BUG	   the system will simply hang.
		BUG	   now in this code, the system will
		BUG        not hang it will just sound a beep
		BUG	   when the help file is not present

		mov	ah, DOS_FILE_FIND_FIRST
		mov	dx, offset helpFilenameFullpath
		int	21h

		jnc	@_fileExisting


		mov	dx, [prevDTAOffs]
		push	[prevDTASeg]
		pop	ds
		mov	ah, DOS_SET_DTA
		int	21h

		mov	ah, DOS_DISPLAY_OUTPUT
		mov	dl, BEEP
		int	21h

		ret

	@_fileExisting:

                push    cs
		pop     es

		mov     ah, DOS_FILE_OPEN
		mov	al, READ_ACCESS
		mov     dx, offset helpFilenameFullpath
                int     21h
		mov     [helpFileHandle], ax


	@_readFromTop:
		mov	[clipboardLength], 0

		mov	ah, DOS_FILE_MOVE_PTR
		mov	al, DOS_FILE_BEGIN
		mov	bx, [helpFileHandle]
		mov	cx, 0
		mov	dx, 0
		int	21h


                REM     -- read first character at line
                mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
                int     21h

                jmp     @_loopUntilTopicFoundOrEOF

        @_loopUntilTopicFoundOrEof:

	@_loopUntilTopicMarkerFound:
		cmp     ax, 0
			ohYes   @_noTopicFound

                cmp     [buffer], TOPIC_MARKER
			ohYes   @_whatIsTheTopic



                mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
		int     21h

                jmp     @_loopUntilTopicMarkerFound

        @_whatIsTheTopic:
                REM     -- skip marker
                mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
                int     21h

                mov     [bytesRead], ax

                REM     -- register DI will be our counter for
                REM        number of characters of keyword from file
                mov     di, 0
                mov     si, offset keywordFromFile

                jmp     @_loopUntilKeywordEoln

	@_loopUntilKeywordEoln:

                cmp     [bytesRead], 0
                        ohYes   @_stopReading

                cmp     [buffer], NEXTLINE_MARKER
                        ohYes   @_keywordFromFileFinish

                mov     al, [buffer]
                mov     [byte si], al

                mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
                int     21h


                inc     di
                inc     si
                jmp     @_loopUntilKeywordEoln

        @_keywordFromFileFinish:
		mov     dx, di
                mov     [keywordFromFileLen], dl


                mov     al, [keywordAtCursorLen]
                mov     bl, [keywordFromFileLen]
                cmp     al, bl
                        ohNo    @_stringLenNotMatch


                mov     ch, 0
                mov     cl, [keywordAtCursorLen]
                mov     si, offset keywordAtCursor
                mov     di, offset keywordFromFile
                cld
                repe    cmpsb
                        ohNo    @_loopUntilTopicFoundOrEOF

                jmp     @_topicFound

        @_stringLenNotMatch:
                mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
                int     21h

                jmp     @_loopUntilTopicFoundOrEof


;............................................................................
	@_noTopicFound:

		push	ax
		push	dx
		mov	ah, DOS_DISPLAY_OUTPUT
		mov	dl, 07
		int	21h
		pop	dx
		pop	ax
		jmp	@_stopReading


;............................................................................
	@_topicFound:

                mov     [topicPageCount], 0

		REM     -- skip NEW LINE character ASCII 0Ah
		mov     ah, DOS_FILE_READ
		mov     bx, [helpFileHandle]
		mov     dx, offset buffer
		mov     cx, size buffer
		int     21h

                REM     -- for the moment let's make this simpler

                REM      -- display immediately the character


                call    preserveBackground

                call    showWindow

                push    cs
                pop     ds

                push    cs
		pop     es

                


		mov	bx, [helpFileHandle]
		call	getCurrentFilePointer


                mov	[topicFirstPageLoc.dataHiWord], dx
		mov	[topicFirstPageLoc.dataLoWord], ax

		mov	[topicPageLocList.dataHiWord], dx
		mov	[topicPageLocList.dataLoWord], ax

		mov	[topicPageCount], 0
                mov	[lineCountTheFile], 0

	@_savePagesLocation:

		mov	[bytesRead], ax

		cmp	[bytesRead], 0
			ohYes	@_savePagesLocationFinished

		cmp	[buffer], NEXTLINE_MARKER
			ohYes   @_incrementLine

		cmp	[buffer], SAMPLE_MARKER
			ohYes	@_copySample

		cmp     [buffer], END_OF_TOPIC_MARKER
			ohYes   @_savePagesLocationFinished

		mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
                int     21h


		jmp     @_savePagesLocation

	@_incrementLine:
		inc	[lineCountTheFile]
		cmp	[lineCountTheFile], MAX_LINE_IN_PAGE
			ohYes	@_saveThePageLocation

		REM	-- this will skip the newline character
		mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
                int     21h

		jmp	@_savePagesLocation

	@_saveThePageLocation:
		mov	[lineCountTheFile], 0
		inc	[topicPageCount]

		REM	-- this will skip the newline character
		mov     ah, DOS_FILE_READ
		mov     bx, [helpFileHandle]
		mov     dx, offset buffer
		mov     cx, size buffer
		int     21h

		mov	bx, [helpFileHandle]
		call    getCurrentFilePointer

		REM	-- this is not a heavy trick, this is very
		REM         common in assembly language routines,
		REM	    where if you want to multiply the number
		REM	    by increment of twos you can shift left
		REM 	    it, instead of using the mul instruction.
		REM	    Since we want to multiply by 4(size of
		REM	    doubleword), we must shift left by 2.
                mov	bx, [topicPageCount]
		shl	bx, 2

		mov	[(topicPageLocList+bx).dataHiWord], dx
		mov	[(topicPageLocList+bx).dataLoWord], ax

		jmp	@_savePagesLocation


	@_copySample:

		REM	-- this will skip the Carriage Return character
		mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
                int     21h

		mov     [bytesRead], ax

		REM	-- this will skip the Linefeed character
		mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
                int     21h

		mov     [bytesRead], ax

		mov	[clipboardLinesCount], 0
		mov	[clipboardLength], 0

		mov	si, offset clipboardBuffer

	@_collectSample:
                mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
                int     21h

		mov     [bytesRead], ax

		cmp	[buffer], NEXTLINE_MARKER
			ohYes	@_incClipboardLinesCount

		cmp	[buffer], END_OF_TOPIC_MARKER
			ohYes	@_finishCopyingClipboard

		mov	al, [buffer]
		mov     [byte si], al
		inc	si
		inc     [clipboardLength]

		jmp	@_collectSample

	@_incClipboardLinesCount:
        	mov	al, [buffer]
		mov     [byte si], al
		inc	si

		REM	-- skip the newline character
		mov     ah, DOS_FILE_READ
		mov     bx, [helpFileHandle]
		mov     dx, offset buffer
		mov     cx, size buffer
		int     21h

		mov     [bytesRead], ax

		inc	[clipboardLinesCount]
		inc	[clipboardLength]

		mov	[byte si], HOME
		inc	si

		inc	[clipboardLength]

		jmp	@_collectSample

	@_finishCopyingClipboard:

		mov	cx, [clipboardLinesCount]
		add	[clipboardLength], cx

	@_insertUPS:
		mov     [byte si], UP
		inc	si

		loop	@_insertUPS

		jmp	@_savePagesLocationFinished


	@_savePagesLocationFinished:

		jmp	@_dumpInformation



;............................................................................
	@_dumpInformation:


		mov	[topicCurrentPage], 0
	@_dumpInformationLoop:

		REM	-- 0 as of the moment, we have not yet dumped
		REM	   the whole page
		mov	[relatedTopicsCount], 0


		call    showWindow
		push	cs
		pop	ds

		push	cs
		pop	es

		REM	-- it is customary to use register BX as base
		REM	    register for array but since we ran out of
		REM	    register variables, we opt use the SI register
		mov     si, [topicCurrentPage]
		shl	si, 2

		mov	ah, DOS_FILE_MOVE_PTR
		mov	al, DOS_FILE_BEGIN
		mov	bx, [helpFileHandle]
		mov	cx, [(topicPageLocList+si).dataHiWord]
		mov	dx, [(topicPageLocList+si).dataLoWord]
		int	21h

                REM     -- dump the character in the window

                mov     [lineCountTheScreen], 0

	@_loopRow:
        	mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
                int     21h

		mov     [bytesRead], ax

                mov     cx, [lineCountTheScreen]
		add     cx, WIN_Y1+1
                inc     cx
                mov     ah, BIOS_SET_CURSOR_POS
                mov     bh, 0
		mov     dl, WIN_X1+2
                mov     dh, cl
                int     10h



		cmp     [lineCountTheScreen], MAX_LINE_IN_PAGE
			ohYes   @_finishDisplayPage

		inc     [lineCountTheScreen]

        @_loopUntilEoln:
                cmp     [bytesRead], 0
                        ohYes   @_finishDisplayLine

                cmp     [buffer], NEXTLINE_MARKER
			ohYes   @_finishDisplayLine

		cmp	[buffer], RELATED_TOPIC_MARKER
			ohYes	@_linkTheTopic

		cmp	[buffer], SAMPLE_MARKER
			ohYes	@_sampleFound

                cmp     [buffer], END_OF_TOPIC_MARKER
                        ohYes   @_finishDisplayPage



		call	displayTheChar

                mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
                int     21h

                mov     [bytesRead], ax

                jmp     @_loopUntilEoln

        @_finishDisplayLine:
		REM     -- this will skip the new line character
		mov     ah, DOS_FILE_READ
		mov     bx, [helpFileHandle]
		mov     dx, offset buffer
		mov     cx, size buffer
		int     21h

                mov     [bytesRead], ax

                jmp     @_loopRow


;............................................................................
	@_sampleFound:
		push	ax
		push	bx
		push	dx
                mov     ah, BIOS_SET_CURSOR_POS
                mov     bh, 0
		mov     dl, WIN_X2-2
		mov     dh, WIN_Y1
		int     10h

		mov	ah, DOS_DISPLAY_OUTPUT
		REM	-- happy face
		mov	dl, 1
		int	21h
		pop	dx
		pop	bx
		pop	ax

;............................................................................
	@_finishDisplayPage:
		REM	-- is related topics not available ?
		cmp	[relatedTopicsCount], 0
			je      @_controlPageByKey


		REM	-- available so highlight all the related topics

		mov	bx, 0

	@_highlightRelateds:

		imul	di, bx, size topicLink


		lea	si, [(relatedTopics+di).description]

                mov	ch, 0
		mov	cl, [(relatedTopics+di).stringLength]

		mov	ah, BIOS_SET_CURSOR_POS
		mov	bh, 0
		mov	dl, [(relatedTopics+di).column]
		mov	dh, [(relatedTopics+di).row]
		int	10h

		lodsb

		cld
	@_displayHighlightedRelated:

                push	cx
		push	bx

		mov	ah, BIOS_WRITE_CHAR_ATTR
		mov	cx, 1
		mov	bl, WIN_RELATED_BGCOLOR
		shl	bl, 4
		or	bl, WIN_RELATED_FGCOLOR
		int	10h

                mov	ah, BIOS_SET_CURSOR_POS
		mov	bh, 0
		inc	dl
		int	10h

		pop	bx
		pop	cx

		lodsb
		loop	@_displayHighlightedRelated

		inc	bx
		cmp	bx, [relatedTopicsCount]
			jl	@_highlightRelateds


		mov	[relatedTopicIndex], 0

		mov	ax, [relatedTopicIndex]
		imul	bx, ax, size topicLink

		call	focusHighlight

		jmp	@_controlPageByKey


;............................................................................
	@_linkTheTopic:
		REM     -- this will skip the tag marker
                mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
		int     21h

		mov	ah, BIOS_GET_CURSOR_POS
		mov	bh, 0
		int	10h

		mov	ax, [relatedTopicsCount]
		imul	bx, ax, size topicLink

		mov	[(relatedTopics+bx).column], dl
		mov	[(relatedTopics+bx).row], dh

		mov	[(relatedTopics+bx).stringLength], 0
		lea	si, [(relatedTopics+bx).description]
		jmp	@_displayRelatedTopicChars


	@_displayRelatedTopicChars:

		cmp	[buffer], RELATED_TOPIC_MARKER
			ohYes	@_finishCollectingRelatedTopicChars

		mov	al, [buffer]
		mov	[byte si], al

		call	displayTheChar

                push	bx
		mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
		int     21h
		pop	bx


		inc	[(relatedTopics+bx).stringLength]
		inc	si
		jmp	@_displayRelatedTopicChars


	@_finishCollectingRelatedTopicChars:

                mov     ah, DOS_FILE_READ
                mov     bx, [helpFileHandle]
                mov     dx, offset buffer
                mov     cx, size buffer
                int     21h

		mov     [bytesRead], ax

		inc	[relatedTopicsCount]

		jmp	@_loopUntilEoln



;............................................................................
        @_controlPageByKey:
                mov     ah, BIOS_OLD_READKEY
                pushf
                call    [preAHAddr]

                cmp     ax, KB_ESCAPE
			ohYes   @_backToTheEditor

		cmp	ax, KB_PAGE_UP
			ohYes	@_goToPrevPage

		cmp	ax, KB_PAGE_DOWN
			ohYes	@_goToNextPage

		cmp	ax, KB_SHIFT_TAB
			ohYes	@_highlightPrevTopic

		cmp	ax, KB_TAB
			ohYes	@_highlightNextTopic

		cmp	ax, KB_ENTER
			ohYes	@_changeTopic

		cmp	ax, KB_INSERT
			ohYes	@_insertSample

                jmp     @_controlPageByKey

;............................................................................
	@_insertSample:
		cmp	[clipboardLength], 0
			je	@_controlPageByKey

		mov	[ptrToText], offset clipboardBuffer
		mov	bx, [clipboardLength]
		lea     ax, [clipboardBuffer+bx]
		mov	[endingInsertOffset], ax

		jmp	@_backToTheEditor

;............................................................................
	@_highlightPrevTopic:
		cmp	[relatedTopicsCount], 0
			je	@_controlPageByKey

		cmp	[relatedTopicIndex], 0
			je	@_highlightPrevTopicContinue

                call	unfocusHighlight
		dec     [relatedTopicIndex]
		mov	ax, [relatedTopicIndex]
		imul	bx, ax, size topicLink
		call	focusHighlight

		jmp	@_highlightPrevTopicContinue

	@_highlightPrevTopicContinue:
		jmp	@_controlPageByKey


;............................................................................
	@_highlightNextTopic:
        	cmp	[relatedTopicsCount], 0
			je	@_controlPageByKey

		mov	ax, [relatedTopicsCount]
		dec	ax
		cmp	[relatedTopicIndex], ax
			jnl	@_highlightNextTopicContinue


		call	unfocusHighlight
		inc     [relatedTopicIndex]
		mov	ax, [relatedTopicIndex]
		imul	bx, ax, size topicLink
		call	focusHighlight

		jmp	@_highlightNextTopicContinue

	@_highlightNextTopicContinue:
		jmp     @_controlPageByKey


;............................................................................
	@_changeTopic:
		mov	ax, [relatedTopicIndex]
		imul	bx, ax, size topicLink

		mov	cl, [(relatedTopics+bx).stringLength]
		mov	[keywordAtCursorLen], cl
		lea	si, [(relatedTopics+bx).description]
		mov	di, offset keywordAtCursor
		mov	ch, 0
		cld
		rep	movsb

		call    restoreBackground
		push	cs
		pop	es
		jmp	@_readFromTop


;............................................................................
	@_goToPrevPage:
		cmp	[topicCurrentPage], 0
			je	@_goToPrevPageContinue

		dec	[topicCurrentPage]
		jmp     @_dumpInformationLoop

	@_goToPrevPageContinue:
        	jmp     @_controlPageByKey


;............................................................................
	@_goToNextPage:
		mov	ax, [topicPageCount]
		cmp	[topicCurrentPage], ax
			jnl	@_goToNextPageContinue

		inc	[topicCurrentPage]
                jmp     @_dumpInformationLoop

	@_goToNextPageContinue:
		jmp	@_controlPageByKey

;............................................................................
	@_backToTheEditor:


        @_unpopWindow:
                call    restoreBackground

        @_stopReading:

		mov	dx, [prevDTAOffs]
		push	[prevDTASeg]
		pop	ds
		mov	ah, DOS_SET_DTA
		int	21h

                push    cs
                pop     ds


                mov     ah, DOS_FILE_CLOSE
                mov     bx, [helpFileHandle]
                int     21h

                ret


        endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
	proc    doHelp
		pushf

		push	ax
		push	bx
		push	cx
		push	dx
		push	si
		push	ds
		push	di
		push	es



                call    whatIsTheKeyword?
			ohNo    @_noTopicAtCursor

                jmp     @_topicAtCursor

	@_quiet:

		pop	es
		pop	di
		pop	ds
		pop	si
		pop	dx
		pop	cx
		pop	bx
                pop	ax
		popf
                ret


	@_topicAtCursor:

		

		call    displayTopic
                pop	es
		pop	di
		pop	ds
		pop	si
		pop	dx
		pop	cx
		pop	bx
                pop	ax
		popf
                ret

        @_noTopicAtCursor:
		REM     -- put a message here, or just beep


                mov	[cs:keywordAtCursor], 'M'
		mov	[cs:keywordAtCursor+1], 'L'
		mov	[cs:keywordAtCursor+2], 'T'
		mov	[cs:keywordAtCursor+3], 'H'
		mov	[cs:keywordAtCursorLen], 4

		call    displayTopic

		pop	es
		pop	di
		pop	ds
		pop	si
		pop	dx
		pop	cx
		pop	bx
                pop	ax
		popf
                ret
	endp



;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
        proc    keyIntercept
		jmp	@_beginning

		tsrMarker	db 'AH-MLTH'

	@_beginning:


		pushf
                push    es
                push    di
                les     di, [cs:dosBusyFlagAddr]
                cmp     [byte ptr es:di], 0
			ohYes    @_continueBeginningLanguage
	@_donotContinueBeginningLanguage:
		pop	di
		pop	es
		popf
		jmp	[cs:preAHAddr]
	@_continueBeginningLanguage:
                pop     di
                pop     es
		popf



                call    isPascalInMem?
			ohYes	@_continueBeginningPascal
		call	isCCPlusplusInMem?
			ohYes	@_continueBeginningCCPlusplus

		jmp	@_doOld


;............................................................................
	@_continueBeginningPascal:
		jmp	@_continueBeginning

;............................................................................
	@_continueBeginningCCPlusplus:
		jmp	@_continueBeginning

;............................................................................
	@_continueBeginning:

                cmp     ah, BIOS_OLD_READKEY
                        ohYes   @_tryKeyread

                cmp     ah, BIOS_NEW_READKEY
                        ohYes   @_tryKeyread

		cmp	ah, BIOS_OLD_KEYSTAT
			ohYes	@_tryKeystat

		cmp	ah, BIOS_NEW_KEYSTAT
			ohYes	@_tryKeystat

		jmp     @_doOld


;............................................................................
	@_tryKeystat:
		cmp	[cs:stuffing], TRUE
			ohYes	@_keystatInsert

		pushf
		call	[cs:preAHAddr]
		;;;;

		jnz	@_keystatTestPasting
		stz
		retf	2

	@_keystatTestPasting:
		cmp	ax, PASTE_HOTKEY
			ohYes	@_keystatInsertIntro

		cmp	ax, KB_F11
			ohYes	@_keystatInsertIntroF11


		clz
		retf	2

	@_keystatInsertIntro:
		mov	ah, BIOS_OLD_READKEY
		pushf
		call	[cs:preAHAddr]

		mov	[cs:stuffing], TRUE
		jmp	@_keystatInsert


	@_keystatInsertIntroF11:
		mov	ah, BIOS_NEW_READKEY
		pushf
		call	[cs:preAHAddr]

		mov	[cs:stuffing], TRUE
		jmp	@_keystatInsert

	@_keystatInsert:

		push	bx

		mov	ah, 00h
		mov	bx, [cs:ptrToText]
		mov	al, [byte cs:bx]

		cmp	bx, [cs:endingInsertOffset]
			jl	@_continueKeystatInsert

		mov	[cs:stuffing], FALSE
		pop	bx

		stz
		retf	2


	@_continueKeystatInsert:
		mov	[cs:stuffing], TRUE


		cmp	al, HOME
			ohYes	@_keystatInsertHome

		jmp	@_keystatInsertOrdinary

	@_keystatInsertHome:
		pop	bx

		mov	ax, KB_HOME

		clz
		retf	2


	@_keystatInsertOrdinary:
		pop	bx
		clz
		retf	2

;............................................................................
	@_tryKeyread:
		cmp	[cs:stuffing], TRUE
			ohYes	@_keyreadInsert

		pushf
		call	[cs:preAHAddr]

		cmp	ax, SHORTCUT_HOTKEY
			ohYes    @_performHelp

		cmp	ax, PASTE_HOTKEY
			ohYes	@_keyreadPasteExample

		cmp	ax, KB_F11
			ohYes 	@_keyreadPasteExample

		jmp	@_normalKey


	@_keyreadPasteExample:
		mov	[cs:stuffing], TRUE
		jmp     @_keyreadInsert


	@_performHelp:

		call    doHelp

		iret

	@_keyreadInsert:

		push	bx

		mov	ah, 00h
		mov	bx, [cs:ptrToText]
		mov	al, [byte cs:bx]

		cmp	bx, [cs:endingInsertOffset]
		setl	[cs:stuffing]

		pop	bx

		cmp	al, HOME
			ohYes	@_keyreadInsertHome

		jmp	@_keyreadInsertOrdinary

	@_keyreadInsertHome:

		mov	ax, KB_HOME
		inc	[cs:ptrToText]
		dec	[cs:clipboardLength]


		iret


	@_keyreadInsertOrdinary:

                inc	[cs:ptrToText]
		dec	[cs:clipboardLength]


		iret


;............................................................................
	@_normalKey:
                iret


;............................................................................
	@_doOld:
		jmp	[cs:preAHAddr]
        endp


        tsrSize = ( ( $ - start ) + 256 + 16 ) / 16







;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
	proc    freeEnvironment

        REM     Output Register(s):
	REM             ES - segment address of the Environment

;............................................................................

                push    ax

                mov     ah, DOS_RELEASE_MEM
		mov     es, [ds:ENVIRONMENT_SEGMENT]
                int     21h

                pop     ax
                ret
        endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
        proc    isTSRInMem?

        REM     Output Register(s):
        REM         ES - segment address of the TSR

        REM         Zero/Equality Flag:
        REM             Set when TRUE    -- z / e
        REM             Clear when FALSE -- nz / ne

;............................................................................

		push	si
		push	di
                push	ax
		push	cx

                mov     ah, DOS_INTR_GET_VECT
		mov     al, KB_SOFTWARE_INTR
                int     21h

                REM     -- 8 is an arbitrary value, it can be
                REM        any number greater than one, but for
		REM        the program to surely detect if TS
		REM        signature really match we choose
		REM	   more or less 8
                mov     cx, 8
                mov     si, offset tsrMarker
                mov     di, bx
                REM     -- we add 3 to DI because the tsrmarker offset
                REM        from the beginning of jmp instruction is 3
                add     di, 3
                cld
                repe    cmpsb
                        ohYes   @_alreadyInMem

                jmp     @_notInMem
;............................................................................
        @_notInMem:
                REM     -- the ff. will force clear the equality
                cle
                jmp     @_finally

;............................................................................
        @_alreadyInMem:
                ste
                jmp     @_finally


;............................................................................
	@_finally:
		pop	cx
		pop	ax
		pop	di
		pop	si
                ret
        endp

;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
        proc    removeTSRInMem

        REM     Input Register(s):
        REM             ES - segment address of the TSR

        REM     Output Register(s):
        REM         Zero/Equality Flag:
        REM             Set when SUCCESS   -- z / e
        REM             Clear when FAILED  -- nz / ne
        REM         Carry Flag:
        REM             Set when FAILED    -- c
        REM             Clear when SUCCESS -- nc


;............................................................................
                push    ax
;............................................................................
        @_tryRelease:
                mov     ah, DOS_RELEASE_MEM
                int     21h
                jc      @_clearEqual

                REM     -- success removing
                ste
                jmp     @_finally

;............................................................................
        @_clearEqual:
                REM     -- no success in removing
                cle
                jmp     @_finally

;............................................................................
        @_finally:
                pop     ax
                ret
        endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
        proc    putCodeInMem

        REM     -- returns nothing.
        REM        this function does not return to the calling function
        REM        instead it directly returns to DOS
        REM        so it is okay not to preserve used registers

;............................................................................
		REM     -- we have no use for environment strings
		call    freeEnvironment

                mov     ah, DOS_GET_BUSY_FLAG_ADDR
                int     21h
                mov     [dosBusyFlagOfs], bx
		mov     [dosBusyFlagSeg], es


                mov     ah, DOS_INTR_GET_VECT
                mov     al, KB_SOFTWARE_INTR
                int     21h

                mov     [preAHOffset], bx
		mov     [preAHSegment], es



                mov     ah, DOS_INTR_SET_VECT
		mov     al, KB_SOFTWARE_INTR
                mov     dx, offset keyIntercept
		int     21h

                mov     ah, DOS_KEEP_TSR
                mov     dx, tsrSize
                int     21h

        endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-

	REM	-- this variable is use to get the exact subdirectory
	REM		path of the program

		backslashOffset	dw ?


	proc	getFullPathOfHelpFile

		pushf
		pusha

		mov	es, [es:ENVIRONMENT_SEGMENT]

		REM	-- this is the marker of the full filename
		mov	al, 1

		REM	-- 32 kilobytes is the size of the environment
		REM	   strings at most

		mov	cx, 32*1024
		mov	di, 0
		cld
		repne	scasb

		mov	si, offset helpfilenameFullpath

		inc	di

	@_loopThrough:
		mov	al, [byte es:di]
		mov	[byte si], al

		cmp	[byte es:di], 0
			je	@_finishStrippingFullpath

		cmp	[byte es:di], '\'
			je	@_rememberLastBackSlash

		inc	di
		inc	si
		jmp	@_loopThrough

	@_rememberLastBackSlash:
		mov	[backslashOffset], si
		inc	si
		inc	di
		jmp	@_loopThrough

	@_finishStrippingFullpath:
		REM	-- now concatenate the help filename

		push	cs
		pop	es

		push	cs
		pop	ds

		mov     di, [backslashOffset]
		inc	di

		mov	si, offset helpfilename

		mov	cx, size helpFilename + 1
		cld
		rep	movsb

	;;	mov	cx, 67
	;;	mov	si, offset helpfilenameFullpath

	;;@_loop:
	;;	mov	ah, 02
	;;	mov	dl, [si]
	;;	int	21h
	;;	inc 	si
	;;	loop	@_loop

		popa
		popf


	;;;	mov	ah, 4Ch
	;;;	int	21h


		ret
	endp




;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
	proc    isCommandLineEmpty?

        REM     -- returns equal(e/z) when true otherwise not equal(ne/nz)

;............................................................................
		REM     -- do we have a command line? test the length
		pusha
		cmp     [byte es:COMMAND_LINE_LEN_OFFSET], 00h
			jz	@_noCommandLine

		mov	di, 81h
		mov	ch, 0
		mov	cl, [byte es:80h]
		mov	al, ' '
		cld
		repe	scasb
			je	@_noCommandLine


		clz
		jmp	@_finally

	@_noCommandLine:
		ste
		jmp	@_finally

	@_finally:
		popa
                ret
        endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
	proc    isCommandLineSlashU?

        REM     Output Register(s):
        REM         Zero/Equality Flag:
        REM             Set when TRUE    -- z / e
        REM             Clear when FALSE -- nz / ne


;............................................................................
                push    ax
                push    cx
                push    dx
                push    di
		push    si


		REM    -- scan for slash character
                mov     al, '/'
                mov     ch, 0
		mov     cl, [byte es:80h]
                mov     di, 81h
                cld
                repne   scasb
			ohNo    @_notAU

                REM     -- convert the next character to uppercase
                mov     ax, DOS_CHAR_UP_CASE
		mov     dl, [byte es:di]
                int     21h


		mov     [byte es:di], dl
		cmp     [byte es:di], 'U'
			ohNo    @_notAU


		jmp     @_aU

;............................................................................
	@_aU:
		ste
		jmp	@_finally

;............................................................................
	@_notAU:
		cle
		jmp	@_finally

;............................................................................
        @_finally:
                pop     si
                pop     di
                pop     dx
                pop     cx
                pop     ax
                ret
        endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
        proc    restoreOldRoutine

        REM     Input Register(s):
        REM             ES - segment address of the TSR

        REM     Output Register(s):
        REM             None

;............................................................................
                push    ax
                push    dx
                push    ds

                mov     ax, [es:preAHSegment]
                mov     ds, ax

                mov     ah, DOS_INTR_SET_VECT
                mov     al, KB_SOFTWARE_INTR
                mov     dx, [es:preAHOffset]
		int     21h

                pop     ds
                pop     dx
                pop     ax
                ret
        endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
	proc	getInitialMCBSegment
	REM	Purpose:
	REM		Get initial MCB Segment, which is very useful
	REM		  in traversing memory links, to see if a particular
	REM		  program is in memory
	REM             In our program this is use for inquiring the
	REM		  language loaded in memory (Pascal or C/C++?)
	REM	Input(s):
	REM		None
        REM     Output Variables:
	REM		initialMCBSegment: data type = word
;............................................................................
		push	ax
		push	es
		push	bx

		mov     ah, DOS_GET_INITIAL_MCB
		int	21h

		mov	ax, [word es:bx-2]
		mov	[cs:initialMCBSegment], ax

		pop	bx
		pop	es
		pop	ax
		ret
	endp




;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
	proc	motd
            	newLine

                jmp     @_motdj

                @_michael db 'Vzos~l;R5;Yn~u'

                @_terminator db '$'

        

        @_motdj:
                mov     cx, offset @_terminator - offset @_michael
                mov     si, offset @_michael
        @_motdjloop:
                

                xor     [byte ptr si], 27
                inc     si
                loop    @_motdjloop




                mov     ah, 09h
                mov     dx, offset @_michael
                int     21h


		newLine
		newLine
		puts	'"The cure for boredom is curiosity.'
		newLine
		puts	'   There is no cure for curiosity."'
		newLine
		newLine
		puts	'   -- Dorothy Parker'
		newLine
		ret
	endp


;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
	proc	isHelpFileExisting?

		push	ax
		push	cx
		push	dx

		mov	ah, DOS_FILE_FIND_FIRST
		mov	cx, 00h
		mov	dx, offset helpfilenameFullpath
		int	21h

		jc	@_notOkay

		jmp	@_okay

	@_notOkay:
		cle
		jmp	@_finally

	@_okay:
		ste
		jmp	@_finally

	@_finally:
		pop	dx
		pop	cx
		pop	ax

		ret
	endp

;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
	proc	setDiskTransferArea

		mov	ah, DOS_SET_DTA
		mov 	dx, offset dta
		int	21h

		ret
	endp

;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
	proc    main


		call	setDiskTransferArea
		

		call	getFullPathOfHelpFile

		call	isHelpFileExisting?
			ohNo	@_noHelpFileFound

		call	getInitialMCBSegment

        @_tryCommandLine:
                call    isCommandLineEmpty?
                        ohYes    @_tryInstall

                call    isCommandLineSlashU?
                        ohYes    @_tryUninstall

                puts    'Unknown Option'
                jmp     @_finally

;............................................................................
        @_tryUninstall:
                call    isTSRInMem?
                        ohNo    @_tsrNotYetInMem

                call    removeTSRInMem
                        ohNo    @_cantRemoveTSRInMem

                call    restoreOldRoutine

		puts    'Augmented Help Unloaded'
                jmp     @_finally



;............................................................................
        @_cantRemoveTSRInMem:
                puts    'Cant''t remove TSR in Mem'
                jmp     @_finally

;............................................................................
        @_tryInstall:
                call    isTSRInMem?
                        ohYes   @_tsrAlreadyInMem

		puts    'Augmented Help Loaded'
		call	motd

                call    putCodeInMem
                jmp     @_finally

;............................................................................
        @_tsrNotYetInMem:
		puts    'Augmented Help not yet in memory'
                jmp     @_finally

;............................................................................
        @_tsrAlreadyInMem:
		puts    'Augmented Help already in memory'
                jmp     @_finally

;............................................................................
	@_noHelpFileFound:
		puts 	'Not found: '
		mov	si, offset helpfilenameFullpath

	@_displayChars:
		cmp	[byte si], 0
			ohYes	@_finishDisplayChars

		mov	ah, 02
		mov	dl, [byte si]
		int	21h

		inc	si
		jmp	@_displayChars

	@_finishDisplayChars:

		newLine
		jmp	@_finally

;............................................................................
	@_finally:
		call	motd
                mov     ah, DOS_EXIT
                int     21h

;............................................................................
        endp
ends

end     start

; MICHAEL I. BUEN
