Old school source code management :-)
; FILENAME: AB.ASM
P386
IDEAL
JUMPS
LOCALS @_
INCLUDE "USEFUL.INC"
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
segment code
org 100h
assume cs:code, ds:code, es:nothing, ss:code
start:
jmp main
REM -- if you've finish coding a program (C/C++ or Pascal)
REM after 3 months(an average span of medium-size
REM software development) which coding frequency is
REM 4 hours every day and saving the program is 5 minutes,
REM this number(5000) in theory could let you retrieve
REM your initial project code roughly 3 months ago,
REM allowing other programmer, who wants tinker with your
REM code and see how you gradually develop your program
MAX_FILE_COUNT = 5000
label oldTSRAddr dword
oldTSROfs dw ?
oldTSRSeg dw ?
REM -- backup is false tentatively
canWeBackup db 0
handleOfFileToBackup dw ?
handleOfDuplicate dw ?
REM -- length does not include the NULL byte terminator
filenameLength dw ?
extensionList db ' .PAS .INC .C .H .CPP .HPP'
db ' .ASM .MAC .CXX .HXX .HDR ', 0
fileNameExtLastCharOffset dw ?
fileNameExtLength dw ?
nextFnameExtLastCharOffset dw ?
fileToBackup db DOS_MAXPATHLEN dup(?)
filenameToAdjust db DOS_MAXPATHLEN dup(?)
fnameMostSignificantExtOffset dw ?
REM -- the NULL is copied when you copy the digit
REM extension to the extension fileToBackup.
REM this is the digit filename
toDigit db 8 dup(?), NULL
REM -- pascal is a special case in our TSR program
REM I found out that Turbo Pascal Editor,
REM version 7 in particular don't directly save the
REM source code to a .PAS, rather it renames the
REM editor temporary file which has an extension
REM of .$$$ to a .PAS
pascalFNameOffset dw ?
buffer db 1 dup(?)
mcbAsciiNameLength dw ?
struc langNameList
len dw ?
desc db 8 dup(NULL)
ends
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 ?
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:
mov ah, DOS_GET_INITIAL_MCB
pushf
call [cs:oldTSRAddr]
push cs
pop ds
mov es, [word es:bx-2]
;............................................................................
@_traverseMCB:
mov bx, [cs:langToDetect]
@_loopPascalLang:
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 @_loopPascalLang
@_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
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
REM -- you might think that 10 can be stored in byte variable
REM of course it is, but since we want to obtain a quotient
REM of double word we must divide it by 2 double words.
REM EDX(high doubleword:remainder) EAX(low doubleword:quotient)
by10 dd 10
proc regEAXConvertTo8Digit
push ebx
push ecx
push edx
push eax
mov cx, 8
mov bx, 8
mov edx, 0
@_divideBy10:
div [cs:by10]
dec bx
add dl, '0'
mov [cs:toDigit+bx], dl
mov edx, 0
loop @_divideBy10
pop eax
pop edx
pop ecx
pop ebx
ret
endp
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
proc createNewName
pusha
pushf
push cs
pop ds
mov ah, DOS_GET_DTA
pushf
call [cs:oldTSRAddr]
push es
pop [prevDTASeg]
push bx
pop [prevDTAOffs]
mov ah, DOS_SET_DTA
mov dx, offset dta
pushf
call [cs:oldTSRAddr]
push cs
pop es
mov cx, [cs:filenameLength]
mov di, offset fileToBackup
add di, cx
mov al, '.'
std
repne scasb
REM -- create a subdirectory out of fileToBackup
add di, 3
mov [byte es:di], '@'
mov [byte es:di+1], 'B'
mov [byte es:di+2], NULL
REM -- we have no use for carry
mov ah, DOS_CREATE_DIRECTORY
mov dx, offset fileToBackup
pushf
call [cs:oldTSRAddr]
mov [byte es:di+2], '\'
mov [byte es:di+3], NULL
REM -- for example a file is named
REM MP1.C this will create a number filename
REM in subdirectory MP1.C@B
REM -- skip past the directory's at sign
add di, 3
mov [cs:fnameMostSignificantExtOffset], di
jmp @_startOfFindANewFilename
;............................................................................;
@_startOfFindANewFilename:
REM -- the number filename
mov eax, 0
jmp @_findANewFilename
;............................................................................
@_findANewFileName:
call regEAXConvertTo8Digit
REM -- if we exhaust filenames number list adjust ...
cmp eax, MAX_FILE_COUNT + 1
ohYes @_adjustListOfFileHistory
jmp @_createAUniqueFilename
@_createAUniqueFilename:
inc eax
REM -- preserved the file counter
push eax
mov di, [cs:fnameMostSignificantExtOffset]
REM -- 8 digit number filename plus NULL character
mov cx, 9
mov si, offset toDigit
cld
rep movsb
mov ah, DOS_FILE_FIND_FIRST
mov cx, DOS_NORMAL_FILE
mov dx, offset fileToBackup
pushf
call [cs:oldTSRAddr]
REM -- restore the file counter
pop eax
REM -- file is existing
jnc @_findANewFileName
REM -- the above loop is terminated when
REM we found a file name that does not already
REM exist
jmp @_finally
;............................................................................
@_adjustListOfFileHistory:
pusha
REM -- we will remove the first file from the list
mov eax, 0
call regEAXConvertTo8Digit
mov di, [cs:fnameMostSignificantExtOffset]
REM -- 8 digit number filename plus NULL character
mov cx, 9
mov si, offset toDigit
cld
rep movsb
mov ah, DOS_FILE_DELETE
mov dx, offset fileToBackup
pushf
call [cs:oldTSRAddr]
REM -- for ax := 0 to MAX_FILE_COUNT - 1 do
REM adjust filenames
mov eax, 0
@_adjustThis:
mov si, offset fileToBackup
mov di, offset filenameToAdjust
mov cx, DOS_MAXPATHLEN
cld
rep movsb
REM -- construct the name of file to be rename
call regEAXConvertTo8Digit
mov di, [cs:fnameMostSignificantExtOffset]
REM -- 8 digit number filename plus NULL character
mov cx, 9
mov si, offset toDigit
cld
rep movsb
REM -- construct the new name for file to renamed
inc eax
call regEAXConvertTo8Digit
mov di, [cs:fnameMostSignificantExtOffset]
REM -- filenameToBackup and filenameToAdjust is
REM adjacent in memory, so it is just
REM okay to do the following light trick:
REM di += DOS_MAXPATHLEN; which essentially
REM will point DI to the new name or the
REM filenameToAdjust's dot character
add di, DOS_MAXPATHLEN
mov si, offset toDigit
REM -- 8 digit number filename plus NULL character
mov cx, 9
cld
rep movsb
REM -- preserve the file counter
push eax
REM -- now we can rename the file
mov ah, DOS_FILE_RENAME
mov dx, offset filenameToAdjust
mov di, offset fileToBackup
pushf
call [cs:oldTSRAddr]
REM -- restore the file counter
pop eax
cmp eax, MAX_FILE_COUNT
ohYes @_stopRenaming
jmp @_adjustThis
;............................................................................
@_stopRenaming:
REM -- from MAX_FILE_NUMBER to MAX_FILE_NUMBER - 1
REM so when create a unique filename is performed
REM it has no knowing that MAX_FILE_NUMBER
REM adjustments were made, then after inc eax
REM is performed, register EAX holds
REM the number MAX_FILE_NUMBER again
popa
mov eax, MAX_FILE_COUNT - 1
jmp @_createAUniqueFilename
;............................................................................
@_finally:
mov ah, DOS_SET_DTA
push [cs:prevDTAOffs]
pop dx
push [cs:prevDTASeg]
pop ds
pushf
call [cs:oldTSRAddr]
popf
popa
ret
endp
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
proc copyByteByByte
pusha
push cs
pop ds
REM -- go the beginning of file, from there we will
REM do a byte by byte read of the file to backup
mov bx, [cs:handleOfFileToBackup]
mov ah, DOS_FILE_MOVE_PTR
mov al, DOS_FILE_BEGIN
REM -- longword offset is in CX:DX pair,
REM conventionally longword is put in DX:AX pair,
REM but since AX register is use in function
REM the designer of DOS opted to put the
REM longword file offset in CX:DX
mov cx, 0
mov dx, 0
pushf
call [cs:oldTSRAddr]
mov ah, DOS_FILE_CREATE
mov dx, offset fileToBackup
mov cx, 00
pushf
call [cs:oldTSRAddr]
mov [cs:handleOfDuplicate], ax
jmp @_doTheCopying
;............................................................................
@_doTheCopying:
mov dx, offset buffer
@_byteRead:
mov bx, [cs:handleOfFileToBackup]
mov ah, DOS_FILE_READ
mov cx, size buffer
pushf
call [cs:oldTSRAddr]
REM -- if read size is 0 then no more to read
REM so just end the loop
cmp ax, 0
ohYes @_finally
@_byteWrite:
mov cx, ax
mov bx, [cs:handleOfDuplicate]
mov ah, DOS_FILE_WRITE
pushf
call [cs:oldTSRAddr]
jmp @_byteRead
;............................................................................
@_finally:
mov bx, [cs:handleOfDuplicate]
mov ah, DOS_FILE_CLOSE
pushf
call [cs:oldTSRAddr]
popa
ret
endp
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
proc extensionMatch?
REM Input Register(s):
REM DS:DX = offset of filename
REM Output Register(s):
REM DS:DX = offset of filename
REM Zero/Equality Flag:
REM Set when TRUE -- z / e
REM Clear when FALSE -- nz / ne
;............................................................................
REM -- for an unknown reason Turbo Pascal
REM editor seems to be lacking in stack space
REM whenever we push all the registers(using PUSHA)
REM the rename function can't continue, so I
REM opt to preserve only those registers that
REM are used in this function
push ax
push cx
push dx
push es
push ds
push si
push di
push ds
pop es
REM -- find the offset of NULL character
REM dx holds the offset of the filename
REM of the interrupted program
mov di, dx
REM -- scan the AsciiZ NULL character
mov al, NULL
mov cx, DOS_MAXPATHLEN
cld
repne scasb
REM -- inc cx instr. excludes the null byte from
REM string length
inc cx
mov [cs:filenameLength], DOS_MAXPATHLEN
sub [cs:filenameLength], cx
REM -- 2 is the distance of the DI register termination
REM back to the character before the NULL character
sub di, 2
REM -- from the NULL character offset - 2 is the last
REM character
mov [cs:fileNameExtLastCharOffset], di
REM -- the following instr. is use for the
REM comparison(cmpsb) of the asciiz filename
REM against the extension list
push cs
pop es
mov [cs:nextFnameExtLastCharOffset], offset extensionList
jmp @_tryExtIfMatchExtList
;............................................................................
@_tryExtIfMatchExtList:
mov di, [cs:nextFnameExtLastCharOffset]
@_tryFindTheDotCharacter:
inc di
cmp [byte cs:di], '.'
ohYes @_countTheCharacter
cmp [byte cs:di], NULL
ohYes @_noExtMatch
jmp @_tryFindTheDotCharacter
@_countTheCharacter:
mov cx, 0
@_thenCount:
inc di
inc cx
cmp [byte cs:di], ' '
ohNo @_thenCount
REM -- exclude the space character
dec cx
mov [cs:fileNameExtLength], cx
dec di
mov [cs:nextFnameExtLastCharOffset], di
mov cx, [cs:fileNameExtLength]
mov si, [cs:fileNameExtLastCharOffset]
mov di, [cs:nextFnameExtLastCharOffset]
std
repe cmpsb
ohYes @_extMatch
mov di, [cs:nextFnameExtLastCharOffset]
jmp @_tryFindTheDotCharacter
@_extMatch:
pop di
pop si
pop ds
pop es
pop dx
pop cx
pop ax
ste
ret
@_noExtMatch:
pop di
pop si
pop ds
pop es
pop dx
pop cx
pop ax
cle
ret
endp
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
proc dosIntercept
jmp @_beginning
tsrMarker db 'AB-MLTH'
@_beginning:
pushf
REM -- Pascal 7 Editor is a special case, it doesn't
REM directly saves the source file to .PAS, instead
REM it save it first to temporary file then save
REM rename it to .PAS
cmp ah, DOS_FILE_RENAME
ohYes @_tryRename
cmp ah, DOS_FILE_CREATE
ohYes @_tryExtension
cmp ah, DOS_FILE_CREATE_SAFE
ohYes @_tryExtension
cmp ah, DOS_FILE_CLOSE
ohYes @_tryBackup
jmp @_toOldRoutine
;............................................................................
REM -- this is a special case for Turbo Pascal 7 Editor
REM which does not directly save source code to its
REM Pascal filename, rather, it renames the editor
REM swap file which has an extension of .$$$ to .PAS
@_tryRename:
call isCCPlusplusInMem?
ohNo @_tryIfPascalRename
jmp @_continueInterceptingRename
@_tryIfPascalRename:
call isPascalInMem?
ohNo @_toOldRoutine
jmp @_continueInterceptingRename
@_continueInterceptingRename:
mov [cs:pascalFNameOffset], di
push ds
push dx
REM -- from the calling rename:
REM DS:DX = ES:DI
REM where ES:DI is the new name of the rename
REM and DS:DX is the filename to test its
REM extension
push es
pop ds
push di
pop dx
call extensionMatch?
ohNo @_pascalNoMatch
jmp @_backupPascalFilenameAndHandle
;............................................................................
@_pascalNoMatch:
REM -- no match so do the ff:
REM restore the previous registers,
REM then the flag of the interrupted program
pop dx
pop ds
popf
pushf
call [cs:oldTSRAddr]
jc @_contNoMatchFinal
@_contNoMatchFinal:
retf 2
;............................................................................
@_backupPascalFilenameAndHandle:
REM -- no match so do the ff:
REM restore the previous registers,
pop dx
pop ds
push ds
push si
push es
push di
REM -- then from the rename do the copy string of
REM of the renamed's new name to the
REM fileToBackup
REM assign: ES:DI = DS:SI
REM destination:
REM ES = CS
REM DI = offset fileToBackup
REM source:(the new name of to be renamed temp file)
REM DS = ES
REM SI = [cs:pascalFNameOffset] --> previously
REM this is the DI, but we save
REM first DI to the variable
REM pascal filename offset to avoid
REM confusion in variable assignments
push es
pop ds
mov si, [cs:pascalFNameOffset]
push cs
pop es
mov di, offset fileToBackup
mov cx, [cs:filenameLength]
inc cx
cld
rep movsb
pop di
pop es
pop si
pop ds
REM -- restore the flag of the interrupted program
popf
REM -- the rename
pushf
call [cs:oldTSRAddr]
jnc @_cont
push ax
push dx
mov ah, 02
mov dl, 176
pushf
call [cs:oldTSRAddr]
pop dx
pop ax
retf 2
@_cont:
REM -- preserve rename's flag and registers
pushf
push ax
push ds
push dx
push cs
pop ds
mov ah, DOS_FILE_OPEN
mov al, 0
mov dx, offset fileToBackup
pushf
call [cs:oldTSRAddr]
jnc @_continueBackuppingPascalHandle
jmp @_doNotBackupPascalHandleAndDoNotCloseHandle
;............................................................................
@_continueBackuppingPascalHandle:
mov [cs:handleOfFileToBackup], ax
setnc [cs:canWeBackup]
REM -- restore rename's registers and flag
pop dx
pop ds
pop ax
popf
REM -- preserve it we are doing the file close
pushf
push ax
push bx
REM -- when the file is close it will be
REM be backupped
mov ah, DOS_FILE_CLOSE
mov bx, [cs:handleOfFileToBackup]
int 21h
REM -- restore the rename's previous registers
REM and flag, not from the file close
pop bx
pop ax
popf
retf 2
;............................................................................
@_doNotBackupPascalHandleAndDoNotCloseHandle:
REM -- cannot open a file so just do the ff:
REM restore previous registers and,
REM restore flag of the interrupted
REM program
pop dx
pop ds
pop ax
popf
REM -- return to interrupted program
retf 2
;............................................................................
@_tryExtension:
REM -- before we invoke the hooked FILE CREATE/FILE CREATE SAFE
REM we test first if the filename's extension if it
REM match our filename extension list
call isCCPlusplusInMem?
ohNo @_tryIfPascalExtension
jmp @_continueInterceptingExtension
@_tryIfPascalExtension:
call isPascalInMem?
ohNo @_toOldRoutine
jmp @_continueInterceptingExtension
@_continueInterceptingExtension:
call extensionMatch?
ohYes @_backupFilenameAndHandle
jmp @_noExtensionMatch
;............................................................................
@_backupFilenameAndHandle:
pusha
push cs
pop es
mov di, offset fileToBackup
mov si, dx
mov cx, [cs:filenameLength]
BUG -- this just one line that is missing from the
BUG distributed diskette cause a very erroneous
BUG critical error when the file is saved
inc cx
cld
rep movsb
popa
REM -- restore previous state of flag
REM this flag comes from the interrupted program
REM not from this routine
REM then invoke the hooked routine which is
REM FILE CREATE/FILE CREATE SAFE
popf
pushf
call [cs:oldTSRAddr]
setnc [cs:canWeBackup]
mov [cs:handleOfFileToBackup], ax
REM -- return to the interrupted program,
REM but do not load the flags from the stack
REM instead leave it as it is
retf 2
;............................................................................
@_noExtensionMatch:
REM -- filename's extension does not match our filenames
REM extension list, so just invoke the hooked routine
REM which is the FILE CREATE/FILE CREATE SAFE
jmp @_toOldRoutine
;............................................................................
@_tryBackup:
cmp bx, [cs:handleOfFileToBackup]
ohNo @_toOldRoutine
cmp [cs:canWeBackup], 1
ohYes @_sound
mov [cs:canWeBackup], 0
jmp @_toOldRoutine
;............................................................................
@_sound:
call createNewName
call copyByteByByte
mov [cs:canWeBackup], 0
jmp @_toOldRoutine
;............................................................................
@_toOldRoutine:
popf
jmp [cs:oldTSRAddr]
endp
tsrSize = ( ( $ - start ) + 256 + 16 ) / 16
hookedIntr = 21h
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
proc freeEnvironment
REM Output Register(s):
REM ES - segment address of the Environment Offset
;............................................................................
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
;............................................................................
mov ah, DOS_INTR_GET_VECT
mov al, 21h
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 it really match
REM we choose more or less 8
mov cx, 8
mov si, offset tsrMarker
mov di, bx
REM -- we add 3 to DI, 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:
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_INTR_GET_VECT
mov al, hookedIntr
int 21h
mov [oldTSROfs], bx
mov [oldTSRSeg], es
mov ah, DOS_INTR_SET_VECT
mov al, hookedIntr
lea dx, [dosIntercept]
int 21h
mov ah, DOS_KEEP_TSR
mov dx, tsrSize
int 21h
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 ds:COMMAND_LINE_LEN_OFFSET]
mov di, COMMAND_LINE_OFFSET
cld
repne scasb
ohNo @_finally
REM -- convert the next character to uppercase
mov ax, DOS_CHAR_UP_CASE
mov dl, [byte di]
int 21h
mov [byte di], dl
cmp [byte di], 'U'
ohNo @_finally
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:oldTSRSeg]
mov ds, ax
mov ah, DOS_INTR_SET_VECT
mov al, hookedIntr
mov dx, [es:oldTSROfs]
int 21h
pop ds
pop dx
pop ax
ret
endp
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
proc motd
newLine
jmp @_motdj
@_michael db 'Vrxsz~w;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 '"Programming today is a race between software'
newLine
puts ' engineers striving to build bigger and better'
newLine
puts ' idiot-proof programs, and the universe'
newLine
puts ' trying to produce bigger and better idiots.'
newLine
puts ' So far, the universe is winning."'
newLine
newLine
puts ' -- Rich Cook'
newLine
ret
endp
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
proc main
;............................................................................
@_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 Backups Unloaded'
jmp @_finally
;............................................................................
@_cantRemoveTSRInMem:
puts 'Cant''t Remove Augmented Backups in Memory'
jmp @_finally
;............................................................................
@_tryInstall:
call isTSRInMem?
ohYes @_tsrAlreadyInMem
puts 'Augmented Backups Loaded'
call motd
call putCodeInMem
jmp @_finally
;............................................................................
@_tsrNotYetInMem:
puts 'Augmented Backups Not Yet In Memory'
jmp @_finally
;............................................................................
@_tsrAlreadyInMem:
puts 'Augmented Backups Already in Memory'
jmp @_finally
;............................................................................
@_finally:
call motd
mov ah, DOS_EXIT
int 21h
;............................................................................
endp
ends
end start
; MICHAEL BUEN
AK.ASM
Augmented Key is a keyboard automator for Turbo C and Turbo Pascal. I love keyboard shortcuts, there's no mouse shortcuts yet at the time :p heheh
; FILENAME: AK.ASM
P386
IDEAL
JUMPS
LOCALS @_
include 'useful.inc'
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
segment code
org 100h
assume cs:code, ds:code, es:nothing, ss:code
start:
jmp main
REM -- Backspace and CarriageReturn key respectively
BS = 08h
NL = 0Dh
TAB = 09h
REM -- we use the alternate keyboard cursor movements(Wordstar-like)
REM hotkey, as the Turbo C++ editor refuse
REM to distinguish LEFT from CTRL+LEFT, and also
REM with RIGHT from CTRL+RIGHT when we
REM press the hotkey CTRL+ENTER.
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
KB_UP = 4800h
KB_DOWN = 5000h
KB_LEFT = 4B00h
KB_RIGHT = 4D00h
KB_CTRL_RIGHT_BRACKET = 1B1Dh
KB_CTRL_LEFT_BRACKET = 1A1Bh
INDENT_HOTKEY = KB_CTRL_RIGHT_BRACKET
UNINDENT_HOTKEY = KB_CTRL_LEFT_BRACKET
UP = KB_CTRL_E
DOWN = KB_CTRL_X
LEFT = KB_CTRL_S
RIGHT = KB_CTRL_D
REM -- ASCII code of Enter
KB_CTRL_ENTER_ASCII = 1C0Ah
REM -- Scan code of Enter
SHORTCUT_HOTKEY = KB_CTRL_ENTER_ASCII
KB_SOFTWARE_INTR = 16h
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
label dosBusyFlagAddr dword
dosBusyFlagOfs dw ?
dosBusyFlagSeg dw ?
struc keyTemplates
label shortcut word
firstKey db ' '
secondKey db ' '
textToInsertOffset dw ?
ends
stuffing db FALSE
ptrToText dw ?
label keyBuff word
firstKeyBuff db 0
secondKeyBuff db 0
C_DoubleKeys keyTemplates< 'e', 'i', C_elseIf >
keyTemplates< 's', 't', C_struct >
keyTemplates< 's', 'w', C_switch >
keyTemplates< 'i', 'e', C_ifElse >
keyTemplates< 'c', 'a', C_case >
keyTemplates< 'c', 'o', C_continue >
keyTemplates< 'c', 'l', C_class >
keyTemplates< '#', 'i', C_include >
keyTemplates< '#', 'd', C_define >
keyTemplates< '#', '#', C_includeU >
keyTemplates< 'i', 'n', C_intFunc >
keyTemplates< 'v', 'o', C_voidFunc >
keyTemplates< 'd', 'o', C_doubleFunc >
keyTemplates< 'c', 'p', C_cprintf >
keyTemplates< 'c', 's', C_cscanf >
db NULL, NULL
C_SingleKeys keyTemplates< , 'i', C_if >
keyTemplates< , 'w', C_while >
keyTemplates< , 'u', C_unsigned >
keyTemplates< , 'e', C_else >
keyTemplates< , 'd', C_do >
keyTemplates< , 'f', C_for >
keyTemplates< , 'b', C_break >
keyTemplates< , 'r', C_return >
keyTemplates< , 'g', C_gotoxy >
keyTemplates< , 'p', C_printf >
keyTemplates< , 's', C_scanf >
keyTemplates< , '!', C_program >
db NULL, NULL
Pas_DoubleKeys keyTemplates< 'w', 'h', Pas_while >
keyTemplates< 'w', 'i', Pas_with >
keyTemplates< 'r', 'u', Pas_repeatUntil >
keyTemplates< 'r', 'e', Pas_recordEnd >
keyTemplates< 'f', 'o', Pas_for >
keyTemplates< 'f', 'd', Pas_for_down >
keyTemplates< 'f', 'u', Pas_function >
keyTemplates< 'c', 'a', Pas_case >
keyTemplates< 'c', 'o', Pas_continue >
keyTemplates< 'b', 'e', Pas_beginEnd >
keyTemplates< 'b', 'r', Pas_break >
keyTemplates< 'i', 'e', Pas_ifElse >
keyTemplates< 'e', 'i', Pas_elseIf >
keyTemplates< 'i', 'n', Pas_integer >
keyTemplates< 'o', 'b', Pas_object >
db NULL, NULL
Pas_SingleKeys keyTemplates< , 'p', Pas_procedure >
keyTemplates< , 'e', Pas_else >
keyTemplates< , 'i', Pas_if >
keyTemplates< , 'a', Pas_array >
keyTemplates< , 'w', Pas_writeln >
keyTemplates< , 'r', Pas_readln >
keyTemplates< , 'g', Pas_gotoxy >
keyTemplates< , '!', Pas_program >
db NULL, NULL
REM -- Pascal double keys
Pas_while db BS, BS, 'do', NL
db 'begin', NL, NL
db 'end;', LEFT, LEFT, LEFT, LEFT
db UP, UP, UP
db 'while '
db LEFT
db NULL
Pas_with db BS, BS, 'do', NL
db 'begin', NL, NL
db 'end;', LEFT, LEFT, LEFT, LEFT
db UP, UP, UP
db 'with '
db LEFT
db NULL
Pas_repeatUntil db BS, BS
db 'repeat', NL, NL
db 'until ;', LEFT
db NULL
Pas_recordEnd db 'cord', NL, NL
db 'end;'
db NULL
Pas_for db BS, BS, ':= to do', NL
db 'begin', NL, NL
db 'end;', LEFT, LEFT, LEFT, LEFT
db UP, UP, UP
db 'for '
db LEFT
db NULL
Pas_for_down db BS, BS, ':= downto do', NL
db 'begin', NL, NL
db 'end;', LEFT, LEFT, LEFT, LEFT
db UP, UP, UP
db 'for '
db LEFT
db NULL
Pas_function db BS, BS, ':;', NL
db 'begin', NL, NL
db 'end;', NL
db UP, UP, UP, UP
db 'function '
db NULL
Pas_case db BS, BS, 'of', NL
db ':', NL
db ':', NL
db 'end;', LEFT, LEFT, LEFT, LEFT
db UP, UP, UP
db 'case '
db LEFT
db NULL
Pas_continue db 'ntinue;', NL
db NULL
Pas_beginEnd db 'gin', NL, NL
db 'end;', LEFT, LEFT, LEFT, LEFT
db UP, TAB
db NULL
Pas_break db 'eak;', NL
db NULL
Pas_ifElse db BS, BS, 'then', NL
db 'begin', NL, NL
db 'end', NL
db 'else', NL
db 'begin', NL, NL
db 'end;', LEFT, LEFT, LEFT, LEFT
db UP, UP, UP, UP
db UP, UP, UP
db 'if '
db LEFT
db NULL
Pas_elseIf db BS, BS, 'then', NL
db 'begin', NL, NL
db 'end', LEFT, LEFT, LEFT
db UP, UP, UP
db 'else if '
db LEFT
db NULL
Pas_integer db 'teger;', NL
db NULL
Pas_object db BS, BS, 'object', NL
db 'private', NL, NL
db 'public', NL, NL
db 'end;', LEFT, LEFT, LEFT, LEFT
db UP, UP, UP, UP, UP
db NULL
REM -- Pascal Single Keys
Pas_procedure db BS, ';', NL
db 'begin', NL, NL
db 'end;', NL
db UP, UP, UP, UP
db 'procedure '
db NULL
Pas_else db 'lse', NL
db 'begin', NL, NL
db 'end;', LEFT, LEFT, LEFT, LEFT
db UP
db NULL
Pas_if db BS, 'then', NL
db 'begin', NL, NL
db 'end;', LEFT, LEFT, LEFT, LEFT
db UP, UP, UP
db 'if '
db LEFT
db NULL
Pas_array db 'rray [ .. ] of'
db LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT
db NULL
Pas_writeln db 'riteln;', LEFT
db NULL
Pas_readln db 'eadln;', LEFT
db NULL
Pas_gotoxy db 'otoxy( , );'
db LEFT, LEFT, LEFT, LEFT, LEFT
db NULL
Pas_program db BS
db 'uses crt, dos, printer, graph;', NL
db 'var', NL
db NL
db NL
db 'begin', NL
db NL
db 'end.', LEFT, LEFT, LEFT, LEFT
db UP, UP, UP, UP, TAB
db NULL
REM -- C double keys
C_elseIf db BS, BS, ')',NL
db '{', NL, NL
db '}', LEFT
db UP, UP, UP
db 'else if( '
db LEFT
db NULL
C_struct db 'ruct', NL
db '{', NL
db NL
db '};', LEFT, LEFT
db UP, UP, UP
db RIGHT, RIGHT, RIGHT, RIGHT
db RIGHT, RIGHT
db ' '
db NULL
C_switch db BS, BS, ')', NL
db '{', NL
db 'case :',NL, NL
db ' break;', NL, NL, BS
db 'case :',NL, NL
db ' break;', NL, NL, BS
db 'default:', NL, NL
db ' break;', NL, BS
db '}', LEFT
db UP, UP, UP, UP, UP, UP, UP
db UP, UP, UP, UP, UP, UP
db 'switch( '
db LEFT
db NULL
C_ifElse db BS, BS, ')', NL
db '{', NL, NL
db '}', NL
db 'else', NL
db '{', NL, NL
db '}', LEFT
db UP, UP, UP, UP
db UP, UP, UP
db 'if( '
db LEFT
db NULL
C_case db 'se:', NL, NL
db ' break;'
db LEFT, LEFT, LEFT, LEFT, LEFT, LEFT
db UP, UP, ' '
db NULL
C_continue db 'ntinue;', NL
db NULL
C_class db 'ass', NL
db '{', NL
db 'private:', NL, NL
db 'protected:', NL, NL
db 'public:', NL, NL
db '};', LEFT, LEFT
db UP, UP, UP, UP, UP, UP, UP, UP
db RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, ' '
db NULL
C_include db 'nclude <.h>', LEFT, LEFT, LEFT
db NULL
C_define db 'efine '
db NULL
C_includeU db BS, 'include ".h"', LEFT, LEFT, LEFT
db NULL
C_intFunc db 't ()', NL
db '{', NL
db NL
db '}', NL
db UP, UP, UP, UP, RIGHT, RIGHT, RIGHT, RIGHT
db NULL
C_voidFunc db 'id ()', NL
db '{', NL
db NL
db '}', NL
db UP, UP, UP, UP, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT
db NULL
C_doubleFunc db 'uble ()', NL
db '{', NL
db NL
db '}', NL
db UP, UP, UP, UP
db RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT
db NULL
C_cprintf db 'rintf( "", );'
db LEFT, LEFT, LEFT, LEFT, LEFT, LEFT
db NULL
C_cscanf db 'canf( "", );'
db LEFT, LEFT, LEFT, LEFT, LEFT, LEFT
db NULL
REM -- C single keys
C_if db BS, ')', NL
db '{', NL, NL
db '}', LEFT
db UP, UP, UP
db 'if( '
db LEFT
db NULL
C_while db BS, ')', NL
db '{', NL, NL
db '}', LEFT
db UP, UP, UP
db 'while( '
db LEFT
db NULL
C_unsigned db 'nsigned '
db NULL
C_else db 'lse', NL
db '{', NL, NL
db '}', LEFT
db UP
db NULL
C_do db 'o', NL
db '{', NL
db '}', NL
db 'while( );'
db LEFT, LEFT, LEFT
db NULL
C_for db BS, '; ; )', NL
db '{', NL, NL
db '}', LEFT
db UP, UP, UP
db 'for( '
db NULL
C_break db 'reak;', NL
db NULL
C_return db 'eturn '
db NULL
C_printf db 'rintf( "", );'
db LEFT, LEFT, LEFT, LEFT, LEFT, LEFT
db NULL
C_scanf db 'canf( "", );'
db LEFT, LEFT, LEFT, LEFT, LEFT, LEFT
db NULL
C_gotoxy db 'otoxy( , );'
db LEFT, LEFT, LEFT, LEFT, LEFT
db NULL
C_program db BS
db '#include <stdio.h>', NL
db '#include <io.h>', NL
db '#include <conio.h>', NL
db '#include <math.h>', NL
db NL
db 'void main()', NL
db '{', NL
db NL
db '}', LEFT, UP, TAB
db NULL
CPas_indent db 0Bh, 'I'
db NULL
CPas_unindent db 0Bh, 'U'
db NULL
doublekeysPtr dw ?
singlekeysPtr dw ?
REM -- prev address of keyboard interrupt 16h
label preAKAddr dword
preAKOffset dw ?
preAKSegment dw ?
initialMCBSegment dw ?
mcbAsciiNameLength dw ?
struc langNameList
len dw ?
desc db 8 dup(NULL)
ends
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 ?
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
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 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(s):
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 insertAtOurBuffer
REM Purpose:
REM Simulate keyboard buffer reading
REM Input(s):
REM None
REM Output(s):
REM keybuff: data type = word
REM has two components:
REM firstkeyBuff
REM secondkeyBuff
;............................................................................
pusha
mov ah, BIOS_GET_CURSOR_POS
REM -- 0 is page number
mov bh, 0
int 10h
mov cx, dx
REM -- DH is row DL is column
dec dl
mov ah, BIOS_SET_CURSOR_POS
int 10h
mov ah, BIOS_READ_CHAR_AT_POS
int 10h
mov [cs:secondKeyBuff], al
REM -- DH is row DL is column
dec dl
mov ah, BIOS_SET_CURSOR_POS
int 10h
mov ah, BIOS_READ_CHAR_AT_POS
int 10h
mov [cs:firstKeyBuff], al
mov ah, BIOS_SET_CURSOR_POS
REM -- 0 is page number
mov bh, 0
mov dx, cx
int 10h
popa
ret
endp
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
proc keyIntercept
jmp @_beginning
tsrMarker db 'AK-MLTH'
@_beginning:
pushf
push es
push di
les di, [cs:dosBusyFlagAddr]
cmp [byte ptr es:di], 0
ohYes @_continueBeginning
@_donotContinueBeginning:
pop di
pop es
popf
jmp @_doOld
@_continueBeginning:
pop di
pop es
popf
cmp ah, BIOS_OLD_READKEY
ohYes @_tryReadkey
cmp ah, BIOS_NEW_READKEY
ohYes @_tryReadkey
cmp ah, BIOS_OLD_KEYSTAT
ohYes @_tryKeystat
cmp ah, BIOS_NEW_KEYSTAT
ohYes @_tryKeystat
;............................................................................
@_tryReadkey:
cmp [cs:stuffing], TRUE
ohYes @_fakeReadkey
jmp @_realReadkey
;............................................................................
@_realReadkey:
pushf
call [cs:preAKAddr]
cmp ax, SHORTCUT_HOTKEY
ohYes @_readKeyShortcutContinue
cmp ax, INDENT_HOTKEY
ohYes @_readkeyIndent
cmp ax, UNINDENT_HOTKEY
ohYes @_readkeyUnindent
jmp @_readkeyShortcutNotTriggerBackToCaller
@_readkeyIndent:
mov [cs:stuffing], TRUE
mov [cs:ptrToText], offset CPas_indent
jmp @_fakeReadkey
@_readkeyUnindent:
mov [cs:stuffing], TRUE
mov [cs:ptrToText], offset CPas_unindent
jmp @_fakeReadkey
@_readkeyShortcutContinue:
call insertAtOurBuffer
call isPascalInMem?
ohYes @_readkeyPascal
call isCCPlusplusInMem?
ohYes @_readkeyCCPlusplus
jmp @_doOld
;............................................................................
@_readkeyPascal:
mov [cs:doublekeysPtr], offset Pas_doubleKeys
mov [cs:singlekeysPtr], offset Pas_singleKeys
jmp @_readkeyLanguage
;............................................................................
@_readkeyCCPlusplus:
mov [cs:doublekeysPtr], offset C_doubleKeys
mov [cs:singlekeysPtr], offset C_singleKeys
jmp @_readkeyLanguage
;............................................................................
@_readkeyLanguage:
push dx
push bx
mov dx, [cs:keyBuff]
mov bx, [cs:doublekeysPtr]
@_readkeyDoublekeyCheckKeysLoop:
cmp [(keyTemplates cs:bx).shortcut], NULL
ohYes @_readkeyDoublekeyShortcutNotAvailable
cmp [(keyTemplates cs:bx).shortcut], dx
ohYes @_readkeyDoublekeyShortcutAvailable
add bx, size keyTemplates
jmp @_readkeyDoublekeyCheckKeysLoop
@_readkeyDoublekeyShortcutAvailable:
REM -- clear first our own keyboard buffer
mov [cs:keyBuff], 0000h
mov bx, [(keyTemplates cs:bx).textToInsertOffset]
mov [cs:ptrToText], bx
mov [cs:stuffing], TRUE
jmp @_readkeyDoublekeyCheckKeysStop
@_readkeyDoublekeyShortcutNotAvailable:
mov [cs:ptrToText], 0
mov [cs:stuffing], FALSE
jmp @_readkeyDoublekeyCheckKeysStop
@_readkeyDoublekeyCheckKeysStop:
pop bx
pop dx
cmp [cs:stuffing], TRUE
je @_fakeReadkey
push dx
push bx
mov dl, [cs:secondKeybuff]
mov bx, [cs:singlekeysPtr]
@_readkeySinglekeyCheckKeysLoop:
cmp [(keyTemplates cs:bx).secondKey], NULL
ohYes @_readkeySinglekeyShortcutNotAvailable
cmp [(keyTemplates cs:bx).secondKey], dl
ohYes @_readkeySinglekeyShortcutAvailable
add bx, size keyTemplates
jmp @_readkeySinglekeyCheckKeysLoop
@_readkeySinglekeyShortcutAvailable:
REM -- clear first our own keyboard buffer
mov [cs:keyBuff], 0000h
mov bx, [(keyTemplates cs:bx).textToInsertOffset]
mov [cs:ptrToText], bx
mov [cs:stuffing], TRUE
jmp @_readkeySinglekeyCheckKeysStop
@_readkeySinglekeyShortcutNotAvailable:
mov [cs:ptrToText], 0
mov [cs:stuffing], FALSE
jmp @_readkeySinglekeyCheckKeysStop
@_readkeySinglekeyCheckKeysStop:
pop bx
pop dx
cmp [cs:stuffing], TRUE
je @_fakeReadkey
iret
;............................................................................
@_fakeReadkey:
push bx
mov bx, [cs:ptrToText]
mov al, [byte cs:bx]
mov ah, 0
inc [cs:ptrToText]
mov bx, [cs:ptrToText]
cmp [byte cs:bx], NULL
setne [cs:stuffing]
pop bx
iret
;............................................................................
@_readkeyShortcutNotTriggerBackToCaller:
iret
;............................................................................
@_tryKeystat:
cmp [cs:stuffing], TRUE
ohYes @_fakeKeystat
jmp @_realKeystat
;............................................................................
@_realKeystat:
pushf
call [cs:preAKAddr]
REM -- Zero keys Available so just back to caller
jz @_keystatBackToCaller
cmp ax, SHORTCUT_HOTKEY
ohYes @_keyStatShortcutContinue
cmp ax, INDENT_HOTKEY
ohYes @_keystatIndent
cmp ax, UNINDENT_HOTKEY
ohYes @_keystatUnindent
jmp @_keystatBackToCaller
@_keystatIndent:
mov ah, BIOS_OLD_READKEY
pushf
call [cs:preAKAddr]
mov [cs:stuffing], TRUE
mov [cs:ptrToText], offset CPas_indent
jmp @_fakeKeystat
@_keystatUnindent:
mov ah, BIOS_OLD_READKEY
pushf
call [cs:preAKAddr]
mov [cs:stuffing], TRUE
mov [cs:ptrToText], offset CPas_unindent
jmp @_fakeKeystat
@_keystatShortcutContinue:
REM -- we do this just to remove the hotkey
REM so it won't be evaluated again,
REM if you try to remove this
REM three lines of code you'll see
REM the insertion of keys will go into
REM infinitum
mov ah, BIOS_OLD_READKEY
pushf
call [cs:preAKAddr]
call insertAtOurBuffer
call isPascalInMem?
ohYes @_keystatPascal
call isCCPlusplusInMem?
ohYes @_keystatCCPlusplus
stz
retf 2
;............................................................................
@_keystatPascal:
mov [cs:doublekeysPtr], offset Pas_doubleKeys
mov [cs:singlekeysPtr], offset Pas_singleKeys
jmp @_keystatLanguage
;............................................................................
@_keystatCCPlusplus:
mov [cs:doublekeysPtr], offset C_doubleKeys
mov [cs:singlekeysPtr], offset C_singleKeys
jmp @_keystatLanguage
;............................................................................
@_keystatLanguage:
push dx
push bx
mov dx, [cs:keyBuff]
mov bx, [cs:doublekeysPtr]
@_keystatDoubleCheckKeysLoop:
cmp [(keyTemplates cs:bx).shortcut], NULL
ohYes @_keystatDoubleShortcutNotAvailable
cmp [(keyTemplates cs:bx).shortcut], dx
ohYes @_keystatDoubleShortcutAvailable
add bx, size keyTemplates
jmp @_keystatDoubleCheckKeysLoop
@_keystatDoubleShortcutAvailable:
REM -- clear first our own keyboard buffer
mov [cs:keyBuff], 0000h
mov bx, [(keyTemplates cs:bx).textToInsertOffset]
mov [cs:ptrToText], bx
mov [cs:stuffing], TRUE
jmp @_keystatDoubleCheckKeysStop
@_keystatDoubleShortcutNotAvailable:
mov [cs:ptrToText], 0
mov [cs:stuffing], FALSE
jmp @_keystatDoubleCheckKeysStop
@_keystatDoubleCheckKeysStop:
pop bx
pop dx
cmp [cs:stuffing], TRUE
je @_fakekeystat
push dx
push bx
mov dl, [cs:secondKeybuff]
mov bx, [cs:singlekeysPtr]
@_keystatSingleCheckKeysLoop:
cmp [(keyTemplates cs:bx).secondKey], NULL
ohYes @_keystatSingleShortcutNotAvailable
cmp [(keyTemplates cs:bx).secondKey], dl
ohYes @_keystatSingleShortcutAvailable
add bx, size keyTemplates
jmp @_keystatSingleCheckKeysLoop
@_keystatSingleShortcutAvailable:
REM -- clear first our own keyboard buffer
mov [cs:keyBuff], 0000h
mov bx, [(keyTemplates cs:bx).textToInsertOffset]
mov [cs:ptrToText], bx
mov [cs:stuffing], TRUE
jmp @_keystatSingleCheckKeysStop
@_keystatSingleShortcutNotAvailable:
mov [cs:ptrToText], 0
mov [cs:stuffing], FALSE
jmp @_keystatSingleCheckKeysStop
@_keystatSingleCheckKeysStop:
pop bx
pop dx
cmp [cs:stuffing], TRUE
je @_fakekeyStat
mov [cs:keyBuff], 0
stz
retf 2
;............................................................................
@_fakeKeystat:
push bx
mov bx, [cs:ptrToText]
mov al, [byte cs:bx]
mov ah, 0
cmp al, NULL
ohNo @_continueKeystatOrdinaryKey
mov [cs:stuffing], FALSE
stz
retf 2
@_continueKeystatOrdinaryKey:
jmp @_keystatInsert
@_keystatInsert:
pop bx
REM -- clear zero meaning simulate key availability
clz
retf 2
;............................................................................
@_keystatShortcutNotTriggerBackToCaller:
clz
retf 2
;............................................................................
@_keystatBackToCaller:
retf 2
;............................................................................
@_doOld:
jmp [cs:preAKAddr]
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, 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 [preAKOffset], bx
mov [preAKSegment], 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
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
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 ds:80h]
mov di, 81h
cld
repne scasb
ohNo @_finally
REM -- convert the next character to uppercase
mov ax, DOS_CHAR_UP_CASE
mov dl, [byte di]
int 21h
mov [byte di], dl
cmp [byte di], 'U'
ohNo @_finally
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:preAKSegment]
mov ds, ax
mov ah, DOS_INTR_SET_VECT
mov al, KB_SOFTWARE_INTR
mov dx, [es:preAKOffset]
int 21h
pop ds
pop dx
pop ax
ret
endp
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
proc motd
newLine
jmp @_motdj
@_michael db 'Vrxsz~w;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 '"From the programmer''s point of view,'
newLine
puts ' a user is just a peripheral that types'
newline
puts ' in when the program issues a read request."'
newLine
newLine
puts ' -- From Java Book(the source Sun)'
newLine
ret
endp
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
proc main
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 Keys Unloaded'
jmp @_finally
;............................................................................
@_cantRemoveTSRInMem:
puts 'Cant''t Remove Augmented Keys in Memory'
jmp @_finally
;............................................................................
@_tryInstall:
call isTSRInMem?
ohYes @_tsrAlreadyInMem
puts 'Augmented Keys Loaded'
call motd
call putCodeInMem
jmp @_finally
;............................................................................
@_tsrNotYetInMem:
puts 'Augmented Keys not yet in memory'
jmp @_finally
;............................................................................
@_tsrAlreadyInMem:
puts 'Augmented Keys already in memory'
jmp @_finally
;............................................................................
@_finally:
call motd
mov ah, DOS_EXIT
int 21h
;............................................................................
endp
ends
end start
; MICHAEL BUEN
AH.ASM
Augumented Help. Extends Turbo C/C++ and Turbo Pascal help functionality
; 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 diskette 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, the tsrmarker's 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 'Vrxsz~w;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 BUEN
The program library. The old school .NET framework, heheh :D
; FILENAME: USEFUL.INC
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
macro REM
endm
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
macro BUG
endm
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
DOS_MAXPATHLEN = 67
REM -- DOS interrupt 0x21
DOS_DISPLAY_OUTPUT = 02h
REM Input(s):
REM DL - 8 bit character data
;............................................................................
REM -- DOS interrupt 0x21
DOS_FILE_CREATE = 3Ch
REM Input(s):
REM CX - File Attribute
REM 0000h Normal
REM 0002h Hidden
REM 0004h System
REM 0006h Hidden+System
REM DS:DX - Pointer to ASCIIZ filename
REM Output(s):
REM Carry Flag Clear if Successful
REM AX - File Handle
REM Carry Flag Set if Error
REM AX - Error Code
PATH_NOT_FOUND = 03h
NO_HANDLES_AVAILABLE = 04h
ACCESS_DENIED = 05h
;............................................................................
REM -- DOS Interrupt 21h
DOS_FILE_CREATE_SAFE = 5Bh
REM Input(s):
REM CX - File Attribute
REM 0000h Normal
REM 0002h Hidden
REM 0004h System
REM 0006h Hidden+System
REM DS:DX - Pointer to ASCIIZ filename
REM Output(s):
REM Carry Flag Clear if Successful
REM AX - File Handle
REM Carry Flag Set if Error
REM AX - Error Code
PATH_NOT_FOUND = 03h
NO_HANDLES_AVAILABLE = 04h
ACCESS_DENIED = 05h
FILE_ALREADY_EXIST = 50h
;............................................................................
REM -- DOS Interrupt 21h
DOS_FILE_CLOSE = 3Eh
REM Input(s):
REM BX - File Handle
REM Output(s):
REM Carry Flag Clear if Successful
REM Carry Flag Set if Error
REM AX - Error Code
INVALID_HANDLE = 06h
;............................................................................
REM -- DOS Interrupt 21h
DOS_FILE_OPEN = 3Dh
REM Input(s):
REM AL - Access Mode
REM Bit
REM 76543210
REM .....000 Read Access
REM .....001 Write Access
REM .....010 Read/Write Access
READ_ACCESS = 0h
WRITE_ACCESS = 1h
READ_WRITE_ACCESS = 2h
REM DS:DX - ASCIIZ Filename
REM Output(s):
REM AX - File Handle
REM Carry Flag Clear if Successful
REM Carry Flag Set if Error
REM Error Codes in AX:
INVALID_FUNCTION = 01h
FILE_NOT_FOUND = 02h
PATH_NOT_FOUND = 03h
NO_HANDLES_AVAILABLE = 04h
ACCESS_DENIED = 05h
INVALID_ACCESS_CODE = 0Ch
;............................................................................
REM -- DOS interrupt 21h
DOS_FILE_WRITE = 40h
REM Input(s):
REM BX - File Handle
REM CX - Number of Bytes
REM DS:DX - Pointer to Buffer
REM Output(s):
REM AX - number of bytes rad
REM Carry Flag Clear if Successful
REM Carry Flag Set if error
REM Error Code in AX:
ACCESS_DENIED = 05h
INVALID_HANDLE = 06h
;............................................................................
REM -- DOS interrupt 21h
DOS_FILE_READ = 3Fh
REM Input(s):
REM BX - File Handle
REM CX - Number of Bytes
REM DS:DX - Pointer to Buffer
REM Output(s):
REM AX - number of bytes rad
REM Carry Flag Clear if Successful
REM Carry Flag Set if error
REM Error Code in AX:
REM 05h - Access Denied
REM 06h - Invalid Handle
;............................................................................
REM -- DOS interrupt 21h
DOS_FILE_MOVE_PTR = 42h
REM Input(s):
REM BX - File Handle
REM AL - METHOD CODE
DOS_FILE_BEGIN = 00h
DOS_FILE_CURRENT = 01h
DOS_FILE_END = 02h
REM CX - Most Significant Part of Offset
REM DX - Least Significant Part of Offset
REM Output(s):
REM DX:AX - New File Pointer Location
REM Carry Flag Clear if Successful
REM Carry Flag Set if Error
REM Error Code in AX:
REM 01h - Invalid Function
REM 06h - Invalid Handle
;............................................................................
DOS_NORMAL_FILE = 0000h
;............................................................................
REM -- DOS interrupt 21h
DOS_FILE_FIND_FIRST = 4Eh
REM Input(s):
REM CX - Attribute to use in search
REM DS:DX - pointer to ASCIIZ file specification
REM Output(s):
REM Carry Flag Clear if Successful
REM Carry Flag Set if Error
REM Error Code in AX:
DOS_FILE_NOT_FOUND = 0002h
DOS_INVALID_PATH = 0003h
DOS_NO_MORE_FILES = 0012h
;............................................................................
REM -- DOS interrupt 21h
DOS_CHAR_UP_CASE = 6520h
REM Input(s):
REM DL - character to be uppercased
REM Output(s):
REM DL - uppercased character
REM Carry Flag Clear if Successful
REM Carry Flag Set if Error
;............................................................................
REM -- DOS interrupt 21h
DOS_INTR_GET_VECT = 35h
REM Input(s):
REM AL - Interrupt Number
REM Output(s):
REM ES:BX - Pointer to Handler
;............................................................................
REM -- DOS interrupt 21h
DOS_INTR_SET_VECT = 25h
REM Input(s):
REM AL - Interrupt Handler
REM DS:DX - Pointer to Interrupt Handler
;............................................................................
REM -- DOS interrupt 21h
DOS_KEEP_TSR = 31h
REM Input(s):
REM AL - Return Code
REM DX - Memory size to reserve in paragraph
;............................................................................
REM -- DOS interrupt 21h
DOS_FILE_DELETE = 41h
REM Input(s):
REM DS:DX - Pointer to ASCIIZ file specification
REM Output(s):
REM Carry Flag Clear if Successful
REM Carry Flag Set if Error
REM AX - Error Code
FILE_NOT_FOUND = 0002h
ACCESS_DENIED = 0005h
;............................................................................
REM -- DOS interrupt 21h
DOS_FILE_RENAME = 56h
REM Input(s):
REM DS:DX - Pointer to ASCIIZ current file name
REM ES:DI - Pointer to ASCIIZ new filename
REM Output(s):
REM Carry Flag Clear if Successful
REM Carry Flag Set if Error
REM AX - Error Code
PATH_NOT_FOUND = 0003h
NO_HANDLES_AVAILABLE = 0004h
ACCESS_DENIED = 0005h
NOT_THE_SAME_DEVICE = 0011h
;............................................................................
REM -- DOS interrupt 21h
DOS_CREATE_DIRECTORY = 39h
REM Input(s):
REM DS:DX - Pointer to ASCIIZ path specification
REM Output(s):
REM Carry Flag Clear if Successful
REM Carry Flag Set if Error
PATH_NOT_FOUND = 0003h
ACCESS_DENIED = 0005h
;............................................................................
REM -- DOS interrupt 21h
DOS_GET_INITIAL_MCB = 52h
REM Output(s):
REM ES:BX - Pointer to first MCB
;............................................................................
REM -- DOS interrupt 21h
DOS_GET_BUSY_FLAG_ADDR = 34h
REM Output(s):
REM ES:BX - Pointer to InDOS Flag
REM value is 0 if not busy
;............................................................................
REM -- DOS interrupt 21h
DOS_EXIT = 4Ch
REM Input(s):
REM AL - Return Code
;............................................................................
REM -- DOS interrupt 21
DOS_RELEASE_MEM = 49h
REM Input(s):
REM ES - Segment Address of Block to Freed
REM Output(s):
REM Carry Flag clear if Successful
REM AX - Error Code
MCB_DESTROYED = 0007h
MCB_INVALID = 0009h
;............................................................................
REM -- DOS interrupt 16h
DOS_SET_DTA = 1Ah
REM Input(s):
REM DS:DX - pointer to a new DTA
;............................................................................
REM -- DOS interrupt 16h
DOS_GET_DTA = 1Ah
REM Output(s):
REM ES:BX - pointer to DTA
;............................................................................
REM -- BIOS interrupt 16h
BIOS_OLD_KEYSTAT = 01h
REM Output(s):
REM AL - ASCII Code
REM AH - Scan Code
REM Zero Flag Clear if there is a key available
REM Zero Flag Set if there is no key available
;............................................................................
REM -- BIOS interrupt 16h
BIOS_NEW_KEYSTAT = 11h
REM Output(s):
REM AL - ASCII Code
REM AH - Scan Code
REM Zero Flag Clear if there is a key available
REM Zero Flag Set if there is no key available
;............................................................................
REM -- BIOS interrupt 16h
BIOS_OLD_READKEY = 00h
REM Output(s):
REM AL - ASCII Code
REM AH - Scan Code
;............................................................................
REM -- BIOS interrupt 16h
BIOS_NEW_READKEY = 10h
REM Output(s):
REM AL - ASCII Code
REM AH - Scan Code
;............................................................................
REM -- BIOS interrupt 10h
BIOS_TELETYPE_WRITE = 0Eh
REM Input(s):
REM AL - Character
REM BH - Display Page
REM BL - Foreground Color
;............................................................................
REM -- BIOS interrupt 10h
BIOS_GET_CURSOR_POS = 03h
REM Input(s):
REM BH - page number
REM Output(s):
REM DL - column
REM DH - row
;............................................................................
REM -- BIOS interrupt 10h
BIOS_SET_CURSOR_POS = 02h
REM Input(s):
REM BH - page number
REM DL - column
REM DH - row
;............................................................................
REM -- BIOS interrupt 10h
BIOS_READ_CHAR_AT_POS = 08h
REM Input(s):
REM BH - page number
REM Output(s):
REM AL - the character
;............................................................................
REM -- BIOS interrupt 10h
BIOS_SCROLL_WIN_UP = 06h
REM Input(s):
REM AL - Number of lines to scroll
REM BH - Attribute use for blank area
REM CH - Row, upper left corner
REM CL - Column, upper lef corner
REM DH - Row, lower right corner
REM DL - Column, lower right corner
;............................................................................
REM -- BIOS interrupt 10h
BIOS_READ_CHAR_ATTR = 08h
REM Input(s):
REM BH - Display Page
REM Output(s):
REM AH - Attribute Byte
REM AL - Ascii Character
;............................................................................
REM -- BIOS interrupt 10h
BIOS_WRITE_CHAR_ATTR = 09h
REM Input(s):
REM AL - Character
REM BH - Display Page
REM BL - Attribute bye of character in AL
REM CX - Number of Characters to write
;............................................................................
REM - COLORS -
REM -- dark colors
BLACK = 00h
BLUE = 01h
GREEN = 02h
CYAN = 03h
RED = 04h
MAGENTA = 05h
BROWN = 06h
LIGHTGRAY = 07h
DARKGRAY = 08h
REM -- light colors
LIGHTBLUE = 09h
LIGHTGREEN = 0Ah
LIGHTCYAN = 0Bh
LIGHTRED = 0Ch
LIGHTMAGENTA = 0Dh
YELLOW = 0Eh
WHITE = 0Fh
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
macro ohNo addr
jne addr
endm
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
macro ohYes addr
je addr
endm
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
macro cle
push ax
mov ax, 0
cmp ax, 1
pop ax
endm
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
macro ste
push ax
mov ax, 1
cmp ax, 1
pop ax
endm
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
macro clz
push ax
mov ax, 0
cmp ax, 1
pop ax
endm
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
macro stz
push ax
mov ax, 1
cmp ax, 1
pop ax
endm
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
macro puts str
local disp
local s
jmp disp
s db str, '$'
disp:
mov ah, 09
mov dx, offset s
int 21h
endm
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
macro newLine
push ax
push dx
mov ah, DOS_DISPLAY_OUTPUT
mov dl, 0Dh
int 21h
mov dl, 0Ah
int 21h
pop dx
pop ax
endm
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
REM -- VARIOUS DATA STRUCTURES GOES HERE
;--)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)---)-
struc mcb
REM -- 'M' more to follow 'Z' zero to follow
linkIndicator db ?
segOfOwner dw ?
paragraphLen dw ?
db 3 dup(?)
asciiName db 8 dup(?)
ends
COMMAND_LINE_LEN_OFFSET = 80h
COMMAND_LINE_OFFSET = 81h
ENVIRONMENT_SEGMENT = 2Ch
FALSE = 0
TRUE = 1
NULL = 0
; MICHAEL BUEN