home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Lion Share
/
lionsharecd.iso
/
utils_mz
/
v10n03.zip
/
JOURNAL.ASM
< prev
next >
Wrap
Assembly Source File
|
1991-01-03
|
186KB
|
4,836 lines
_TEXT SEGMENT PUBLIC 'CODE'
ASSUME CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
; Fix 3/1/90 for no cursor on in some applications.
; Fix 3/7/90 for ASCII archive file.
; Fix 8/29/90 for /A nopopup.
ORG 80H
DTA LABEL BYTE
ORG 100H
START: JMP INITIALIZE
; DATA AREA
; ---------
CR EQU 13
LF EQU 10
FF EQU 12
CTRL_Z EQU 26
SPACE EQU 32
BOX EQU 254
BELL EQU 7
TAB EQU 9
ESC_SCAN EQU 1
ENTER_SCAN EQU 1CH
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
SHIFT_F7_SCAN EQU 5AH
KB_FLAG EQU 17H
APP_LEN EQU 29 ;Chars per appointment.
APP_HEIGHT EQU 16 ;Appointment rows.
NOTE_LEN EQU 73 ;Notepad line length.
NOTE_HEIGHT EQU 3 ;Notepad rows.
DATE_LEN EQU 11 ;Date length in ASCII.
NOTEPAD_LEN EQU (81 - 4) + 81 + (81 - 4) ;Total notepad size.
DATA_RECORD STRUC
DATE_BINARY DW 2 DUP (?)
DATE_ASCII DB DATE_LEN DUP (?)
DATA_TEXT DB (APP_HEIGHT * APP_LEN * 2) DUP (?)
NOTEPAD_TEXT DB NOTEPAD_LEN DUP (?)
DATA_RECORD ENDS
BUFFER DB ((82 * 25) + 2 - ($ - OFFSET DTA)) DUP (?)
SIGNATURE DB SPACE,CR,CR,LF
COPYRIGHT DB "JOURNAL 1.0 (c) 1990 Ziff Communications Co.",CR,LF
PROGRAMMER DB "PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF,"$"
DB CTRL_Z
COLOR_ATTRIBS STRUC
B DB 017H ;White on blue.
H DB 071H ;Blue on white.
Y DB 01EH ;Yellow on blue.
C DB 03BH ;Bright cyan on cyan.
A DB 01BH ;Bright cyan on blue.
P DB 07EH ;Yellow on white.
COLOR_ATTRIBS ENDS
COLOR COLOR_ATTRIBS <>
COLOR_ATTR COLOR_ATTRIBS <>
MONO_ATTR COLOR_ATTRIBS <07H, 70H, 70H, 70H, 07H, 07H>
MONO_FLAG DB 0 ; =1 if forced Black and white.
NOTE DW 1046 ;C note
DOS_SEGMENT DW ? ;Segment of internal DOS flags.
INDOS_OFFSET DW ? ;Offset of INDOS flag.
ERRFLAG_OFFSET DW ? ;Offset of critical error flag.
PROGRAM_STATUS DB 0 ;Popup status; non-zero=popped up.
BUSY_FLAGS LABEL WORD
FLAG_10h DB 0 ;Status of interrupt 10h.
FLAG_13h DB 0 ;Status of interrupt 13h.
BACK_FLAGS LABEL WORD
FLAG_8h DB 0 ;Status of interrupt 8h.
FLAG_28h DB 0 ;Status of interrupt 28h.
REQUEST_FLAG DB 0 ;Status of processing request.
SS_REGISTER DW ? ;SS register storage.
SP_REGISTER DW ? ;SP register storage.
OLDPSP DW ? ;PSP segment storage.
BIOS_ACTIVE_PAGE EQU 62H
ACTIVE_PAGE DB ?
ADDR_6845 DW ?
BIOS_CRT_MODE EQU 49H
CRT_MODE DB ?
CRT_COLS DW ?
CRT_LEN DW ?
CRT_START DW ?
CRT_DATA_LENGTH EQU $ - CRT_MODE
CRT_WIDTH DW ? ;Width in bytes of CRT.
CRT_ROWS DB ?
VIDEO_SEG DW ?
STATUS_REG DW ?
CURSOR_MODE DW ? ;Cursor shape.
CURSOR_POS DW ? ;Cursor position.
CURSOR_ADDR DW ? ;Cursor CRTC address.
SCH_CURSOR DW ?
DOS_VERSION DW ?
TSR_SEGMENT DW ?
OLD8 DW ?,? ;Old interrupt addresses.
OLD9 DW ?,?
OLD10 DW ?,?
OLD13 DW ?,?
OLD28 DW ?,?
OLD1B DW ?,?
OLD23 DW ?,?
OLD24 DW ?,?
OLD_DTA DW ?,?
BREAK DB ? ;Ctrl break state.
CLOCK DB "xx:xxxm",0
STATE DW CALENDAR ;Pop up screen.
EXIT_FLAG DB 0 ; =1 if Hotkey pressed.
CTRL_STATE EQU 4
ALT_STATE EQU 8
COMBO DB "J"
HOT_KEY_SCAN DB 24H ;"J"
HOT_SHIFT_KEY DB ALT_STATE
MODIFY_FLAG DB 0 ; =1 if changes made in apps.
PORT_A EQU 60H
PORT_B EQU 61H
COMMAND_PORT EQU 20H
EOI EQU 20H
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
;---------------------------------------------------------------------------;
; Code Format: 0 = compressed string; followed by string length and char. ;
; 1 = display drop shade char. ;
; 2 = color follows. ;
; 3 = string end; if followed by -1 then menu end. ;
; 4 = drop shade string end followed by string length. ;
; 5 = insert date ;
; 6 = insert appointment blocks ;
; 7 = skip count / 2 follows. ;
;---------------------------------------------------------------------------;
CAL_MENU LABEL BYTE
DB 2,B
DB " F3 Today F7 Journal ─┘= Appointment PgUp/Dn=Month Esc=Exit ",3
DB " ┌─────────────────────────────────────────────────┬──────────────────────────┐ ",3
DB " │ ",2,Y,"Calendar",2,B," ■ PC Magazine ■ Michael J. Mefford │ ",2,Y,SPACE
CAL_DATE LABEL BYTE
DB " ",7,14,2,B," │ ",3
DB " ╞══════════╤══════════╤══════════╤══════════╤═════╧════╤══════════╤══════════╡ ",3
DB " │ "
DAYS LABEL BYTE
DB "Sun │ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │ ",3
DB " ├──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┤ ",3,-1
CAL_DUP LABEL BYTE
DB " ├──┴┴┴┴┴┴┴┴┼──┴┴┴┴┴┴┴┴┼──┴┴┴┴┴┴┴┴┼──┴┴┴┴┴┴┴┴┼──┴┴┴┴┴┴┴┴┼──┴┴┴┴┴┴┴┴┼──┴┴┴┴┴┴┴┴┤ ",3
CAL_MIDDLE LABEL BYTE
DB " │",7 DUP (5,6,"┤"),SPACE,3
DB " │",7 DUP (SPACE,SPACE,6,"┤"),SPACE,3,-1
DB " └──┴┴┴┴┴┴┴┴┴──┴┴┴┴┴┴┴┴┴──┴┴┴┴┴┴┴┴┴──┴┴┴┴┴┴┴┴┴──┴┴┴┴┴┴┴┴┴──┴┴┴┴┴┴┴┴┴──┴┴┴┴┴┴┴┴┘ ",3
DB " Appointment block 1 hour periods; 6:00am - 1:30 1st row; 2:00pm - 9:30 2nd row ",3,-1
APPOINTMENT_BLOCKS LABEL BYTE ;Storage for small block chars.
BLOCK_COUNT EQU 31 * 16
DB BLOCK_COUNT DUP (SPACE)
APP_MENU LABEL BYTE
DB 2,B
DB " F2 Save F3 Today F4 Purge F5 Print F6 Clear Line F7 Calendar PgUp/Dn=Day ",3
DB " ┌┬────────────────────────────────────────────────┬──────────────────────────┐ ",3
DB " ╞╡ ",2,Y,"Appointment",2,B," ■ PC Magazine ■ Michael J. Mefford │ ",2,Y,SPACE
APP_DATE LABEL BYTE
DB " ",7,14,2,B," │ ",3
DB " ╞╪════════════════════════════════════════════════╧══════════════════════════╡ ",3
APP_START LABEL BYTE
APP_COL_SPACE EQU 7 ;Distance from end left to start right.
APP_ROW_SPACE EQU 16 ;Distance from end right to start left.
APP_LEFT_START EQU $ + 12
APP_RIGHT_START EQU APP_LEFT_START + APP_LEN + APP_COL_SPACE
APP_NOTE_SPACE EQU 8
DB " ╞╡ 6:00am 2:00 │ ",3
DB " ╞╡ 6:30 2:30 │ ",3
DB " ╞╡ 7:00 3:00 │ ",3
DB " ╞╡ 7:30 3:30 │ ",3
DB " ╞╡ 8:00 4:00 │ ",3
DB " ╞╡ 8:30 4:30 │ ",3
DB " ╞╡ 9:00 5:00 │ ",3
DB " ╞╡ 9:30 5:30 │ ",3
DB " ╞╡ 10:00 6:00 │ ",3
DB " ╞╡ 10:30 6:30 │ ",3
DB " ╞╡ 11:00 7:00 │ ",3
DB " ╞╡ 11:30 7:30 │ ",3
DB " ╞╡ 12:00pm 8:00 │ ",3
DB " ╞╡ 12:30 8:30 │ ",3
DB " ╞╡ 1:00 9:00 │ ",3
DB " ╞╡ 1:30 9:30 │ ",3
DB " ╞╪══════════════════════════════[Mini Notepad]═══════════════════════════════╡ ",3
DB " ╞╡ "
NOTEPAD LABEL BYTE
DB " │ ",3
DB " ╞╡ │ ",3
DB " ╞╡ │ ",3
APP LABEL BYTE
DB " └┴───────────────────────────────────────────────────────────────────────────┘ ",3,-1
APP_WIDTH EQU $ - APP - 1
SCH_REPORT_MSG DB 2,H,"╔", 0,27,"═", "╗",3
DB "║ F7 Schedule Report - LPT1 ║",1
DB "║ F8 Schedule Report - LPT2 ║",1
DB "║ F9 Schedule Report - File ║",1
DB "║ Esc to Cancel ║",1
DB "╚", 0,27,"═", "╝",1,4,29
;----------------------------------------------;
DISK_FULL_MSG DB 2,H,"╔", 0,25,"═", "╗",3
DB "║ Not enough disk space. ║",1
DB "║ Press any key. ║",1
DB "╚", 0,25,"═", "╝",1,4,27
PERMANENT_MSG DB 2,H,"╔", 0,25,"═", "╗",3
DB "║ Do you wish to save the ║",1
DB "║ changes to disk? Y/N ║",1
DB "╚", 0,25,"═", "╝",1,4,27
PERMANENT_FAIL DB 2,H,"╔", 0,25,"═", "╗",3
DB "║ Update failed. Press ║",1
DB "║ any key to continue. ║",1
DB "╚", 0,25,"═", "╝",1,4,27
SAVED_MSG DB 2,H,"╔",0,9, "═╗",3
DB "║ Saved ║",1
DB "╚",0,9, "═╝",1,4,11
DISK LABEL BYTE
DB 2,H,"╔", 0,27,"═", "╗",3
DB "║", 0,27,SPACE, "║",1
DISK_NAME LABEL BYTE
DB "║ Error reading drive X ║",1,3,-1
ERR_BOT LABEL BYTE
DB "║ (R)etry or (A)bort ? ║",1
DB "║", 0,27,SPACE, "║",1
DB "╚", 0,27,"═", "╝",1,4,ERR_WIDTH
PRN LABEL BYTE
DB 2,H,"╔", 0,27,"═", "╗",3
DB "║", 0,27,SPACE, "║",1
DB "║",0,7," Printer Error",0,7," ║",1,3,-1
ERR_WIDTH EQU 29
ERR_HEIGHT EQU 6
ERR_ROW EQU ((25 - ERR_HEIGHT) / 2) + 3
ERR_COL EQU ((80 - ERR_WIDTH) / 2)
PURGE_MSG DB 2,H,"╔",0,41, "═", "╗",3
DB "║ Appointment Purge Date: ",2,P
PUR_DATE DB " ",2,H,"║",1
DB "║ PgUp/Dn to change Date; F3 = Today ║",1
DB "║ F7 Purge up to and including Date ║",1
DB "║ F8 Purge Date Only Esc to Cancel ║",1
DB "╚",0,41, "═", "╝",1,4,43
ARCHIVE_MSG DB 2,H,"╔",0,17, "═╗",3
DB "║ Archive Y/N? ║",1
DB "╚",0,17, "═╝",1,4,19
PURGING_MSG DB 2,H,"╔",0,11, "═╗",3
DB "║ Purging ║",1
DB "╚",0,11, "═╝",1,4,13
;------------------------------------------------------------------------------
;Execution comes here thru interrupt 9 every time a key is pressed or released.
;------------------------------------------------------------------------------
KEYBOARD PROC NEAR
PUSH AX
PUSH DS
MOV AX,40H
MOV DS,AX
MOV AH,DS:[KB_FLAG] ;Get keyboard shift status
PUSH CS
POP DS
KEYSTROKE: IN AL,PORT_A
TEST AH,HOT_SHIFT_KEY ;Our shift key?
JZ KB_EXIT ;No, then exit
CMP AL,HOT_KEY_SCAN ;Our hotkey?
JNZ KB_EXIT
CMP PROGRAM_STATUS,0 ;Popup routine already active?
JNZ KB_EXIT ;Yes, then ignore keypress
IN AL,PORT_B ;Retrieve Port B.
OR AL,80H ;Turn bit 7 on to reset
JMP $ + 2 ;I/O delay.
OUT PORT_B,AL ;Reset KBD.
AND AL,NOT 80H ;Turn bit 7 back off.
JMP $ + 2 ;I/O delay.
OUT PORT_B,AL ;Restore port.
CLI ;Interrupts off.
MOV AL,EOI ;Send End Of Interrupt
OUT COMMAND_PORT,AL ; to 8259A PIC.
MOV REQUEST_FLAG,18 ;Try to popup for one second.
POP DS
POP AX
IRET
KB_EXIT: POP DS
POP AX
JMP DWORD PTR CS:OLD9 ;Call keyboard handling routine.
KEYBOARD ENDP
;------------------------------------------------------------------------------
;Interrupt 8 handling routine.
;------------------------------------------------------------------------------
LAST_MIN DB ? ;Last minute.
BELL_FLAG DB 0 ; =1 if chiming.
BELL_CNT DB ? ; no. of chimes.
POPUP_FLAG DB 0 ; =1 if alarm or day rollover.
NOPOPUP_FLAG DB 0 ; =1 if ignore POPUP_FLAG.
NOBELL_FLAG DB 0 ; =1 if ignore chime.
NOMIDNIGHT_FLAG DB 0 ; =1 if ignore rollover pop up.
ALARM_FLAG DB 0 ; =1 only on alarm to avoid homing cursor.
REREAD_FLAG DB 0 ; =1 if forced reread of disk.
TIMER PROC NEAR
CLI
PUSHF
CALL CS:DWORD PTR OLD8
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
PUSH BP
CLD
MOV BX,CS
MOV DS,BX
CMP PROGRAM_STATUS,0 ;Already popped up?
JNZ CK_TIME
CMP FLAG_8h,0
JNZ CK_TIME
CMP POPUP_FLAG,1 ;Alarm or rollover popup?
JNZ CK_REQ_FLAG
MOV REQUEST_FLAG,18 ;Request to popup for 1 sec.
CK_REQ_FLAG: CMP REQUEST_FLAG,0
JZ CK_TIME
CK_TSRSTATE: INC FLAG_8h
STI
CALL TSR_STATE ;Save to enter Dos?
JC DECTIME
CALL MAIN
JMP SHORT TIMER_DONE
DECTIME: CMP REQUEST_FLAG,0
JZ TIMER_DONE
DEC REQUEST_FLAG
JZ TIMER_BEEP
CMP REQUEST_FLAG,9 ;Beep twice, once every 1/2 sec.
JNZ TIMER_DONE
TIMER_BEEP: CALL BEEP
TIMER_DONE: CLI
DEC FLAG_8h
TIMER_END: POP BP
POP ES
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
IRET
;----------------------------------------------;
CK_TIME: STI
MOV AX,40H
MOV ES,AX
MOV CX,ES:[6CH] ;TIMER_LOW
MOV AX,ES:[6EH] ;TIMER_HIGH
MOV BP,AX ;Save hour.
PUSH CS
POP ES
MOV BL,"a" ;Convert time to 12 hour version.
CMP AX,24
JZ GOT_MUNDI
CMP AX,11
JBE GOT_MUNDI
MOV BL,"p"
GOT_MUNDI: OR AX,AX
JNZ CK_NOON
MOV AX,12
CK_NOON: CMP AX,12
JBE GOT_HOUR
SUB AX,12
GOT_HOUR: MOV DI,OFFSET CLOCK
XOR SI,SI ;Suppress leading zero.
CALL STORE_NUMBER
MOV AX,CX
XOR DX,DX
MOV CX,1093 ;Convert ticks to minutes.
DIV CX
INC SI ;Store leading zero.
MOV CL,CLOCK + 4 ;Retrieve current minute.
MOV LAST_MIN,CL ;Store new current minute.
CALL STORE_NUMBER
MOV [DI - 1],BL ;Store am or pm.
CK_DISP_CLOCK: CMP PROGRAM_STATUS,2 ;If not popped up, no
JNZ CK_BELL ; clock display.
DISP_TIME: MOV AX,2
CALL CALC_ADDR
ADD DI,70 * 2
MOV BH,COLOR.Y
MOV SI,OFFSET CLOCK
MOV DX,STATUS_REG
PUSH ES
MOV ES,VIDEO_SEG
JMP SHORT WRITE_CLOCK
NEXT_CLOCK: CALL WRITE_SCREEN ;Display clock.
WRITE_CLOCK: LODSB
OR AL,AL
JNZ NEXT_CLOCK
POP ES
CK_BELL: CMP BELL_FLAG,0 ;Is alarm chiming?
JZ CK_MINUTE
JMP DO_BELL
CK_MINUTE: MOV AX,WORD PTR CLOCK + 3 ;Retrieve current minute.
CMP AH,LAST_MIN ;Same as last minute?
JNZ CK_ALARM
JMP TIMER_END ;If yes, done.
CK_ALARM: CMP AX,"1" SHL 8 + "0" ;Else, is it :01?
JZ CK_ROLLOVER ;If yes, check if 12:01.
SUB AX,"0" SHL 8 + "0" ;Else, adjust to binary.
OR AH,AH ;Minute zero?
JZ ADJUST_TIME
TIMER_LILLY: JMP TIMER_END ;If no, done.
CK_ROLLOVER: OR BP,BP ;Is it 12:01am?
JNZ TIMER_LILLY ;If no, done.
MOV REREAD_FLAG,1 ;Else, reread disk alarms.
CMP PROGRAM_STATUS,0 ;Are we popped up?
JNZ FIX_DATE ;If yes, fix date now.
CMP NOMIDNIGHT_FLAG,1 ;Else, ignore rollover?
JZ TIMER_LILLY ;If yes, done.
MOV POPUP_FLAG,1 ;Else, popup request.
JMP TIMER_LILLY
FIX_DATE: CALL UPDATE_DATE ;Fix date.
JMP TIMER_LILLY
ADJUST_TIME: SUB BP,6 ; 6:00am
JS EXIT_TIMER
CMP BP,15 ; 9:00pm
JA EXIT_TIMER
OR AL,AL ; xx:00
JZ CK_MATCH
CMP AL,3 ; xx:30
JNZ EXIT_TIMER
AND AL,1 ;Convert to index.
CK_MATCH: CMP PROGRAM_STATUS,0 ;Popped up?
JNZ EXIT_TIMER ;If yes, no alarms.
CBW
SHL BP,1 ;Hour * 2.
ADD AX,BP ; + half hour index.
MOV DI,AX
CMP BYTE PTR ALARMS[DI],1 ;Appointment?
JNZ EXIT_TIMER ;If no, done.
CMP NOPOPUP_FLAG,1 ;No pop up request by user?
JZ CK_BELL_FLAG ;If yes, check chime.
MOV ALARM_FLAG,1 ;Else, flag no cursor change
MOV APP_INDEX,APP_LEFT ; when disk reread to today.
MOV DX,DI
XCHG DH,DL ;Place cursor on appointment.
MOV DL,12
CMP DH,16
JB MOVE_CURSOR
MOV APP_INDEX,APP_RIGHT
SUB DH,16
MOV DL,48
MOVE_CURSOR: ADD DH,4 ;Starts on fourth row.
MOV APP_CURSOR,DX
MOV POPUP_FLAG,1 ;If yes, just pop up.
CK_BELL_FLAG: CMP NOBELL_FLAG,1 ;No chime request by user?
JZ EXIT_TIMER
START_BELL: MOV BELL_CNT,14 * 2 ;14 chirps for chime.
MOV BELL_FLAG,1
CALL SETUP_BELL
DO_BELL: CALL FLIP_BELL
EXIT_TIMER: JMP TIMER_END
TIMER ENDP
;-------------------------------------------------------------
; INPUT: SI = 0 not to suppress leading zero; SI = 1 suppress.
STORE_NUMBER: MOV BH,10
DIV BH
ADD AX,"00"
OR SI,SI
JNZ STORE_IT
CMP AL,"0"
JNZ STORE_IT
MOV AL,SPACE
STORE_IT: STOSB
XCHG AH,AL
STOSB
INC DI
RET
;------------------------------------------------------------------------------
;Interrupt 10h handling routine.
;------------------------------------------------------------------------------
VIDEO PROC NEAR
INC CS:FLAG_10H ;No popup while in a int 10h.
PUSHF
CLI
CALL DWORD PTR CS:OLD10
DEC CS:FLAG_10H
IRET
VIDEO ENDP
;------------------------------------------------------------------------------
;Interrupt 13h handling routine.
;------------------------------------------------------------------------------
BDISK PROC FAR
PUSHF
INC CS:FLAG_13H ;No popup while disk activity.
CLI
CALL DWORD PTR CS:OLD13 ;Call BIOS routine
PUSHF
DEC CS:FLAG_13H
POPF
STI
RET 2 ;Preserve flags.
BDISK ENDP
;------------------------------------------------------------------------------
;Interrupt 28h handling routine.
;------------------------------------------------------------------------------
BACKPROC PROC NEAR
PUSH AX
PUSH DS
MOV AX,CS
MOV DS,AX
CLI
PUSHF
CALL DWORD PTR OLD28
CMP REQUEST_FLAG,0 ;Popup requested?
JZ BP_EXIT
CMP BACK_FLAGS,0 ;Save to popup?
JNZ BP_EXIT
CMP PROGRAM_STATUS,0 ;Already popped up?
JNZ BP_EXIT
INC FLAG_28h
STI
CLD
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH ES
PUSH BP
CALL TSR_STATE ;Save to enter Dos?
JC BP_DONE
CALL MAIN
BP_DONE: POP BP
POP ES
POP DI
POP SI
POP DX
POP CX
POP BX
DEC FLAG_28h
BP_EXIT: POP DS
POP AX
IRET
BACKPROC ENDP
;----------------------------------------------;
TSR_STATE: PUSH AX
CMP BUSY_FLAGS,0
JNZ TSR_BUSY
MOV ES,DOS_SEGMENT ;Check INDOS flag.
MOV BX,INDOS_OFFSET
MOV AL,ES:[BX]
MOV BX,ERRFLAG_OFFSET ;Check critical error flag.
MOV AH,ES:[BX]
XOR BX,BX
CMP BL,FLAG_28h
RCL BL,1
CMP BX,AX
JC TSR_END
; Checking for hardware interrupts will avoid lost of chars in Async.
MOV AX,00001011B
OUT 20H,AL
JMP $ + 2
IN AL,20H
CMP AH,AL
JC TSR_END
TSR_OK: CLC
JMP SHORT TSR_END
TSR_BUSY: STC
TSR_END: POP AX
RET
;-----------------------------------------------;
; This is the new Critical Error interrupt 24h. ;
;-----------------------------------------------;
ERR_CURSOR DW ? ; Current cursor position.
ERR_CORNER DW ? ; Address for error message.
ABORT DB 0 ; =1 if user chose to abort.
IOERR: STI
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH BP
PUSH DS
PUSH ES
MOV BX,CS
MOV DS,BX
MOV ES,BX
CLD
ADD AL,"A"
MOV DISK_NAME + 24,AL ;Convert and save drive letter.
MOV SI,OFFSET DISK ;Disk or printer critical error?
TEST AH,10000000B
JZ SAVE_IT
MOV SI,OFFSET PRN
SAVE_IT: PUSH SI ;Save screen contents we are
MOV BH,ACTIVE_PAGE ; going to write over.
MOV AH,3
INT 10H
MOV ERR_CURSOR,DX ;Save cursor position and
CALL HIDE_CURSOR ; hide it off screen.
MOV AX,ERR_ROW ;Popup error message.
CALL CALC_ADDR
ADD AX,ERR_COL * 2
MOV ERR_CORNER,AX
MOV SI,AX
MOV DI,OFFSET ERR_SAVE
MOV CX,ERR_HEIGHT + 1
MOV BP,ERR_WIDTH + 2
CALL DO_SAVE
POP SI
MOV DI,ERR_CORNER
CALL POP_WINDOW
MOV DI,ERR_CORNER
MOV AX,CRT_WIDTH
ADD DI,AX
ADD DI,AX
ADD DI,AX
MOV SI,OFFSET ERR_BOT
CALL POP_WINDOW
CALL BEEP
WAIT_KEY: XOR AH,AH ;Get a user response.
INT 16H
MOV AL,1
CMP AH,13H ;Was it scan code for "R"?
JZ ERR_END
CMP AH,1EH ;Was it "A"?
JNZ WAIT_KEY ;If no, wait until valid
MOV ABORT,1 ; response.
MOV AL,3 ;Fail.
CMP DOS_VERSION,300H ;DOS 2 can't handle fail request.
JAE ERR_END
XOR AL,AL
ERR_END: PUSH AX
MOV DI,ERR_CORNER ;Restore screen.
MOV SI,OFFSET ERR_SAVE
MOV CX,ERR_HEIGHT + 1
MOV BP,ERR_WIDTH + 2
CALL DO_RESTORE
MOV DX,ERR_CURSOR
CALL SET_CURSOR ;Restore cursor position.
POP AX
POP ES ;Restore registers.
POP DS
POP BP
POP DI
POP SI
POP DX
POP CX
POP BX
IOEXIT: IRET
;------------------------------------------------------------------------------
;MAIN is the routine called to pop up the window.
;------------------------------------------------------------------------------
MAIN PROC NEAR
MOV PROGRAM_STATUS,1 ;Flag in process of popping up.
MOV REQUEST_FLAG,0 ;Reset request counter.
MOV SS_REGISTER,SS ;Setup own stack.
MOV SP_REGISTER,SP
MOV AX,CS
MOV SS,AX
MOV SP,OFFSET OUR_STACK
STI
MOV ES,AX
CALL GET_BIOS_DATA
MOV AL,CRT_MODE ;Is it video mode BW80, CO80
CMP AL,3 ; or MONO?
JZ MAIN1
CMP AL,2
JZ MAIN1
CMP AL,7
JZ MAIN1
QUICK_EXIT: CMP POPUP_FLAG,1 ;If no, can't popup; beep to tell
JZ EXIT ; user only if was hotkey popup.
CALL BEEP
;----------------------------------------------;
; MAIN exit. ;
;----------------------------------------------;
EXIT: CLI
MOV SS,SS_REGISTER ;Restore stack.
MOV SP,SP_REGISTER
MOV PROGRAM_STATUS,0
RET
;----------------------------------------------;
MAIN1: CMP CRT_COLS,80 ;At least 80 columns?
JB QUICK_EXIT
GET_COLORS: CALL GET_CUR_ADDR ;Save cursor address.
CMP MONO_FLAG,1 ;Forced Black and white?
JZ DO_MONO
MOV SI,OFFSET COLOR_ATTR ;Select color or mono
CMP CRT_MODE,3 ; attributes.
JZ GOT_ATTR
DO_MONO: MOV SI,OFFSET MONO_ATTR
GOT_ATTR: MOV DI,OFFSET COLOR
MOV CX,SIZE COLOR_ATTRIBS
REP MOVSB
MAIN5: MOV AH,51H
CALL INT21_PSP ;Get PSP.
MOV OLDPSP,BX
PUSH CS
POP BX
MOV AH,50H ;Set PSP.
CALL INT21_PSP
MOV AH,2FH
INT 21H
MOV OLD_DTA[0],BX ;Get DTA.
MOV OLD_DTA[2],ES
MOV DX,OFFSET DTA
MOV AH,1AH ;Set DTA.
INT 21H
MOV AX,3300H ;Get break.
INT 21H
MOV BREAK,DL
XOR DL,DL ;Break off.
MOV AX,3301H
INT 21H
MAIN6: PUSH CS
POP ES
CALL IOSET ;Set up critical error handler.
CALL UPDATE_DATE
CALL SAVE_SCREEN
MOV EXIT_FLAG,0
CMP POPUP_FLAG,1 ;Alarm or rollover?
JNZ READY
MOV POPUP_FLAG,0
MOV STATE,OFFSET APPOINTMENT ;If yes, popup in appointments
CALL CTODAY ; on today.
READY: MOV PROGRAM_STATUS,2 ;Flag so clock displayed.
MOV CX,SCH_CURSOR
MOV AH,1
INT 10H
;------------------------------;
; M A I N L O O P ;
;------------------------------;
NEXT_STATE: MOV REREAD_FLAG,1
CALL HIDE_CURSOR
CALL STATE
CMP EXIT_FLAG,1 ;If Esc Calendar or Hotkey, exit.
JNZ NEXT_STATE
ESCAPE: MOV PROGRAM_STATUS,1 ;Disable clock display.
CALL RESTORE_SCREEN
MOV BX,OLDPSP ;Restore PSP.
MOV AH,50H
CALL INT21_PSP
PUSH DS ;Restore DTA.
LDS DX,DWORD PTR OLD_DTA
MOV AH,1AH
INT 21H
POP DS
MOV DL,BREAK ;Restore BREAK.
MOV AX,3301H
INT 21H
CALL IORESET ;Restore critical handler.
MOV BH,ACTIVE_PAGE ;Restore cursor.
MOV DX,CURSOR_POS
MOV AH,2
INT 10H
MOV DX,ADDR_6845 ;Recover CRTC base address
MOV CX,CURSOR_ADDR
MOV AL,14
OUT DX,AL
INC DX
MOV AL,CH
OUT DX,AL
DEC DX
MOV AL,15
OUT DX,AL
INC DX
MOV AL,CL
OUT DX,AL
MOV CX,CURSOR_MODE
MOV AH,1
INT 10H
JMP EXIT
MAIN ENDP
;----------------------------------------------;
INT21_PSP: CMP DOS_VERSION,30AH ;PSP call DOS 3 or above.
JB INT21_PSP2
INT 21H
RET
INT21_PSP2: PUSH DS ;Else, fake via error.
MOV DI,ERRFLAG_OFFSET
MOV DS,DOS_SEGMENT
INC BYTE PTR [DI]
INT 21H
DEC BYTE PTR [DI]
POP DS
RET
;------------------------------------------;
; OUTPUT: ZF=1 if aborted. CY=1 if failed ;
;------------------------------------------;
ZR EQU 1000000B ;Bit for zero flag in register.
INT21_IO: INT 21H
PUSH AX
LAHF ;Save flag's results of DOS call.
AND AH,NOT ZR ;Assume zero flag zero.
CMP ABORT,1 ;Was there an abort from
JNZ INT21_IO_END ; critical error?
OR AH,ZR ;If yes, turn zero bit on.
MOV ABORT,0 ;Reset abort flag.
INT21_IO_END: SAHF ;Return results in flags reg.
POP AX
RET
;----------------------------------------------;
UPDATE_DATE: MOV AH,2AH ;Get the date from DOS.
INT 21H
MOV YEAR_TODAY,CX
MOV DAY_MON_TODAY,DX
RET
;**********************************************;
; F U N C T I O N C A L L S
;**********************************************;
MONTHS DB "JanFebMarAprMayJunJulAugSepOctNovDec"
NUMDAYS DB 31,28,31,30,31,30,31,31,30,31,30,31
YEAR_CAL DW ? ;Year displayed.
DAY_MON_CAL LABEL WORD
DAY_CAL DB ? ;Day cursor is on.
MONTH_CAL DB ? ;Month displayed.
YEAR_TODAY DW ? ;Current year.
DAY_MON_TODAY LABEL WORD
DAY_TODAY DB ? ;Current day.
MONTH_TODAY DB ? ;Current month.
YEAR_CUR DW ? ;Last year displayed.
DAY_MON_CUR LABEL WORD
DAY_CUR DB ? ;Last day displayed.
MONTH_CUR DB -1 ;Last month displayed.
WEEKDAY DB ? ;Day of week for 1st.
LAST_DAY DB ? ;Last day of month.
DAY_COUNTER DB ? ;Day display counter.
BLOCK_COUNTERS LABEL WORD
BLOCK_COUNTER DB ?,? ;Block display counters.
BLOCK_ROW DW 0 ;Block row index.
CTABLE DB 3DH
DB 4BH, 4DH, 48H, 50H, 47H, 4FH
DB 49H, 51H, 84H, 76H, 77H, 75H
DB 73H, 74H
CTABLE_LEN EQU $ - CTABLE
DW CTODAY
DW CLEFT, CRIGHT, CUP, CDOWN, CHOME, CEND
DW CPGUP, CPGDN, CCTRLPGUP, CCTRLPGDN, CCTRLHOME, CCTRLEND
DW CHOME, CEND
CALENDAR: MOV SI,OFFSET SCH_DAT
CALL APPEND
CALL CK_DATE ;See if date changed.
MOV SI,OFFSET CAL_MENU ;Pop up calendar screen.
CALL POP_MENU
MOV DAY_COUNTER,0 ;Counters for day and
MOV BLOCK_COUNTERS,0 ; cursor display.
MOV SI,OFFSET CAL_MIDDLE
CALL POP_WINDOW
MOV CX,5
NEXT_CALROW: PUSH CX
MOV SI,OFFSET CAL_DUP
CALL POP_WINDOW
POP CX
LOOP NEXT_CALROW
INC SI
CALL POP_WINDOW
CALL GETKEY ;Get a keystroke.
JC CALENDAR_DONE ;Exit if Esc or hotkey.
CMP AL,ENTER_SCAN ;If Enter, then go to
JZ GOTO_APP ; appointment screen.
CMP AL,31H ;If "N" scan code.
JZ GOTO_NOTE
CMP AL,SHIFT_F7_SCAN
JNZ CK_CAL_F7
MOV STATE,OFFSET APPOINTMENT
JMP SHORT CALENDAR_END
CK_CAL_F7: CMP AL,F7_SCAN ; or F6, go directly
JNZ CAL_DISPATCH ; to Journal
MOV STATE,OFFSET JOURNAL
JMP SHORT CALENDAR_END
GOTO_NOTE: MOV STATE,OFFSET APPOINTMENT
CALL CK_DATE
MOV APP_CURSOR,A_NOTE_CURSOR
MOV APP_INDEX,APP_NOTE
JMP SHORT CALENDAR_END
GOTO_APP: MOV STATE,OFFSET APPOINTMENT
JMP SHORT CALENDAR_END
CAL_DISPATCH: MOV SI,YEAR_CAL ;Pass variables in registers
MOV DL,DAY_CAL ; to calendar keyboard
MOV DH,MONTH_CAL ; functions.
MOV BL,WEEKDAY
MOV BH,LAST_DAY
MOV DI,OFFSET CTABLE
MOV CX,CTABLE_LEN
CALL DISPATCH
CMP EXIT_FLAG,1
JZ CALENDAR_END
JMP CALENDAR
CALENDAR_DONE: MOV EXIT_FLAG,1 ;Tell MAIN to exit.
CALENDAR_END: RET
;----------------------------------------------;
; INPUT: SI=YEAR_CAL; DL=DAY_CAL; DH=MONTH_CAL; BL=WEEKDAY; BH=LAST_DAY
CTODAY: MOV SI,YEAR_TODAY ;Today's date.
MOV DX,DAY_MON_TODAY
JMP SHORT CFUNC_UPDATE
CPGDN: INC DH ;Next month.
CMP DH,12 ;Past Dec?
JBE CFUNC_UPDATE
MOV DH,1 ;Jan.
INC SI ;Next year.
JMP SHORT CK_YEAR
CPGUP: DEC DH ;Previous month.
JNZ CFUNC_UPDATE ;Before Jan?
MOV DH,12 ;Dec.
DEC SI ;Previous year.
JMP SHORT CK_YEAR
CCTRLPGDN: INC SI ;Next year.
JMP SHORT CK_YEAR
CCTRLPGUP: DEC SI ;Previous year.
CK_YEAR: CMP SI,10000 ;Stay within Gregorian
JAE CFUNC_END ; calendar.
CMP SI,1582
JA CFUNC_UPDATE
JMP SHORT CFUNC_END
CLEFT: DEC DL ;Previous day.
JNZ CFUNC_UPDATE
JMP SHORT CFUNC_END
CRIGHT: INC DL ;Next day.
CMP DL,BH
JBE CFUNC_UPDATE
JMP SHORT CFUNC_END
CUP: MOV AL,7
SUB AL,BL ;Adjust for weekday.
CMP DL,AL ;If first week, ignore
JBE CFUNC_END
SUB DL,7 ;Previous week.
JA CFUNC_UPDATE
MOV DL,1 ;First day, if out of bounds.
JMP SHORT CFUNC_UPDATE
CDOWN: MOV CL,7
MOV AL,CL
SUB AL,BL
FIND_BOTTOM: ADD AL,CL ;Find last week row.
CMP AL,BH
JBE FIND_BOTTOM
SUB AL,CL
CMP DL,AL
JA CFUNC_END ;Ignore if on last row.
ADD DL,7 ;Next week.
CMP DL,BH
JBE CFUNC_UPDATE
MOV DL,BH ;Last day if out of bounds.
JMP SHORT CFUNC_UPDATE
CCTRLHOME: MOV DL,1 ;First day.
JMP SHORT CFUNC_UPDATE
CCTRLEND: MOV DL,BH ;Last day.
CFUNC_UPDATE: MOV YEAR_CAL,SI ;Store new day/year.
MOV DAY_MON_CAL,DX
CFUNC_END: RET
CHOME: MOV AL,DL ;Adjust for weekday.
ADD AL,BL
DEC AL
CBW
MOV CL,7
DIV CL
MOV DL,1 ;First day if at start of row.
OR AH,AH
JZ CFUNC_UPDATE
MUL CL
SUB AL,BL
INC AL
JBE CFUNC_UPDATE
MOV DL,AL ;Else go to start of row.
JMP CFUNC_UPDATE
CEND: MOV AL,DL ;Adjust for weekday.
ADD AL,BL
CBW
MOV CL,7
DIV CL
MOV DL,BH ;Last day if at end of row.
OR AH,AH
JZ CFUNC_UPDATE
MUL CL
ADD AL,CL
SUB AL,BL
MOV DL,AL ;Else, end of row.
CMP DL,BH
JBE CFUNC_UPDATE
MOV DL,BH
JMP CFUNC_UPDATE
;----------------------------------------------;
CK_DATE: MOV AX,DAY_MON_CAL ;Retrieve calendar day/year.
MOV BX,YEAR_CAL
CMP REREAD_FLAG,1 ;Forced reread?
JZ GET_CAL
CMP AH,MONTH_CUR ;Has month changed?
JNZ GET_CAL
CMP BX,YEAR_CUR ;Has year changed?
JNZ GET_CAL
CMP STATE,OFFSET CALENDAR
JZ CK_DATE_END ;If appointment screen,
CMP AL,DAY_CUR ; has day changed?
JZ CK_DATE_END
GET_CAL: MOV REREAD_FLAG,0 ;Reset flag.
PUSH AX
PUSH BX
CALL PERMANENT ;See if changes have been made
POP BX ; in appointment screen.
POP AX
MOV MONTH_CUR,AH ;Store current day/year.
MOV YEAR_CUR,BX
CALL FIRSTDAY ;Find first day of month.
CALL READ_DATA ;Read data off of disk.
CMP ALARM_FLAG,1 ;Was this alarm?
JZ RESET_ALARM ;If yes, leave cursor on app.
MOV A_LEFT.CURSOR,A_LEFT_CURSOR
MOV A_RIGHT.CURSOR,A_RIGHT_CURSOR
MOV A_NOTE.CURSOR,A_NOTE_CURSOR
MOV APP_INDEX,APP_LEFT
MOV APP_CURSOR,A_LEFT_CURSOR
MOV JOU_CURSOR,JOU_HOME
MOV JOU_INDEX,0
RESET_ALARM: MOV ALARM_FLAG,0
CK_DATE_END: RET
;----------------------------------------------;
FIRSTDAY: MOV SI,YEAR_CAL ;Year.
MOV NUMDAYS[1],28 ;Assume this isn't a leap year.
TEST SI,3 ;Year divisible by 4?
JNZ GETDAY ;Assumed right.
MOV NUMDAYS[1],29 ;Leap year = 29 days.
GETDAY: MOV BX,6 ;Saturday,(weekday of 1/1/1583)
MOV AX,SI ;Calendar year.
SUB AX,1583 ;No. years since our base year.
ADD BX,AX ;Calendar advances 1 weekday per
; year unless leap year.
ADD AX,2 ;Adj diff, so even #, if year
MOV CX,4 ; was after a leap year.
CWD
DIV CX ;No. leap years before this.
ADD BX,AX ;Add 1 day, for each leap yr.
CMP SI,1700 ;Things work normally 'til 1700.
JL CNVRT ;Not a leap year.
MOV AX,SI
SUB AX,1600 ;Get no. years since 1600.
MOV CL,100
CWD ;Convert to number of centuries.
DIV CX
OR DX,DX ;If remain=0 this is centennial.
JNZ DEDUCT
TEST AX,3 ;If century divisible by
JZ DECAX ; 400, it is also leap year.
MOV NUMDAYS[1],28 ;Other centennial years have 28.
DECAX: DEC AX ;If centennial, sub 1 from cent.
DEDUCT: SUB BX,AX ;Subtract 1 weekday per century.
CWD
MOV CL,4
DIV CX ;Calculate centuries mod 400.
ADD BX,AX ;Add back 1 day per 400 years.
CNVRT: MOV SI,OFFSET NUMDAYS ;Add in days per month, this yr.
XOR AH,AH
MOV CL,MONTH_CAL ;Calendar month.
DEC CL
MOV DI,CX
MOV DL,NUMDAYS[DI]
MOV LAST_DAY,DL
JCXZ FINAL ;If Jan, ready for final calc.
ADDMNTH: LODSB
ADD BX,AX ;Add to days count.
LOOP ADDMNTH ;Cont. until prior months added.
FINAL: MOV AX,BX ;Days advanced since 1/1/1583.
CWD
MOV CL,7 ;Find no. full weeks since 1583.
DIV CX ;Weekday of 1st of cal's month.
MOV WEEKDAY,DL ;Result is first day of week.
MOV AL,DAY_CAL ;Fix last day.
FIX_CURSOR: CMP AL,LAST_DAY
JBE STORE_CURSOR2
DEC AL
JMP FIX_CURSOR
STORE_CURSOR2: MOV DAY_CAL,AL ;Store fix.
MOV DAY_CUR,AL
CALL STORE_DATE
RET
;----------------------------------------------;
STORE_DATE: MOV BP,5 ;Five places need dates.
MOV DI,OFFSET CAL_DATE ;Calendar screen.
NEXT_DATE: PUSH DI
MOV AL,MONTH_CAL ;Month
DEC AL
MOV CX,3
MUL CL
ADD AX,OFFSET MONTHS
MOV SI,AX
REP MOVSB
INC DI
CMP BP,5
JZ STORE_YEAR
MOV AL,DAY_CAL ;Number of day.
CBW
CALL STORE_NUM
MOV AL,SPACE
STOSB
STORE_YEAR: MOV AX,YEAR_CAL ;Year.
CALL STORE_NUM
MOV AL,SPACE
STOSB
POP DI
CMP BP,5
JZ LOOP_DATE
ADD DI,12
MOV AL,WEEKDAY
ADD AL,DAY_CAL
DEC AL
CBW
MOV CL,7
DIV CL
MOV AL,AH
MOV CL,11
MUL CL
ADD AX,OFFSET DAYS ;Name of weekday; ie. Mon etc.
MOV SI,AX
MOV CX,3
REP MOVSB
LOOP_DATE: DEC BP
JZ STORE_DATE_END
MOV DI,OFFSET APP_DATE ;Appointment screen.
CMP BP,4
JZ NEXT_DATE
MOV DI,OFFSET PUR_DATE ;Purge window.
CMP BP,3
JZ NEXT_DATE
MOV DI,OFFSET JOU_DATE
CMP BP,2
JZ NEXT_DATE
MOV DI,OFFSET REPORT_DATE
JMP NEXT_DATE
STORE_DATE_END:RET
;----------------------------------------------;
STORE_NUM: MOV BX,10
XOR CX,CX ;Zero in counter.
NEXT_COUNT: CWD ;Zero in high half.
DIV BX ;Divide by ten.
ADD DL,"0" ;Convert to ASCII.
PUSH DX ;Save results.
INC CX ;Also increment count.
OR AX,AX ;Are we done?
JNZ NEXT_COUNT ;Continue until zero.
NEXT_NUMBER: POP AX ;Retrieve numbers.
STOSB
LOOP NEXT_NUMBER
RET
;----------------------------------------------;
SCAN_DAY: CALL SCAN_APP ;Find appointments.
MOV AL,DAY_CAL ;Store small box char.
CALL STORE_BLOCKS ; if appointment found.
MOV AX,YEAR_CAL
CMP AX,YEAR_TODAY
JNZ SCAN_DAY_END
MOV AX,DAY_MON_CAL
CMP AX,DAY_MON_TODAY
JNZ SCAN_DAY_END
CALL STORE_ALARMS ;Store alarm if today.
SCAN_DAY_END: RET
;----------------------------------------------;
SCAN_APP: PUSH BP
MOV SI,OFFSET WORK_SPACE ;Spaces in work space.
MOV AL,SPACE
MOV BP,OFFSET APP_LEFT_START ;Scan appointments for
MOV CX,2 ; non-space chars.
NEXT_COL: PUSH CX
MOV DX,APP_HEIGHT
NEXT_DAY: MOV DI,BP
MOV CX,APP_LEN
XOR AH,AH ;Mark with zero if no app.
REP SCASB
JZ TEMP_APP
INC AH ;Else, mark with one for alarm.
TEMP_APP: MOV [SI],AH
INC SI
ADD BP,APP_WIDTH
DEC DX
JNZ NEXT_DAY
MOV BP,OFFSET APP_RIGHT_START
POP CX
LOOP NEXT_COL
POP BP
RET
;----------------------------------------------;
; INPUT: AL = Calendar day.
STORE_BLOCKS: DEC AL
CBW
MOV CL,3
SHL AX,CL
MOV DI,AX
ADD DI,OFFSET APPOINTMENT_BLOCKS
MOV SI,OFFSET WORK_SPACE
MOV CX,2
NEXT_SET: PUSH CX
MOV DX,APP_HEIGHT / 2
NEXT_BLOCK2: LODSW
OR AX,AX
MOV AL,SPACE ;Store a space if no appointment.
JZ STORE_BLOCK
MOV AL,"■" ;Else, store little block char.
STORE_BLOCK: STOSB
DEC DX
JNZ NEXT_BLOCK2
ADD DI,(BLOCK_COUNT / 2) - 8
POP CX
LOOP NEXT_SET
RET
;----------------------------------------------;
ALARMS DB APP_HEIGHT * 2 DUP (0)
WORK_SPACE DB APP_HEIGHT * 2 DUP (?)
STORE_ALARMS: MOV SI,OFFSET WORK_SPACE ;Copy results of work space
MOV DI,OFFSET ALARMS ; into alarm array.
MOV CX,SIZE ALARMS / 2
REP MOVSW
RET
TODAY_FLAG EQU 001B ;Data applies to today.
CAL_FLAG EQU 010B ;Data applies to calendar.
APP_FLAG EQU 100B ;Data applies to appointment.
READ_DATA: CMP STATE,OFFSET JOURNAL
JNZ READ_DATA2
JMP READ_JOURNAL
READ_DATA2: MOV DI,OFFSET APPOINTMENT_BLOCKS
MOV CX,BLOCK_COUNT / 2
MOV AX,SPACE SHL 8 + SPACE
REP STOSW ;Spaces in Appointment blocks.
MOV BP,APP_HEIGHT
MOV BX,APP_LEN
MOV DI,OFFSET APP_LEFT_START
NEXT_BLANK: MOV CX,BX
REP STOSB
ADD DI,APP_COL_SPACE
MOV CX,BX
REP STOSB ;Spaces in Appointment book.
ADD DI,APP_ROW_SPACE
DEC BP
JNZ NEXT_BLANK
MOV BP,3
MOV BX,NOTE_LEN
MOV DI,OFFSET NOTEPAD
NEXT_PAD: MOV CX,BX
REP STOSB ;Spaces in Notepad.
ADD DI,APP_NOTE_SPACE
DEC BP
JNZ NEXT_PAD
MOV DI,OFFSET ALARMS
MOV CX,SIZE ALARMS / 2
REP STOSW ;Spaces in Alarms.
CALL OPEN ;Open data file.
JBE READ_DONE ;If none, then done.
NEXT_READ: CALL READ_DATE ;Read the date.
JBE READ_FAILED
OR AX,AX
JZ READ_END
XOR BP,BP ;Initialize date flag.
CMP CX,YEAR_TODAY ;Data same day/month/year
JNZ CK_YEAR_CAL ; as today?
CMP DX,DAY_MON_TODAY
JNZ CK_YEAR_CAL
OR BP,TODAY_FLAG ;If yes, today.
CK_YEAR_CAL: CMP CX,YEAR_CAL ;Same as day/month/year
JNZ CK_READ ; as calendar?
CMP DX,DAY_MON_CAL
JNZ CK_MON_CAL
OR BP,CAL_FLAG OR APP_FLAG ;If yes, then applies to
JMP SHORT DO_READ ; calendar and appointment.
CK_MON_CAL: CMP DH,MONTH_CAL ;Same as month/year only.
JNZ CK_READ
OR BP,CAL_FLAG ;If yes, applies to calendar.
CK_READ: OR BP,BP ;Does data apply to anything?
JNZ DO_READ
CALL NEXT_RECORD ;If no, bump file pointer
JBE READ_FAILED ; to next record.
JMP NEXT_READ
DO_READ: CALL READ_APP ;If applies, read in the data.
JBE READ_FAILED
TEST BP,APP_FLAG ;Apply to appointments?
JZ CK_TODAY_CAL
CALL MOVE_APP ;If yes, move data into app.
CK_TODAY_CAL: CALL SCAN_DTA ;Scan the data for appointments.
TEST BP,TODAY_FLAG ;Does it apply to today.
JZ CK_MON_CAL2
CALL STORE_ALARMS ;If yes, store alarms.
CK_MON_CAL2: TEST BP,CAL_FLAG ;Apply to calendar?
JZ NEXT_READ
MOV AL,BYTE PTR DTA.DATE_BINARY + 2
CALL STORE_BLOCKS ;If yes, store small block chars.
JMP NEXT_READ
READ_END: MOV AH,3EH ;Close data file.
CALL INT21_IO
READ_DONE: RET
READ_FAIL: CALL FAILED ;If failed, display message.
RET
READ_FAILED: CALL FAILED_CLOSE
RET
READ_JOURNAL: MOV DI,OFFSET DTA.DATA_TEXT
MOV CX,SIZE JOU_FIELDS / 2
MOV AX,SPACE SHL 8 + SPACE
REP STOSW
CALL STORE_JOURNAL
CALL OPEN
JBE READ_DONE
NEXT_READ_JOU: CALL READ_DATE
JBE READ_FAILED
OR AX,AX
JZ READ_END
CMP CX,YEAR_CAL
JNZ JOU_RECORD
CMP DX,DAY_MON_CAL
JNZ JOU_RECORD
MOV DX,OFFSET DTA.DATE_ASCII
MOV CX,SIZE DATE_ASCII+SIZE JOU_FIELDS
MOV AH,3FH
CALL INT21_IO ;Read data record.
JBE READ_FAILED
CALL STORE_JOURNAL
JMP READ_END
JOU_RECORD: CALL NEXT_RECORD
JBE READ_FAILED
JMP NEXT_READ_JOU
;----------------------------------------------;
SCAN_DTA: PUSH BP
MOV SI,OFFSET WORK_SPACE
MOV AL,SPACE
MOV BP,OFFSET DTA.DATA_TEXT
MOV CX,2
NEXT_DTA: PUSH CX
MOV DX,APP_HEIGHT ;Scan data read off disk
NEXT_DTA2: MOV DI,BP ; and store a 1 in work space
MOV CX,APP_LEN ; if non-space char.
XOR AH,AH
REP SCASB
JZ TEMP_APP2
INC AH
TEMP_APP2: MOV [SI],AH
INC SI
ADD BP,APP_LEN * 2
DEC DX
JNZ NEXT_DTA2
MOV BP,OFFSET DTA.DATA_TEXT + APP_LEN
POP CX
LOOP NEXT_DTA
POP BP
RET
;----------------------------------------------;
MOVE_APP: MOV SI,OFFSET DTA.DATA_TEXT
MOV DI,OFFSET APP_LEFT_START
MOV DX,APP_HEIGHT
NEXT_MOVE: MOV CX,APP_LEN
REP MOVSB ;Move DTA appointments into
ADD DI,APP_COL_SPACE ; screen app. storage space.
MOV CX,APP_LEN
REP MOVSB
ADD DI,APP_ROW_SPACE
DEC DX
JNZ NEXT_MOVE
MOV SI,OFFSET DTA.NOTEPAD_TEXT
MOV DI,OFFSET NOTEPAD ;Move DTA Notepad into
MOV CX,NOTEPAD_LEN ; screen Notepad space.
REP MOVSB
RET
;***************************************************************************;
APP_BOUNDS STRUC ;Cursor bounds in 3 sections.
COL_HOME DB ?
COL_END DB ?
ROW_HOME DB ?
ROW_END DB ?
CURSOR DW ?
APP_BOUNDS ENDS
APP_LEFT EQU 0
APP_RIGHT EQU SIZE APP_BOUNDS
APP_NOTE EQU APP_RIGHT + SIZE APP_BOUNDS
APP_INDEX DW APP_LEFT ;Section index.
A_LEFT_CURSOR EQU 4 SHL 8 + 12 ;Home cursor positions.
A_RIGHT_CURSOR EQU 4 SHL 8 + 48
N_ROW EQU 4 + APP_HEIGHT + 1
A_NOTE_CURSOR EQU N_ROW SHL 8 + 4
BOUNDS LABEL BYTE
A_LEFT APP_BOUNDS < 12, 12 + APP_LEN, 4, 4 + APP_HEIGHT - 1, A_LEFT_CURSOR >
A_RIGHT APP_BOUNDS < 48, 48 + APP_LEN, 4, 4 + APP_HEIGHT - 1, A_RIGHT_CURSOR >
A_NOTE APP_BOUNDS <4,4+NOTE_LEN,N_ROW,4+APP_HEIGHT+NOTE_HEIGHT,A_NOTE_CURSOR >
APP_CURSOR LABEL WORD
APP_CUR_COL DB 12 ;Appointment cursor position.
APP_CUR_ROW DB 4
REPAINT_FLAG DB 1 ; 1 = Repaint the screen.
ATABLE DB 3CH, 3DH, 3EH, 3FH, 40H, 59H
DB 63H, 4BH, 4DH, 48H, 50H, 47H
DB 4FH, 49H, 51H, 84H, 76H, 77H
DB 75H, 73H, 74H, 0FH, 53H
ATABLE_LEN EQU $ - ATABLE
DW SAVE, ATODAY, PPURGE, PRINT, CLEAR, SHIFT_CLEAR
DW CTRL_CLEAR, ALEFT, ARIGHT, AUP, ADOWN, AHOME
DW AEND, APGUP, APGDN, ACTRLPGUP, ACTRLPGDN, ACTRLHOME
DW ACTRLEND, AHOME, AEND, SHIFT_TAB, ADEL
APPOINTMENT: MOV SI,OFFSET SCH_DAT
CALL APPEND
CALL CK_DATE ;Check if date changed.
CMP REPAINT_FLAG,1
JNZ NEXT_APPOINT
MOV SI,OFFSET APP_MENU ;Display appointment screen.
CALL POP_MENU
MOV REPAINT_FLAG,0
NEXT_APPOINT: MOV DX,APP_CURSOR
CALL SET_CURSOR
CALL GETKEY ;Get a keystroke.
CMP EXIT_FLAG,1 ;Exit if hotkey.
JZ APPOINT_END
CMP AL,SHIFT_F7_SCAN
JNZ CK_APP_F7
CALL PERMANENT
MOV STATE,OFFSET JOURNAL
JMP SHORT APPOINT_END
CK_APP_F7: CMP AL,F7_SCAN
JNZ CK_APP_ESC
CALL PERMANENT
MOV STATE,OFFSET CALENDAR
JMP SHORT APPOINT_END
CK_APP_ESC: CMP AL,ESC_SCAN ;Back to calendar if Esc.
JNZ APP_DISPATCH
CALL PERMANENT
MOV STATE,OFFSET CALENDAR
JMP SHORT APPOINT_END
APP_DISPATCH: CALL CALC_APP_ADDR ;Get cursor bounds.
MOV BP,APP_INDEX
MOV BX,WORD PTR BOUNDS[BP]
OR AH,AH ;Extended scan code?
JZ GOT_DISPATCH
CALL CK_ENTRY
JMP NEXT_APPOINT
GOT_DISPATCH: MOV DI,OFFSET ATABLE
MOV CX,ATABLE_LEN
CALL DISPATCH
CMP EXIT_FLAG,1
JNZ APPOINTMENT
APPOINT_END: MOV REPAINT_FLAG,1 ;Flag to repaint screen.
CALL PERMANENT ;Check for changes.
CALL SCAN_DAY ;Scan appointments.
RET
;----------------------------------------------;
; INPUT: DX = Cursor address; OUTPUT: SI -> Start of row.
CALC_APP_ADDR: PUSH AX
MOV CX,DX
SUB CH,4 ;Appointments start on line 4.
MOV AX,APP_WIDTH
MUL CH
MOV SI,AX
XOR CH,CH
ADD SI,CX
ADD SI,OFFSET APP_START
POP AX
RET
;----------------------------------------------;
; INPUT: SI -> appointments; DX=Cursor; BP=APP_INDEX; BH=COL_END; BL=COL_HOME
CK_ENTRY: XCHG AH,AL
CMP AL,TAB ;Tab?
JNZ CK_BACKSPACE
SHIFT_TAB: MOV CX,SIZE APP_BOUNDS
MOV BX,BP ;Save index.
MOV AH,2
INT 16H ;Get shift status.
TEST AL,11B ;Left or Right Shift?
JZ DO_TAB
NEG CX
DO_TAB: MOV AX,APP_NOTE
ADD BP,CX
JNS CK_HIGH
MOV BP,AX
CK_HIGH: CMP BP,AX
JBE NEW_FIELD
XOR BP,BP
NEW_FIELD: MOV APP_INDEX,BP ;New section.
MOV BOUNDS.CURSOR[BX],DX ;Save current cursor position.
MOV DX,BOUNDS.CURSOR[BP] ;Get new cursor position.
JMP SHORT ENTRY_UPDATE
CK_BACKSPACE: CMP AL,8 ;Backspace?
JNZ CK_PAD_CR
CMP DL,BL
JZ ENTRY_END
DEC SI ;Move back one space.
DEC DL
MOV APP_CURSOR,DX ;Save cursor position.
CALL ADEL ;Delete that character.
JMP SHORT ENTRY_END
CK_PAD_CR: CMP AL,CR ;Carriage return?
JNZ APP_ASCII
MOV DL,BL
CMP DH,BOUNDS.ROW_END[BP] ;Move to start of line.
JZ ENTRY_UPDATE
INC DH ;Next row if not at bottom.
JMP SHORT ENTRY_UPDATE
APP_ASCII: CMP AL,SPACE ;Text character?
JB ENTRY_END
INC DL ;Next column.
SUB BH,DL
JC ENTRY_END ;If last column, ignore.
JZ STORE_APP ;If next to last column, store.
MOV CL,BH
XOR CH,CH
ADD SI,CX
MOV DI,SI
DEC SI
STD
REP MOVSB ;Else, insert mode so shove
CLD ; everything in front up one.
INC SI
STORE_APP: MOV [SI],AL ;Store character.
ENTRY_CHANGE: MOV MODIFY_FLAG,1 ;Flag that change made.
ENTRY_UPDATE: MOV APP_CURSOR,DX ;Store new cursor position.
MOV SI,OFFSET APP_START
CALL DISPLAY_LINE ;Display just that changed line
; for better response time.
ENTRY_END: RET
;----------------------------------------------;
ACTRLHOME: MOV DL,BL ;Beginning of field.
JMP SHORT DO_HOME
AHOME: CMP DL,BL ;Beginning of field unless
MOV DL,BL ; already there, then go
JNZ ENTRY_UPDATE ; to section home.
DO_HOME: MOV DH,BOUNDS.ROW_HOME[BP]
JMP ENTRY_UPDATE
ACTRLEND: MOV DL,BH ;End of field
JMP SHORT DO_END
AEND: CALL GET_WORD
CMP DI,SI
JZ DO_END1
MOV BX,DI
MOV CX,SI
SUB BX,CX
ADD DL,BL
JMP ENTRY_UPDATE
DO_END1: MOV DL,BH
DO_END: MOV DH,BOUNDS.ROW_END[BP]
JMP ENTRY_UPDATE
ALEFT: CMP DL,BL ;Left one space unless
JNZ DO_LEFT ; already column home.
CMP BP,APP_RIGHT
JNZ ENTRY_END
MOV APP_INDEX,APP_LEFT ;If in col home of right section,
SUB DL,6 ; go to left section.
DO_LEFT: DEC DL
JMP ENTRY_UPDATE
ARIGHT: INC DL ;Right on space unless
CMP DL,BH ; already column end.
JBE ENTRY_UPDATE
CMP BP,APP_LEFT
JNZ ENTRY_END
MOV APP_INDEX,APP_RIGHT ;If in col end of left section,
ADD DL,6 ; go to right section.
JMP ENTRY_UPDATE
ADOWN: CMP DH,BOUNDS.ROW_END[BP] ;If at bottom, go and not
JNZ UPDATE_DOWN ; in Notepad, go to Notepad.
CMP BP,APP_NOTE
JZ ENTRY_END
INC DH ;Else, next row.
MOV APP_INDEX,APP_NOTE
UPDATE_DOWN: INC DH
JMP ENTRY_UPDATE
AUP: CMP DH,BOUNDS.ROW_HOME[BP] ;If in top row of NotePad
JNZ DO_UP ; go to either left or right
CMP BP,APP_NOTE ; section.
JNZ ENTRY_END
DEC DH
MOV BP,APP_RIGHT
CMP DL,BOUNDS.COL_HOME[BP]
JAE UPDATE_UP
MOV BP,APP_LEFT
MOV BX,WORD PTR BOUNDS[BP]
CMP DL,BL
JA CK_UP_END
MOV DL,BL
JMP SHORT UPDATE_UP
CK_UP_END: CMP DL,BH
JBE UPDATE_UP
MOV DL,BH
UPDATE_UP: MOV APP_INDEX,BP
DO_UP: DEC DH ;Else, just decrement row.
JMP ENTRY_UPDATE
ADEL: SUB BH,DL ;Ignore if in last column.
MOV CL,BH
XOR CH,CH
JCXZ ADEL_END
MOV DI,SI
INC SI
REP MOVSB ;Else, move everything to right
MOV SI,OFFSET APP_START
CALL DISPLAY_LINE ; of cursor left one space.
MOV MODIFY_FLAG,1
ADEL_END: RET
;---------------------------;
GET_WORD: MOV CL,BH
SUB CL,DL
XOR CH,CH
MOV DI,SI
ADD DI,CX
MOV CL,BH
SUB CL,BL
XOR CH,CH
GET_WORD2: CMP BYTE PTR [DI-1],SPACE
JNZ GOT_WORD
DEC DI
LOOP GET_WORD2
GOT_WORD: RET
;----------------------------------------------;
ATODAY: CALL PERMANENT
MOV SI,YEAR_TODAY
MOV YEAR_CAL,SI ;Go to today.
MOV DX,DAY_MON_TODAY
MOV DAY_MON_CAL,DX
JMP SHORT DAY_UPDATE
APGUP: CALL PERMANENT
PPGUP: MOV AL,-1 ;Previous day.
JMP SHORT CK_DAY
APGDN: CALL PERMANENT
PPGDN: MOV AL,1 ;Next day.
CK_DAY: MOV DL,DAY_CAL
ADD DL,AL
JZ NEW_MONTH
CMP DL,LAST_DAY ;Past month bounds?
JA NEW_MONTH
UPDATE_MONTH: MOV DAY_CAL,DL ;If no, OK.
JMP SHORT DAY_UPDATE
NEW_MONTH: MOV DAY_CAL,1 ;Move to new month.
JA PCTRLPGDN
MOV DAY_CAL,31
JMP SHORT PCTRLPGUP
ACTRLPGUP: CALL PERMANENT
PCTRLPGUP: MOV AX,-1 ;Previous month.
JMP SHORT CK_MONTH
ACTRLPGDN: CALL PERMANENT
PCTRLPGDN: MOV AX,1 ;Next month.
CK_MONTH: MOV DH,MONTH_CAL
ADD DH,AL
JNZ CK_MONTH2
MOV DH,12 ;Past year bounds?
JMP SHORT CK_YEAR2
CK_MONTH2: CMP DH,12
JBE UPDATE_MONTH2
MOV DH,1
JMP SHORT CK_YEAR2
UPDATE_MONTH2: MOV MONTH_CAL,DH
JMP SHORT DAY_UPDATE
CK_YEAR2: MOV MONTH_CAL,DH
MOV SI,YEAR_CAL
ADD SI,AX ;Next/Previous year.
CMP SI,10000
JAE DAY_END
CMP SI,1582 ;Check bounds.
JB DAY_END
MOV YEAR_CAL,SI
DAY_UPDATE: MOV REPAINT_FLAG,1 ;Repaint the screen.
DAY_END: RET
;----------------------------------------------;
CLEAR: MOV DL,BL
CALL CALC_APP_ADDR
MOV DI,SI ;Appointment address line.
MOV CX,BX
SUB CH,CL
MOV CL,CH
XOR CH,CH
MOV AL,SPACE ;Store spaces.
REP STOSB
MOV APP_CURSOR,DX ;Home cursor.
MOV BOUNDS.CURSOR[BP],DX
MOV APP_INDEX,BP
JMP SHORT F6_END
SHIFT_CLEAR: MOV CX,WORD PTR BOUNDS.ROW_HOME[BP]
MOV DH,CH
SUB CH,CL
MOV CL,CH
XOR CH,CH
INC CX
NEXT_SHIFT_F6: PUSH CX ;Rows in section.
CALL CLEAR ;Clear all rows.
DEC DH
POP CX
LOOP NEXT_SHIFT_F6
JMP SHORT F6_END
CTRL_CLEAR: MOV BP,APP_NOTE ;Start with Notepad.
MOV CX,3 ;Three sections to clear.
NEXT_CTRL_F6: PUSH CX
MOV BX,WORD PTR BOUNDS[BP]
CALL SHIFT_CLEAR ;Clear section.
SUB BP,SIZE APP_BOUNDS
POP CX
LOOP NEXT_CTRL_F6
F6_END: MOV MODIFY_FLAG,1
MOV REPAINT_FLAG,1
RET
;----------------------------------------------;
; INPUT: DX = Cursor position; SI -> Storage.
DISPLAY_LINE: MOV AL,DH
SUB AL,4 ;Calc start of app. line
MOV CX,APP_WIDTH ; to display.
MUL CL
ADD SI,AX
MOV AL,DH
XOR AH,AH
CALL CALC_ADDR ;Calc corresponding display
PUSH ES ; address.
MOV DX,STATUS_REG
MOV ES,VIDEO_SEG
MOV BH,COLOR.B
DEC CX
NEXT_LINE: LODSB ;Display line.
CALL WRITE_SCREEN
LOOP NEXT_LINE
POP ES
RET
;***************************************************************************;
DATEONLY_FLAG DB ? ; =1 if purge date only.
PTABLE DB 49H, 51H, 84H, 76H, 3DH
PTABLE_LEN EQU $ - PTABLE
DW PPGUP, PPGDN, PCTRLPGUP, PCTRLPGDN, CTODAY
PPURGE: PUSH YEAR_CAL ;Preserve calendar variables.
PUSH DAY_MON_CAL
PUSH YEAR_CUR
PUSH DAY_MON_CUR
CALL HIDE_CURSOR
NEXT_F4: CALL FIRSTDAY ;Store purge date in window.
MOV AX,1
CALL CALC_ADDR
ADD DI,9 * 2
MOV SI,OFFSET PURGE_MSG
CALL POP_WINDOW ;Display purge window.
CALL GETKEY ;Get a keystroke.
JC F4_DONE ;If Esc, exit.
MOV DATEONLY_FLAG,0 ;Assume F7.
CMP AL,F7_SCAN ;Is it F7?
JZ CK_APPEND
MOV DATEONLY_FLAG,1 ;Assume F8.
CMP AL,F8_SCAN ;Is it F8.
JZ CK_APPEND
MOV DI,OFFSET PTABLE
MOV CX,PTABLE_LEN
CALL DISPATCH
CMP EXIT_FLAG,1
JNZ NEXT_F4
JMP SHORT F4_DONE
F4_END: MOV REREAD_FLAG,1
F4_DONE: POP DAY_MON_CUR ;Restore calendar variables.
POP YEAR_CUR
POP DAY_MON_CAL
POP YEAR_CAL
CALL FIRSTDAY ;Fix calendar and appointment
MOV REPAINT_FLAG,1 ; ASCII date; repaint screen.
RET
;----------------------------------------------;
ARCHIVE_FLAG DB 0 ; =1 if archive.
READ_HANDLE DW -1 ;File handles.
WRITE_HANDLE DW -1
ARCHIVE_HANDLE DW -1
RECORD_SIZE DW ? ;Size of Jou or App data record.
CK_APPEND: MOV ARCHIVE_FLAG,0 ;Reset archive flag.
MOV AX,6
CALL CALC_ADDR
ADD DI,40 * 2
MOV SI,OFFSET ARCHIVE_MSG
CALL POP_WINDOW ;Display archive window.
NEXT_APPEND: CALL GETKEY ;Get a keystroke.
JC F4_DONE
CMP AL,N_SCAN
JZ DO_PURGE
CMP AL,Y_SCAN ;"Y" = archive.
JNZ NEXT_APPEND
MOV ARCHIVE_FLAG,1
DO_PURGE: CALL OPEN ;Open data file for reading.
JBE F4_DONE ;If doesn't exist, nothing to
MOV READ_HANDLE,AX ; purge; else save handle.
MOV AX,8
CALL CALC_ADDR
ADD DI,50 * 2
MOV SI,OFFSET PURGING_MSG
CALL POP_WINDOW ;Display purging window.
CALL OPEN ;Open data file for writing.
JBE PURGE_FAIL
MOV WRITE_HANDLE,AX
MOV SI,OFFSET SCH_ARC
MOV RECORD_SIZE,SIZE DATA_RECORD
CMP STATE,OFFSET APPOINTMENT
JZ ARCHIVE_NAME
MOV SI,OFFSET JOU_ARC
MOV RECORD_SIZE,JOURNAL_REC
ARCHIVE_NAME: CALL APPEND
CMP ARCHIVE_FLAG,1 ;Archive?
JNZ NEXT_PURGE
CALL OPEN ;If yes, open archive file.
JA SAVE_HANDLE2
XOR CX,CX
MOV AH,3CH ;If doesn't exist, create one.
CALL INT21_IO
JBE PURGE_FAIL
SAVE_HANDLE2: MOV ARCHIVE_HANDLE,AX
MOV BX,AX
XOR CX,CX
XOR DX,DX
MOV AX,4202H ;Move to end of archive file
CALL INT21_IO ; to append.
JA NEXT_PURGE
PURGE_FAIL: CALL CLOSE_HANDLES ;Failure exit.
CALL FAILED
JMP F4_END
NEXT_PURGE: MOV CX,RECORD_SIZE
MOV BX,READ_HANDLE
CALL READ_RECORD ;Read a record.
JBE PURGE_FAIL
OR AX,AX ;EOF?
JZ PURGE_DONE
CMP DATEONLY_FLAG,1 ;Purge everything < purge date.
JZ CK_THISDATE
CMP CX,YEAR_CAL ;If no, year < purge date?
JB CK_ARCHIVE ;If yes, purge.
JA WRITE_DATA ;If above write data back.
CMP DX,DAY_MON_CAL ;Else, day/month <= purge date?
JBE CK_ARCHIVE ;Is yes, purge.
JMP SHORT WRITE_DATA ;Else, write data back.
CK_THISDATE: CMP CX,YEAR_CAL ;Purge date only.
JNZ WRITE_DATA
CMP DX,DAY_MON_CAL
JZ CK_ARCHIVE
WRITE_DATA: MOV DX,OFFSET DTA ;Write data back to data file.
MOV CX,RECORD_SIZE
MOV BX,WRITE_HANDLE
CALL WRITE_RECORD
JBE PURGE_FAIL
JMP NEXT_PURGE
CK_ARCHIVE: CMP ARCHIVE_FLAG,1 ;Archive?
JNZ NEXT_PURGE
CALL ARCHIVE
JBE PURGE_FAIL
JMP NEXT_PURGE
PURGE_DONE: MOV BX,WRITE_HANDLE
XOR CX,CX ;Truncate data file to
CALL WRITE_RECORD ; current pointer location.
JBE PURGE_FAIL
CALL CLOSE_HANDLES ;Close all file handles.
JMP F4_END
;----------------------------------------------;
CLOSE_HANDLES: MOV BX,READ_HANDLE
CALL CLOSE_SAVE
MOV BX,WRITE_HANDLE
CALL CLOSE_SAVE
MOV BX,ARCHIVE_HANDLE
CALL CLOSE_SAVE
RET
;----------------------------------------------;
ARCHIVE: MOV BX,ARCHIVE_HANDLE
MOV DX,OFFSET DTA.DATE_ASCII
MOV CX,SIZE DATE_ASCII ;Write date in ASCII.
CALL WRITE_RECORD
JBE ARCHIVE_END
MOV DTA,CR
MOV DTA + 1,LF
CALL WRITE_CRLF ;Add Carriage return/linefeed.
JBE ARCHIVE_END
CMP STATE,OFFSET JOURNAL
JNZ APP_ARCHIVE
JMP SHORT DO_JOU_ARC
APP_ARCHIVE: MOV BP,APP_HEIGHT
MOV SI,OFFSET APP_START + 4
MOV DI,OFFSET DTA.DATA_TEXT
NEXT_ARCHIVE: MOV DX,SI
MOV CX,8
CALL WRITE_RECORD ;Write times.
JBE ARCHIVE_END
MOV DX,DI
MOV CX,APP_LEN
CALL WRITE_RECORD ;Write appointments.
JBE ARCHIVE_END
ADD SI,37
ADD DI,APP_LEN
MOV DX,SI
MOV CX,7
CALL WRITE_RECORD
JBE ARCHIVE_END
MOV DX,DI
MOV CX,APP_LEN
CALL WRITE_RECORD
JBE ARCHIVE_END
CALL WRITE_CRLF
JBE ARCHIVE_END
ADD SI,44
ADD DI,APP_LEN
DEC BP
JNZ NEXT_ARCHIVE
MOV BP,3
MOV SI,OFFSET DTA.NOTEPAD_TEXT
NEXT_NOTEPAD: MOV DX,SI
MOV CX,73
CALL WRITE_RECORD ;Write Notepad.
JBE ARCHIVE_END
CALL WRITE_CRLF
JBE ARCHIVE_END
ADD SI,APP_WIDTH
DEC BP
JNZ NEXT_NOTEPAD
CALL WRITE_CRLF
ARCHIVE_DONE: OR AL,1 ;Indicate successful.
ARCHIVE_END: RET
DO_JOU_ARC: MOV BP,JOU_HEIGHT
MOV DX,OFFSET JOU_START + 3
NEXT_JOU_ARC: MOV CX,APP_WIDTH - 6
CALL WRITE_RECORD
JBE ARCHIVE_END
PUSH DX
CALL WRITE_CRLF
POP DX
JBE ARCHIVE_END
ADD DX,APP_WIDTH
DEC BP
JNZ NEXT_JOU_ARC
CALL WRITE_CRLF
JMP ARCHIVE_DONE
WRITE_CRLF: MOV DX,OFFSET DTA
MOV CX,2
CALL WRITE_RECORD
RET
APPEND: MOV DI,PATH_END ;LINE 2159
NEXT_APPEND2: LODSB
STOSB
OR AL,AL
JNZ NEXT_APPEND2
RET
;**********************************************;
; J O U R N A L ;
;**********************************************;
NUM_SIZE EQU 10
TEXT_SIZE EQU 50
JOU_FIELDS STRUC
BUSINESS DB TEXT_SIZE DUP (?)
TAXI DB NUM_SIZE DUP (?)
AUTO_R DB NUM_SIZE DUP (?)
TRAIN DB NUM_SIZE DUP (?)
AUTO_P DB NUM_SIZE DUP (?)
AIRFARE DB NUM_SIZE DUP (?)
PARKING DB NUM_SIZE DUP (?)
TOLL DB NUM_SIZE DUP (?)
OTHER_TRAVEL DB NUM_SIZE DUP (?)
LODGING DB NUM_SIZE DUP (?)
BREAKFAST DB NUM_SIZE DUP (?)
LUNCH DB NUM_SIZE DUP (?)
DINNER DB NUM_SIZE DUP (?)
OTHER_MEALS DB NUM_SIZE DUP (?)
ENTERTAINMENT DB NUM_SIZE DUP (?)
PLACE DB TEXT_SIZE DUP (?)
NATURE DB TEXT_SIZE DUP (?)
PERSONS DB TEXT_SIZE DUP (?)
PURPOSE DB TEXT_SIZE DUP (?)
PHONE DB NUM_SIZE DUP (?)
OTHER DB NUM_SIZE DUP (?)
ADVANCE DB NUM_SIZE DUP (?)
PRE_PAID DB NUM_SIZE DUP (?)
JOU_FIELDS ENDS
JOURNAL_REC EQU SIZE DATE_BINARY + SIZE DATE_ASCII + SIZE JOU_FIELDS
FIELDS STRUC
ACC_ROW DB ?
ACC_COL DB ?
ACC_LEN DW ?
FIELDS ENDS
JOU_ROW_HOME EQU 4
JOU_COL_HOME EQU 21
JOU_HOME EQU JOU_ROW_HOME SHL 8 + JOU_COL_HOME
JOU_CURSOR DW JOU_HOME
JOU_INDEX DW 0
ACC_FIELDS LABEL BYTE
A_BUSINESS FIELDS < JOU_ROW_HOME - 4, JOU_COL_HOME, SIZE BUSINESS >
A_TAXI FIELDS < 2, 11, SIZE TAXI >
A_AUTO_R FIELDS < 2, 43, SIZE AUTO_R >
A_TRAIN FIELDS < 3, 16, SIZE TRAIN >
A_AUTO_P FIELDS < 3, 50, SIZE AUTO_P >
A_AIRFARE FIELDS < 4, 14, SIZE AIRFARE >
A_PARKING FIELDS < 4, 37, SIZE PARKING >
A_TOLL FIELDS < 5, 11, SIZE TOLL >
A_OTHER_TRAVEL FIELDS < 5, 35, SIZE OTHER_TRAVEL >
A_LODGING FIELDS < 6, 12, SIZE LODGING >
A_BREAKFAST FIELDS < 8, 16, SIZE BREAKFAST >
A_LUNCH FIELDS < 8, 33, SIZE LUNCH >
A_DINNER FIELDS < 8, 51, SIZE DINNER >
A_OTHER_MEALS FIELDS < 8, 68, SIZE OTHER_MEALS >
A_ENTERTAIN FIELDS <10, 13, SIZE ENTERTAINMENT >
A_PLACE FIELDS <11, 12, SIZE PLACE >
A_NATURE FIELDS <12, 28, SIZE NATURE >
A_PERSONS FIELDS <13, 26, SIZE PERSONS >
A_PURPOSE FIELDS <14, 14, SIZE PURPOSE >
A_PHONE FIELDS <15, 18, SIZE PHONE >
A_OTHER FIELDS <16, 10, SIZE OTHER >
A_ADVANCE FIELDS <17, 12, SIZE ADVANCE >
A_PRE_PAID FIELDS <18, 26, SIZE PRE_PAID >
FIELDS_CNT = ($ - OFFSET ACC_FIELDS) / SIZE FIELDS
JOU_MENU LABEL BYTE
DB 2,B
DB " F2 Save F3 Today F4 Purge F5 Report F6 Clear F7 Appointment PgUp/Dn=Day ",3
JOU_REPORT LABEL BYTE
DB " ┌─────────────────────────────────────────────────┬──────────────────────────┐ ",3
DB " │ ",2,Y,"Journal",2,B," ■ PC Magazine ■ Michael J. Mefford │ ",2,Y,SPACE
JOU_DATE LABEL BYTE
DB " ",7,14,2,B," │ ",3
DB " ╞═════════════════════════════════════════════════╧══════════════════════════╡ ",3
JOU_START LABEL BYTE
DB " │ BUSINESS PURPOSE: │ ",3
DB " │ TRAVEL: "
TRAVEL_ENTRY LABEL BYTE
DB " │ ",3
DB " │ Taxi: Auto (Rental): │ ",3
DB " │ Train/Bus: Auto (pers.)/mileage: │ ",3
DB " │ Airfare: Parking: │ ",3
DB " │ Toll: Other: │ ",3
DB " │ LODGING: │ ",3
DB " │ MEALS: "
MEALS_ENTRY LABEL BYTE
DB " │ ",3
DB " │ Breakfast: Lunch: Dinner: Other: │ ",3
DB " │ ENTERTAINMENT: │ ",3
DB " │ Amount: │ ",3
DB " │ Place: │ ",3
DB " │ Nature of expenditure: │ ",3
DB " │ Persons entertained: │ ",3
DB " │ Purpose: │ ",3
DB " │ TELEPHONE/FAX: │ ",3
DB " │ OTHER: │ ",3
DB " │ ADVANCE: │ ",3
DB " │"
COMPANY_PAID LABEL BYTE
DB " COMPANY PAID EXPENSES: "
COMPANY_LEN EQU $ - COMPANY_PAID
DB " │ ",3
JOU_HEIGHT EQU ($ - JOU_START) / APP_WIDTH
DB " │ "
TOTAL_ENTRY LABEL BYTE
DB " │ ",3
DB " └────────────────────────────────────────────────────────────────────────────┘ ",3,-1
REPORT_MSG DB 2,H,"╔",0,41, "═", "╗",3
DB "║ Journal Report Date: ",2,P
REPORT_DATE DB " ",2,H,"║",1
DB "║ PgUp/Dn to change Date; F3 = Today ║",1
DB "║ Report up to and including Date ║",1
DB "║ F6 Total only ║",1
DB "║ F7 Complete Report - LPT1 ║",1
DB "║ F8 Complete Report - LPT2 ║",1
DB "║ F9 Complete Report - File ║",1
DB "║ Esc to Cancel ║",1
DB "╚",0,41, "═", "╝",1,4,43
FILENAME_MSG DB 2,H,"╔", 0,23,"═", "╗",3
DB "║ "
FILENAME DB " "
FILENAME_LEN EQU $
DB " ║",1
DB "╚", 0,23,"═", "╝",1,4,25
GRAND_MSG DB 2,H,"╔", 0,28,"═", "╗",3
DB "║"
GRAND_AMOUNT DB " GRAND TOTAL: "
GRAND_VALUE DB " "
GRAND_LEN EQU $ - GRAND_VALUE
GRAND_LEN2 EQU $ - GRAND_AMOUNT
DB "║",1
DB "║ Press any key to continue. ║",1
DB "╚", 0,28,"═", "╝",1,4,30
JTABLE DB 3CH, 3DH, 3EH, 3FH, 40H, 59H
DB 63H, 4BH, 4DH, 48H, 50H, 47H
DB 4FH, 49H, 51H, 84H, 76H, 77H
DB 75H, 73H, 74H, 0FH, 53H
JTABLE_LEN EQU $ - JTABLE
DW SAVE, ATODAY, PPURGE, REPORT, JCLEAR, JSHIFT_CLEAR
DW JCTRL_CLEAR,JLEFT, JRIGHT, JSHIFT_TAB, NEXT_FIELD, JHOME
DW JEND, APGUP, APGDN, ACTRLPGUP, ACTRLPGDN, JCTRLHOME
DW JCTRLEND, JHOME, JEND, JSHIFT_TAB, JDEL
JOURNAL: MOV SI,OFFSET JOU_DAT
CALL APPEND
CALL CK_DATE
MOV SI,OFFSET JOU_MENU
CALL POP_MENU
NEXT_JOURNAL: MOV DX,JOU_CURSOR
CALL SET_CURSOR
CALL GETKEY
CMP EXIT_FLAG,1
JZ JOURNAL_END
CMP AL,SHIFT_F7_SCAN
JNZ CK_JOU_F7
CALL PERMANENT
MOV STATE,OFFSET CALENDAR
JMP SHORT JOURNAL_END
CK_JOU_F7: CMP AL,F7_SCAN
JNZ CK_JOU_ESC
CALL PERMANENT
MOV STATE,OFFSET APPOINTMENT
JMP SHORT JOURNAL_END
CK_JOU_ESC: CMP AL,ESC_SCAN ;Back to calendar if Esc.
JNZ JOU_DISPATCH
CALL PERMANENT
MOV STATE,OFFSET CALENDAR
JMP SHORT JOURNAL_END
JOU_DISPATCH: MOV BP,JOU_INDEX
CALL CALC_JOU_ADDR ;Get cursor bounds.
OR AH,AH ;Extended scan code?
JZ GOT_JDISPATCH
CALL CK_JENTRY
JMP NEXT_JOURNAL
GOT_JDISPATCH: MOV DI,OFFSET JTABLE
MOV CX,JTABLE_LEN
CALL DISPATCH
CMP EXIT_FLAG,1
JNZ JOURNAL
CALL PERMANENT
JOURNAL_END: RET
;----------------------------------------------;
; INPUT: BP=JOU_INDEX; DX=cursor position
; OUTPUT: BH=column end; BL=column home; CL=row home; SI-> storage
CALC_JOU_ADDR: PUSH AX
MOV AX,BP
MOV AH,SIZE FIELDS
MUL AH
MOV SI,AX
ADD SI,OFFSET ACC_FIELDS
LODSB ;Home row
MOV CL,AL
MOV CH,APP_WIDTH
MUL CH
ADD AX,OFFSET JOU_START
MOV DI,AX
MOV AX,DX
XOR AH,AH
ADD DI,AX
LODSB ;Home column
MOV BL,AL
LODSW
MOV BH,BL
ADD BH,AL
DEC BH ;End column
MOV SI,DI
POP AX
RET
;----------------------------------------------;
; INPUT: BP=JOU_INDEX; DX=Cursor; BH=column end; BL=column home; SI-> storage
JSHIFT_TAB: MOV CX,-1
JMP SHORT NEXT_FIELD2
CK_JENTRY: XCHG AH,AL
CMP AL,TAB
JZ NEXT_FIELD
CMP AL,CR
JNZ CK_JBACKSPACE
MOV AH,2
INT 16H
TEST AL,1 OR 2
JNZ JSHIFT_TAB
NEXT_FIELD: MOV CX,1
NEXT_FIELD2: MOV AX,FIELDS_CNT - 1
ADD BP,CX
JNS CK_JHIGH
MOV BP,AX
CK_JHIGH: CMP BP,AX
JBE GET_FIELD
XOR BP,BP
GET_FIELD: MOV JOU_INDEX,BP
CALL CALC_JOU_ADDR
MOV DH,CL
ADD DH,4
MOV DL,BL
JMP SHORT JOU_UPDATE
CK_JBACKSPACE: CMP AL,8
JNZ JOU_ASCII
CMP DL,BL
JZ JENTRY_END
DEC SI
DEC DL
MOV JOU_CURSOR,DX
CALL JDEL
JMP SHORT JENTRY_END
JOU_ASCII: CMP AL,SPACE
JB JENTRY_END
OR BP,BP
JZ CK_ROOM
CMP BP,15
JB CK_NUMERIC
CMP BP,18
JBE CK_ROOM
CK_NUMERIC: CMP AL,"$"
JZ CK_ROOM
CMP AL,"."
JZ CK_ROOM
CMP AL,"0"
JB ILLEGAL
CMP AL,"9"
JBE CK_ROOM
ILLEGAL: CALL BEEP
JMP SHORT JENTRY_END
CK_ROOM: INC DL
SUB BH,DL
JC JENTRY_END
JZ STORE_JOU
MOV CL,BH
XOR CH,CH
ADD SI,CX
MOV DI,SI
DEC SI
STD
REP MOVSB
CLD
INC SI
STORE_JOU: MOV [SI],AL
JOU_CHANGE: MOV MODIFY_FLAG,1
JOU_UPDATE: MOV JOU_CURSOR,DX
MOV SI,OFFSET JOU_START
CALL DISPLAY_LINE
JENTRY_END: RET
;----------------------------------------------;
JCLEAR: CALL CLEAR_IT
JMP JOU_CHANGE
CLEAR_IT: CALL CALC_JOU_ADDR
MOV DL,BL
CALL CALC_JOU_ADDR
SUB BH,BL
MOV CL,BH
XOR CH,CH
MOV AL,SPACE
REP STOSB
RET
JSHIFT_CLEAR:
JCTRL_CLEAR: MOV BP,FIELDS_CNT
NEXT_CLEAR: DEC BP
CALL CLEAR_IT
OR BP,BP
JNZ NEXT_CLEAR
MOV DH,JOU_ROW_HOME
MOV JOU_INDEX,BP
JMP JOU_CHANGE
JHOME: CMP DL,BL ;Beginning of field unless
MOV DL,BL ; already there, then go
JNZ JOU_UPDATE ; to section home.
JCTRLHOME: MOV DX,JOU_HOME
XOR BP,BP
MOV JOU_INDEX,BP
JMP JOU_UPDATE
JEND: CALL GET_WORD
CMP DI,SI
JZ JCTRLEND
MOV BX,DI
MOV CX,SI
SUB BX,CX
ADD DL,BL
JMP JOU_UPDATE
JCTRLEND: MOV DH,A_PRE_PAID.ACC_ROW
ADD DH,4
MOV DL,A_PRE_PAID.ACC_COL
ADD DL,SIZE PRE_PAID - 1
MOV BP,FIELDS_CNT - 1
MOV JOU_INDEX,BP
JMP JOU_UPDATE
JLEFT: DEC DL
CMP DL,BL ;Left one space unless
JAE JOU_UPDATE
JMP JENTRY_END
JRIGHT: INC DL ;Right on space unless
CMP DL,BH ; already column end.
JBE JOU_UPDATE
JMP JENTRY_END
JDEL: SUB BH,DL ;Ignore if in last column.
MOV CL,BH
XOR CH,CH
JCXZ JDEL_END
MOV DI,SI
INC SI
REP MOVSB ;Else, move everything to right
MOV SI,OFFSET JOU_START
CALL DISPLAY_LINE ; of cursor left one space.
MOV MODIFY_FLAG,1
JDEL_END: RET
;----------------------------------------------;
STORE_JOURNAL: PUSH BX
PUSH BP
MOV SI,OFFSET DTA.DATA_TEXT
MOV BP,FIELDS_CNT
MOV BX,OFFSET ACC_FIELDS
MOV DL,APP_WIDTH
NEXT_STORE_JOU:MOV AL,[BX]
INC BX
MUL DL
MOV DI,AX
MOV AL,[BX]
INC BX
XOR AH,AH
ADD DI,AX
ADD DI,OFFSET JOU_START
MOV CX,[BX]
INC BX
INC BX
REP MOVSB
DEC BP
JNZ NEXT_STORE_JOU
POP BP
POP BX
RET
;----------------------------------------------;
COMPLETE_FLAG DB ? ; =1 if complete report.
REPORT_SORT STRUC
DATE DD ?
RECORD_NO DW ?
REPORT_SORT ENDS
REPORT_MAX EQU 365
REPORT_INDEX REPORT_SORT REPORT_MAX DUP (<>)
REPORT_INDEX_END EQU $
VARS LABEL BYTE
J_TRAVEL DW 2 DUP (?)
J_MEALS DW 2 DUP (?)
TOTAL DW 2 DUP (?)
VARS_LEN EQU $ - VARS
T_PRE_PAID DW 2 DUP (?)
GRAND_TOTAL DW 2 DUP (?)
FF_FLAG DB 0 ;Toggle for 2 reports/page.
PRINTER_FLAG DB 0 ; 1= output to printer.
REPORT: CALL PERMANENT
MOV SI,OFFSET JOU_MENU
CALL POP_MENU
PUSH YEAR_CAL ;Preserve calendar variables.
PUSH DAY_MON_CAL
PUSH YEAR_CUR
PUSH DAY_MON_CUR
CALL HIDE_CURSOR
NEXT_REPORT: CALL FIRSTDAY ;Store purge date in window.
MOV AX,1
CALL CALC_ADDR
ADD DI,9 * 2
MOV SI,OFFSET REPORT_MSG
CALL POP_WINDOW ;Display purge window.
CALL GETKEY ;Get a keystroke.
JC REPORT_DONE ;If Esc, exit.
MOV COMPLETE_FLAG,0
CMP AL,F6_SCAN ;Is it F6?
JZ REPORTS
MOV COMPLETE_FLAG,1
MOV PRINTER,0
MOV FF_FLAG,3
MOV PRINTER_FLAG,1
CMP AL,F7_SCAN ;Is it F7.
JZ PRINTER_OUT
MOV PRINTER,1
CMP AL,F8_SCAN
JNZ CK_FILE_OUT
PRINTER_OUT: CALL PRINTER_SETUP
JC REPORT_DONE
JMP SHORT REPORTS
CK_FILE_OUT: CMP AL,F9_SCAN
JNZ R_DISPATCH
MOV PRINTER_FLAG,0
CALL GET_FILENAME
JC REPORT_DONE
JMP SHORT REPORTS
R_DISPATCH: MOV DI,OFFSET PTABLE
MOV CX,PTABLE_LEN
CALL DISPATCH
CMP EXIT_FLAG,1
JNZ NEXT_REPORT
REPORT_DONE: POP DAY_MON_CUR ;Restore calendar variables.
POP YEAR_CUR
POP DAY_MON_CAL
POP YEAR_CAL
CALL CLS_TRA_MEALS
MOV REREAD_FLAG,1
CALL FLUSH_KEY
RET
;----------------------;
REPORTS: CALL OPEN
MOV READ_HANDLE,BX
JBE LILLY_ERR2
MOV DI,OFFSET REPORT_INDEX
MOV SI,-1 ;Entry no.
NEXT_READ_REP: MOV CX,JOURNAL_REC
CALL READ_RECORD
JBE LILLY_ERR2
OR AX,AX
JZ SORT_REPORTS
INC SI
CMP CX,YEAR_CAL
JB DO_INDEX
JA NEXT_READ_REP
CMP DX,DAY_MON_CAL
JA NEXT_READ_REP
DO_INDEX: MOV AX,CX
STOSW
MOV AX,DX
STOSW
MOV AX,SI
STOSW
CMP DI,OFFSET REPORT_INDEX_END
JB NEXT_READ_REP
CALL BEEP
JMP REPORTS_DONE
SORT_REPORTS: MOV AX,-1
STOSW
OR SI,SI ;If less than 2 records,
JZ SHORT READ_REPORTS ; don't sort.
CALL SORT
;----------------------;
READ_REPORTS: CALL ZERO_VARS
XOR BP,BP ; REPORT_INDEX
NEXT_REPORTS: MOV AH,1
INT 16H
JZ NEXT_REPORTS2
CALL GETKEY
CMP AL,ESC_SCAN
JZ TOTAL_REPORT
NEXT_REPORTS2: CMP WORD PTR REPORT_INDEX.DATE[BP],-1
JZ TOTAL_REPORT
MOV AX,REPORT_INDEX.RECORD_NO[BP]
ADD BP,SIZE REPORT_SORT
MOV DX,JOURNAL_REC
MUL DX
MOV CX,DX
MOV DX,AX
MOV BX,READ_HANDLE
MOV AX,4200H
CALL INT21_IO
LILLY_ERR2: JBE REPORTS_DONE
MOV CX,JOURNAL_REC
CALL READ_RECORD
JBE REPORTS_DONE
CALL ADD_FIELDS
CMP COMPLETE_FLAG,1
JNZ NEXT_REPORTS
CALL SUB_REPORT
JC REPORTS_DONE
JMP NEXT_REPORTS
TOTAL_REPORT: CALL DO_TOTAL
REPORTS_DONE: MOV BX,READ_HANDLE
MOV AH,3EH
CALL INT21_IO
CMP PRINTER_FLAG,1
JZ REPORTS_END
MOV BX,OUTPUT_HANDLE
MOV AH,3EH
CALL INT21_IO
REPORTS_END: CALL PPURGE
JMP REPORT_DONE
;----------------------;
ZERO_VARS: MOV T_PRE_PAID[0],0
MOV T_PRE_PAID[2],0
MOV GRAND_TOTAL[0],0
MOV GRAND_TOTAL[2],0
RET
;----------------------;
; OUTPUT: CF=1 if abort.
FILE_HOME EQU 19
FILE_CURSOR LABEL WORD
FILE_COL DB FILE_HOME
DB 14
OUTPUT_HANDLE DW ?
GET_FILENAME: MOV AX,13
CALL CALC_ADDR
ADD DI,17 * 2
MOV SI,OFFSET FILENAME_MSG
CALL POP_WINDOW
MOV DX,FILE_CURSOR
CALL SET_CURSOR
XOR DH,DH
ADD DX,OFFSET FILENAME - FILE_HOME
MOV DI,DX
CALL GETKEY
JC FILENAME_END
XCHG AH,AL
OR AH,AH
JZ GET_FILENAME
CMP AL,CR
JZ GOT_FILENAME
CMP AL,8
JNZ CK_FILE_ASCII
CMP DI,OFFSET FILENAME
JZ GET_FILENAME
DEC FILE_COL
MOV BYTE PTR [DI-1],SPACE
JMP GET_FILENAME
CK_FILE_ASCII: CMP AL,SPACE
JB GET_FILENAME
CMP DI,OFFSET FILENAME_LEN
JZ GET_FILENAME
STOSB
INC FILE_COL
JMP GET_FILENAME
FILENAME_END: RET
GOT_FILENAME: XOR AL,AL
STOSB
MOV DX,OFFSET FILENAME
MOV AX,3D01H
CALL INT21_IO
JBE CREATE_FILE
MOV BX,AX
MOV OUTPUT_HANDLE,AX
XOR CX,CX
XOR DX,DX
MOV AX,4202H
CALL INT21_IO
JMP SHORT FILENAME_OK
CREATE_FILE: XOR CX,CX
MOV AH,3CH
CALL INT21_IO
MOV OUTPUT_HANDLE,AX
JA FILENAME_OK
MOV BYTE PTR [DI-1],SPACE
CALL BEEP
STC
JMP FILENAME_END
FILENAME_OK: CLC
MOV BYTE PTR [DI-1],SPACE
JMP FILENAME_END
;----------------------;
ADD_FIELDS: MOV DI,OFFSET VARS
MOV CX,VARS_LEN / 2
XOR AX,AX
REP STOSW ;Zero out vars. except GRAND_TOTAL
; and PRE_PAID
MOV SI,OFFSET DTA.DATA_TEXT.TAXI
MOV CX,8 ;Eight travel entries.
NEXT_TRAVEL: PUSH CX
CALL ACCUMULATE
ADD J_TRAVEL[0],AX
ADC J_TRAVEL[2],DX
POP CX
LOOP NEXT_TRAVEL
CALL ACCUMULATE ;Lodging.
ADD TOTAL[0],AX
ADC TOTAL[2],DX
MOV CX,4 ;Four meal entries.
NEXT_MEAL: PUSH CX
CALL ACCUMULATE
ADD J_MEALS[0],AX
ADC J_MEALS[2],DX
POP CX
LOOP NEXT_MEAL
CALL ACCUMULATE ;Entertainment.
ADD TOTAL[0],AX
ADC TOTAL[2],DX
ADD SI,SIZE PLACE + SIZE NATURE + SIZE PERSONS + SIZE PURPOSE
CALL ACCUMULATE ;Telephone.
ADD TOTAL[0],AX
ADC TOTAL[2],DX
CALL ACCUMULATE ;Other.
ADD TOTAL[0],AX
ADC TOTAL[2],DX
CALL ACCUMULATE ;Advance.
SUB TOTAL[0],AX
SBB TOTAL[2],DX
CALL ACCUMULATE ;Pre-paid.
ADD T_PRE_PAID[0],AX
ADC T_PRE_PAID[2],DX
MOV AX,J_TRAVEL[0] ;Travel total.
MOV DX,J_TRAVEL[2]
ADD TOTAL[0],AX
ADC TOTAL[2],DX
MOV AX,J_MEALS[0] ;Meals total.
MOV DX,J_MEALS[2]
ADD TOTAL[0],AX
ADC TOTAL[2],DX
MOV AX,TOTAL[0] ;Grand total.
MOV DX,TOTAL[2]
ADD GRAND_TOTAL[0],AX
ADC GRAND_TOTAL[2],DX
RET
;----------------------;
;OUTPUT: CF = 1 if abort.
IBM_FLAG DB 0 ; If 1, use line drawing chars.
IBM_CHARS DB "╞╡│╪┬─╤═╧■┌"
EPSON_CHARS DB "||||--===*+" ;Replacements for line chars.
CHARS_LEN EQU $ - EPSON_CHARS
TOTAL_MSG DB "TOTAL: "
TOTAL_MSG_LEN EQU $ - TOTAL_MSG
SUB_REPORT: CALL CLS_TRA_MEALS
CALL STORE_JOURNAL
MOV SI,OFFSET DTA.DATE_ASCII
MOV DI,OFFSET JOU_DATE
MOV CX,SIZE DATE_ASCII
REP MOVSB
MOV AL,SPACE
MOV CX,4
REP STOSB ;Space out day of week.
MOV AX,J_TRAVEL[0]
MOV DX,J_TRAVEL[2]
MOV DI,OFFSET TRAVEL_ENTRY
CALL AMOUNT_ASCII
MOV AX,J_MEALS[0]
MOV DX,J_TRAVEL[2]
MOV DI,OFFSET MEALS_ENTRY
CALL AMOUNT_ASCII
MOV SI,OFFSET TOTAL_MSG
MOV DI,OFFSET TOTAL_ENTRY
MOV CX,TOTAL_MSG_LEN
REP MOVSB
MOV AX,TOTAL[0]
MOV DX,TOTAL[2]
CALL AMOUNT_ASCII
MOV SI,OFFSET JOU_REPORT
MOV DI,OFFSET DTA
NEXT_FORMAT: LODSB
CMP AL,-1
JZ FORMAT_DONE
CMP AL,7
JNZ CK_EOL
LODSB
SHR AL,1
MOV CL,AL
XOR CH,CH
MOV AL,SPACE
REP STOSB
JMP NEXT_FORMAT
CK_EOL: CMP AL,3
JZ FORMAT_CRLF
CMP AL,SPACE
JB NEXT_FORMAT
CALL CK_IBM
STOSB
JMP NEXT_FORMAT
FORMAT_CRLF: CALL STORE_CRLF
JMP NEXT_FORMAT
FORMAT_DONE: CALL STORE_CRLF
SUB DI,OFFSET DTA
MOV CX,DI
CMP PRINTER_FLAG,1
JZ SUB_PRINTER
OUTPUT2: MOV BX,OUTPUT_HANDLE
MOV DX,OFFSET DTA
MOV AH,40H
CALL INT21_IO
JMP SHORT SUB_REPORT_END
;----------------------;
SUB_PRINTER: MOV DX,PRINTER
DEC FF_FLAG
JNZ PRINT_REPORT
MOV FF_FLAG,2
MOV AL,FF
CALL PRINT_IT
JC SUB_REPORT_END
PRINT_REPORT: MOV SI,OFFSET DTA
NEXT_PR_REPORT:CALL PRINT_A_CHAR
JC SUB_REPORT_END
LOOP NEXT_PR_REPORT
SUB_REPORT_END:RET
;----------------------;
CLS_TRA_MEALS: MOV AX,SPACE SHL 8 + SPACE
MOV DI,OFFSET TRAVEL_ENTRY
MOV CX,NUM_SIZE
REP STOSW
MOV DI,OFFSET MEALS_ENTRY
MOV CX,NUM_SIZE
REP STOSW
MOV DI,OFFSET TOTAL_ENTRY
MOV CX,NUM_SIZE
REP STOSW
MOV DI,OFFSET GRAND_VALUE
MOV CX,GRAND_LEN
REP STOSB
RET
;----------------------;
DO_TOTAL: MOV AX,GRAND_TOTAL[0]
MOV DX,GRAND_TOTAL[2]
MOV DI,OFFSET GRAND_VALUE
CALL AMOUNT_ASCII
CMP COMPLETE_FLAG,1
JZ DO_COMPLETE
MOV AX,13
CALL CALC_ADDR
ADD DI,17 * 2
MOV SI,OFFSET GRAND_MSG
CALL POP_WINDOW
CALL FLUSH_KEY
XOR AH,AH
INT 16H
JMP SHORT DO_TOTAL_END
DO_COMPLETE: MOV DI,OFFSET DTA
MOV SI,OFFSET COMPANY_PAID
MOV CX,COMPANY_LEN
REP MOVSB
MOV AX,T_PRE_PAID[0]
MOV DX,T_PRE_PAID[2]
CALL AMOUNT_ASCII
CALL STORE_CRLF
MOV SI,OFFSET GRAND_AMOUNT
MOV CX,GRAND_LEN2
REP MOVSB
CALL STORE_CRLF
CALL STORE_CRLF
MOV SI,OFFSET DTA
MOV DX,PRINTER
SUB DI,SI
MOV CX,DI
CMP PRINTER_FLAG,1
JZ PRINTER_COM
MOV DX,SI
JMP OUTPUT2
PRINTER_COM: CALL PRINT_A_CHAR
JC DO_TOTAL_END
LOOP PRINTER_COM
MOV AL,FF
CALL PRINT_IT
DO_TOTAL_END: RET
;----------------------;
STORE_CRLF: MOV AL,CR
STOSB
MOV AL,LF
STOSB
RET
;--------------------------------------------------------;
; INPUT: SI-> Journal field; OUTPUT: DX:AX = number * 100.
DECIMAL_FLAG DB ? ; =1 if decimal point found.
DECIMAL_CNT DB ? ; Initialized to 2.
ACCUMULATE: PUSH BP ;Preserve.
MOV DECIMAL_FLAG,0 ;Initialize flag
MOV DECIMAL_CNT,2 ; and counter.
MOV CX,NUM_SIZE ;Length of field.
XOR DX,DX
XOR BP,BP ;DX:BP = number; zero to start.
NEXT_ACC: LODSB
CMP AL,"." ;Decimal point?
JNZ CK_NUM
MOV DECIMAL_FLAG,1
JMP SHORT LOOP_ACC
CK_NUM: SUB AL,"0" ;Between 0 and 9?
JB LOOP_ACC
CMP AL,9
JA LOOP_ACC
CMP DECIMAL_FLAG,1 ;Decimal portion?
JNZ ACC
CMP DECIMAL_CNT,0 ;If yes, two decimals yet?
JZ LOOP_ACC ;If yes, skip.
DEC DECIMAL_CNT ;Else decrement.
ACC: CBW
XCHG AX,BP
CALL MULTIPLY ;Last result * 10.
ADD BP,AX ;Add in new number.
ADC DX,0
LOOP_ACC: LOOP NEXT_ACC
MOV AX,BP
MOV CL,DECIMAL_CNT ;Number of decimal places
XOR CH,CH ; remaining.
JCXZ ACC_END
NEXT_DEC: CALL MULTIPLY
LOOP NEXT_DEC
ACC_END: POP BP
RET
;----------------------;
; INPUT: DX:AX * 10
MULTIPLY: PUSH DX ;Save high half.
MOV BX,10 ; DX:AX
MUL BX ; * BX
MOV DI,AX ; -------
POP AX ; DX:AX
PUSH DX ; + DX:AX
MUL BX ; ===========
POP DX ; DX:AX
ADD DX,AX
MOV AX,DI
RET
;--------------------------------------;
; INPUT: DX:AX = number; DI -> storage
AMOUNT_ASCII: MOV BX,100 ;Divisor of 100.
CMP DX,BX ;Will it fit?
JB AMOUNT_OK ;If yes, no overflow.
NEG DX ;Else, assume negative and
NEG AX ; negate.
SBB DX,0
MOV BYTE PTR [DI],"-" ;Store minus sign.
INC DI
CMP DX,BX ;Assume right? Does it fit?
JB AMOUNT_OK
CALL BEEP ;If no, beep and exit.
JMP SHORT AMOUNT_END
AMOUNT_OK: MOV BYTE PTR [DI],"$"
INC DI
DIV BX
PUSH DX
MOV BX,10 ;Divisor of 10.
XOR CX,CX ;Count of ASCII chars.
NEXT_AMOUNT: CMP CX,3 ;Insert comma delimiter?
JNZ NEXT_AMOUNT2
MOV DL,","
PUSH DX
INC CX
NEXT_AMOUNT2: XOR DX,DX ;Zero in high half.
DIV BX
ADD DL,"0" ;Convert to ASCII.
PUSH DX
INC CX
OR AX,AX ;Continue until no integer.
JNZ NEXT_AMOUNT
NEXT_NUMBER2: POP AX ;Display number.
STOSB
LOOP NEXT_NUMBER2
MOV AL,"." ;Display decimal point.
STOSB
POP AX
DIV BL
ADD AX,"0" SHL 8 + "0" ;Display decimal remainder.
STOSB
MOV AL,AH
STOSB
AMOUNT_END: RET
;----------------------;
; Selection sort algorithm.
SORT: MOV SI,OFFSET REPORT_INDEX ;SI = first record.
NEXT_SORT: MOV AX,SI ;Carry source pointer in AX.
MOV BX,SI ;Carry destination pointer in DX.
ADD BX,SIZE REPORT_SORT
CMP WORD PTR [BX],-1 ;Sort is done when last record.
JZ SORT_END
PUSH SI ;Save record pointer.
NEXT_RECORD3: MOV SI,AX ;Restore inside loop pointers.
MOV DI,BX
MOV CX,SIZE DATE / 2
REPZ CMPSW ;Compare the name fields.
JB NO_SWITCH ;If below, no switch.
SWAP: MOV AX,BX ;Else, AX = selected record.
NO_SWITCH: ADD BX,SIZE REPORT_SORT ;Move to next record in list.
CMP WORD PTR [BX],-1 ;End of list?
JNZ NEXT_RECORD3 ;If no, continue.
POP SI ;Else, restore outside loop ptr.
CMP SI,BX ;Did we make a selection?
JZ SELECT_LOOP ;If no, go to next list.
PUSH SI ;Else, save pointer.
MOV CX,SIZE REPORT_SORT / 2
MOV DI,AX
NEXT_SWAP: MOV AX,[DI] ;Swap the selection into place.
MOVSW
MOV [SI - 2],AX
LOOP NEXT_SWAP
POP SI
SELECT_LOOP: ADD SI,SIZE REPORT_SORT ;Next record.
JMP NEXT_SORT
SORT_END: RET
;***************************************************************************;
SETUP_CODES DB 10 DUP (0), 0 ;Printer setup codes.
PRINTER DW ?
PRINT: CALL HIDE_CURSOR
MOV AX,1
CALL CALC_ADDR
ADD DI,9 * 2
MOV SI,OFFSET SCH_REPORT_MSG
CALL POP_WINDOW ;Display window.
NEXT_PRINT1: CALL GETKEY ;Get a keystroke.
JNC NEXT_PRINT3
JMP PRINT_DONE ;If Esc, exit.
NEXT_PRINT3: MOV PRINTER,0
MOV PRINTER_FLAG,1
CMP AL,F7_SCAN
JZ FIX_SCREEN
MOV PRINTER,1
CMP AL,F8_SCAN
JZ FIX_SCREEN
MOV PRINTER_FLAG,0
CMP AL,F9_SCAN
JNZ NEXT_PRINT1
CALL GET_FILENAME
JC PRINT_DONE
FIX_SCREEN: MOV SI,OFFSET APP_MENU
CALL POP_MENU ;Fix screen cause that's where
; we're getting our data.
MOV AX,1
CALL CALC_ADDR ;Printing starts with row 1.
MOV BX,DI
MOV BP,24
MOV DI,OFFSET DTA
NEXT_PRINT: MOV SI,BX
MOV CX,80 ;80 characters/line.
NEXT_PRINT2: CALL GET_CHAR
CALL CK_IBM
STOSB
LOOP NEXT_PRINT2
CALL STORE_CRLF
ADD BX,CRT_WIDTH
DEC BP
JNZ NEXT_PRINT
MOV CX,9
NEXT_CRLF: CALL STORE_CRLF
LOOP NEXT_CRLF
SUB DI,OFFSET DTA
MOV CX,DI
CMP PRINTER_FLAG,1
JZ PRINT_SCH
MOV BX,OUTPUT_HANDLE
MOV DX,OFFSET DTA
MOV AH,40H
CALL INT21_IO
MOV AH,3EH
CALL INT21_IO
JMP SHORT PRINT_DONE
PRINT_SCH: CALL PRINTER_SETUP
JC PRINT_DONE
MOV SI,OFFSET DTA
NEXT_PRINT_SCH:MOV DX,PRINTER
CALL PRINT_A_CHAR
JC PRINT_DONE
LOOP NEXT_PRINT_SCH
PRINT_DONE: MOV REPAINT_FLAG,1
RET
;----------------------------------------------;
CK_IBM: TEST AL,10000000B
JZ IBM_END
CMP IBM_FLAG,1
JZ IBM_END
PUSH DI
PUSH CX
MOV DI,OFFSET IBM_CHARS
MOV CX,CHARS_LEN
REPNZ SCASB
ADD DI,CHARS_LEN - 1
MOV AL,[DI]
POP CX
POP DI
IBM_END: RET
;----------------------------------------------;
PRINT_A_CHAR: LODSB
PRINT_IT: PUSH AX
MOV AH,2
INT 17H
TEST AH,00101001B ;Printer ready?
JNZ NOT_READY
TEST AH,11111001B
JNZ DO_PRINT
NOT_READY: POP AX
CALL BEEP ;If no, beep and exit.
STC
JMP SHORT PRINT_END
DO_PRINT: POP AX
XOR AH,AH ;Print via BIOS.
INT 17H
CLC
PRINT_END: RET
;----------------------------------------------;
PRINT_CRLF: MOV AL,CR
CALL PRINT_IT
JC CRLF_END
MOV AL,LF
CALL PRINT_IT
CRLF_END: RET
;----------------------;
PRINTER_SETUP: MOV SI,OFFSET SETUP_CODES ;Send printer setup codes.
PRINTER_STRING:MOV DX,PRINTER
P_STRING: LODSB
OR AL,AL
JZ SETUP_END2
CALL PRINT_IT
JNC P_STRING
SETUP_END2: RET
;**********************************************;
; S U B R O U T I N E S ;
;**********************************************;
;INPUT: AL = Scan code; DI -> Valid scan codes table; CX = length of table
DISPATCH: PUSH AX
PUSH DX
PUSH BP
MOV BP,CX
MOV DX,DI
ADD DX,CX
REPNZ SCASB ;Scan for match.
JZ DO_DISPATCH
POP BP
POP DX
JMP SHORT NO_DISPATCH
DO_DISPATCH: SUB BP,CX
DEC BP
SHL BP,1
ADD BP,DX
MOV DI,BP ;Calc address of subroutine.
POP BP
POP DX
CALL [DI] ;Process the command.
NO_DISPATCH: CLC
DISPATCH_END: POP AX
RET
;----------------------------------------------;
PERMANENT: CMP MODIFY_FLAG,1 ;Any changes been made?
JNZ PERMANENT_END ;If no, done.
MOV MODIFY_FLAG,0
CALL HIDE_CURSOR
MOV AX,10
CALL CALC_ADDR
ADD DI,25 * 2
MOV SI,OFFSET PERMANENT_MSG
CALL POP_WINDOW ;Display "Changes to disk?"
QUERY: CALL GETKEY
JC PERMANENT_END
CMP AL,N_SCAN
JZ PERMANENT_END
CMP AL,Y_SCAN ;If "Y", then save.
JNZ QUERY
JMP SHORT SAVE2
PERMANENT_END: RET
;----------------------------------------------;
SAVE: CALL SAVE2 ;Save appointments.
JC F2_END
MOV AX,1
CALL CALC_ADDR
ADD DI,2
MOV SI,OFFSET SAVED_MSG
CALL POP_WINDOW ;Display saved message.
CALL PAUSE ;Pause for keystroke.
F2_END: RET
SAVE2: MOV MODIFY_FLAG,0
CALL OPEN ;Open data file.
JNC SAVE_HANDLE
XOR CX,CX ;If doesn't exist, create one.
MOV AH,3CH
CALL INT21_IO
JBE FAILED
MOV BX,AX
SAVE_HANDLE: MOV BP,AX
CK_EOF: CALL READ_DATE ;Read date of data.
JBE FAILED_CLOSE
OR AX,AX ;EOF?
JNZ MATCH_DATE ;If yes, append data.
CALL GET_SPACE
JBE FAILED_CLOSE
CMP BX,2 ;At least two clusters free?
MOV BX,BP ;Retrieve file handle.
JAE ENOUGH_ROOM
CALL CLOSE_SAVE
MOV SI,OFFSET DISK_FULL_MSG
JMP SHORT FAILED_MSG
ENOUGH_ROOM: CALL WRITE_APP ;Write the data.
JMP SHORT CLOSE_SAVE ;Done.
MATCH_DATE: CMP CX,YEAR_CUR ;Date of data on disk
JNZ NO_MATCH ; match appointment date?
CMP DX,DAY_MON_CUR
JZ GOT_DATE ;If yes, write over.
NO_MATCH: CALL NEXT_RECORD ;Else, search next record.
JBE FAILED_CLOSE
JMP CK_EOF
GOT_DATE: CALL WRITE_APP2
JBE FAILED_CLOSE
CLOSE_SAVE: MOV AH,3EH ;Close data file.
CALL INT21_IO
MOV REPAINT_FLAG,1
SAVE_END: RET
FAILED_CLOSE: MOV AH,3EH
CALL INT21_IO
FAILED: MOV SI,OFFSET PERMANENT_FAIL
FAILED_MSG: MOV AX,10
CALL CALC_ADDR
ADD DI,25 * 2
CALL POP_WINDOW ;If failed, display failed
CALL FLUSH_KEY ; message.
XOR AH,AH ;Pause.
INT 16H
MOV REPAINT_FLAG,1
STC
RET
;----------------------------------------------;
OPEN: MOV DX,OFFSET PATH
MOV AX,3D02H ;Open data file for reading
CALL INT21_IO ; and writing.
MOV BX,AX ;Filehandle.
RET
;----------------------------------------------;
; OUTPUT: CX = Year; DH = Month; DL = Day
READ_DATE: MOV CX,SIZE DATE_BINARY
READ_RECORD: MOV DX,OFFSET DTA
MOV AH,3FH ;Read first four bytes.
CALL INT21_IO
MOV CX,WORD PTR DTA.DATE_BINARY ;Return binary date.
MOV DX,WORD PTR DTA.DATE_BINARY + 2
RET
;----------------------------------------------;
GET_SPACE: MOV DL,BYTE PTR PATH
SUB DL,"A" - 1
MOV AH,36H ;See if room to tack on app.
CALL INT21_IO
RET
;----------------------------------------------;
NEXT_RECORD: XOR CX,CX
MOV DX,SIZE DATE_ASCII+SIZE JOU_FIELDS
CMP STATE,OFFSET JOURNAL
JZ NEXT_RECORD2
MOV DX,SIZE DATE_ASCII+SIZE DATA_TEXT+SIZE NOTEPAD_TEXT
NEXT_RECORD2: MOV AX,4201H
CALL INT21_IO ;Bump pointer to next record.
RET
;----------------------------------------------;
; OUTPUT: CY = 1 OR ZF = 1 if write failed.
WRITE_APP: MOV DX,OFFSET YEAR_CUR ;Write binary date.
MOV CX,SIZE DATE_BINARY
CALL WRITE_RECORD
JBE WRITE_APP_END
WRITE_APP2: MOV DX,OFFSET APP_DATE ;Write ASCII date.
MOV CX,DATE_LEN
CALL WRITE_RECORD
JBE WRITE_APP_END
CMP STATE,OFFSET APPOINTMENT
JZ WRITE_APP3
PUSH BX ;Handle
MOV DI,OFFSET DTA.DATA_TEXT
MOV BP,FIELDS_CNT
MOV BX,OFFSET ACC_FIELDS
MOV DL,APP_WIDTH
NEXT_JOU_STORE:MOV AL,[BX]
INC BX
MUL DL
MOV SI,AX
MOV AL,[BX]
INC BX
XOR AH,AH
ADD SI,AX
ADD SI,OFFSET JOU_START
MOV CX,[BX]
INC BX
INC BX
REP MOVSB
DEC BP
JNZ NEXT_JOU_STORE
POP BX
MOV DX,OFFSET DTA.DATA_TEXT
MOV CX,SIZE JOU_FIELDS
CALL WRITE_RECORD
JMP SHORT WRITE_APP_END
WRITE_APP3: MOV SI,APP_HEIGHT ;16 Rows.
MOV DI,OFFSET APP_LEFT_START
MOV CX,APP_LEN
NEXT_WRITE: MOV DX,DI
CALL WRITE_RECORD ;Write appointments.
JBE WRITE_APP_END
ADD DX,APP_LEN + APP_COL_SPACE
CALL WRITE_RECORD
JBE WRITE_APP_END
ADD DI,APP_WIDTH
DEC SI
JNZ NEXT_WRITE
WRITE_NOTEPAD: MOV DX,OFFSET NOTEPAD
MOV CX,NOTEPAD_LEN
CALL WRITE_RECORD ;Write Notepad.
JBE WRITE_APP_END
INC SI ;Flag as successful.
CLC
WRITE_APP_END: RET
WRITE_RECORD: MOV AH,40H ;DOS write.
CALL INT21_IO
RET
;----------------------------------------------;
READ_APP: MOV DX,OFFSET DTA.DATE_ASCII
MOV CX,SIZE DATE_ASCII+SIZE DATA_TEXT+SIZE NOTEPAD_TEXT
MOV AH,3FH
CALL INT21_IO ;Read data record.
RET
;----------------------------------------------;
BEEP: PUSH AX
PUSH BX
PUSH CX
PUSH DX
CALL SETUP_BELL
MOV CX,1 ;One timer tick.
CALL DELAY ;Wait till clock rolls over.
CALL TOGGLE_BELL
MOV CX,1 ;Number of seconds.
CALL DELAY ;Delay seconds.
CALL RESET_BELL
POP DX
POP CX
POP BX
POP AX
RET
SETUP_BELL: MOV BX,CS:NOTE
XOR AX,AX
MOV DX,12H ;120000h dividend constant.
DIV BX ; Divide to get
MOV BX,AX ; 8253 countdown.
CALL RESET_BELL
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
RET
RESET_BELL: IN AL,PORT_B ;Port B.
AND AL,NOT 3 ;Turn off speaker.
JMP $+2
OUT PORT_B,AL
RET
FLIP_BELL: DEC BELL_CNT
JNZ TOGGLE_BELL
CALL RESET_BELL
CMP PROGRAM_STATUS,0 ;Are we popped up.
JNZ FLIP_END ;If yes, done.
CMP NOPOPUP_FLAG,1 ;User requested no-popup?
JZ FLIP_END ;If yes, done.
MOV POPUP_FLAG,1 ;Else, try to popup.
FLIP_END: MOV BELL_FLAG,0 ;Reset bell flag.
RET
TOGGLE_BELL: IN AL,PORT_B
XOR AL,3
JMP $+2
OUT PORT_B,AL
RET
;----------------------------------------------;
; INPUT: CX = 1/18 seconds. ;
DELAY: PUSH DS ;Preserve data segment.
MOV AX,40H ;Point to BIOS data segment.
MOV DS,AX
NEXT_TICK: MOV AX,DS:[6CH] ;Retrieve timer low.
NEXT_DELAY: MOV DX,DS:[6CH] ;Retrieve timer low.
CMP DX,AX ;Have we timed out?
JZ NEXT_DELAY ;If not, wait until timer tick.
LOOP NEXT_TICK
POP DS ;Restore data segment.
RET
;----------------------------------------------;
SAVE_SCREEN: XOR AX,AX ;Top left of screen.
CALL CALC_ADDR
MOV SI,AX
MOV DI,OFFSET WIN_SAVE ;Storage space.
MOV CX,25
MOV BP,80
CALL DO_SAVE ;Save entire screen.
RET
DO_SAVE: PUSH DS
MOV DX,STATUS_REG
MOV DS,VIDEO_SEG
NEXT_SAVE: PUSH CX
PUSH SI
MOV CX,BP
NEXT_SAVE2: IN AL,DX ;Get status.
RCR AL,1 ;Is it low?
JC NEXT_SAVE2 ;If not, wait until it is.
CLI ;No more interrupts.
HWAIT3: IN AL,DX ;Get status.
RCR AL,1 ;Is it high?
JNC HWAIT3 ;If no, wait until it is.
MOVSW
STI
LOOP NEXT_SAVE2
POP SI
ADD SI,CS:CRT_WIDTH ;Next row.
POP CX
LOOP NEXT_SAVE
POP DS
RET
;----------------------------------------------;
RESTORE_SCREEN:XOR AX,AX ;Top left of screen.
CALL CALC_ADDR
MOV SI,OFFSET WIN_SAVE
MOV CX,25
MOV BP,80
CALL DO_RESTORE ;Restore all 25 rows.
RET
DO_RESTORE: PUSH ES
MOV ES,VIDEO_SEG
MOV DX,STATUS_REG
NEXT_SCREEN: PUSH CX
PUSH DI
MOV CX,BP
NEXT_SCREEN2: IN AL,DX ;Get status.
RCR AL,1 ;Is it low?
JC NEXT_SCREEN2 ;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.
MOVSW
STI
LOOP NEXT_SCREEN2
POP DI
ADD DI,CRT_WIDTH ;Next row.
POP CX
LOOP NEXT_SCREEN
POP ES
RET
;----------------------------------------------;
POP_MENU: XOR AX,AX ;Top left of screen.
CALL CALC_ADDR
;--------------------------------------------------------;
; INPUT: DI -> Video destination; SI -> Window to popup. ;
POP_WINDOW: PUSH ES
MOV DX,STATUS_REG
MOV ES,VIDEO_SEG
NEXT_POP: PUSH DI
NEXT_WIN: LODSB
CMP AL,7 ;Format code?
JBE CK_COMPRESS
CALL WRITE_SCREEN ;If no, write to screen.
JMP NEXT_WIN
CK_COMPRESS: DEC AL ;Character to repeat?
JNS CK_DROP
LODSW ;If yes, get count and char.
MOV CL,AL
XOR CH,CH
XCHG AL,AH
CALL REPEAT_CHAR ;Repeat to screen.
JMP NEXT_WIN
CK_DROP: DEC AL ;Transparent black attribute?
JNS CK_COLOR
MOV CX,2
CALL DROP_SHADE ;If yes, display drop shade.
JMP SHORT STRING_END
CK_COLOR: DEC AL ;New color?
JNS CK_STRING
LODSB
MOV BL,AL
XOR BH,BH
MOV BH,BYTE PTR COLOR[BX] ;If yes, look it up.
JMP NEXT_WIN
CK_STRING: DEC AL ;End of string?
JNS DROP_STRING
STRING_END: POP DI
ADD DI,CRT_WIDTH ;If yes, go to next line.
CMP BYTE PTR [SI],-1 ;End of window?
JNZ NEXT_POP ;If yes, done.
JMP SHORT POP_END
DROP_STRING: DEC AL ;Bottom drop shade?
JNS INSERT_DATE
LODSB ;Get length of window.
CBW
MOV CX,AX
ADD DI,4 ;Shift right 2 columns.
CALL DROP_SHADE
POP DI
JMP SHORT POP_END
INSERT_DATE: DEC AL ;Special date insert?
JNS INSERT_APP
CALL DATE_INSERT
JMP NEXT_WIN
INSERT_APP: DEC AL ;Special small char. insert?
JNS SKIP
CALL APP_INSERT
JMP NEXT_WIN
SKIP: LODSB ;Else, skip some characters.
XOR AH,AH
ADD DI,AX
JMP NEXT_WIN
POP_END: POP ES
RET
;----------------------------------------------;
DROP_SHADE: MOV BL,8
INC DI
ATTR: IN AL,DX ;Get status.
RCR AL,1 ;Is it low?
JC ATTR ;If not, wait until it is.
CLI ;No more interrupts.
HWAIT6: IN AL,DX ;Get status.
RCR AL,1 ;Is it high?
JNC HWAIT6 ;If no, wait until it is.
MOV AL,BL
STOSB
STI ;Interrupts back on.
INC DI
LOOP ATTR
RET
;----------------------------------------------;
DATE_INSERT: PUSH BX
MOV AH,WEEKDAY
INC DAY_COUNTER
MOV AL,DAY_COUNTER
CMP AL,AH ;Are we to first day of month?
JBE DO_BLANK ;If no, blanks.
SUB AL,AH
CBW
CMP AL,LAST_DAY ;Are we past last day of month?
JA DO_BLANK ;If yes, blanks.
CMP AL,DAY_TODAY
JNZ DO_DAY
MOV CL,MONTH_TODAY
CMP CL,MONTH_CAL
JNZ DO_DAY
MOV CX,YEAR_TODAY
CMP CX,YEAR_CAL
JNZ DO_DAY
MOV BH,COLOR.Y ;Use highlight color if today.
DO_DAY: CALL DECIMAL_ASCII ;Write the date.
JMP SHORT D_INSERT_END
DO_BLANK: MOV AL,SPACE
CALL WRITE_SCREEN
MOV AL,SPACE
CALL WRITE_SCREEN
D_INSERT_END: POP BX
RET
;----------------------------------------------;
APP_INSERT: PUSH BX
MOV BH,COLOR.A ;Assume small block color.
MOV AH,WEEKDAY
MOV BP,BLOCK_ROW ;Block row index (0 or 1).
INC BLOCK_COUNTER[BP] ;Block day counter.
MOV AL,BLOCK_COUNTER[BP]
CMP AL,AH ;If before first day, blanks.
JBE DO_BLANK2
PUSH AX ;Save block counter.
CBW
MOV CL,7
DIV CL
OR AH,AH
JNZ CALC_BLOCK
XOR BLOCK_ROW,1 ;Once a week flip block row index
CALC_BLOCK: POP AX
SUB AL,AH
CMP AL,LAST_DAY ;Past last day?
JA DO_BLANK2 ;If so, blanks.
CBW
CMP AL,DAY_CAL
JNZ CK_ROW
MOV BH,COLOR.C ;If today, user cursor color.
CK_ROW: MOV CL,3
DEC AX
SHL AX,CL ;Index * 8 into array.
TEST BP,1
JZ GOT_INDEX
ADD AX,BLOCK_COUNT / 2 ; + Array size / 2 for odd rows.
GOT_INDEX: MOV BP,AX
MOV CX,8
NEXT_BLOCK: MOV AL,APPOINTMENT_BLOCKS[BP]
CALL WRITE_SCREEN ;Write the 8 block chars.
INC BP
LOOP NEXT_BLOCK
JMP SHORT A_INSERT_END
DO_BLANK2: MOV AL,SPACE
MOV CX,8
CALL REPEAT_CHAR
A_INSERT_END: POP BX
RET
;----------------------------------------------;
CALC_ADDR: MUL CRT_WIDTH ;Address = row * screen width
ADD AX,CRT_START ; + start of screen buffer.
MOV DI,AX
RET
;----------------------------------------------;
;INPUT: CX=char count; AX=character
REPEAT_CHAR: PUSH AX
CALL WRITE_SCREEN
POP AX
LOOP REPEAT_CHAR
RET
;----------------------------------------------;
WRITE_SCREEN: 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.
RET ;Return
;----------------------------------------------;
GET_CHAR: PUSH DS
PUSH DX
MOV DX,STATUS_REG
MOV DS,VIDEO_SEG
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.
HWAIT4: IN AL,DX ;Get status.
RCR AL,1 ;Is it high?
JNC HWAIT4 ;If no, wait until it is.
LODSW
STI
POP DX
POP DS
RET
;----------------------------------------------;
DECIMAL_ASCII: MOV CL,10
DIV CL
ADD AX,"0" SHL 8 + "0"
PUSH AX
CMP AL,"0"
JNZ DO_DECIMAL
MOV AL,SPACE
DO_DECIMAL: CALL WRITE_SCREEN
POP AX
MOV AL,AH
CALL WRITE_SCREEN
RET
;------------------------------------------------------------------------------
; OUTPUT: AL=scan code; AH=char; CY=1 if hotkey or Esc; EXIT_FLAG=1 if hotkey
GETKEY: MOV AH,1 ;Keystroke waiting?
INT 16H
JNZ GETKEY1
INT 28H ;DOS idle interrupt.
JMP GETKEY
GETKEY1: XOR AH,AH ;Get keystroke.
INT 16H
XCHG AL,AH
CMP AL,ESC_SCAN ;Esc key?
JZ EXIT_KEY
CK_HOT: CMP AL,HOT_KEY_SCAN ;Hotkey?
JNZ GETKEY_END
PUSH AX
MOV AH,2
INT 16H
TEST AL,HOT_SHIFT_KEY
POP AX
JZ GETKEY_END
MOV EXIT_FLAG,1
EXIT_KEY: STC
RET
GETKEY_END: CLC
RET
;----------------------------------------------;
FLUSH_IT: XOR AH,AH ;Flush keyboard buffer.
INT 16H
FLUSH_KEY: MOV AH,1
INT 16H
JNZ FLUSH_IT
RET
;----------------------------------------------;
PAUSE: MOV AH,1 ;Wait till keystroke in buffer.
INT 16H
JZ PAUSE
RET
;---------------------------------------------;
; Move BIOS video data into our data segment. ;
;---------------------------------------------;
GET_BIOS_DATA: PUSH DS
PUSH ES
MOV AX,40H ;BIOS data area.
MOV DS,AX
PUSH CS
POP ES
MOV SI,BIOS_ACTIVE_PAGE ;Start with active page.
MOV DI,OFFSET ACTIVE_PAGE
MOVSB ;Retrieve active page
MOVSW ; and address of 6845 port.
MOV SI,BIOS_CRT_MODE ;Retrieve CRT mode, CRT columns,
MOV CX,CRT_DATA_LENGTH ; CRT length, CRT start.
REP MOVSB
XOR BH,BH
MOV DL,24 ;Assume 24 logical rows.
MOV AX,1130H ;Get Information via BIOS.
INT 10H
STORE_ROWS: POP ES
POP DS
MOV CRT_ROWS,DL ;Store rows.
MOV BH,ACTIVE_PAGE
MOV AH,3
INT 10H ;Get Cursor mode.
MOV CURSOR_MODE,CX
MOV CURSOR_POS,DX
MOV DX,ADDR_6845
ADD DX,6
MOV STATUS_REG,DX
MOV AX,0B000H
MOV SCH_CURSOR,0B0CH
CMP DX,3BAH
JZ STORE_VIDEO
MOV SCH_CURSOR,0607H
ADD AX,800H
STORE_VIDEO: MOV VIDEO_SEG,AX ;Video address.
MOV AX,CRT_COLS
SHL AX,1
MOV CRT_WIDTH,AX ;CRT width = columns * 2.
RET
;------------------------------------------------------------------------------;
; Read port directly for programs like 123 that do not use BIOS to set address.;
;------------------------------------------------------------------------------;
GET_CUR_ADDR: MOV DX,ADDR_6845
MOV AL,14
OUT DX,AL
INC DX
IN AL,DX
MOV AH,AL
DEC DX
MOV AL,15
OUT DX,AL
INC DX
IN AL,DX
MOV CURSOR_ADDR,AX
RET
;----------------------------------------------;
HIDE_CURSOR: MOV DH,CRT_ROWS
INC DH
XOR DL,DL
SET_CURSOR: PUSH AX
MOV BH,ACTIVE_PAGE
MOV AH,2
INT 10H
POP AX
RET
;------------------------------------------------------------------------------
;IOSET vectors interrupts 1Bh, 23h and 24h to internal handlers. IORESET
;restores the original vector values.
;------------------------------------------------------------------------------
IOSET PROC NEAR
PUSH ES
MOV AX,351BH ;BIOS Ctrl break interrupt.
INT 21H
MOV OLD1B[0],BX
MOV OLD1B[2],ES
MOV DX,OFFSET IOEXIT ;Ignore.
MOV AX,251BH
INT 21H
MOV AX,3523H ;DOS Ctrl break interrupt.
INT 21H
MOV OLD23[0],BX
MOV OLD23[2],ES
MOV DX,OFFSET IOEXIT ;Ignore.
MOV AX,2523H
INT 21H
MOV AX,3524H ;Critical error interrupt.
INT 21H
MOV OLD24[0],BX
MOV OLD24[2],ES
MOV DX,OFFSET IOERR ;Install ours.
MOV AX,2524H
INT 21H
POP ES
RET
IOSET ENDP
;-------------------------------------------;
IORESET PROC NEAR
PUSH DS
MOV DX,OLD24[0]
MOV DS,OLD24[2]
MOV AX,2524H ;Restore Critical.
INT 21H
MOV DX,CS:OLD23[0]
MOV DS,CS:OLD23[2]
MOV AX,2523H ;Restore DOS Ctrl break.
INT 21H
MOV DX,CS:OLD1B[0]
MOV DS,CS:OLD1B[2]
MOV AX,251BH ;Restore BIOS Ctrl break.
INT 21H
POP DS
RET
IORESET ENDP
;------------------------------------------------------------------------------
;INITIALIZE prepares the program for residency.
;------------------------------------------------------------------------------
SCH_DAT DB "SCHEDULE.DAT",0
SCH_ARC DB "SCHEDULE.ASC",0
JOU_DAT DB "JOURNAL.DAT",0
JOU_ARC DB "JOURNAL.ASC",0
PATH_END DW ?
PATH_LEN EQU 100
PATH DB PATH_LEN DUP (0)
EVEN
DB (256 / 8) DUP ("STACK ")
OUR_STACK = $
ERR_SAVE DB (((ERR_WIDTH + 2) * 2) * (ERR_HEIGHT + 1)) DUP (?)
WIN_SAVE DB ((80 * 2) * 25) DUP (?)
RESIDENT_END = $
DB 16 DUP (?) ;Allocation block.
SYNTAX DB "Syntax: Journal [/I] [/U] [/Hn] [/Pn...n] [/G] [/A] [/C] [/M] [/B]",CR,LF
DB "/I = Install Memory-resident",CR,LF
DB "/U = Uninstall",CR,LF
DB "/H = Hotkey assignment; Ctrl or Alt plus new hotkey",CR,LF
DB " eg. /H Ctrl Y or /H Alt 1; default is Alt J",CR,LF
DB "/P = Printer setup string in decimal; 10 maximum.",CR,LF
DB " eg. /P 27 40 115 66 is boldface on a LaserJet",CR,LF
DB "/G = Graphical characters in printing; Use appropriate /P",CR,LF
DB " setup for your printer to switch to IBM character set",CR,LF
DB "/A [OFF|ON] = Appointment pop up OFF or ON; default = OFF",CR,LF
DB "/C [OFF|ON] = Chime OFF or ON; default = OFF",CR,LF
DB "/M [OFF|ON] = Midnight update pop up OFF or ON; default = OFF",CR,LF
DB "/B = Black and white attributes"
DB CR,LF,LF,"$"
CANT_FIND DB "Can't find Journal.com",CR,LF
DB "Change to Journal's directory before running.",CR,LF,"$"
NOT_INSTALLED DB "Journal not installed",CR,LF,"$"
ALREADY_MSG DB "Journal already installed",CR,LF,"$"
UNLOAD_MSG DB "Journal can't be uninstalled",CR,LF
DB "Uninstall resident programs in reverse order",CR,LF,"$"
NOT_ENOUGH DB "Not enough memory to install Journal",CR,LF,"$"
ALLOCATE_MSG DB "Memory allocation error",CR,LF,BELL,"$"
INSTALL_MSG DB "Installed",CR,LF,"$"
UNINSTALL_MSG DB "Uninstalled",CR,LF,"$"
TSR DB "JOURNAL.COM",0
CRITICAL_MSG DB "DOS Critical Error Flag not found",CR,LF
DB "Can't install",CR,LF,"$"
HOTKEY_MSG DB "Press $"
HOTKEY_MSG2 DB " to pop-up Journal",CR,LF,"$"
SIDEKICK_MSG DB "SideKick must be loaded last.",CR,LF
DB "Uninstall SideKick and then install Journal",CR,LF,"$"
WRONG_VERSION DB "Needs DOS 2.0 or later$"
SCAN_CODES LABEL BYTE
DB "1",2,"2",3,"3",4,"4",5,"5",6,"6",7,"7",8,"8",9,"9",0AH,"0",0BH,"-",0CH
DB "=",0DH,"Q",10H,"W",11H,"E",12H,"R",13H,"T",14H,"Y",15H,"U",16H,"I",17H
DB "O",18H,"P",19H,"[",1AH,"]",1BH,"A",1EH,"S",1FH,"D",20H,"F",21H,"G",22H
DB "H",23H,"J",24H,"K",25H,"L",26H,";",27H,39,28H,96,29H,"\",2BH,"Z",2CH
DB "X",2DH,"C",2EH,"V",2FH,"B",30H,"N",31H,"M",32H,",",33H,".",34H,"/",35H
SCAN_COUNT EQU ($ - SCAN_CODES) / 2
INSTALL_FLAG DB 0 ; =1 if /I found.
UNINSTALL_FLAG DB 0 ; =1 if /U found.
ALT DB " Alt $"
CTRL DB "Ctrl $"
ALT_CAPS DB "ALT"
CTRL_CAPS DB "CTRL"
;----------------------------------------------;
INITIALIZE PROC NEAR
CLD
MOV BX,OFFSET SIGNATURE ;Point to start of code.
NOT BYTE PTR [BX] ;Change a byte so no false match.
MOV AX,CS ;Store our segment in AX.
MOV DX,0A000H - 1
NEXT_PARAG: INC DX ;Next paragraph.
MOV ES,DX
CMP DX,AX ;Is it our segment?
JZ SAVE_SEG ;If yes, search is done.
MOV SI,BX ;Else, point to our signature.
MOV DI,BX ; and offset of possible match.
MOV CX,16 ;Check 16 bytes for match.
REP CMPSB
JNZ NEXT_PARAG ;If no match, keep looking.
;----------------------------------------------;
SAVE_SEG: MOV TSR_SEGMENT,ES
MOV SI,81H ;Point to command line.
NEXT_CAP: LODSB ;Capitalize parameters.
CMP AL,CR
JZ PARSE
CMP AL,"a"
JB NEXT_CAP
CMP AL,"z"
JA NEXT_CAP
AND BYTE PTR [SI - 1],5FH
JMP SHORT NEXT_CAP
;----------------------------------------------;
PARSE: MOV SI,81H ;Point to command line again.
NEXT_SWITCH: LODSB
CMP AL,CR ;Is it carriage return?
JNZ CK_SPACE
JMP INSTALL ;If yes, done here.
CK_SPACE: CMP AL,SPACE ;If space or below, ignore.
JBE NEXT_SWITCH
CMP AL,"/" ;Is it a switch character?
JZ GET_SWITCH ;If yes, continue.
CALL ANNOUNCE
JMP ERROR_EXIT ;Else, error; exit.
GET_SWITCH: LODSB
CMP AL,CR
JZ INSTALL
CMP AL,"U" ;Is it "U" ?
JNZ CK_I
MOV UNINSTALL_FLAG,1
CALL CK_INSTALLED ;Else, see if installed.
JZ NO_TSR
JMP UNINSTALL ;Else, uninstall.
NO_TSR: MOV DX,OFFSET NOT_INSTALLED ;If no, exit with error message.
JMP MSG_EXIT
CK_I: CMP AL,"I" ;Is it (I)nstall?
JNZ CK_G
MOV INSTALL_FLAG,1
JMP NEXT_SWITCH
CK_G: CMP AL,"G" ;Is it (G)raphic chars?
JNZ CK_P
MOV ES:IBM_FLAG,1
JMP NEXT_SWITCH
CK_P: CMP AL,"P" ;Is it (P)rinter setup codes?
JNZ CK_H
CALL GET_SETUP
JMP NEXT_SWITCH
CK_H: CMP AL,"H" ;Is it (H)otkey?
JNZ CK_C
CALL CHANGE_HOT
JMP NEXT_SWITCH
CK_C: CMP AL,"C" ;Is it (C)hime OFF?
JNZ CK_A
CALL GET_ON_OFF
MOV ES:NOBELL_FLAG,AH
JMP NEXT_SWITCH
CK_A: CMP AL,"A" ;Is it (A)ppointment popup OFF?
JNZ CK_M
CALL GET_ON_OFF
MOV ES:NOPOPUP_FLAG,AH
JMP NEXT_SWITCH
CK_M: CMP AL,"M" ;Is it (M)idnight rollover OFF?
JNZ CK_B
CALL GET_ON_OFF
MOV ES:NOMIDNIGHT_FLAG,AH
JMP NEXT_SWITCH
CK_B: CMP AL,"B" ;Is it (B)lack and white switch
JZ GOT_B
JMP TERMINATE
GOT_B: MOV ES:MONO_FLAG,1
JMP NEXT_SWITCH
;----------------------------------------------;
INSTALL: CALL CK_INSTALLED ;Check if already installed.
JZ CK_AVAILABLE ;If no, see if enough memory.
CALL ANNOUNCE
MOV DX,OFFSET ALREADY_MSG ;If yes, display "Already
CALL PRINT_STRING ; installed" and
CALL DISP_HOTKEY ; current hotkey.
XOR AL,AL ; EL = 0
JMP TERMINATE
;----------------------------------------------;
CK_AVAILABLE: MOV BX,OFFSET RESIDENT_END
ADD BX,15 ;Round up.
MOV CL,4
SHR BX,CL ;Convert to paragraphs.
MOV AH,4AH
INT 21H ;Allocate memory.
JNC GET_VERSION
MOV DX,OFFSET NOT_ENOUGH ;Exit if not enough
JMP MSG_EXIT ; with message.
GET_VERSION: MOV AH,30H ;Get DOS version
INT 21H
XCHG AL,AH
MOV DOS_VERSION,AX ; and save.
CMP AH,2
JAE GET_PATH
MOV DX,OFFSET WRONG_VERSION ;If not DOS 2 or above, exit.
JMP MSG_EXIT
GET_PATH: MOV DX,OFFSET TSR ;Open .COM file.
MOV AX,3D00H
INT 21H
JNC FOUND_PATH
NOT_FOUND: MOV DX,OFFSET CANT_FIND ;If can't find, exit
JMP MSG_EXIT ; with message.
FOUND_PATH: MOV BX,AX ;Close .COM file.
MOV AH,3EH
INT 21H
MOV AH,19H ;Get default drive.
INT 21H
ADD AL,"A"
MOV DI,OFFSET PATH
STOSB
MOV AL,":" ;Add delimiters.
STOSB
MOV AL,"\"
STOSB
MOV SI,DI
XOR DL,DL
MOV AH,47H ;Get default directory.
INT 21H
JC NOT_FOUND
FIND_END: LODSB ;Find end of path.
OR AL,AL
JNZ FIND_END
MOV DI,SI
DEC DI
MOV AL,"\" ;Add on delimiter if root.
CMP [DI-1],AL
JZ STORE_PATH
STOSB
STORE_PATH: MOV PATH_END,DI
GET_INDOS: MOV AH,34H ;Undocumented INDOS call.
INT 21H
MOV DOS_SEGMENT,ES
MOV INDOS_OFFSET,BX
MOV AX,3E80H ;CMP opcode
MOV CX,2000H ;Max search length
MOV DI,BX ;Look for Critical error address.
INIT4: REPNZ SCASW
JCXZ INIT5
CMP BYTE PTR ES:[DI+5],0BCH
JZ FOUND
JMP INIT4
INIT5: MOV CX,2000H
INC BX ;Odd addresses.
MOV DI,BX
INIT6: REPNZ SCASW
JCXZ NOTFOUND
CMP BYTE PTR ES:[DI+5],0BCH
JZ FOUND
JMP INIT6
NOTFOUND: MOV DX,OFFSET CRITICAL_MSG
JMP MSG_EXIT
FOUND: MOV AX,ES:[DI]
MOV ERRFLAG_OFFSET,AX
CMP INSTALL_FLAG,1 ;Install request?
JZ CK_SIDEKICK
MOV AH,0FH ;If no, change to text
INT 10H ; video mode if necessary.
CMP AL,2
JZ GET_VECTORS
CMP AL,7
JZ GET_VECTORS
CMP AL,3
JZ GET_VECTORS
MOV AX,3
INT 10H
JMP SHORT GET_VECTORS
CK_SIDEKICK: XOR AX,AX ;Check if SideKick installed.
MOV ES,AX
MOV ES,ES:[(9 * 4) + 2] ;INT 9 segment
CMP WORD PTR ES:[16CH],"KS" ;SideKick signature.
JNZ GET_VECTORS
MOV DX,OFFSET SIDEKICK_MSG
JMP MSG_EXIT
GET_VECTORS: PUSH CS
POP ES
CALL UPDATE_DATE ;Update calendar variables.
MOV YEAR_CAL,CX
MOV DAY_MON_CAL,DX
CALL GET_BIOS_DATA ;Get BIOS variables.
MOV SI,OFFSET SCH_DAT
CALL APPEND
CALL CK_DATE
MOV AX,3508H ;INT 8
INT 21H
MOV OLD8[0],BX
MOV OLD8[2],ES
MOV DX,OFFSET TIMER ;Install new interrupt.
MOV AX,2508H
INT 21H
MOV AX,3510H ;Get INT 10 interrupt.
INT 21H
MOV OLD10[0],BX ;Save old interrupt.
MOV OLD10[2],ES
MOV DX,OFFSET VIDEO ;Install new interrupt.
MOV AX,2510H
INT 21H
MOV AX,3513H ;Get INT 13 vector.
INT 21H
MOV OLD13[0],BX ;Save old interrupt.
MOV OLD13[2],ES
MOV DX,OFFSET BDISK ;Install new interrupt.
MOV AX,2513H
INT 21H
MOV AX,3528H ;Get INT 28 interrupt.
INT 21H
MOV OLD28[0],BX ;Save old interrupt.
MOV OLD28[2],ES
MOV DX,OFFSET BACKPROC ;Install new interrupt.
MOV AX,2528H
INT 21H
CMP INSTALL_FLAG,1 ;Install request?
JZ INSTALL_INT9 ;If no, skip INT 9
CALL MAIN ; and just popup now.
JMP SHORT UNINSTALL ;Uninstall vectors on return.
STAY_RESIDENT: CALL PRINT_STRING
INSTALL_INT9: MOV AX,3509H ;Get INT 9 vector.
INT 21H
MOV OLD9[0],BX ;Save old interrupt.
MOV OLD9[2],ES
MOV DX,OFFSET KEYBOARD ;Install new interrupt.
MOV AX,2509H
INT 21H
MOV AX,DS:[2CH] ;Get environment segment.
MOV ES,AX
MOV AH,49H ;Free up environment.
INT 21H
CALL ANNOUNCE
MOV DX,OFFSET INSTALL_MSG ;Display install message.
CALL PRINT_STRING
CALL DISP_HOTKEY
MOV DX,OFFSET RESIDENT_END
ADD DX,15 ;Round up.
MOV CL,4
SHR DX,CL ;Convert to paragraphs.
MOV AX,3100H ;Return error code of zero.
INT 21H ;Terminate but stay resident.
;-------------------------------------------------------------------;
; Exit. Return ERRORLEVEL code 0 if successful, 1 if unsuccessful. ;
;-------------------------------------------------------------------;
MSG_EXIT: PUSH DX
CALL ANNOUNCE
POP DX
CALL PRINT_STRING
ERROR_EXIT: MOV AL,1 ;ERRORLEVEL = 1.
TERMINATE: MOV AH,4CH ;Terminate.
INT 21H
;---------------------------------------------------;
; This subroutine uninstalls the resident TSR. ;
;---------------------------------------------------;
UNINSTALL: MOV CX,ES ;Save segment in CX.
DO_VECTORS: MOV AX,3508H ;Get interrupt 8h.
INT 21H
CMP BX,OFFSET TIMER ;Has it been hooked by another?
JNZ UNINSTALL_ERR ;If yes, exit with error message.
MOV BX,ES
CMP BX,CX ;Is the segment vector same?
JNZ UNINSTALL_ERR ;If no, exit with error message.
MOV AX,3510H ;Get interrupt 10h.
INT 21H
CMP BX,OFFSET VIDEO ;Has it been hooked by another?
JNZ UNINSTALL_ERR ;If yes, exit with error message.
MOV BX,ES
CMP BX,CX ;Is the segment vector same?
JNZ UNINSTALL_ERR ;If no, exit with error message.
MOV AX,3513H ;Get interrupt 13h.
INT 21H
CMP BX,OFFSET BDISK ;Has it been hooked by another?
JNZ UNINSTALL_ERR ;If yes, exit with error message.
MOV BX,ES
CMP BX,CX ;Is the segment vector same?
JNZ UNINSTALL_ERR ;If no, exit with error message.
MOV AX,3528H ;Get interrupt 28h.
INT 21H
CMP BX,OFFSET BACKPROC ;Has it been hooked by another?
JNZ UNINSTALL_ERR ;If yes, exit with error message.
MOV BX,ES
CMP BX,CX ;Is the segment vector same?
JNZ UNINSTALL_ERR
CMP UNINSTALL_FLAG,1 ;Uninstall request?
JNZ DO_UNINSTALL ;If no, skip INT 9.
MOV AX,3509H ;Get interrupt 9h.
INT 21H
CMP BX,OFFSET KEYBOARD ;Has it been hooked by another?
JNZ UNINSTALL_ERR ;If yes, exit with error message.
MOV BX,ES
CMP BX,CX ;Is the segment vector same?
JZ DEALLOCATE ;If no, exit with error message.
UNINSTALL_ERR: MOV DX,OFFSET UNLOAD_MSG ;And exit with error message.
CMP UNINSTALL_FLAG,1 ;Uninstall request?
JZ LILLY_ERR ;If yes, just exit.
JMP STAY_RESIDENT ;Else, go resident.
LILLY_ERR: JMP MSG_EXIT
DEALLOCATE: MOV AH,49H ;Return memory to system pool.
INT 21H
MOV DX,OFFSET ALLOCATE_MSG
JC LILLY_ERR ;Display message if problem.
MOV DX,ES:OLD9[0] ;Restore old INT 9.
MOV DS,ES:OLD9[2]
MOV AX,2509H
INT 21H
DO_UNINSTALL: MOV DX,ES:OLD8[0] ;Restore old INT 8.
MOV DS,ES:OLD8[2]
MOV AX,2508H
INT 21H
MOV DX,ES:OLD10[0] ;Restore old INT 10.
MOV DS,ES:OLD10[2]
MOV AX,2510H
INT 21H
MOV DX,ES:OLD13[0] ;Restore old INT 13.
MOV DS,ES:OLD13[2]
MOV AX,2513H
INT 21H
MOV DX,ES:OLD28[0] ;Restore old INT 28.
MOV DS,ES:OLD28[2]
MOV AX,2528H
INT 21H
PUSH CS
POP DS ;Point to our data.
CALL ANNOUNCE
CMP UNINSTALL_FLAG,1
JNZ UNINSTALL_END
MOV DX,OFFSET UNINSTALL_MSG ;Display uninstall message.
CALL PRINT_STRING
UNINSTALL_END: XOR AL,AL ;Exit with ERRORLEVEL = 0.
JMP TERMINATE
INITIALIZE ENDP
;-------------------------------------------------------;
; OUTPUT: ZR = 1 if not installed; ZR = 0 if installed. ;
;-------------------------------------------------------;
CK_INSTALLED: MOV AX,ES
MOV BX,CS
CMP AX,BX ;Compare segments.
RET
;----------------------------------------------;
CHANGE_HOT: MOV BP,ES ;Save segment.
MOV DX,CS
CALL FIND_START ;Find start of parameter.
CMP AL,CR
JZ HOT_END
MOV BX,SI
MOV ES,DX
MOV DI,OFFSET ALT_CAPS ;Is it "ALT"?
MOV CX,3
REP CMPSB
JNZ CK_CTRL
MOV ES,BP
MOV ES:HOT_SHIFT_KEY,ALT_STATE
JMP SHORT GET_HOT
CK_CTRL: MOV SI,BX
MOV DI,OFFSET CTRL_CAPS ;Is it "CTRL"?
MOV CX,4
REP CMPSB
JZ GOT_CTRL
MOV SI,BX
JMP SHORT GET_HOT
GOT_CTRL: MOV ES,BP
MOV ES:HOT_SHIFT_KEY,CTRL_STATE
GET_HOT: CALL FIND_START ;Find parameter start.
CMP AL,CR
JZ HOT_END
LODSB
MOV CX,SCAN_COUNT
MOV ES,DX
MOV DI,OFFSET SCAN_CODES
NEXT_HOT: SCASB ;Look up hotkey.
JZ FOUND_HOT
INC DI
LOOP NEXT_HOT
JMP SHORT HOT_END
FOUND_HOT: MOV AH,[DI]
MOV ES,BP
MOV ES:COMBO,AL ;Store hotkey ASCII
MOV ES:HOT_KEY_SCAN,AH ; and scan code.
HOT_END: MOV ES,BP
RET
;----------------------------------------------;
FIND_START: LODSB
CMP AL,CR
JZ START_END
CMP AL,SPACE
JBE FIND_START
START_END: DEC SI
RET
;----------------------------------------------;
GET_SETUP: MOV DI,OFFSET SETUP_CODES ;Printer setup code storage.
MOV BP,10 ;Ten codes maximum.
NEXT_SETUP2: CALL FIND_START ;Find parameter.
CMP AL,CR
JZ SETUP_END
CMP AL,"/"
JZ SETUP_END
XOR BL,BL
MOV CL,10
NEXT_DECIMAL: LODSB ;Get a character.
CMP AL,"/"
JZ STORE_SETUP
CMP AL,SPACE
JBE STORE_SETUP
SUB AL,"0" ;ASCII to binary.
JC SETUP_END ;If not between 0 and 9, skip.
CMP AL,9
JA SETUP_END
XCHG AL,BL ;Swap old and new number.
MUL CL ; last entry by ten.
ADD BL,AL ;Add new number and store in BX.
JMP NEXT_DECIMAL
STORE_SETUP: MOV AL,BL
STOSB ;Store printer code.
DEC SI
DEC BP
JNZ NEXT_SETUP2
SETUP_END: XOR AL,AL ;NULL terminate.
STOSB
RET
;----------------------------------------------;
DISP_HOTKEY: PUSH DS
MOV DX,OFFSET HOTKEY_MSG ;Display hotkey message.
CALL PRINT_STRING
MOV DS,TSR_SEGMENT
MOV BL,COMBO
MOV DX,OFFSET ALT
CMP HOT_SHIFT_KEY,ALT_STATE
JZ DISP_STATE
MOV DX,OFFSET CTRL
DISP_STATE: POP DS
CALL PRINT_STRING ;And current hotkey.
MOV DL,BL
MOV AH,2
INT 21H
MOV DX,OFFSET HOTKEY_MSG2
CALL PRINT_STRING
RET
;----------------------------------------------;
ANNOUNCE: MOV DX,OFFSET SIGNATURE + 1 ;Display our signature.
CALL PRINT_STRING
MOV DX,OFFSET SYNTAX ;And syntax.
CALL PRINT_STRING
RET
;----------------------------------------------;
; INPUT: SI-> Next command line param.
; OUTPUT: AH=1 if OFF; AH=0 if ON; Default=OFF.
GET_ON_OFF: MOV AH,1
LODSB
CMP AL,SPACE
JZ GET_ON_OFF
CMP AL,CR
JZ ON_OFF_DONE
CMP AL,"O"
JNZ ON_OFF_DONE
LODSB
CMP AL,"N"
JZ GOT_ON
CMP AL,"F"
JNZ GOT_OFF
LODSB
CMP AL,"F"
JZ GOT_OFF
JMP SHORT ON_OFF_DONE
GOT_ON: DEC AH
GOT_OFF: INC SI
ON_OFF_DONE: DEC SI
RET
;----------------------------------------------;
PRINT_CHAR: MOV DL,AL
MOV AH,2 ;Print character via DOS.
JMP SHORT DOS_INT
PRINT_STRING: MOV AH,9 ;Print string via DOS.
DOS_INT: INT 21H
RET
_TEXT ENDS
END START