Category : Files from Magazines
Archive   : VOL10N13.ZIP
Filename : FILECTRL.ASM

 
Output of file : FILECTRL.ASM contained in archive : VOL10N13.ZIP
;--------------------------------------------------------------------;
; FILECTRL * Michael J. Mefford ;
; ;
; File viewer and deleter ;
;--------------------------------------------------------------------;

_TEXT SEGMENT PUBLIC 'CODE'
ASSUME CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT

ORG 100H
START: JMP MAIN

; DATA AREA
; ---------
COLOR_ATTRIBS STRUC
B DB 71H ;Blue on lt. gray
W DB 17H ;Lt. gray on blue
C DB 31H ;Blue on cyan
I DB 1FH ;White on blue
D DB 17H ;Lt. gray on blue
A DB 07H ;White on black
COLOR_ATTRIBS ENDS

COLOR COLOR_ATTRIBS <>

COLOR_ATTR COLOR_ATTRIBS <>
MONO_ATTR COLOR_ATTRIBS <70H, 07H, 70H, 0FH, 0FH, 70H>

BORDER_FLAG DB 0 ; =1 to disable.

ASCEND EQU 0
DESCEND EQU 3

NAME_SORT EQU 0 ;Index into SORT_TABLE JNZ
EXT_SORT EQU 4
SIZE_SORT EQU 8
DATE_SORT EQU 12
NO_SORT EQU 0FFH

SORT_ORDER DW ASCEND ;Index into SORTS_CODE (0 or 3)
SORT_INDEX DW NAME_SORT ;Default is Name.

COPYRIGHT DB "FILECTRL 1.0 Copyright (c) 1991 Michael J. Mefford",CR,LF
FIRST_RIGHTS DB "First Published in PC Magazine, July 16, 1991",CR,LF,LF

SYNTAX LABEL BYTE
DB "Syntax: FILECTRL [filespec] [options]",CR,LF,LF

DB "/M [+|-] + = Only include files modified since last backup",CR,LF
DB " - = Only include files NOT modified since last backup",CR,LF
DB "/H = Include Hidden files",CR,LF
DB "/R = Include Read-only files",CR,LF
DB "/P date = Only include files ON or Prior date",CR,LF
DB "/A date = Only include files ON or After date",CR,LF
DB " date format = mm/dd/yy",CR,LF
DB "/W WordStar files; remove high bit",CR,LF
DB "/N = Sort by Name",CR,LF
DB "/E = Sort by Extension",CR,LF
DB "/S = Sort by Size",CR,LF
DB "/D = Sort by Date",CR,LF
DB "/O = Sort by Original DOS DIR order",CR,LF
DB " default = Sort by Name",CR,LF
DB "/F Sort in descending order",CR,LF
DB "$"

SWITCH_CHARS DB "MHRP"
DB "AWNE"
DB "SDOF"
SWITCH_LEN EQU $ - SWITCH_CHARS

SWITCH_DISPATCH DW SW_MODIFIED, SW_HIDDEN, SW_READ_ONLY, SW_PRIOR
DW SW_AFTER, SW_WORDSTAR, SW_NAME, SW_EXT
DW SW_SIZE, SW_DATE, SW_ORIGINAL, SW_FORMAT


TAB EQU 9
CR EQU 13
LF EQU 10
CTRL_Z EQU 26
SPACE EQU 32
BOX EQU 254
FF EQU 12
SHIFT_KEYS EQU 3
ESC_SCAN EQU 1
Y_SCAN EQU 15H
N_SCAN EQU 31H
F1_SCAN EQU 3BH
F2_SCAN EQU 3CH
F3_SCAN EQU 3DH
F4_SCAN EQU 3EH
F5_SCAN EQU 3FH
F6_SCAN EQU 40H
F7_SCAN EQU 41H
F8_SCAN EQU 42H
F9_SCAN EQU 43H
F10_SCAN EQU 44H
KB_FLAG EQU 17H
UP_SCAN EQU 48H
DOWN_SCAN EQU 50H
LEFT_SCAN EQU 4BH
RIGHT_SCAN EQU 4DH
PGUP_SCAN EQU 49H
PGDN_SCAN EQU 51H
BS_SCAN EQU 0EH
DEL_SCAN EQU 53H
HOME_SCAN EQU 47H
END_SCAN EQU 4FH
ENTER_SCAN EQU 1CH
TAB_SCAN EQU 0FH
CTRL_HOME_SCAN EQU 77H
CTRL_END_SCAN EQU 75H
PLUS1_SCAN EQU 0DH
PLUS2_SCAN EQU 4EH
MINUS1_SCAN EQU 0CH
MINUS2_SCAN EQU 4AH
SHIFT_F4 EQU 57H
SHIFT_F5 EQU 58H
SHIFT_F6 EQU 59H
SHIFT_F9 EQU 5CH
SHIFT_F10 EQU 5DH
CTRL_F2 EQU 5FH
ALT_F1 EQU 68H
SPACE_SCAN EQU 39H

LEFT_ARROW EQU 27
RIGHT_ARROW EQU 26
UP_ARROW EQU 24
DOWN_ARROW EQU 25
COMMA EQU ","
DECIMAL_POINT EQU "."
PLUS_SIGN EQU "+"
MINUS_SIGN EQU "-"
NOTE EQU 1046 ; C

PORT_A EQU 60H

TRUE EQU 1
FALSE EQU 0

WORDSTAR_MASK DB 0FFH ;Storage for WordStar mask.
WORDSTAR DB 0FFH ;7Fh if strip WordStar high bit.
DOS_VERSION DW ?
SCREEN_COLOR DB ?
BREAK DB ?
DEFAULT_DRIVE DB ?
WORKING_DRIVE DB ?
CURRENT_DIR DB 66 DUP (?)
WORKING_DIR DB 66 DUP (?)

MATCHING STRUC
RESERVED DB 21 DUP (?)
ATTRIBUTE DB ?
FILE_TIME DW ?
FILE_DATE DW ?
SIZE_LOW DW ?
SIZE_HIGH DW ?
FILE_NAME DB 13 DUP (?)
MATCHING ENDS

FILE_RECORD STRUC
MARK DB ?
LIST_NAME DB 12 DUP (?)
LIST_BYTES DB 8 DUP (?)
LIST_DATE DB 11 DUP (?)
LIST_TIME DB 8 DUP (?)
FILE_RECORD ENDS

DIR_PTRS STRUC
TOP_LOC DW ?
BAR_LOC DW ?
DIR_PTRS ENDS

DIR_LEVEL DW 0
DIR_LEVEL_MAX EQU 20
DIR_POINTERS DIR_PTRS DIR_LEVEL_MAX DUP (<>)

KILOBYTES = 1024
PARAGRAPH = 16
FILENAME_SIZE = 64 ;64K
FILEBUFF_SIZE = 8 ;8K
FILENAME_SEG DW ?
FILEBUFF_SEG DW ?

TEMP_RECORD EQU FILENAME_SIZE * KILOBYTES - SIZE FILE_RECORD

DTA DB SIZE MATCHING DUP (?)
MARK_NAME DB ? ;Mark part of name.
ASCIIZ_NAME DB 13 DUP (?) ;ASCIIZ name.

EOF_FLAG DB FALSE
CURRENT_PAGE DW 0
BUFFER_PTR DW 0
BYTES_READ DW ?
FILE_POINTER DW ?,?
BUFFER_END DW ?
FILE_END DW ?,?
PAGE_INDEX DW 0 ;Index to current page address.
PAGE_MAX EQU 256 * 2 ; 2 bytes per page
PAGES DW PAGE_MAX DUP (?)
FAIL_FLAG DB FALSE ;True if open failed.
FILE_TYPE DW ? ;Address of file-type handler.
FILE_LINE DW ? ;Address of file-lines handler.
ROW DW 0
EXEC_EXTENSION DB "EXECOM"


CRT_MODE EQU 49H
CRT_COLS EQU 4AH
CRT_ROWS EQU 84H
COLUMNS DW ?
CRT_WIDTH DW ?
CRT_START DW ?
STATUS_REG DW 3BAH
VIDEO_SEG DW 0B000H
ROWS DB 24

LISTING_LEN DW ?
LISTING_ADDR DW 0
BAR_ADDR DW 0
LAST_ADDR DW ?

FILENAME DW ? ;Address of filespec to parse.
FILESPEC DW ? ;Address of parsed filespec.
FILESPEC_END DW ?
ATTR DW 10H ;Default = normal files and DIRs.

CASE DB 5FH ;Capitalize; =FFh if case sensitive.
JB_CODE EQU 72H
JA_CODE EQU 77H

STATE DW LISTING
FILE_CURRENT DB FALSE

SHORT_NAME EQU 0
LONG_NAME EQU 1
FULL_FILE EQU 2
ZOOM_STATE DB SHORT_NAME

LCOLUMN_START DW ?
LCOLUMN_LEN DW ?
LCOLUMN_BAL DW ?

FCOLUMN_START DW ?
FCOLUMN_LEN DW ?

MENU LABEL BYTE
DB " F2 Remove F3 New F5 Zoom F6 Sort "
SORT_MENU1 DB ?
DB " ("
SORT_MENU2 DB ?
DB ") F7 Name F8 Ext F9 Size F10 Date",0
DB " Ctrl-F2 Remove marked +/- Mark/Unmark "
DB "Tab, ", LEFT_ARROW, SPACE, RIGHT_ARROW, " select window Esc to Exit",0

PARENT DB "Dot-dot is the Parent directory",0
STAR_DOT_STAR DB "*.*",0
NOT_ENOUGH DB "Not enough memory",CR,LF,LF,"$"
NOT_FOUND DB "File not found",CR,LF,LF,"$"
ILLEGAL_PARAM DB "Illegal parameter"
CRLFLF DB CR,LF,LF,"$"

; CODE AREA
; ---------
KBD_STATUS DB ?

INT_9 PROC NEAR

PUSH AX
IN AL,PORT_A
CMP AL,0E0H
JZ INT_9_END
CMP AL,0E1H
JZ INT_9_END
MOV CS:KBD_STATUS,AL

INT_9_END: POP AX
JMP DWORD PTR CS:OLD9

INT_9 ENDP

;----------------------------------------------;
INT_24 PROC NEAR

STI
PUSHF
MOV CS:FAIL_FLAG,TRUE
MOV AL,3
CMP CS:DOS_VERSION,300H
JAE INT_24_END
XOR AL,AL
INT_24_END: POPF
IRET

INT_24 ENDP

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

MAIN PROC NEAR
CLD

MOV AH,30H
INT 21H
XCHG AL,AH
MOV DOS_VERSION,AX

CALL INSTALL_9
CALL INSTALL_24

XOR BH,BH
MOV AH,8
INT 10H
MOV SCREEN_COLOR,AH

MOV AX,3300H ;Get Ctrl-Break state.
INT 21H
MOV BREAK,DL

XOR DL,DL
MOV AX,3301H
INT 21H

MOV AH,19H ;Get default drive so can
INT 21H ; restore after we change it.
MOV DEFAULT_DRIVE,AL
MOV WORKING_DRIVE,AL

MOV SI,OFFSET CURRENT_DIR
CALL GET_DIR

MOV BX,OFFSET STACK_POINTER + 15
MOV CL,4
SHR BX,CL
ADD BX,(FILENAME_SIZE+FILEBUFF_SIZE) * (KILOBYTES/PARAGRAPH)
MOV AH,4AH ;Allocate memory.
INT 21H
JNC SETUP_STACK
MOV DX,OFFSET NOT_ENOUGH
JMP SHORT ERROR_EXIT ;If not enough, exit.

SETUP_STACK: MOV AX,OFFSET STACK_POINTER
MOV SP,AX ;Set up stack.
ADD AX,15
MOV CL,4
SHR AX,CL
MOV CX,DS
ADD AX,CX
MOV FILENAME_SEG,AX ;And data segments.
ADD AX,FILENAME_SIZE * (KILOBYTES / PARAGRAPH)
MOV FILEBUFF_SEG,AX

MOV DX,OFFSET DTA
MOV AH,1AH
INT 21H

MOV FILENAME,81H
CALL NEW_FILESPEC
JC ERROR_EXIT
CALL VIDEO_SETUP
CALL DISP_DIR
CALL INIT_ZOOM
CALL DISPLAY_MENU
CALL DISP_LISTING
CALL DISP_FILE
JMP SHORT NEXT_KEY

;************* Main Loop *************;

NEXT_KEY: CALL GETKEY
JC GOOD_EXIT
CMP AH,CR
JNZ CK_PLUS
CALL ENTER
JMP NEXT_KEY

CK_PLUS: CMP AH,"+"
JZ MAIN_DISPATCH
CMP AH,"-"
JZ MAIN_DISPATCH
CMP AH,SPACE
JBE MAIN_DISPATCH
CALL SEARCH
JMP NEXT_KEY

MAIN_DISPATCH: CALL [STATE]
JMP NEXT_KEY

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

ERROR_EXIT: CALL PRINT_STRING
MOV AL,1
JMP SHORT EXIT

GOOD_EXIT: CALL CLOSE_SCREEN
XOR AL,AL ;EL=0.

EXIT: PUSH AX
CALL UNINSTALL_9
CALL RESTORE_DIR
MOV DL,DEFAULT_DRIVE
MOV AH,0EH
INT 21H

MOV DL,BREAK
MOV AX,3301H
INT 21H

TERMINATE: MOV DX,OFFSET COPYRIGHT
CALL PRINT_STRING
POP AX
MOV AH,4CH
INT 21H

MAIN ENDP


;**************
; SUBROUTINES *
;**************
SEARCH: PUSH DS

CMP STATE,OFFSET LISTING
JNZ NO_MATCH

CMP AH,"a"
JB DO_SEARCH
CMP AH,"z"
JA DO_SEARCH
AND AH,5FH

DO_SEARCH: MOV SI,BAR_ADDR
MOV DS,FILENAME_SEG
CMP [SI.LIST_NAME],AH
JZ NEXT_SEARCH
XOR SI,SI
JMP SHORT NEXT_SEARCH2

NEXT_SEARCH: ADD SI,SIZE FILE_RECORD
NEXT_SEARCH2: CMP [SI.LIST_NAME],-1
JZ NO_MATCH
CMP [SI.LIST_NAME],AH
JNZ NEXT_SEARCH

POP DS
MOV BAR_ADDR,SI
MOV AX,LISTING_LEN
SHR AX,1
MOV BX,SIZE FILE_RECORD
MUL BX
SUB SI,AX
JNC STORE_MATCH
XOR SI,SI
STORE_MATCH: MOV LISTING_ADDR,SI
MOV FILE_CURRENT,FALSE
JMP SHORT SEARCH_END

NO_MATCH: POP DS
CALL BEEP

SEARCH_END: CALL DISP_LISTING
CALL DISP_FILE
RET

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

M_TAB: JMP SHORT DO_TOGGLE


M_LEFT: CMP STATE,OFFSET LISTING
JZ TOGGLE_END
JMP SHORT DO_TOGGLE

M_RIGHT: CMP STATE,OFFSET FILE
JZ TOGGLE_END

DO_TOGGLE: MOV BX,OFFSET FILE
CMP STATE,OFFSET FILE
JNZ CHANGE_STATE
MOV BX,OFFSET LISTING
CMP ZOOM_STATE,FULL_FILE
JNZ CHANGE_STATE
MOV AL,LAST_ZOOM
MOV ZOOM_STATE,AL
CHANGE_STATE: MOV STATE,BX
CALL INIT_ZOOM
CALL DISP_LISTING
CALL DISP_FILE

TOGGLE_END: RET

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

L_DISPATCH DB UP_SCAN, DOWN_SCAN, PGUP_SCAN, PGDN_SCAN
DB HOME_SCAN, END_SCAN, PLUS1_SCAN, PLUS2_SCAN
DB MINUS1_SCAN, MINUS2_SCAN, SPACE_SCAN

DB TAB_SCAN, LEFT_SCAN, RIGHT_SCAN, SHIFT_F5
DB F2_SCAN, F3_SCAN, F5_SCAN, F6_SCAN
DB F7_SCAN, F8_SCAN, F9_SCAN, F10_SCAN
DB CTRL_F2

L_LEN EQU $ - L_DISPATCH

DW LUP, LDOWN, LPGUP, LPGDN
DW LHOME, LEND, PLUS, PLUS
DW MINUS, MINUS, FLOP_MARK

DW M_TAB, M_LEFT, M_RIGHT, SHIFT_ZOOM
DW REMOVE, NEW_FILE, ZOOM, SORT_DIR
DW SORT_NAME, SORT_EXT, SORT_SIZE, SORT_DATE
DW REMOVE_MARKS

;INPUT: AL=scan code.

LISTING: MOV DI,OFFSET L_DISPATCH
MOV CX,L_LEN
CALL DISPATCH
CALL DISP_LISTING
RET

;----------------------------------------------;
; INPUT: AX=Listing page; BP=BAR_ADDR; DX=LISTING_ADDR; CX=LAST_ADDR.
; OUTPUT: LISTING_FLAG=TRUE if listing changed.

FLOP_MARK: PUSH DS
MOV DS,FILENAME_SEG
MOV AL,DS:[BP]
CMP AL,"<"
JNZ GET_FLOP
POP DS
JMP LPAGE_END
GET_FLOP: MOV AH,SPACE
CMP AL,AH
JNZ DO_FLOP
MOV AH,RIGHT_ARROW
DO_FLOP: MOV DS:[BP],AH
POP DS
JMP LPAGE_END


PLUS: MOV AL,RIGHT_ARROW ;Use little right arrow for mark.
JMP SHORT PLUSMINUS

MINUS: MOV AL,SPACE ;Remove mark with space char.

PLUSMINUS: PUSH DS
MOV DS,FILENAME_SEG
CMP DS:BYTE PTR [BP],"<"
JZ PLUSMINUS2
MOV DS:[BP],AL
PLUSMINUS2: POP DS
JMP SHORT LDOWN


LUP: SUB BP,SIZE FILE_RECORD ;Move bar up a line.
JL LPAGE_END ;If < 0, ignore.
CMP BP,DX ;If bar below top, OK.
JAE LPAGE_UPDATE
SUB DX,SIZE FILE_RECORD ;Else, move listing up a line.
JMP SHORT LPAGE_UPDATE

LDOWN: ADD BP,SIZE FILE_RECORD ;Move bar down a line.
CMP BP,CX ;If > last line, then ignore.
JA LPAGE_END
ADD AX,DX ;Listing top + page length =
CMP BP,AX ; listing bottom; If bar below
JB LPAGE_UPDATE ; listing bottom, OK.
ADD DX,SIZE FILE_RECORD ;Else move listing down a line.
JMP SHORT LPAGE_UPDATE

LPGUP: SUB BP,AX ;Move bar up a page.
SUB DX,AX ;Move listing up a page.
JC LHOME ;If listing < top, then home.
JMP SHORT LPAGE_UPDATE ;Else, OK.

LPGDN: ADD DX,AX ;Move listing down a page.
CMP DX,CX ;If <= last line, do bar.
JBE DO_BAR
SUB DX,AX ;Else, back to where we were
MOV BP,CX ; and move bar to last line
JMP SHORT LPAGE_UPDATE ; and update.
DO_BAR: ADD BP,AX ;Move bar down a page.
CMP BP,CX ;If bar <= last line, OK.
JBE LPAGE_UPDATE
MOV BP,CX ;Else, move bar to last line.
JMP SHORT LPAGE_UPDATE

LHOME: XOR BP,BP ;Move bar to top.
XOR DX,DX ;Move listing to top.
JMP SHORT LPAGE_UPDATE

LEND: MOV BP,CX ;Move bar to last line.
ADD CX,SIZE FILE_RECORD ;Last line + 1 - page length =
SUB CX,AX ; top of last page.
CMP DX,CX ;If less than a full page,
JG LPAGE_UPDATE ; then already at last page.
MOV DX,CX ;Else, move listing to last page.

LPAGE_UPDATE: MOV BAR_ADDR,BP ;Store the new bar
MOV LISTING_ADDR,DX ; and listing line start.
MOV FILE_CURRENT,FALSE
MOV FAIL_FLAG,FALSE

LPAGE_END: RET

;----------------------------------------------;
F_DISPATCH DB UP_SCAN, DOWN_SCAN, PGUP_SCAN, PGDN_SCAN
DB HOME_SCAN, END_SCAN

DB TAB_SCAN, LEFT_SCAN, RIGHT_SCAN, SHIFT_F5
DB F2_SCAN, F3_SCAN, F5_SCAN, F6_SCAN
DB F7_SCAN, F8_SCAN, F9_SCAN, F10_SCAN
DB CTRL_F2

F_LEN EQU $ - F_DISPATCH

DW FUP, FDOWN, FPGUP, FPGDN
DW FHOME, FEND

DW M_TAB, M_LEFT, M_RIGHT, SHIFT_ZOOM
DW REMOVE, NEW_FILE, ZOOM, SORT_DIR
DW SORT_NAME, SORT_EXT, SORT_SIZE, SORT_DATE
DW REMOVE_MARKS

FILE: CMP FILE_CURRENT,TRUE
JZ DISPATCH_FILE
CALL OPEN_FILE
JC END_FILE

DISPATCH_FILE: MOV DI,OFFSET F_DISPATCH
MOV CX,F_LEN
CALL DISPATCH
END_FILE: RET

;----------------------------------------------;
FUP: CMP ROW,0
JNZ DEC_ROW
CMP PAGE_INDEX,0
JNZ CK_UP
JMP NO_UPDATE
CK_UP: MOV AX,LISTING_LEN
DEC AX
MOV ROW,AX
JMP SHORT FPGUP
DEC_ROW: DEC ROW
JMP FILE_UPDATE

;--------------;
FDOWN: MOV AX,ROW
INC AX
MOV ROW_CNT,AX
MOV SI,CURRENT_PAGE
MOV BYTE PTR DISPLAY_FLAG,FALSE
PUSH DS
MOV DS,FILEBUFF_SEG
FDOWN2: CALL CS:[FILE_LINE]
DEC CS:ROW_CNT
JNZ FDOWN2
POP DS
CMP SI,BUFFER_END
JNZ CK_ROW
CMP EOF_FLAG,TRUE
JZ NO_UPDATE

CK_ROW: MOV AX,ROW
INC AX
CMP AX,LISTING_LEN
JB INC_ROW
MOV ROW,0
CALL INC_PAGE
JMP SHORT FILE_UPDATE

INC_ROW: INC ROW
JMP SHORT FILE_UPDATE

;--------------;
FPGUP: CMP PAGE_INDEX,0
JNZ DEC_PG
MOV ROW,0
JMP SHORT FILE_UPDATE

DEC_PG: MOV SI,CURRENT_PAGE
MOV BX,PAGE_INDEX
SUB SI,PAGES[BX]
JNC DEC_PG2
CALL BACKWARD
JMP DEC_PG
DEC_PG2: SUB PAGE_INDEX,2
MOV CURRENT_PAGE,SI
JMP SHORT FILE_UPDATE

;--------------;
FPGDN: CALL CK_PAGE
JC NO_UPDATE
JMP SHORT FILE_UPDATE

;--------------;
FHOME: CALL OPEN_FILE
JMP SHORT FILE_UPDATE

;--------------;
FEND: CALL CK_PAGE
JNC FEND

FILE_UPDATE: CALL DISP_FILE
NO_UPDATE: RET

;--------------;
CK_PAGE: CMP PAGE_INDEX,PAGE_MAX
JAE NO_PAGE

MOV SI,CURRENT_PAGE
MOV AX,LISTING_LEN
MOV ROW_CNT,AX

MOV BYTE PTR DISPLAY_FLAG,FALSE
PUSH DS
MOV DS,FILEBUFF_SEG
NEXT_PAGE: CALL CS:[FILE_LINE]
DEC CS:ROW_CNT
JNZ NEXT_PAGE
POP DS

CMP SI,BUFFER_END
JNZ INC_PAGE
CMP EOF_FLAG,TRUE
JZ NO_PAGE
INC_PAGE: MOV DX,CURRENT_PAGE
MOV CURRENT_PAGE,SI
SUB SI,DX
MOV BX,PAGE_INDEX
INC BX
INC BX
MOV PAGE_INDEX,BX
MOV PAGES[BX],SI
CLC
JMP SHORT CK_PAGE_END

NO_PAGE: STC
CK_PAGE_END: RET

;----------------------------------------------;
; OUTPUT: CF = 1 if failed.

OPEN_FILE: PUSH AX
MOV BP,BAR_ADDR
CALL MAKE_FILENAME
CMP MARK_NAME,-1
JZ OPEN_FAIL
CMP MARK_NAME,"<"
JNZ OPEN_FILE2
MOV FILE_TYPE,OFFSET SUBDIR
MOV FILE_LINE,OFFSET DUMMY_RET
JMP SHORT OPEN_GOOD

OPEN_FILE2: MOV FILE_POINTER[0],0
MOV FILE_POINTER[2],0
MOV FILE_END[0],-1
MOV FILE_END[2],-1 ;Large number to fill buffer.

MOV CURRENT_PAGE,FILEBUFF_SIZE * KILOBYTES / 2
MOV PAGE_INDEX,0
MOV ROW,0

XOR SI,SI
CALL READ
JC OPEN_FAIL
CALL GET_TYPE
OPEN_GOOD: MOV FILE_CURRENT,TRUE
CLC
JMP SHORT OPEN_END

OPEN_FAIL: CALL CLEAR_FILE
CALL BEEP
STC

OPEN_END: POP AX
RET

;----------------------------------------------;
; INPUT: SI -> Read offset (0 or FILEBUFF_SIZE * KILOBYTES / 2)
; OUTPUT: CF=1 if read failed.

READ: CMP FAIL_FLAG,TRUE
JNZ READ_NAME
STC
JMP READ_END

READ_NAME: MOV DX,OFFSET ASCIIZ_NAME
MOV AX,3D00H
INT 21H
JC READ_END
CMP FAIL_FLAG,TRUE
STC
JZ READ_END

MOV BX,AX

MOV DX,FILE_POINTER[0]
MOV CX,FILE_POINTER[2]
MOV AX,4200H
INT 21H
JC CLOSE

MOV CX,DX
MOV DX,AX
MOV AX,FILE_END[0]
MOV DI,FILE_END[2]
SUB AX,DX
SBB DI,CX
OR AX,AX
JNZ READ1
OR DI,DI
JZ DO_EOF

READ1: MOV CX,FILEBUFF_SIZE * KILOBYTES / 2
OR DI,DI
JNZ READ2
CMP CX,AX
JB READ2
MOV CX,AX

READ2: MOV DX,SI
PUSH DS
MOV DS,FILEBUFF_SEG
MOV AH,3FH
INT 21H
POP DS
CMP FAIL_FLAG,TRUE
STC
JZ CLOSE

MOV BYTES_READ,AX
ADD FILE_POINTER[0],AX
ADC FILE_POINTER[2],0
MOV DX,AX
ADD DX,FILEBUFF_SIZE * KILOBYTES / 2
MOV BUFFER_END,DX
MOV EOF_FLAG,FALSE
CMP AX,FILEBUFF_SIZE * KILOBYTES / 2
JZ CLOSE1

DO_EOF: MOV EOF_FLAG,TRUE

CLOSE1: CLC

CLOSE: PUSHF
MOV AH,3EH
INT 21H
POPF

READ_END: RET

;----------------------------------------------;
FORWARD: PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH BP
PUSH DS
PUSH ES

MOV CX,FILEBUFF_SIZE * KILOBYTES / 2
SUB CS:BUFFER_PTR,CX
SUB CS:CURRENT_PAGE,CX
MOV SI,CX
XOR DI,DI
MOV AX,DS
MOV ES,AX
SHR CX,1
REP MOVSW
MOV SI,DI
PUSH CS
POP DS
CALL READ

POP ES
POP DS
POP BP
POP DI
POP DX
POP CX
POP BX
POP AX
FORWARD_END: RET

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

BACKWARD: PUSH DS
PUSH ES
MOV CX,FILEBUFF_SIZE * KILOBYTES / 2
ADD CURRENT_PAGE,CX
MOV DI,CX
XOR SI,SI
MOV AX,FILEBUFF_SEG
MOV DS,AX
MOV ES,AX
SHR CX,1
REP MOVSW
POP ES
POP DS

MOV AX,BYTES_READ
ADD AX,FILEBUFF_SIZE * KILOBYTES
SUB FILE_POINTER[0],AX
SBB FILE_POINTER[2],0
XOR SI,SI
CALL READ
JC BACKWARD_END
ADD FILE_POINTER[0],FILEBUFF_SIZE * KILOBYTES / 2
ADC FILE_POINTER[2],0

BACKWARD_END: RET

;----------------------------------------------;
WP_FILE_PREFACE STRUC
WPCorp_FILE_ID DB -1,"WPC" ;Signature
START_OF_DOC DW ?,?
PRODUCT_TYPE DB 1 ;WordPerfect
WP_FILE_TYPE DB 10 ;Document
MAJOR_VER DB 0
MINOR_VER DB 0
ENCRYPTION_KEY DW 0 ;0 = not encrypted
WP_RESERVED DW 0
WP_FILE_PREFACE ENDS

WP_PREFACE WP_FILE_PREFACE <>

;--------------;
WORD_FILE_INFORMATION_BLOCK STRUC
wIdent DW 0BE31H ;Signature
dtyDW DW 0 ;Document type
wTool DW 0AB00H ;Signature
pnNextFib DW ? ;Pointer to incremental save
pnChar DW ? ;Pointer to Char formatting
pnPlcpcd DW ? ;Pointer to piece table
wReserved2 DW ? ;Paragraph height table
fcMac DW ?,? ;File char pos of file end
pnPara DW ? ;Location of para formatting
pnFntb DW ? ;Location of footnote table
pnBkmk DW ? ;Bookmarks and sequence info
pnSetb DW ? ;Section table
pnBftb DW ? ;Buffer table
pnSumd DW ? ;Summary information
szSsht DB 66 DUP(?) ;Style sheet path
wReserve DW ? ;For Windows Write use
rgchPrtNm DB 8 DUP(?) ;Printer name
pnMac DW ? ;One past end of document
DOP DB 8 DUP(?) ;Document properties
version DB ? ;word version
fAsv DB ? ;Autosave
pnPagb DW ? ;Word 5.0 page table
pnMacBkmk DW ? ;Mac of Bkmk stuff
pnFilename DW ? ;Only used for Asv files
pnRhtb DW ? ;Running head table
codepage DW ? ;codepage
WORD_FILE_INFORMATION_BLOCK ENDS

WORD_FIB WORD_FILE_INFORMATION_BLOCK <>

;--------------;
QandA_HDR STRUC
sig DB "TBWP",0 ;Touchbase signature
QandA_date DB 13 DUP (?) ;Date file last updated
QandA_time DB 9 DUP (?) ;Time file last updated
reltxtloc DW ?,? ;File rel loc of start of text
txtsize DW ?,? ;Size of the text
ver DW ? ;Version number
ehdr DB ? ;End of file header
QandA_HDR ENDS

;Q&A files have for the signature either
; TBWP (TouchBase Word Processing file) or
; TBTX (TouchBase TeXt file).

sig2 DB "TBTX",0

QandA_HEADER QandA_HDR <>

;----------------------------------------------;
GET_TYPE: PUSH DS
MOV FILE_POINTER[0],0
MOV FILE_POINTER[2],0

;----------------;
; Executable
MOV FILE_TYPE,OFFSET EXECUTABLE
MOV FILE_LINE,OFFSET DUMMY_RET
MOV BX,BAR_ADDR
ADD BX,10 ;Extension.
MOV SI,BX
MOV DS,FILENAME_SEG
MOV DI,OFFSET EXEC_EXTENSION
MOV CX,3
REPZ CMPSB
JZ EXEC_TYPE
MOV SI,BX
MOV DI,OFFSET EXEC_EXTENSION + 3
MOV CX,3
REPZ CMPSB
JNZ GET_TYPE2
EXEC_TYPE: POP DS
JMP TYPE_END

;----------------;
;WordPerfect

GET_TYPE2: MOV DS,CS:FILEBUFF_SEG
MOV CS:FILE_TYPE,OFFSET DOCUMENT
MOV CS:FILE_LINE,OFFSET WP_LINES
CMP CS:BYTES_READ,SIZE WP_PREFACE
JB GET_TYPE3
XOR SI,SI
MOV DI,OFFSET WP_PREFACE
MOV CX,4
REPZ CMPSB
JNZ GET_TYPE3
LODSW ;Start low word
MOV CS:FILE_POINTER[0],AX
LODSW ;Start high word
MOV CS:FILE_POINTER[2],AX
ADD DI,4
MOV CX,SIZE PRODUCT_TYPE + SIZE WP_FILE_TYPE
REPZ CMPSB
JNZ GET_TYPE3
INC SI
INC SI
INC DI
INC DI
CMPSB ;Encryption Key.
JNZ GET_TYPE3

POP DS
MOV DX,OFFSET ASCIIZ_NAME
MOV AH,4EH
INT 21H
MOV AX,WORD PTR DTA.SIZE_LOW
MOV FILE_END[0],AX
MOV AX,WORD PTR DTA.SIZE_HIGH
MOV FILE_END[2],AX
JMP READ_FILE

;----------------;
;Word

GET_TYPE3: MOV CS:FILE_TYPE,OFFSET DOCUMENT
MOV CS:FILE_LINE,OFFSET ASCII_LINES
MOV CS:WORDSTAR,0FFH
CMP CS:BYTES_READ,SIZE WORD_FIB
JB GET_TYPE4
XOR SI,SI
MOV DI,OFFSET WORD_FIB
MOV CX,6
REPZ CMPSB
JNZ GET_TYPE4
; CMP DS:fAsv,0 ;Only if temp file.
; JNZ GET_TYPE4
MOV AX,DS:fcMac[0]
MOV DX,DS:fcMac[2]

POP DS
MOV FILE_END[0],AX
MOV FILE_END[2],DX
MOV FILE_POINTER[0],128
MOV FILE_POINTER[2],0
JMP SHORT READ_FILE

;----------------;
GET_TYPE4: MOV CS:FILE_TYPE,OFFSET DOCUMENT
MOV CS:FILE_LINE,OFFSET QandA_LINES
CMP CS:BYTES_READ,SIZE QandA_HEADER
JB GET_TYPE5
XOR SI,SI
MOV DI,OFFSET QandA_HEADER
MOV CX,5
REPZ CMPSB
JZ GOT_QandA
XOR SI,SI
MOV DI,OFFSET sig2
MOV CX,5
REPZ CMPSB
JNZ GET_TYPE5

GOT_QandA: MOV AX,DS:reltxtloc[0]
MOV DX,DS:reltxtloc[2]
MOV CX,DS:txtsize[0]
MOV BX,DS:txtsize[2]
POP DS
MOV FILE_POINTER[0],AX
MOV FILE_POINTER[2],DX
ADD AX,CX
ADC DX,BX
MOV FILE_END[0],AX
MOV FILE_END[2],DX
JMP SHORT READ_FILE

;----------------;
; Insert other types here

GET_TYPE5:

;----------------;
; ASCII if not any other special type.

POP DS
MOV FILE_TYPE,OFFSET DOCUMENT
MOV FILE_LINE,OFFSET ASCII_LINES
MOV AL,WORDSTAR_MASK
MOV WORDSTAR,AL

MOV DX,OFFSET ASCIIZ_NAME
MOV AH,4EH
INT 21H
MOV AX,WORD PTR DTA.SIZE_LOW
MOV FILE_END[0],AX
MOV AX,WORD PTR DTA.SIZE_HIGH
MOV FILE_END[2],AX

READ_FILE: MOV SI,FILEBUFF_SIZE * KILOBYTES / 2
CALL READ
JNC TYPE_END
MOV FILE_CURRENT,FALSE

TYPE_END: RET

;----------------------------------------------;
CLEAR_FILE: PUSH ES
MOV BP,LISTING_LEN
MOV DX,STATUS_REG ;Retrieve status register.
MOV ES,VIDEO_SEG
MOV DI,FCOLUMN_START
MOV BP,LISTING_LEN
MOV BH,COLOR.W
MOV AL,SPACE

NEXT_CLEAR: PUSH DI
MOV CX,FCOLUMN_LEN
NEXT_CLEAR2: CALL WRITE_CHAR
LOOP NEXT_CLEAR2
POP DI
ADD DI,CRT_WIDTH
DEC BP
JNZ NEXT_CLEAR
POP ES
RET

;--------------------------------------------------------------;
; INPUT: BP -> Source filename; OUTPUT: ASCIIZ_NAME = filename ;
;--------------------------------------------------------------;
MAKE_FILENAME: PUSH DS
MOV DS,FILENAME_SEG ;DS:SI -> Source name.
MOV SI,BP
MOV DI,OFFSET MARK_NAME ;Name storage.
MOVSB ;Copy mark.
MOV CX,8 ;8 characters of name.
NEXT_NAME: LODSB
CMP AL,SPACE ;End of name?
JZ EXTENSION2 ;If yes, do extension.
STOSB
LOOP NEXT_NAME
EXTENSION2: MOV SI,BP ;Retrieve name start.
ADD SI,10 ;Move to extension field.
CMP BYTE PTR [SI],SPACE ;Is there any extension?
JZ NAME_DONE ;If no, done.
MOV AL,"." ;Else, add delimiting dot.
STOSB
MOV CX,3 ;3 characters for extension.
NEXT_EXT: LODSB
CMP AL,SPACE
JZ NAME_DONE
STOSB
LOOP NEXT_EXT
NAME_DONE: XOR AL,AL ;ASCIIZ.
STOSB
POP DS
RET

;----------------------------------------------;
REMOVE_CNT DW ?

REMOVE1_MSG DB " marked files",0
REMOVE2_MSG DB " to be deleted?",0
REMOVE3_MSG DB " Do you wish to delete? Y/N",0

REMOVE_MARKS: PUSH DS
MOV DS,FILENAME_SEG
XOR SI,SI
XOR CX,CX
JMP SHORT NEXT_COUNT2

NEXT_COUNT: ADD SI,SIZE FILE_RECORD
NEXT_COUNT2: CMP SI,LAST_ADDR
JA GOT_COUNT
CMP BYTE PTR [SI],RIGHT_ARROW
JNZ NEXT_COUNT
INC CX
JMP NEXT_COUNT

GOT_COUNT: POP DS
JCXZ MARKS_ERR
MOV REMOVE_CNT,CX
MOV SI,OFFSET REMOVE1_MSG
CALL REMOVE_QUERY
JC MARKS_END

MOV BAR_ADDR,0
MOV LISTING_ADDR,0
JMP SHORT NEXT_REMOVE3

NEXT_REMOVE: CALL GET_PARAMS
CALL LDOWN
NEXT_REMOVE2: CALL DISP_LISTING
NEXT_REMOVE3: PUSH DS
MOV DS,FILENAME_SEG
MOV SI,CS:BAR_ADDR
CMP BYTE PTR [SI],RIGHT_ARROW
POP DS
JNZ NEXT_REMOVE
CALL REMOVE_IT
JC MARKS_ERR
CALL CK_KEY
JNZ MARKS_END
DEC REMOVE_CNT
JNZ NEXT_REMOVE2
JMP SHORT MARKS_END

MARKS_ERR: CALL BEEP
MARKS_END: CALL HIDE_CURSOR
CALL DISPLAY_MENU
CALL DISP_FILE
CALL CLEAR_KEY
RET

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

REMOVE: PUSH DS
MOV SI,BAR_ADDR
MOV DS,FILENAME_SEG
LODSW
POP DS
CMP AL,-1
JZ REMOVE_ERR
CMP AL,"<"
JNZ REMOVE2
CMP AH,"."
JZ REMOVE_ERR

REMOVE2: MOV BP,BAR_ADDR
CALL MAKE_FILENAME
MOV SI,OFFSET ASCIIZ_NAME
CALL REMOVE_QUERY
JC REMOVE_END
CALL REMOVE_IT
JC REMOVE_ERR

MOV FILE_CURRENT,FALSE
CALL DISP_LISTING
CALL DISP_FILE
JMP SHORT REMOVE_END

REMOVE_ERR: CALL BEEP
REMOVE_END: CALL HIDE_CURSOR
CALL DISPLAY_MENU
RET

;--------------;
; INPUT: SI -> msg; REMOVE_CNT = count.
; OUTPUT: CF = 1 if abort.

REMOVE_QUERY: CALL CLEAR_MENU
CALL MENU_OFFSET
PUSH ES
PUSH DI
MOV DX,STATUS_REG
MOV ES,VIDEO_SEG
MOV AL,SPACE
CALL WRITE_CHAR

PUSH SI
CMP SI,OFFSET REMOVE1_MSG
JNZ DO_MSG
MOV AX,REMOVE_CNT
XOR DX,DX
CALL DISP_STATS

DO_MSG: POP SI
CALL WRITE_LINE
MOV SI,OFFSET REMOVE2_MSG
CALL WRITE_LINE
POP DI
ADD DI,CRT_WIDTH
MOV SI,OFFSET REMOVE3_MSG
CALL WRITE_LINE
POP ES

XOR AH,AH
INT 16H
CMP AH,Y_SCAN
STC
JNZ QUERY_END
CLC
QUERY_END: RET

;----------------------------------------------;
; INPUT: DX:AX = number; DI -> Display

DISP_STATS: MOV BP,DX
MOV SI,AX
XOR CX,CX
MOV BX,10
JMP SHORT DO_DIV

NEXT_DIV: CMP CH,3
JNZ DO_DIV
MOV AL,","
PUSH AX
XOR CH,CH
INC CL

DO_DIV: MOV AX,BP
XOR DX,DX
DIV BX
MOV BP,AX
MOV AX,SI
DIV BX
MOV SI,AX
MOV AX,DX
ADD AL,"0"

PUSH AX
ADD CX,0101H
OR BP,BP
JNZ NEXT_DIV
OR SI,SI
JNZ NEXT_DIV

XOR CH,CH
; SUB DI,CX ; Add this to right justify
; SUB DI,CX
MOV BH,COLOR.B
MOV DX,STATUS_REG
NEXT_WRITE: POP AX
CALL WRITE_CHAR
LOOP NEXT_WRITE
RET

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

REMOVE_IT: MOV BP,BAR_ADDR
CALL MAKE_FILENAME
MOV DX,OFFSET ASCIIZ_NAME
XOR CX,CX
MOV AX,4301H ;Normal attribute.
INT 21H

PUSH DS
MOV DS,FILENAME_SEG
MOV AL,DS:[BP]
POP DS
CMP AL,"<"
MOV AH,3AH ;RMDIR
JZ REMOVE_IT2

MOV AH,41H
REMOVE_IT2: INT 21H
JC REMOVE_IT_END
CMP FAIL_FLAG,TRUE
STC
JZ REMOVE_IT_END
CALL MOVE_RECS
CLC
REMOVE_IT_END: RET

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

MOVE_RECS: PUSH DS
PUSH ES
MOV DI,BAR_ADDR
MOV SI,DI
ADD SI,SIZE FILE_RECORD
MOV AX,FILENAME_SEG
MOV DS,AX
MOV ES,AX
NEXT_MOVE: MOV CX,SIZE FILE_RECORD / 2
REP MOVSW
CMP DI,CS:LAST_ADDR
JNA NEXT_MOVE
POP ES
POP DS

MOV CX,SIZE FILE_RECORD
SUB LAST_ADDR,CX

MOV AX,LAST_ADDR
CMP BAR_ADDR,AX
JNA MOVE_END
SUB BAR_ADDR,CX
MOVE_END: RET

;----------------------------------------------;
NEW_FILE: CALL CLEAR_MENU
CALL GET_NAME
JC NEW_END
MOV FILENAME,81H
CALL NEW_FILESPEC
JC NO_NEW
MOV FILE_CURRENT,FALSE
MOV BAR_ADDR,0
MOV LISTING_ADDR,0
MOV DIR_LEVEL,0
CALL DISP_DIR
CALL DISP_LISTING
CALL DISP_FILE
JMP SHORT NEW_END

NO_NEW: CALL BEEP

NEW_END: CALL HIDE_CURSOR
CALL DISPLAY_MENU
RET

;----------------------------------------------;
LAST_STATE DW ?
LAST_ZOOM DB SHORT_NAME

ZOOM: MOV AH,1
JMP SHORT DO_ZOOM
SHIFT_ZOOM: MOV AH,-1

DO_ZOOM: MOV AL,ZOOM_STATE
MOV BL,AL
ADD AL,AH
JNL CK_UPPER
MOV AL,FULL_FILE
CK_UPPER: CMP AL,FULL_FILE
JBE GOT_ZOOM
MOV AL,SHORT_NAME
GOT_ZOOM: CALL CHANGE_ZOOM
RET

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

CHANGE_ZOOM: MOV ZOOM_STATE,AL
MOV LAST_ZOOM,BL
CMP AL,FULL_FILE
JNZ DISP_ZOOM
MOV BX,STATE
MOV LAST_STATE,BX
MOV STATE,OFFSET FILE

DISP_ZOOM: CMP BL,FULL_FILE
JNZ DISP_ZOOM2
MOV BX,LAST_STATE
MOV STATE,BX

DISP_ZOOM2: CALL INIT_ZOOM
CALL DISP_LISTING
CALL DISP_FILE
RET

;----------------------------------------------;
SORT_DIR: XOR SORT_ORDER,DESCEND
CALL SORT
CALL DISPLAY_MENU
MOV FILE_CURRENT,FALSE
CALL DISP_LISTING
CALL DISP_FILE
RET

;----------------------------------------------;
DISP_LISTING: PUSH DS
PUSH ES
MOV DI,LCOLUMN_START

MOV SI,LISTING_ADDR
MOV BP,LISTING_LEN

MOV DX,STATUS_REG ;Retrieve status register.
MOV ES,VIDEO_SEG ;Point to screen segment.
MOV DS,FILENAME_SEG

NEXT_LISTING: PUSH DI
MOV CX,CS:LCOLUMN_LEN
JCXZ CK_LAST_LINE

DISPLAY_LINE: MOV BH,CS:COLOR.I
CMP BYTE PTR [SI],-1
JZ PAD_LISTING
CMP SI,CS:BAR_ADDR
JZ CK_BAR_COLOR
CMP CS:STATE,OFFSET FILE
JNZ DISPLAY_LINE2
MOV BH,CS:COLOR.W
JMP SHORT DISPLAY_LINE2

CK_BAR_COLOR: MOV BH,CS:COLOR.C
CMP CS:STATE,OFFSET FILE
JNZ DISPLAY_LINE2
MOV BH,CS:COLOR.A

DISPLAY_LINE2: LODSB
CALL WRITE_CHAR
LOOP DISPLAY_LINE2

ADD SI,CS:LCOLUMN_BAL

CK_LAST_LINE: POP DI
ADD DI,CS:CRT_WIDTH
DEC BP
JNZ NEXT_LISTING
POP ES
POP DS
RET

PAD_LISTING: CALL PAD_LINE
JMP SHORT CK_LAST_LINE

PAD_LINE: MOV AL,SPACE
PAD_LINE2: CALL WRITE_CHAR
LOOP PAD_LINE2
RET

;----------------------------------------------;
DISPLAY_FLAG DB TRUE
LINE_CNT DW ? ;Counter for display line.
LINE_MAX EQU 80 ;Maximum line length supported.
ROW_CNT DW ?

DISP_FILE: PUSH ES
CMP FILE_CURRENT,TRUE
JZ DISP_FILE2
CALL OPEN_FILE
JC DISP_FILE_END

DISP_FILE2: MOV BH,COLOR.I
CMP STATE,OFFSET FILE
JZ DISP_FILE3
MOV BH,COLOR.W

DISP_FILE3: MOV DX,STATUS_REG ;Retrieve status register.
MOV ES,VIDEO_SEG ;Point to screen segment.
MOV DI,FCOLUMN_START
MOV AX,LISTING_LEN
MOV LINE_CNT,AX
CALL [FILE_TYPE]

DISP_FILE_END: POP ES
RET

;----------------------;
SUBDIRECTORY DB " is a Subdirectory"
SUBEND DB 0
PRESS_ENTER DB " Press Enter to load its files.",0

; INPUT: BH=COLOR; DI=FCOLUMN_START; SI=BUFFER_PTR; DX=STATUS_REG; ES=VIDEO_SEG

SUBDIR: MOV BP,LISTING_LEN
CALL BLANK_LINE
PUSH DI
CALL DISPLAY_NAME

MOV SI,OFFSET SUBEND
CMP BYTE PTR ASCIIZ_NAME,"."
JZ SUBDIR2
MOV SI,OFFSET SUBDIRECTORY
SUBDIR2: CALL WRITE_LINE

MOV AL,SPACE
CALL REPEAT_CHAR
POP DI
ADD DI,CRT_WIDTH

PUSH DI
MOV CX,FCOLUMN_LEN
CALL WRITE_LINE
MOV AL,SPACE
CALL REPEAT_CHAR
POP DI
ADD DI,CRT_WIDTH
DEC BP
DEC BP
DEC BP

NEXT_DIR: CALL BLANK_LINE
DEC BP
JNZ NEXT_DIR
RET

;--------------;
BLANK_LINE: PUSH DI
MOV CX,FCOLUMN_LEN
CALL PAD_LINE
POP DI
ADD DI,CRT_WIDTH
RET

;--------------;
DISPLAY_NAME: MOV CX,FCOLUMN_LEN
MOV AL,SPACE
CALL WRITE_CHAR
DEC CX
MOV SI,OFFSET ASCIIZ_NAME
CMP BYTE PTR [SI],"."
JNZ DISPLAY_NAME2
MOV SI,OFFSET PARENT
DISPLAY_NAME2: CALL WRITE_LINE
RET

;-----------;
; Keeps track of a variable length field in CX while writing string.
WRITE_LINE: LODSB
OR AL,AL
JZ WRITE_LINE_END
CALL WRITE_CHAR
LOOP WRITE_LINE
WRITE_LINE_END:RET

;--------------;
DUMMY_RET: RET

;----------------------------------------------;
EXECUTE DB " is an executable file.",0

EXECUTABLE: MOV BP,LISTING_LEN
CALL BLANK_LINE
PUSH DI
CALL DISPLAY_NAME

MOV SI,OFFSET EXECUTE
CALL WRITE_LINE

MOV AL,SPACE
CALL REPEAT_CHAR
POP DI
ADD DI,CRT_WIDTH

DEC BP
DEC BP

NEXT_EXEC: CALL BLANK_LINE
DEC BP
JNZ NEXT_EXEC
RET

;----------------------------------------------;
DOCUMENT: PUSH DS
MOV SI,CURRENT_PAGE
MOV DISPLAY_FLAG,0
MOV CX,ROW
MOV ROW_CNT,CX
MOV DS,FILEBUFF_SEG
JCXZ NEXT_DOC
DOC_ROW: CALL CS:[FILE_LINE]
DEC CS:ROW_CNT
JNZ DOC_ROW

NEXT_DOC: PUSH DI
MOV CS:DISPLAY_FLAG,TRUE
CALL CS:[FILE_LINE]
POP DI
ADD DI,CS:CRT_WIDTH
DEC CS:LINE_CNT
JNZ NEXT_DOC
POP DS
RET

;------------------;
MULTI_BYTE DB 0

WP_LINES: MOV CX,LINE_MAX
MOV BP,CS:FCOLUMN_LEN

WP_LINES2: CMP SI,CS:BUFFER_END
JNZ WP_CHAR
CMP CS:EOF_FLAG,TRUE
JZ WP_PAD
MOV CS:BUFFER_PTR,SI
CALL FORWARD
JC WP_END
MOV SI,CS:BUFFER_PTR

WP_CHAR: LODSB
CMP CS:MULTI_BYTE,0
JNZ FIND_MULTI
CMP AL,CR
JZ WP_PAD
CMP AL,LF
JZ WP_PAD
CMP AL,SPACE
JB WP_LINES2
CMP AL,80H
JB GOOD_WP

CMP AL,0C0H
JB WP_LINES2
MOV CS:MULTI_BYTE,AL
JMP WP_LINES2

GOOD_WP: PUSH CX
MOV CX,1
CALL CK_WP_DISP
POP CX
LOOP WP_LINES2
CALL CK_BUFF
JC WP_END
CMP BYTE PTR [SI],CR
JNZ WP_END
CMP BYTE PTR [SI],LF
JNZ WP_END
INC SI
WP_END: RET

FIND_MULTI: CMP AL,CS:MULTI_BYTE
JNZ WP_LINES2
MOV CS:MULTI_BYTE,0
JMP WP_LINES2

WP_PAD: MOV AL,SPACE
CK_WP_DISP: CMP CS:DISPLAY_FLAG,TRUE
JNZ CK_WP_END
MOV BL,AL
WP_WRITE: CALL WRITE_CHAR
DEC BP
JNZ WP_LOOP
MOV CS:DISPLAY_FLAG,FALSE
WP_LOOP: LOOP CK_WP_DISP
CK_WP_END: RET

;--------------;
FF_CODE DB 0

QandA_LINES: MOV CX,LINE_MAX
MOV BP,CS:FCOLUMN_LEN

QandA_LINES2: CMP SI,CS:BUFFER_END
JNZ QandA_CHAR
CMP CS:EOF_FLAG,TRUE
JZ QandA_PAD
MOV CS:BUFFER_PTR,SI
CALL FORWARD
JC QandA_END
MOV SI,CS:BUFFER_PTR

QandA_CHAR: LODSB
CMP CS:FF_CODE,0
JNZ FIND_FF_CODE
CMP AL,0FFH
JNZ GOOD_QandA
MOV CS:FF_CODE,AL
JMP QandA_LINES2

GOOD_QandA: PUSH CX
MOV CX,1
CALL CK_QandA_DISP
POP CX
LOOP QandA_LINES2
CALL CK_BUFF
JC QandA_END
LODSB
CMP AL,0FFH
JZ CK_CR
DEC SI
JMP SHORT QandA_END
CK_CR: CALL CK_BUFF
JC QandA_END
LODSB
CMP AL,1 ;CR
JZ QandA_END
DEC SI
DEC SI
QandA_END: RET

FIND_FF_CODE: MOV AH,CS:FF_CODE
CMP AH,0FFH
JZ FIND_FF_CODE2
DEC CS:FF_CODE
JMP QandA_LINES2

FIND_FF_CODE2: CMP AL,1
JNZ FIND_FF_CODE3
MOV CS:FF_CODE,0
JMP SHORT QandA_PAD
FIND_FF_CODE3: XOR AL,AL
XOR AH,32
CMP AH,32
JBE FOUND_FF
MOV AL,2
FOUND_FF: JMP QandA_LINES2


QandA_PAD: MOV AL,SPACE
CK_QandA_DISP: CMP CS:DISPLAY_FLAG,TRUE
JNZ CK_QandA_END
MOV BL,AL
QandA_WRITE: CALL WRITE_CHAR
DEC BP
JNZ QandA_LOOP
MOV CS:DISPLAY_FLAG,FALSE
QandA_LOOP: LOOP CK_QandA_DISP
CK_QandA_END: RET

;--------------;
ASCII_LINES: MOV CX,LINE_MAX
MOV BP,CS:FCOLUMN_LEN

ASCII_LINES2: CMP SI,CS:BUFFER_END
JNZ ASCII_CHAR
CMP CS:EOF_FLAG,TRUE
JZ ASCII_PAD
MOV CS:BUFFER_PTR,SI
CALL FORWARD
JC ASCII_END
MOV SI,CS:BUFFER_PTR

ASCII_CHAR: LODSB
AND AL,CS:WORDSTAR
CMP AL,CR
JZ ASCII_PAD
CMP AL,TAB
JZ ASCII_TAB
CMP AL,LF
JZ ASCII_LINES2
PUSH CX
MOV CX,1
CALL CK_ASCII_DISP
POP CX
LOOP ASCII_LINES2
CALL CK_BUFF
JC ASCII_END
CMP BYTE PTR [SI],CR
JNZ ASCII_END
INC SI
ASCII_END: RET

ASCII_TAB: PUSH CX
DEC CX
AND CX,7
INC CX
PUSH CX
CALL ASCII_PAD
POP AX
POP CX
SUB CX,AX
JNZ ASCII_LINES2
JMP ASCII_END

ASCII_PAD: MOV AL,SPACE
CK_ASCII_DISP: CMP CS:DISPLAY_FLAG,TRUE
JNZ CK_ASCII_END
MOV BL,AL
ASCII_WRITE: CALL WRITE_CHAR
DEC BP
JNZ ASCII_LOOP
MOV CS:DISPLAY_FLAG,FALSE
ASCII_LOOP: LOOP CK_ASCII_DISP
CK_ASCII_END: RET

;--------------;
CK_BUFF: CMP SI,CS:BUFFER_END
CLC
JNZ CK_BUFF_END
CMP CS:EOF_FLAG,TRUE
STC
JZ CK_BUFF_END
MOV CS:BUFFER_PTR,SI
CALL FORWARD
MOV SI,CS:BUFFER_PTR
CK_BUFF_END: RET

;----------------------------------------------;
DIRECTORY DB " Directory of ",0

DISP_DIR: PUSH ES
MOV SI,OFFSET WORKING_DIR
CALL GET_DIR

MOV DX,STATUS_REG ;Retrieve status register.
MOV ES,VIDEO_SEG ;Point to screen segment.
MOV BH,COLOR.B
MOV DI,CRT_WIDTH
MOV CX,DI
SHR CX,1

MOV SI,OFFSET DIRECTORY
CALL WRITE_LINE
MOV AL,WORKING_DRIVE
ADD AL,"A"
CALL WRITE_CHAR
DEC CX
MOV AL,":"
CALL WRITE_CHAR
DEC CX
MOV SI,OFFSET WORKING_DIR
CALL WRITE_LINE
CALL PAD_LINE
POP ES
RET

;----------------------------------------------;
ENTER: MOV BP,BAR_ADDR
CALL MAKE_FILENAME
CMP MARK_NAME,"<"
JNZ DO_ZOOM2

PUSH WORD PTR ASCIIZ_NAME
MOV FILENAME,OFFSET ASCIIZ_NAME
CALL NEW_FILESPEC
POP AX

CMP AL,"." ;Parent dir?
JNZ NEXT_LEVEL
CMP DIR_LEVEL,0
JZ NEXT_LEVEL

DEC DIR_LEVEL
MOV BX,DIR_LEVEL
SHL BX,1
SHL BX,1
MOV AX,DIR_POINTERS.TOP_LOC[BX]
MOV LISTING_ADDR,AX
MOV AX,DIR_POINTERS.BAR_LOC[BX]
MOV BAR_ADDR,AX
CMP AX,LAST_ADDR
JBE SHORT UPDATE_DISP
MOV DIR_LEVEL,0
JMP SHORT HOME_BAR

NEXT_LEVEL: MOV BX,DIR_LEVEL
CMP BX,DIR_LEVEL_MAX
JZ HOME_BAR
SHL BX,1
SHL BX,1
MOV AX,LISTING_ADDR
MOV DIR_POINTERS.TOP_LOC[BX],AX
MOV AX,BAR_ADDR
MOV DIR_POINTERS.BAR_LOC[BX],AX
INC DIR_LEVEL
HOME_BAR: MOV BAR_ADDR,0
MOV LISTING_ADDR,0

UPDATE_DISP: CALL DISP_DIR
CALL DISP_LISTING
CALL DISP_FILE
JMP SHORT LOAD_END

DO_ZOOM2: MOV AL,LAST_ZOOM
MOV BL,ZOOM_STATE
CMP BL,FULL_FILE
JZ DO_ZOOM3
MOV AL,FULL_FILE
DO_ZOOM3: CALL CHANGE_ZOOM

LOAD_END: RET


;------------------------------------------------------------------;
; Parse drive and/or path delimiters. Convert filespec to ASCIIZ. ;
; If drive delimiter found (:), change to requested drive. ;
;------------------------------------------------------------------;
; OUTPUT: CY=1 if invalid filespec.

NEW_FILESPEC: MOV SI,FILENAME
PARSE_LEADING: LODSB ;Get a byte.
CMP AL,SPACE ;Is it a space char or below?
JA LEADING_END ;If no, done here.
CMP AL,CR ;Is it carriage return?
JNZ PARSE_LEADING ;If no, get next byte.
LEADING_END: DEC SI ;Adjust pointer to string start.
MOV BP,SI ;Save start of filespec.
MOV BX,SI ;Use BX as filename start pointer

FIND_END: LODSB ;Get a byte.
CMP AL,":" ;Is it a drive delimiter?
JNZ CK_SLASH ;If no, check path delimiter.
CALL RESTORE_DIR
MOV DL,[SI-2] ;Else, retrieve drive specifier.
AND DL,5FH ;Capitalize.
SUB DL,"A" ;Convert to DOS format.
MOV WORKING_DRIVE,DL
MOV AH,0EH ;Change drive.
INT 21H
PUSH SI
MOV SI,OFFSET CURRENT_DIR
CALL GET_DIR
POP SI
MOV BX,SI ;Save as filename start.
JMP FIND_END ;Continue parsing.

CK_SLASH: CMP AL,"\" ;Is it a path delimiter?
JNZ CK_DELIMITER ;If no, check switch character.
MOV BX,SI ;Else, save as filename start.
CK_DELIMITER: CMP AL,"/" ;Is it a switch delimiter?
JZ FOUND_END ;If yes, end of filespec.
CMP AL,SPACE ;Is it above space character?
JA FIND_END ;If yes, continue until find end.

FOUND_END: DEC SI ;Adjust.
MOV FILESPEC_END,SI
PUSH [SI]
MOV BYTE PTR [SI],0 ;Convert to ASCIIZ.

;-------------------------------------------------;
FIND_PATH: CMP BP,SI ;No filespec?
JZ GLOBAL
CMP BYTE PTR [SI - 1],":" ;Drive-only filespec?
JZ GLOBAL

CK_ROOT: MOV CX,1 ;CX=1:"\"not=root; CX=0:"\"=root.
CMP BYTE PTR [BX - 1],"\" ;Filespec start path delimiter?
JNZ CK_PATH ;If no, not root.
CMP BYTE PTR [BX - 2],":" ;Else, is it prefaced with colon?
JZ ROOT ;If yes, then root.
CMP BYTE PTR [BX - 2],SPACE ;Is it prefaced with white space?
JA CK_TRAILING ;If no, then trailing slash?
ROOT: DEC CX ;Else, root; CX=0 for root flag.
JMP SHORT CK_PATH ;Change default path.

CK_TRAILING: CMP BX,SI ;Filename start = filespec end?
JNZ CK_PATH ;If no, not trailing slash.
MOV BYTE PTR [BX - 1],0 ;Else, zero out trailing slash
MOV BX,OFFSET STAR_DOT_STAR ; and use global filespec.

CK_PATH: MOV DX,BP ;See if filespec is a path
CALL CHANGE_DIR ; by changing directory.
JC CK_FILESPEC ;If failed, remove filename.
GLOBAL: MOV BX,OFFSET STAR_DOT_STAR ;Else, use global for filename.
JMP SHORT GOT_FILESPEC ;Done here.

CK_FILESPEC: JCXZ SAVE_DELIMIT ;Is path root?; If yes leave "\".
DEC BX ;Else, point to slash.
SAVE_DELIMIT: PUSH [BX] ;Preserve filename start.
MOV BYTE PTR [BX],0 ;Temp ASCIIZ twixt path and name.
CALL CHANGE_DIR ;Change directory.
POP [BX] ;Restore first byte of filename.
JCXZ GOT_FILESPEC ;If root, done here.
INC BX ;Else, readjust filename pointer.
GOT_FILESPEC: MOV FILESPEC,BX ;Save filename.
POP [SI]

CALL PARSE
JC NEW_FILE_END
CALL FIND_FILES
NEW_FILE_END: RET

;----------------------------------------------;
; OUTPUT: CF=1 if no files found.

FIND_FILES: PUSH ES ;Preserve extra segment.
MOV ES,FILENAME_SEG ;ES:DI -> filename storage.
XOR DI,DI
MOV DX,FILESPEC

MOV CX,ATTR
MOV AH,4EH ;Find first.
MOV SI,FILESPEC_END
PUSH [SI]
MOV BYTE PTR [SI],0
INT 21H ;Any files?
POP [SI]
MOV DX,OFFSET NOT_FOUND
JC FILES_END ;If no, assumed right.

MOV AX,SPACE SHL 8 + SPACE
MOV CX,FILENAME_SIZE / 2 * KILOBYTES
REP STOSW ;Initialize with spaces.
XOR DI,DI

FIND_NEXT: CALL STORE_NAME ;Store a filename.
CMP DI,TEMP_RECORD - SIZE FILE_RECORD
JA FILES_DONE
MOV AH,4FH ;Find Next Matching.
INT 21H
JNC FIND_NEXT ;If successful store filename.

FILES_DONE: MOV AX,-1 ;Else, mark the end with -1.
STOSW
SUB DI,SIZE FILE_RECORD + 2
JNC STORE_LAST
XOR DI,DI
STORE_LAST: MOV LAST_ADDR,DI
CALL SORT ;Sort 'em.
CLC
FILES_END: POP ES ;Restore extra segment.
RET

;----------------------------------------------;
READ_ONLY EQU 01H
HIDDEN EQU 02H
SUB_DIR EQU 10H
NOT_MODIFIED EQU 00H
MODIFIED EQU 20H
IGNORE EQU -1
MODIFIED_TYPE DB IGNORE

PRIOR EQU 0
AFTER EQU 1
DATE_FLAG DB IGNORE
FILEDATE DW ?


STORE_NAME: MOV AL,DTA.ATTRIBUTE
TEST AL,READ_ONLY
JZ STORE_NAME2
TEST ATTR,READ_ONLY
JZ LILLY_END

STORE_NAME2: TEST AL,SUB_DIR
JNZ STORE_NAME4
CMP MODIFIED_TYPE,IGNORE
JZ STORE_NAME3
AND AL,MODIFIED
CMP AL,MODIFIED_TYPE
JNZ LILLY_END

STORE_NAME3: CMP DATE_FLAG,IGNORE
JZ STORE_NAME4
MOV AX,FILEDATE
CMP DATE_FLAG,PRIOR
JZ CK_PRIOR
CMP DTA.FILE_DATE,AX
JAE STORE_NAME4
JMP SHORT LILLY_END

CK_PRIOR: CMP DTA.FILE_DATE,AX
JBE STORE_NAME4
JMP SHORT LILLY_END

STORE_NAME4: MOV SI,OFFSET DTA.FILE_NAME ;Point to filename.
INC DI ;Bump past Mark.

MOV CX,SIZE LIST_NAME ;Store 12 bytes of filename.
CMP BYTE PTR [SI],"."
JNZ NEXT_STORE
CMP BYTE PTR [SI+1],"."
JZ STORE_DOTDOT
DEC DI
LILLY_END: JMP STORE_NAME_END

STORE_DOTDOT: LODSB
STOSB
STOSB
ADD DI,SIZE LIST_NAME - 2
JMP SHORT CK_DIR

EXTENSION: ADD DI,CX
MOV CX,3
SUB DI,CX

NEXT_STORE: LODSB ;Get a byte.
OR AL,AL ;End of filename?
JZ END_STORE ;If yes, finish with blanks.
CMP AL,"." ;Is it the period?
JZ EXTENSION

STOSB ;Store byte.
LOOP NEXT_STORE ;Get next byte.
END_STORE: ADD DI,CX

CK_DIR: MOV BX,10 ;Convert to decimal.
TEST DTA.ATTRIBUTE,10H
JZ STORE_SIZE
MOV BYTE PTR ES:[DI-SIZE LIST_NAME-SIZE MARK],"<"
MOV BYTE PTR ES:[DI],">"
ADD DI,SIZE LIST_DATE
JMP SHORT STORE_DATE

STORE_SIZE: PUSH DI ;Save pointer.
ADD DI,SIZE LIST_BYTES ;Move to end of bytes field.
MOV DX,DTA.SIZE_LOW ;Retrieve high and low words
MOV AX,DTA.SIZE_HIGH ; of size in bytes.

STD ;Reverse direction.
NEXT_SIZE: MOV CX,DX ;Low word in CX.
XOR DX,DX ;Zero in high half.
DIV BX ;Convert to decimal.
XCHG AX,CX ;Retrieve low word.
DIV BX
XCHG AX,DX ;Retrieve remainder.
ADD AL,"0" ;Convert to ASCII.
STOSB ;Store it.
MOV AX,CX ;Are we done?
OR CX,DX
JNZ NEXT_SIZE ;If no, divide again.

CLD ;Back to forward direction.
POP DI ;Retrieve pointer.
ADD DI,SIZE LIST_DATE ;Move to date field.

STORE_DATE: MOV DX,DTA.FILE_DATE ;Retrieve date.
MOV AX,DX
MOV CL,5 ;Shift to lowest bits.
SHR AX,CL
AND AX,1111B ;Mask off all but month.
MOV CL,0FFH ;Flag as no leading zeros.
MOV CH,"-" ;Delimiting character.
CALL STORE_WORD ;Store it.

MOV AX,DX ;Retrieve date.
AND AX,11111B ;Mask off all but day.
XOR CL,CL ;Flag include leading zeros.
CALL STORE_WORD ;Store it.

MOV AX,DX ;Retrieve date for last time.
MOV CL,9
SHR AX,CL ;Mask off all but year.
ADD AX,80 ;Adjust to ASCII.
CMP AX,100 ;Past year 2000?
JB DISPLAY_DATE ;If no, display. Else, adjust for
SUB AX,100 ; next century. (Planning ahead!)
DISPLAY_DATE: XOR CL,CL ;Display leading zeros.
MOV CH,SPACE
CALL STORE_WORD ;Store it.

TIME: INC DI ;Move to time field.
MOV DX,DTA.FILE_TIME ;Retrieve time.
MOV AX,DX
MOV CL,11 ;Shift to hours bits.
SHR AX,CL
PUSH AX
CMP AX,12 ;Past noon?
JBE MERIDIAN
SUB AX,12 ;If yes, adjust.
MERIDIAN: CMP AX,0 ;Midnight?
JNZ NOT_MIDNIGHT
MOV AX,12 ;If yes, adjust.
NOT_MIDNIGHT: MOV CL,0FFH ;Suppress leading zeros.
MOV CH,":"
CALL STORE_WORD ;Store it.

MOV AX,DX ;Retrieve time.
MOV CL,5 ;Shift to minutes bits.
SHR AX,CL
AND AX,111111B ;Mask off all but minutes.
XOR CL,CL
POP DX ;Retrieve hours.
MOV CH,"p" ;Assume PM.
CMP DX,12 ;Is it PM?
JAE PM
MOV CH,"a" ;If no, AM.

PM: CALL STORE_WORD ;Store it.
STORE_NAME_END:RET ;Done here.

;-----------------------------------------------------------------------;
; Converts a two byte hex number to decimal followed by delimiter. ;
; INPUT: AX = hex number; BL = 10; CH = delimiter character to store. ;
; CL = 0 if zeros are to be stored; CL = -1 if leading zeros ignored. ;
; ES:DI points to storage. ;
;-----------------------------------------------------------------------;
STORE_WORD: DIV BL ;Divide by ten.
ADD AX,"00" ;Convert to ASCII.
CMP CL,0 ;Are we to display leading zero?
JZ STORE_IT ;If yes, store as is.
CMP AL,"0" ;Is it a leading zero?
JNZ STORE_IT ;If no, store it.
MOV AL,SPACE ;Else, store a space.
STORE_IT: STOSW
MOV AL,CH ;Store delimiter character also.
STOSB
RET

;------------------------------------------------------------------------;
; These four subroutines control in which column the sorting will start. ;
;------------------------------------------------------------------------;
SORTS_CODE DB 76H, 77H, 72H, 73H, 72H, 77H
;JBE, JA, JB JAE, JB, JA

SORT_TABLE DW 1,12, 10,3, 14,8, 30,2
;Name Ext Size Date
;offset,length

SORT_NAME: MOV BP,NAME_SORT
JMP SHORT STORE_SORT

SORT_EXT: MOV BP,EXT_SORT
JMP SHORT STORE_SORT

SORT_SIZE: MOV BP,SIZE_SORT
JMP SHORT STORE_SORT

SORT_DATE: MOV BP,DATE_SORT

STORE_SORT: MOV SORT_INDEX,BP
CALL SORT
CALL DISP_LISTING
RET

;---------------------------------------------------;
; Insertion sort; Doesn't destroy secondary sorts. ;
;---------------------------------------------------;
SORT: CMP SORT_ORDER,NO_SORT
JNZ DO_SORT
RET

DO_SORT: MOV SI,OFFSET SORTS_CODE
ADD SI,SORT_ORDER
MODIFY_CODE: LODSB
MOV S1,AL
LODSB
MOV S2,AL
MOV S3,AL
MOV S4,AL
MOV S6,AL
MOV S8,AL
LODSB
MOV S5,AL
MOV S7,AL

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

MOV BP,SORT_INDEX ;BP = Index in sort table field.
MOV BX,SORT_TABLE[BP] ;BX = Sort field offset.
INC BP
INC BP
MOV BP,SORT_TABLE[BP] ;BP = Sort field length

XOR SI,SI ;SI = First record.
MOV DI,SIZE FILE_RECORD ;DI = Second record.
PUSH DS
PUSH ES
MOV ES,FILENAME_SEG
MOV DS,FILENAME_SEG

CMP BYTE PTR [SI],-1
JZ SORT_END
CMP BYTE PTR [DI],-1
JZ SORT_END

NEXT_SORT: CMP DI,CS:LAST_ADDR ;Sort is done when last record.
JA SORT_END

PUSH SI ;Save record pointers.
PUSH DI
MOV AX,SI ;Carry source pointer in AX.
MOV DX,DI ;Carry destination pointer in DX.

NEXT_RECORD: ADD SI,BX ;Index to sort field.
ADD DI,BX
MOV CX,BP ;Field length.
CMP BP,2 ;Sort by date is special case.
JZ DO_DATE
COMPARE: REPZ CMPSB ;Compare the fields.

S1 LABEL BYTE
JBE NO_SWITCH ;If below or equal, no switch.

SWAP: CMP DX,TEMP_RECORD ;Else, if DX points to temporary
JZ DO_SWAP ; storage, safe to move.
MOV SI,DX ;Else, move destination record
MOV DX,TEMP_RECORD ; to temporary storage.
MOV DI,DX
MOV CX,SIZE FILE_RECORD / 2
REP MOVSW

DO_SWAP: MOV SI,AX ;Restore source pointer
MOV DI,SI ;Destination = source +
ADD DI,SIZE FILE_RECORD ; field size.
MOV CX,SIZE FILE_RECORD / 2
REP MOVSW ;Move the record.

MOV DI,DX ;Prepare for next compare.
SUB AX,SIZE FILE_RECORD ;Destination = temporary.
MOV SI,AX ;Move one record towards start.
JNC NEXT_RECORD

NO_SWITCH: MOV SI,TEMP_RECORD ;If DX doesn't point to temporary
CMP DX,SI ; storage, no move was made; next
JNZ NEXT_INSERT ; compare.
MOV DI,AX ;Else, move temporary record
ADD DI,SIZE FILE_RECORD ; into last move location.
MOV CX,SIZE FILE_RECORD / 2
REP MOVSW

NEXT_INSERT: POP DI ;Restore outside loop pointers.
POP SI
ADD SI,SIZE FILE_RECORD ;Move both source and destination
ADD DI,SIZE FILE_RECORD ; to the next record.
JMP NEXT_SORT

SORT_END: POP ES
POP DS
MOV FILE_CURRENT,FALSE
RET

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

DO_DATE: REPZ CMPSB ;Compare year first.

S2 LABEL BYTE
JA SWAP ;If above, swap.
JNZ NO_SWITCH
SUB SI,8 ;Else, adjust and do month/day.
SUB DI,8
MOV CX,5
REPZ CMPSB
S3 LABEL BYTE
JA SWAP ;If above, swap.
JNZ NO_SWITCH
ADD SI,10 ;Else, adjust and do meridian.
ADD DI,10
CMPSB
S4 LABEL BYTE
JA SWAP ;If above, swap.
JNZ NO_SWITCH
SUB SI,6 ;Else, adjust and do time.
SUB DI,6
MOV CX,5
CMP WORD PTR [SI],3231H ;Is it special case "12:"?
JZ CK_MERIDIAN ;If yes, see if same.
CMP WORD PTR [DI],3231H ;Is destination "12:"?
JNZ DATE_END ;If no, normal compare.
CK_MERIDIAN: CMPSB ;Are both "12:"?

S5 LABEL BYTE
JB LONG_JMP ;Swap
S6 LABEL BYTE
JA NO_SWITCH

CMPSB
S7 LABEL BYTE
JB LONG_JMP
S8 LABEL BYTE
JA NO_SWITCH

MOV CX,3 ;Else compare minutes.
DATE_END: JMP COMPARE
LONG_JMP: JMP SWAP

;----------------------------------------------;
; OUTPUT: CF=1 if illegal parameter.

PARSE: MOV SI,FILENAME
CALL CAPITALIZE
NEXT_PARSE: CALL PARSE_DELIMIT
LODSB
CMP AL,CR
JBE PARSE_END1

CMP AL,"/"
JNZ NEXT_PARSE
CALL PARSE_DELIMIT
LODSB
CMP AL,CR
CLC
JZ PARSE_END

CK_SWITCH: MOV CX,SWITCH_LEN
MOV BX,CX
MOV DI,OFFSET SWITCH_CHARS
MOV DX,DI
ADD DX,CX
REPNZ SCASB
JNZ ILLEGAL
SUB BX,CX
DEC BX
SHL BX,1
ADD BX,DX
CALL [BX] ;Process the command.
JC ILLEGAL
JMP NEXT_PARSE

ILLEGAL: MOV DX,OFFSET ILLEGAL_PARAM
STC
JMP SHORT PARSE_END

PARSE_END1: CLC
PARSE_END: RET

;-----------------------------------------------------------------;
; INPUT: SI -> string; OUTPUT SI -> first non-white space or CR. ;
;-----------------------------------------------------------------;
PARSE_DELIMIT: PUSH AX
NEXT_DELIMIT: LODSB ;Get a byte.
OR AL,AL
JZ LEADING_END2
CMP AL,CR
JZ LEADING_END2
CMP AL,SPACE ;Is it a space char or below?
JBE NEXT_DELIMIT
CMP AL,COMMA ;Or comma?
JZ NEXT_DELIMIT
CMP AL,";" ;Or semicolon?
JZ NEXT_DELIMIT ;If yes, parse.
LEADING_END2: DEC SI ;Else, adjust pointer to
POP AX
RET ; string start.

;----------------------------------------------;
; INPUT: SI -> string; SI preserved. ;
;----------------------------------------------;
CAPITALIZE: PUSH SI
NEXT_CAP: LODSB
CMP AL,CR
JZ CAP_END
OR AL,AL
JZ CAP_END
CMP AL,"a"
JB NEXT_CAP
CMP AL,"z"
JA NEXT_CAP
AND BYTE PTR [SI - 1],5FH
JMP NEXT_CAP
CAP_END: POP SI
RET

;----------------------------------------------;
SW_PRIOR: MOV DATE_FLAG,PRIOR
JMP SHORT GET_THE_DATE

SW_AFTER: MOV DATE_FLAG,AFTER

GET_THE_DATE: CALL PARSE_DELIMIT
CALL GET_NUMBER ;Get first number.
JZ BAD_PARAMETER ;Was it a zero or no number?
MOV DH,BL ;If yes, exit, else store month.
CALL PARSE_DATE
JC BAD_PARAMETER
CALL GET_NUMBER ;Get next number.
JZ BAD_PARAMETER ;Was it zero?
MOV DL,BL ;If yes, exit, else store day.
CALL PARSE_DATE
JC BAD_PARAMETER
CALL GET_NUMBER ;Get last number.
JZ BAD_PARAMETER ;Was it zero?
MOV CX,BX ;If yes, exit, else store year.
CALL CONVERT_DATE ;Convert decimal to compressed
MOV FILEDATE,DX ; hex number and store.
JMP SHORT GOOD_SWITCH

BAD_PARAMETER: STC
JMP SHORT SWITCH_END

;--------------;
PARSE_DATE: LODSB
CMP AL,"/"
JZ DATE_END1
CMP AL,"-"
JZ DATE_END1
DEC SI
STC
JMP SHORT DATE_END2

DATE_END1: CLC
DATE_END2: RET

;--------------;
SW_MODIFIED: CALL PARSE_DELIMIT
XOR AL,AL
CMP BYTE PTR [SI],"-"
JZ STORE_MOD1
MOV AL,MODIFIED
CMP BYTE PTR [SI],"+"
JNZ STORE_MOD2
STORE_MOD1: INC SI
STORE_MOD2: MOV MODIFIED_TYPE,AL
MODIFIED_END: JMP SHORT GOOD_SWITCH

;--------------;
SW_HIDDEN: OR ATTR,HIDDEN
JMP SHORT GOOD_SWITCH

;--------------;
SW_READ_ONLY: OR ATTR,READ_ONLY
JMP SHORT GOOD_SWITCH

;--------------;
SW_WORDSTAR: MOV WORDSTAR_MASK,7FH
JMP SHORT GOOD_SWITCH

;--------------;
SW_NAME: MOV SORT_INDEX,NAME_SORT
JMP SHORT GOOD_SWITCH

;--------------;
SW_EXT: MOV SORT_INDEX,EXT_SORT
JMP SHORT GOOD_SWITCH

;--------------;
SW_SIZE: MOV SORT_INDEX,SIZE_SORT
JMP SHORT GOOD_SWITCH

;--------------;
SW_DATE: MOV SORT_INDEX,DATE_SORT
JMP SHORT GOOD_SWITCH

;--------------;
SW_ORIGINAL: MOV SORT_INDEX,NO_SORT
JMP SHORT GOOD_SWITCH

;--------------;
SW_FORMAT: MOV SORT_ORDER,DESCEND
FORMAT_END: JMP SHORT GOOD_SWITCH

GOOD_SWITCH: CLC
SWITCH_END: RET

;----------------------------------------------;
; INPUT: SI -> ASCII number.

GET_NUMBER PROC NEAR

XOR BX,BX ;Start with zero.
NEXT_NUMBER: LODSB
MOV CL,10
XOR AH,AH ;Zero in high half.
CMP AL,CR ;Is byte a carriage return?
JZ NUMBER_END ;If yes, done.
CMP AL,"0" ;Is byte a number?
JB NUMBER_END
CMP AL,"9"
JA NUMBER_END ;If no, done.
SUB AL,"0" ;Else, convert to hex.
XCHG AX,BX ;Store in BX.
MUL CL ;Multiply accumulated by 10.
ADD BX,AX ;Add new number.
JMP SHORT NEXT_NUMBER

NUMBER_END: DEC SI ;Adjust pointer to delimiter.
OR BX,BX ;Set zero flag if results zero.
RET

GET_NUMBER ENDP

;---------------------------------------------------;
; INPUT ;
; CX = Year (1980 - 2099) ;
; DH = Month (1 - 12) ;
; DL = Day (1 - 31) ;
; ;
; OUTPUT ;
; DX = compressed date in directory entry format. ;
; ;
; < DH > < DL > ;
; y y y y y y y m m m m d d d d d ;
; ;
; y = year (0 - 119) ;
; m = month (1 - 12) ;
; d = day (1 - 31) ;
; ;
; BX, CX destroyed. ;
;---------------------------------------------------;

CONVERT_DATE PROC NEAR

SUB CX,80 ;Compress year.
CMP CX,1900 ;Did user abbreviate year?
JB SAVE_MONTH ;If yes, OK.
SUB CX,1900 ;Else, subtract century part.
SAVE_MONTH: MOV BL,DH ;Store month in BL.
XOR BH,BH ;Zero in high half.
SHL CL,1 ;Right justify year.
MOV DH,CL ;Store in DH.
MOV CL,5 ;Shift month left 5 bits.
SHL BX,CL
OR DX,BX ;Add year and month to days.
RET

CONVERT_DATE ENDP

;----------------------------------------------;
VIDEO_SETUP: PUSH ES
MOV AX,500H ;Make sure active page is zero.
INT 10H
MOV AX,40H ;Point to the ROM BIOS data area
MOV ES,AX
MOV AX,ES:CRT_COLS
MOV COLUMNS,AX
SHL AX,1
MOV CRT_WIDTH,AX
MOV AX,ES:[4EH]
MOV CRT_START,AX

MOV AX,ES:[63H]
ADD AX,6
MOV CX,0B000H
CMP AX,3BAH
JZ STORE_SEG
ADD CX,800H
STORE_SEG: MOV STATUS_REG,AX
MOV VIDEO_SEG,CX

MOV SI,OFFSET MONO_ATTR
MOV AL,ES:CRT_MODE ;Retrieve current video mode.
CMP AL,7 ;Is it mono mode?
JZ GET_ROWS ;If yes, continue.
CMP AL,2 ;Is it BW80?
JZ GET_ROWS ;If yes, continue.
MOV SI,OFFSET COLOR_ATTR
CMP AL,3 ;Is it mode CO80?
JZ GET_ROWS ;If yes, continue.
MOV AX,3 ;Else, change video mode to CO80.
INT 10H

GET_ROWS: XOR BH,BH
MOV DL,24
MOV AX,1130H
INT 10H
MOV ROWS,DL ;Store rows.
SUB DL,3
XOR DH,DH
MOV LISTING_LEN,DX

POP ES
MOV DI,OFFSET COLOR
MOV CX,SIZE COLOR_ATTRIBS
REP MOVSB

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

DISPLAY_SETUP: CALL CLS ;Clear screen.

CMP BORDER_FLAG,1
JZ DO_COPYRIGHT
MOV BL,COLOR.W ;Turn on border.
AND BL,7
XOR BH,BH
MOV AH,0BH
INT 10H

DO_COPYRIGHT: XOR AX,AX
CALL CALC_ADDR
INC DI
INC DI
MOV SI,OFFSET COPYRIGHT ;Point to copyright message.
MOV BH,COLOR.B ;Use header attribute.
CALL WRITE_STRING ;And display it.
RET

;----------------------------------------------;
INIT_ZOOM: MOV AX,2
CALL CALC_ADDR
MOV LCOLUMN_START,DI

MOV AX,SIZE MARK + SIZE LIST_NAME + 1
CMP ZOOM_STATE,SHORT_NAME
JZ STORE_ZOOM
MOV AX,SIZE FILE_RECORD
CMP ZOOM_STATE,LONG_NAME
JZ STORE_ZOOM
XOR AX,AX

STORE_ZOOM: MOV LCOLUMN_LEN,AX
MOV BX,SIZE FILE_RECORD
SUB BX,AX
MOV LCOLUMN_BAL,BX

OR AX,AX
JZ GET_FILE_LEN
INC AX
GET_FILE_LEN: MOV BX,COLUMNS
SUB BX,AX
MOV FCOLUMN_LEN,BX

SHL AX,1
ADD DI,AX
MOV FCOLUMN_START,DI

CMP ZOOM_STATE,FULL_FILE
JZ INIT_ZOOM_END
MOV DI,FCOLUMN_START
DEC DI
DEC DI
MOV BH,COLOR.B
MOV BP,LISTING_LEN
MOV AL,SPACE
NEXT_DIVIDER: PUSH DI
CALL WRITE_SCREEN
POP DI
ADD DI,CRT_WIDTH
DEC BP
JNZ NEXT_DIVIDER

INIT_ZOOM_END: RET

;----------------------------------------------;
DISPLAY_MENU: MOV AL,UP_ARROW
MOV AH,"A"
CMP SORT_ORDER,ASCEND
JZ STORE_SORT2
MOV AL,DOWN_ARROW
MOV AH,"D"

STORE_SORT2: MOV SORT_MENU1,AL
MOV SORT_MENU2,AH

CALL MENU_OFFSET
PUSH DI
MOV BH,COLOR.B
MOV SI,OFFSET MENU
CALL WRITE_STRING
POP DI
ADD DI,CRT_WIDTH
CALL WRITE_STRING
CALL HIDE_CURSOR
MENU_END: RET

;----------------------------------------------;
; OUTPUT: CF=1 if Esc pressed; FILENAME -> filename.

ENTER_FILENAME DB " Enter filespec: ",0
NAME_CURSOR EQU $ - ENTER_FILENAME
FILENAME_LEN EQU 80 - NAME_CURSOR - 1

FILE_CURSOR DW ?

GET_NAME: CALL MENU_OFFSET
ADD DI,CRT_WIDTH
MOV BH,COLOR.B
MOV SI,OFFSET ENTER_FILENAME
CALL WRITE_STRING

MOV SI,81H
MOV FILE_CURSOR,SI
MOV DI,SI
MOV CX,FILENAME_LEN
MOV LINE_START,DI
ADD DI,CX
MOV LINE_END,DI
MOV DI,81H
CALL PARSE_DELIMIT

GET_END: LODSB
CMP AL,"/"
JZ GOT_END3
CMP AL,SPACE
JBE GOT_END3
STOSB
JMP GET_END

GOT_END3: MOV CX,LINE_END
SUB CX,DI
INC CX
MOV AL,SPACE
REP STOSB
XOR AL,AL
STOSB
MOV AL,CR
STOSB

NEXT_FILENAME: CALL MENU_OFFSET
ADD DI,CRT_WIDTH
ADD DI,NAME_CURSOR * 2
MOV BH,COLOR.B
MOV SI,LINE_START
CALL WRITE_STRING

MOV DI,FILE_CURSOR
MOV DX,DI
ADD DL,NAME_CURSOR
SUB DX,LINE_START
MOV DH,ROWS
CALL SET_CURSOR
CALL EDITOR
MOV FILE_CURSOR,DI
JC GET_NAME_END
CMP AH,ENTER_SCAN
JNZ NEXT_FILENAME
GET_NAME_END: RET

;*************LINE EDITOR**********************;

LINE_START DW ?
LINE_END DW ?

;INPUT: DI=buffer position; LINE_START, LINE_END.
;OUTPUT: AL=char. AH=scan code. CY=1 if Esc pressed.

EDITOR: CALL GETKEY
XCHG AL,AH
JNC DO_EDIT
JMP EDITOR_END
DO_EDIT: MOV BX,DI
MOV DX,LINE_START
MOV CX,LINE_END

CMP AH,ENTER_SCAN
JNZ CK_RIGHT
JMP EDITOR_DONE

CK_RIGHT: CMP AX,RIGHT_SCAN SHL 8
JNZ CK_LEFT
CMP DI,CX
JZ EDITOR_DONE
CMP BYTE PTR [DI],SPACE
JZ EDITOR_DONE
INC DI

CK_LEFT: CMP AX,LEFT_SCAN SHL 8
JNZ CK_BS
CMP DI,DX
JZ EDITOR_DONE
DEC DI

CK_BS: CMP AH,BS_SCAN
JNZ CK_DEL
CMP DI,DX
JZ EDITOR_DONE
DEC DI
CALL CK_INSERT
JNZ DO_DEL
MOV BYTE PTR [DI],SPACE
JMP SHORT EDITOR_CHANGE

CK_DEL: CMP AX,DEL_SCAN SHL 8
JNZ CK_HOME
DO_DEL: PUSH DI
MOV SI,DI
INC SI
DEC CX
SUB CX,DI
JS DEL_END
REP MOVSB
MOV BYTE PTR [DI],SPACE
DEL_END: POP DI
JMP SHORT EDITOR_CHANGE

CK_HOME: CMP AX,HOME_SCAN SHL 8
JNZ CK_END2
MOV DI,DX

CK_END2: CMP AX,END_SCAN SHL 8
JNZ CK_ASCII
NEXT_CK_END2: CMP DI,CX
JZ EDITOR_DONE
CMP BYTE PTR [DI],SPACE
JZ EDITOR_DONE
INC DI
JMP NEXT_CK_END2

CK_ASCII: CMP AL,SPACE
JB EDITOR_DONE
CMP AL,127
JA EDITOR_DONE
CMP DI,LINE_END
JAE EDITOR_DONE
CALL CK_INSERT
JNZ DO_INSERT
JMP SHORT EDITOR_DONE1

DO_INSERT: PUSH DI
DEC CX
MOV DI,CX
SUB CX,BX
JZ EDITOR_DONE2
MOV SI,DI
DEC SI
STD
REP MOVSB
CLD
EDITOR_DONE2: POP DI
EDITOR_DONE1: STOSB

EDITOR_CHANGE: ; MOV MODIFY_FLAG,1
EDITOR_DONE: CLC
EDITOR_END: RET

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

CK_INSERT: PUSH DS
MOV DX,40H
MOV DS,DX
MOV DL,DS:[17H]
TEST DL,80H ;Insert
POP DS
RET

;----------------------------------------------;
;INPUT: CX=char count; AX=character
REPEAT_CHAR: PUSH AX
CALL WRITE_SCREEN
POP AX
LOOP REPEAT_CHAR
RET

;----------------------------------------------;
; INPUT: AX = Starting line; OUTPUT: DI = Video address.

CALC_ADDR: MUL CRT_WIDTH
ADD AX,CRT_START
MOV DI,AX
RET

;----------------------------------------------;
; INPUT: AL = character to write; BH = attribute.

WRITE_SCREEN: PUSH ES
MOV ES,CS:VIDEO_SEG ;Point to screen segment.
MOV DX,CS:STATUS_REG ;Retrieve status register.
MOV BL,AL ;Store character in BL.

HORZ_RET: IN AL,DX ;Get status.
RCR AL,1 ;Is it low?
JC HORZ_RET ;If not, wait until it is.
CLI ;No more interrupts.

HWAIT: IN AL,DX ;Get status.
RCR AL,1 ;Is it high?
JNC HWAIT ;If no, wait until it is.

MOV AX,BX ;Retrieve character; now it's OK
STOSW ; to write to screen buffer.
STI ;Interrupts back on.
POP ES
RET ;Return

;----------------------------------------------;
; INPUT: ES=VIDEO_SEG; DX=STATUS_REG; AL=character to write; BH=attribute.

WRITE_CHAR: MOV BL,AL ;Store character in BL.

HORZ_RET2: IN AL,DX ;Get status.
RCR AL,1 ;Is it low?
JC HORZ_RET2 ;If not, wait until it is.
CLI ;No more interrupts.

HWAIT2: IN AL,DX ;Get status.
RCR AL,1 ;Is it high?
JNC HWAIT2 ;If no, wait until it is.

MOV AX,BX ;Retrieve character; now it's OK
STOSW ; to write to screen buffer.
STI ;Interrupts back on.
RET ;Return

;----------------------------------------------;
; INPUT: SI -> to string to display; DI -> where to display it.
; Entry point is WRITE_STRING.

WRITE_IT: CALL WRITE_SCREEN ;Write a character.
WRITE_STRING: LODSB ;Retrieve a character.
CMP AL,CR ;Keep writing until a carriage
JA WRITE_IT ; return or zero encountered.
RET

;----------------------------------------------;
CLEAR_MENU: CALL MENU_OFFSET ;Calculate menu screen offset.
PUSH DI
MOV BH,COLOR.B ;Menu attribute.
MOV CX,CRT_WIDTH ;Blank out the two lines of menu.
NEXT_MENU: MOV AL,SPACE
CALL WRITE_SCREEN
LOOP NEXT_MENU
POP DI
RET

;----------------------------------------;
; OUTPUT: DI -> Screen offset for menu. ;
;----------------------------------------;
MENU_OFFSET: MOV AL,ROWS
DEC AL
XOR AH,AH
CALL CALC_ADDR
RET

;----------------------------------------------;
CLS: MOV BH,COLOR.B ;Normal attribute.
CLS2: XOR CX,CX ;Top left corner.
MOV DL,BYTE PTR COLUMNS
DEC DL
MOV DH,ROWS
MOV AX,600H ;Scroll active page.
PUSH BP
INT 10H
POP BP
RET

;----------------------------------------------;
CLOSE_SCREEN: PUSH AX
MOV BH,SCREEN_COLOR
CALL CLS2

CMP BORDER_FLAG,1
JZ PLACE_CURSOR
XOR BX,BX
MOV AH,0BH
INT 10H

PLACE_CURSOR: XOR DX,DX
CALL SET_CURSOR
POP AX
RET

;----------------------------------------------;
BEEP: MOV BX,NOTE ;Tone frequency divisor.
MOV DX,12H
XOR AX,AX
DIV BX
MOV BX,AX ;8253 countdown.

CALL DELAY ;Wait till clock rolls over.

MOV AL,0B6H ;Channel 2 speaker functions.
OUT 43H,AL ;8253 Mode Control.
JMP $+2 ;IO delay.
MOV AX,BX ;Retrieve countdown.
OUT 42H,AL ;Channel 2 LSB.
JMP $+2
MOV AL,AH ;Channel 2 MSB.
OUT 42H,AL
IN AL,61H ;Port B.
OR AL,3 ;Turn on speaker.
JMP $+2
OUT 61H,AL

CALL DELAY ;Delay one second.
IN AL,61H ;Get Port B again.
AND AL,NOT 3 ;Turn speaker off.
JMP $+2
OUT 61H,AL
RET ;Done.

;-----------------------------;
DELAY: PUSH DS ;Preserve data segment.
MOV AX,40H ;Point to BIOS data segment.
MOV DS,AX
MOV AX,DS:[6CH] ;Retrieve timer low.
NEXT_BEEP: MOV DX,DS:[6CH] ;Retrieve timer low.
CMP DX,AX ;Have we timed out?
JZ NEXT_BEEP ;If not, wait until second up.
POP DS ;Restore data segment.
RET

;----------------------------------------------;
; INPUT: SI-> DIR storage.

GET_DIR: MOV BYTE PTR [SI],"\" ;DOS doesn't preface directory
INC SI ; with slash so we must.
XOR DL,DL
MOV AH,47H ;Get current directory.
INT 21H
RET

;----------------------------------------------;
HIDE_CURSOR: MOV DH,ROWS ;Retrieve CRT rows.
INC DH ;Move one line below off screen.
XOR DL,DL ;Column zero.

SET_CURSOR: PUSH BX
XOR BH,BH ;Page zero.
MOV AH,2 ;Set cursor position.
INT 10H
POP BX
RET

;----------------------------------------------;
RESTORE_DIR: MOV DX,OFFSET CURRENT_DIR

;----------------------------------------------;
CHANGE_DIR: MOV AH,3BH ;Change current directory.
INT 21H
RET

;----------------------------------------------;
; INPUT: AL=Scan code; AH=Char; DI -> Valid scan codes table; CX = Table length
; OUTPUT: AL=Scan code; AH=Char.

DISPATCH: PUSH AX
MOV BX,CX
MOV DX,DI
ADD DX,CX
REPNZ SCASB
JNZ DISPATCH_END

GOT_DISPATCH: SUB BX,CX
DEC BX
SHL BX,1
ADD BX,DX
CALL GET_PARAMS
CALL [BX] ;Process the command.
DISPATCH_END: POP AX
RET

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

GET_PARAMS: MOV AX,SIZE FILE_RECORD

MUL LISTING_LEN
MOV BP,BAR_ADDR
MOV DX,LISTING_ADDR
MOV CX,LAST_ADDR
PARAMS_END: RET

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

GETKEY: TEST KBD_STATUS,80H
JNZ KEY_CLEAR
CALL CK_KEY
JNZ GETKEY2
JMP GETKEY

KEY_CLEAR: CALL CLEAR_KEY
MOV KBD_STATUS,0
CMP FILE_CURRENT,TRUE
JZ GETKEY
CALL DISP_FILE
JMP GETKEY

GETKEY2: XOR AH,AH ;Wait for next keyboard input.
INT 16H
XCHG AH,AL
CMP AL,ESC_SCAN
STC
JZ GETKEY_END
CLC
GETKEY_END: RET

CK_KEY: MOV AH,1 ;Is there a keystroke available.
INT 16H
RET

CLEAR_IT: XOR AH,AH
INT 16H ;Read keystrokes until buffer
CLEAR_KEY: CALL CK_KEY ; empty.
JNZ CLEAR_IT
RET

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

WRITE_TTY: MOV AH,0EH
INT 10H
RET

;----------------------------------------------;
PRINT_STRING: MOV AH,9 ;Print string via DOS.
INT 21H
RET

;----------------------------------------------;
OLD9 DW ?,?

INSTALL_9: PUSH ES
MOV AX,3509H ;INT 9
INT 21H
MOV OLD9[0],BX
MOV OLD9[2],ES
MOV DX,OFFSET INT_9 ;Install new interrupt.
MOV AX,2509H
INT 21H
POP ES
RET

;----------------------------------------------;
UNINSTALL_9: PUSH DS
MOV DX,OLD9[0] ;Restore old INT 9.
MOV DS,OLD9[2]
MOV AX,2509H
INT 21H
POP DS
RET

;----------------------------------------------;
INSTALL_24: MOV DX,OFFSET INT_24 ;Install new interrupt.
MOV AX,2524H
INT 21H
RET

EVEN
STACK_POINTER = $ + 256


_TEXT ENDS
END START


  3 Responses to “Category : Files from Magazines
Archive   : VOL10N13.ZIP
Filename : FILECTRL.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/