home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol9n06.zip / SCHEDULE.ASM < prev    next >
Assembly Source File  |  1989-12-12  |  142KB  |  3,489 lines

  1. _TEXT          SEGMENT PUBLIC 'CODE'
  2.                ASSUME  CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
  3.  
  4.                ORG     80H
  5. DTA            LABEL   BYTE
  6.  
  7.                ORG     100H
  8. START:         JMP     INITIALIZE
  9.  
  10. ;              DATA AREA
  11. ;              ---------
  12. CR             EQU     13
  13. LF             EQU     10
  14. FF             EQU     12
  15. CTRL_Z         EQU     26
  16. SPACE          EQU     32
  17. BOX            EQU     254
  18. BELL           EQU     7
  19. TAB            EQU     9
  20. ESC_SCAN       EQU     1
  21. ENTER_SCAN     EQU     1CH
  22. Y_SCAN         EQU     15H
  23. N_SCAN         EQU     31H
  24. F1_SCAN        EQU     3BH
  25. F2_SCAN        EQU     3CH
  26. F6_SCAN        EQU     40H
  27. F7_SCAN        EQU     41H
  28. F8_SCAN        EQU     42H
  29. KB_FLAG        EQU     17H
  30.  
  31. APP_LEN        EQU     29                      ;Chars per appointment.
  32. APP_HEIGHT     EQU     16                      ;Appointment rows.
  33. NOTE_LEN       EQU     73                      ;Notepad line length.
  34. NOTE_HEIGHT    EQU      3                      ;Notepad rows.
  35. DATE_LEN       EQU     11                         ;Date length in ASCII.
  36. NOTEPAD_LEN    EQU     (81 - 4) + 81 + (81 - 4)   ;Total notepad size.
  37.  
  38. DATA_RECORD    STRUC
  39. DATE_BINARY    DW      2 DUP (?)
  40. DATE_ASCII     DB      DATE_LEN DUP (?)
  41. APPOINT_TEXT   DB      (APP_HEIGHT * APP_LEN * 2) DUP (?)
  42. NOTEPAD_TEXT   DB      NOTEPAD_LEN DUP (?)
  43. DATA_RECORD    ENDS
  44.  
  45. BUFFER         DB      (SIZE DATA_RECORD - ($ - OFFSET DTA)) DUP (?)
  46.  
  47. SIGNATURE      DB      SPACE,CR,CR,LF
  48. COPYRIGHT      DB      "SCHEDULE 1.0 (C) 1989 Ziff Communications Co.",CR,LF
  49. PROGRAMMER     DB      "PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF,"$"
  50.                DB      CTRL_Z
  51.  
  52. COLOR_ATTRIBS  STRUC
  53. B              DB     017H                     ;White on blue.
  54. H              DB     071H                     ;Blue on white.
  55. Y              DB     01EH                     ;Yellow on blue.
  56. C              DB     03BH                     ;Bright cyan on cyan.
  57. A              DB     01BH                     ;Bright cyan on blue.
  58. P              DB     07EH                     ;Yellow on white.
  59. COLOR_ATTRIBS  ENDS
  60.  
  61. COLOR          COLOR_ATTRIBS  <>
  62.  
  63. COLOR_ATTR     COLOR_ATTRIBS  <>
  64. MONO_ATTR      COLOR_ATTRIBS  <07H, 70H, 70H, 70H, 07H, 07H>
  65.  
  66. MONO_FLAG      DB      0                       ; =1 if forced Black and white.
  67. NOTE           DW      1046                    ;C note
  68.  
  69. DOS_SEGMENT    DW      ?                    ;Segment of internal DOS flags.
  70. INDOS_OFFSET   DW      ?                    ;Offset of INDOS flag.
  71. ERRFLAG_OFFSET DW      ?                    ;Offset of critical error flag.
  72. PROGRAM_STATUS DB      0                    ;Popup status; non-zero=popped up.
  73.  
  74. BUSY_FLAGS     LABEL   WORD
  75. FLAG_10h       DB      0                    ;Status of interrupt 10h.
  76. FLAG_13h       DB      0                    ;Status of interrupt 13h.
  77. BACK_FLAGS     LABEL   WORD
  78. FLAG_8h        DB      0                    ;Status of interrupt 8h.
  79. FLAG_28h       DB      0                    ;Status of interrupt 28h.
  80.  
  81. REQUEST_FLAG   DB      0                    ;Status of processing request.
  82. SS_REGISTER    DW      ?                    ;SS register storage.
  83. SP_REGISTER    DW      ?                    ;SP register storage.
  84. OLDPSP         DW      ?                    ;PSP segment storage.
  85.  
  86. BIOS_ACTIVE_PAGE       EQU     62H
  87. ACTIVE_PAGE    DB      ?
  88. ADDR_6845      DW      ?
  89. BIOS_CRT_MODE          EQU     49H
  90. CRT_MODE       DB      ?
  91. CRT_COLS       DW      ?
  92. CRT_LEN        DW      ?
  93. CRT_START      DW      ?
  94. CRT_DATA_LENGTH        EQU     $ - CRT_MODE
  95.  
  96. CRT_WIDTH      DW      ?                    ;Width in bytes of CRT.
  97. CRT_ROWS       DB      ?
  98. VIDEO_SEG      DW      ?
  99. STATUS_REG     DW      ?
  100. CURSOR_MODE    DW      ?                    ;Cursor shape.
  101. CURSOR_POS     DW      ?                    ;Cursor position.
  102. CURSOR_ADDR    DW      ?                    ;Cursor CRTC address.
  103.  
  104. DOS_VERSION    DW      ?
  105. TSR_SEGMENT    DW      ?
  106.  
  107. OLD8           DW      ?,?                     ;Old interrupt addresses.
  108. OLD9           DW      ?,?
  109. OLD10          DW      ?,?
  110. OLD13          DW      ?,?
  111. OLD28          DW      ?,?
  112.  
  113. OLD1B          DW      ?,?
  114. OLD23          DW      ?,?
  115. OLD24          DW      ?,?
  116. OLD_DTA        DW      ?,?
  117. BREAK          DB      ?                       ;Ctrl break state.
  118.  
  119. CLOCK          DB      "xx:xxxm",0
  120.  
  121. STATE          DW      CALENDAR                ;Pop up screen.
  122. EXIT_FLAG      DB      0                       ; =1 if Hotkey pressed.
  123.  
  124. CTRL_STATE     EQU     4
  125. ALT_STATE      EQU     8
  126.  
  127. COMBO          DB      "C"
  128. HOT_KEY_SCAN   DB      2EH                     ;"C"
  129. HOT_SHIFT_KEY  DB      ALT_STATE
  130.  
  131. MODIFY_FLAG    DB      0                       ; =1 if changes made in apps.
  132.  
  133. PORT_A         EQU     60H
  134. PORT_B         EQU     61H
  135. COMMAND_PORT   EQU     20H
  136. EOI            EQU     20H
  137.  
  138. MATCHING       STRUC
  139. RESERVED       DB      21 DUP (?)
  140. ATTRIBUTE      DB              ?
  141. FILE_TIME      DW              ?
  142. FILE_DATE      DW              ?
  143. SIZE_LOW       DW              ?
  144. SIZE_HIGH      DW              ?
  145. FILE_NAME      DB      13 DUP (?)
  146. MATCHING       ENDS
  147.  
  148. ;---------------------------------------------------------------------------;
  149. ; Code Format: 0 = compressed string; followed by string length and char.   ;
  150. ;              1 = display drop shade char.                                 ;
  151. ;              2 = color follows.                                           ;
  152. ;              3 = string end; if followed by -1 then menu end.             ;
  153. ;              4 = drop shade string end followed by string length.         ;
  154. ;              5 = insert date                                              ;
  155. ;              6 = insert appointment blocks                                ;
  156. ;              7 = skip count / 2 follows.                                  ;
  157. ;---------------------------------------------------------------------------;
  158. CAL_MENU       LABEL   BYTE
  159. DB 2,B
  160. DB " F2 Save  F3 Today  F4 Purge  F5 Print   ─┘= Appoint.  PgUp/Dn=Month  Esc=Exit ",3
  161. DB " ┌─────────────────────────────────────────────────┬──────────────────────────┐ ",3
  162. DB " │     Schedule ■ PC Magazine ■ Michael J. Mefford │ ",2,Y,SPACE
  163. CAL_DATE       LABEL   BYTE
  164. DB                                                       "                ",7,14,2,B," │ ",3
  165. DB " ╞══════════╤══════════╤══════════╤══════════╤═════╧════╤══════════╤══════════╡ ",3
  166. DB " │   "
  167. DAYS           LABEL   BYTE
  168. DB      "Sun    │   Mon    │   Tue    │   Wed    │   Thu    │   Fri    │   Sat    │ ",3
  169. DB " ├──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┤ ",3,-1
  170.  
  171. CAL_DUP        LABEL   BYTE
  172. DB " ├──┴┴┴┴┴┴┴┴┼──┴┴┴┴┴┴┴┴┼──┴┴┴┴┴┴┴┴┼──┴┴┴┴┴┴┴┴┼──┴┴┴┴┴┴┴┴┼──┴┴┴┴┴┴┴┴┼──┴┴┴┴┴┴┴┴┤ ",3
  173. CAL_MIDDLE     LABEL   BYTE
  174. DB " │",7 DUP (5,6,"┤"),SPACE,3
  175. DB " │",7 DUP (SPACE,SPACE,6,"┤"),SPACE,3,-1
  176.  
  177. DB " └──┴┴┴┴┴┴┴┴┴──┴┴┴┴┴┴┴┴┴──┴┴┴┴┴┴┴┴┴──┴┴┴┴┴┴┴┴┴──┴┴┴┴┴┴┴┴┴──┴┴┴┴┴┴┴┴┴──┴┴┴┴┴┴┴┴┘ ",3
  178. DB " Appointment block 1 hour periods; 6:00am - 1:30 1st row; 2:00pm - 9:30 2nd row ",3,-1
  179.  
  180.  
  181. APPOINTMENT_BLOCKS     LABEL BYTE              ;Storage for small block chars.
  182. BLOCK_COUNT    EQU     31 * 16
  183. DB          BLOCK_COUNT DUP (SPACE)
  184.  
  185. APP_MENU       LABEL   BYTE
  186. DB 2,B
  187. DB " F2 Save  F3 Today  F4 Purge  F5 Print  F6 Clear Line   PgUp/Dn=Day    Esc=Exit ",3
  188. DB " ┌┬────────────────────────────────────────────────┬──────────────────────────┐ ",3
  189. DB " ╞╡ Appointment ■ PC Magazine ■ Michael J. Mefford │ ",2,Y,SPACE
  190. APP_DATE       LABEL   BYTE
  191. DB                                                       "                ",7,14,2,B," │ ",3
  192. DB " ╞╪════════════════════════════════════════════════╧══════════════════════════╡ ",3
  193. APP_START      LABEL   BYTE
  194. APP_COL_SPACE    EQU   7                       ;Distance from end left to start right.
  195. APP_ROW_SPACE    EQU   16                      ;Distance from end right to start left.
  196. APP_LEFT_START   EQU   $ + 12
  197. APP_RIGHT_START  EQU   APP_LEFT_START + APP_LEN + APP_COL_SPACE
  198. APP_NOTE_SPACE   EQU   8
  199. DB " ╞╡  6:00am                                2:00                               │ ",3
  200. DB " ╞╡  6:30                                  2:30                               │ ",3
  201. DB " ╞╡  7:00                                  3:00                               │ ",3
  202. DB " ╞╡  7:30                                  3:30                               │ ",3
  203. DB " ╞╡  8:00                                  4:00                               │ ",3
  204. DB " ╞╡  8:30                                  4:30                               │ ",3
  205. DB " ╞╡  9:00                                  5:00                               │ ",3
  206. DB " ╞╡  9:30                                  5:30                               │ ",3
  207. DB " ╞╡ 10:00                                  6:00                               │ ",3
  208. DB " ╞╡ 10:30                                  6:30                               │ ",3
  209. DB " ╞╡ 11:00                                  7:00                               │ ",3
  210. DB " ╞╡ 11:30                                  7:30                               │ ",3
  211. DB " ╞╡ 12:00pm                                8:00                               │ ",3
  212. DB " ╞╡ 12:30                                  8:30                               │ ",3
  213. DB " ╞╡  1:00                                  9:00                               │ ",3
  214. DB " ╞╡  1:30                                  9:30                               │ ",3
  215. DB " ╞╪══════════════════════════════[Mini Notepad]═══════════════════════════════╡ ",3
  216. DB " ╞╡ "
  217. NOTEPAD        LABEL   BYTE
  218. DB     "                                                                          │ ",3
  219. DB " ╞╡                                                                           │ ",3
  220. DB " ╞╡                                                                           │ ",3
  221. APP            LABEL   BYTE
  222. DB " └┴───────────────────────────────────────────────────────────────────────────┘ ",3,-1
  223. APP_WIDTH      EQU     $ - APP - 1
  224.  
  225. ;----------------------------------------------;
  226. DISK_FULL_MSG  DB 2,H,"╔",      0,25,"═",       "╗",3
  227.                DB     "║  Not enough disk space. ║",1
  228.                DB     "║     Press any key.      ║",1
  229.                DB     "╚",      0,25,"═",       "╝",1,4,27
  230.  
  231. PERMANENT_MSG  DB 2,H,"╔",      0,25,"═",       "╗",3
  232.                DB     "║ Do you wish to save the ║",1
  233.                DB     "║ change to disk?  Y/N    ║",1
  234.                DB     "╚",      0,25,"═",       "╝",1,4,27
  235.  
  236. PERMANENT_FAIL DB 2,H,"╔",      0,25,"═",       "╗",3
  237.                DB     "║  Update failed.  Press  ║",1
  238.                DB     "║  any key to continue.   ║",1
  239.                DB     "╚",      0,25,"═",       "╝",1,4,27
  240.  
  241. PRINTER_NO     DB 2,H,"╔",      0,35,"═",                 "╗",3
  242.                DB     "║ Select printer by pressing 1 or 2 ║",1
  243.                DB     "╚",      0,35,"═",                 "╝",1,4,37
  244.  
  245.  
  246. SAVED_MSG      DB 2,H,"╔",0,9, "═╗",3
  247.                DB     "║  Saved  ║",1
  248.                DB     "╚",0,9, "═╝",1,4,11
  249.  
  250. DISK LABEL BYTE
  251. DB 2,H,"╔",      0,27,"═",         "╗",3
  252. DB     "║",      0,27,SPACE,       "║",1
  253. DISK_NAME     LABEL  BYTE
  254. DB     "║   Error reading drive X   ║",1,3,-1
  255.  
  256. ERR_BOT LABEL BYTE
  257. DB     "║   (R)etry or (A)bort ?    ║",1
  258. DB     "║",      0,27,SPACE,       "║",1
  259. DB     "╚",      0,27,"═",         "╝",1,4,ERR_WIDTH
  260.  
  261. PRN LABEL BYTE
  262. DB 2,H,"╔",      0,27,"═",           "╗",3
  263. DB     "║",      0,27,SPACE,         "║",1
  264. DB     "║",0,7," Printer Error",0,7," ║",1,3,-1
  265.  
  266. ERR_WIDTH      EQU     29
  267. ERR_HEIGHT     EQU     6
  268. ERR_ROW        EQU     ((25 - ERR_HEIGHT) / 2) + 3
  269. ERR_COL        EQU     ((80 - ERR_WIDTH) / 2)
  270.  
  271.  
  272. PURGE_MSG      DB 2,H,"╔",0,41,               "═",              "╗",3
  273.                DB     "║ Appointment Purge Date: ",2,P
  274. PUR_DATE       DB                               "                ",2,H,"║",1
  275.                DB     "║   Use: PgUp/Dn to change Purge Date     ║",1
  276.                DB     "║   F7 Purge up to, but excluding Date    ║",1
  277.                DB     "║   F8 Purge Date Only     Esc to Cancel  ║",1
  278.                DB     "╚",0,41,               "═",              "╝",1,4,43
  279.  
  280. ARCHIVE_MSG    DB 2,H,"╔",0,17,        "═╗",3
  281.                DB     "║  Archive  Y/N?  ║",1
  282.                DB     "╚",0,17,        "═╝",1,4,19
  283.  
  284. PURGING_MSG    DB 2,H,"╔",0,11,  "═╗",3
  285.                DB     "║  Purging  ║",1
  286.                DB     "╚",0,11,  "═╝",1,4,13
  287.  
  288. ;------------------------------------------------------------------------------
  289. ;Execution comes here thru interrupt 9 every time a key is pressed or released.
  290. ;------------------------------------------------------------------------------
  291. KEYBOARD       PROC    NEAR
  292.                PUSH    AX
  293.                PUSH    DS
  294.  
  295.                MOV     AX,40H
  296.                MOV     DS,AX
  297.                MOV     AH,DS:[KB_FLAG]         ;Get keyboard shift status
  298.                PUSH    CS
  299.                POP     DS
  300. KEYSTROKE:     IN      AL,PORT_A
  301.                TEST    AH,HOT_SHIFT_KEY        ;Our shift key?
  302.                JZ      KB_EXIT                 ;No, then exit
  303.                CMP     AL,HOT_KEY_SCAN         ;Our hotkey?
  304.                JNZ     KB_EXIT
  305.                CMP     PROGRAM_STATUS,0        ;Popup routine already active?
  306.                JNZ     KB_EXIT                 ;Yes, then ignore keypress
  307.  
  308.                IN      AL,PORT_B               ;Retrieve Port B.
  309.                OR      AL,80H                  ;Turn bit 7 on to reset
  310.                JMP     $ + 2                   ;I/O delay.
  311.                OUT     PORT_B,AL               ;Reset KBD.
  312.                AND     AL,NOT 80H              ;Turn bit 7 back off.
  313.                JMP     $ + 2                   ;I/O delay.
  314.                OUT     PORT_B,AL               ;Restore port.
  315.  
  316.                CLI                             ;Interrupts off.
  317.                MOV     AL,EOI                  ;Send End Of Interrupt
  318.                OUT     COMMAND_PORT,AL         ; to 8259A PIC.
  319.  
  320.                MOV     REQUEST_FLAG,18         ;Try to popup for one second.
  321.                POP     DS
  322.                POP     AX
  323.                IRET
  324.  
  325. KB_EXIT:       POP     DS
  326.                POP     AX
  327.                JMP     DWORD PTR CS:OLD9       ;Call keyboard handling routine.
  328. KEYBOARD       ENDP
  329.  
  330. ;------------------------------------------------------------------------------
  331. ;Interrupt 8 handling routine.
  332. ;------------------------------------------------------------------------------
  333. LAST_MIN       DB      ?                       ;Last minute.
  334. BELL_FLAG      DB      0                       ; =1 if chiming.
  335. BELL_CNT       DB      ?                       ; no. of chimes.
  336. POPUP_FLAG     DB      0                       ; =1 if alarm or day rollover.
  337. NOPOPUP_FLAG   DB      0                       ; =1 if ignore POPUP_FLAG.
  338. NOBELL_FLAG    DB      0                       ; =1 if ignore chime.
  339. NOMIDNIGHT_FLAG DB     0                       ; =1 if ignore rollover pop up.
  340. ALARM_FLAG     DB      0                       ; =1 only on alarm to avoid homing cursor.
  341. REREAD_FLAG    DB      0                       ; =1 if forced reread of disk.
  342.  
  343. TIMER          PROC    NEAR
  344.                CLI
  345.                PUSHF
  346.                CALL    CS:DWORD PTR OLD8
  347.                PUSH    AX
  348.                PUSH    BX
  349.                PUSH    CX
  350.                PUSH    DX
  351.                PUSH    SI
  352.                PUSH    DI
  353.                PUSH    DS
  354.                PUSH    ES
  355.                PUSH    BP
  356.                CLD
  357.                MOV     BX,CS
  358.                MOV     DS,BX
  359.                CMP     PROGRAM_STATUS,0        ;Already popped up?
  360.                JNZ     CK_TIME
  361.                CMP     FLAG_8h,0
  362.                JNZ     CK_TIME
  363.                CMP     POPUP_FLAG,1            ;Alarm or rollover popup?
  364.                JNZ     CK_REQ_FLAG
  365.                MOV     REQUEST_FLAG,18         ;Request to popup for 1 sec.
  366. CK_REQ_FLAG:   CMP     REQUEST_FLAG,0
  367.                JZ      CK_TIME
  368.  
  369. CK_TSRSTATE:   INC     FLAG_8h
  370.                STI
  371.                CALL    TSR_STATE               ;Save to enter Dos? 
  372.                JC      DECTIME
  373.                CALL    MAIN
  374.                JMP     SHORT TIMER_DONE
  375.  
  376.  
  377. DECTIME:       CMP     REQUEST_FLAG,0
  378.                JZ      TIMER_DONE
  379.                DEC     REQUEST_FLAG
  380.                JZ      TIMER_BEEP
  381.                CMP     REQUEST_FLAG,9          ;Beep twice, once every 1/2 sec.
  382.                JNZ     TIMER_DONE
  383. TIMER_BEEP:    CALL    BEEP
  384. TIMER_DONE:    CLI
  385.                DEC     FLAG_8h
  386.  
  387. TIMER_END:     POP     BP
  388.                POP     ES
  389.                POP     DS
  390.                POP     DI
  391.                POP     SI
  392.                POP     DX
  393.                POP     CX
  394.                POP     BX
  395.                POP     AX
  396.                IRET
  397.  
  398. ;----------------------------------------------;
  399. CK_TIME:       STI
  400.                MOV     AX,40H
  401.                MOV     ES,AX
  402.                MOV     CX,ES:[6CH]             ;TIMER_LOW
  403.                MOV     AX,ES:[6EH]             ;TIMER_HIGH
  404.                MOV     BP,AX                   ;Save hour.
  405.                PUSH    CS
  406.                POP     ES
  407.  
  408.                MOV     BL,"a"                  ;Convert time to 12 hour version.
  409.                CMP     AX,24
  410.                JZ      GOT_MUNDI
  411.                CMP     AX,11
  412.                JBE     GOT_MUNDI
  413.                MOV     BL,"p"
  414. GOT_MUNDI:     OR      AX,AX
  415.                JNZ     CK_NOON
  416.                MOV     AX,12
  417. CK_NOON:       CMP     AX,12
  418.                JBE     GOT_HOUR
  419.                SUB     AX,12
  420. GOT_HOUR:      MOV     DI,OFFSET CLOCK
  421.                XOR     SI,SI                   ;Suppress leading zero.
  422.                CALL    STORE_NUMBER
  423.  
  424.                MOV     AX,CX
  425.                XOR     DX,DX
  426.                MOV     CX,1093                 ;Convert ticks to minutes.
  427.                DIV     CX
  428.                INC     SI                      ;Store leading zero.
  429.                MOV     CL,CLOCK + 4            ;Retrieve current minute.
  430.                MOV     LAST_MIN,CL             ;Store new current minute.
  431.                CALL    STORE_NUMBER
  432.                MOV     [DI - 1],BL             ;Store am or pm.
  433.  
  434. CK_DISP_CLOCK: CMP     PROGRAM_STATUS,2        ;If not popped up, no
  435.                JNZ     CK_BELL                 ; clock display.
  436. DISP_TIME:     MOV     AX,2
  437.                CALL    CALC_ADDR
  438.                ADD     DI,70 * 2
  439.                MOV     BH,COLOR.Y
  440.                MOV     SI,OFFSET CLOCK
  441.                MOV     DX,STATUS_REG
  442.                PUSH    ES
  443.                MOV     ES,VIDEO_SEG
  444.                JMP     SHORT WRITE_CLOCK
  445. NEXT_CLOCK:    CALL    WRITE_SCREEN            ;Display clock.
  446. WRITE_CLOCK:   LODSB
  447.                OR      AL,AL
  448.                JNZ     NEXT_CLOCK
  449.                POP     ES
  450.  
  451. CK_BELL:       CMP     BELL_FLAG,0             ;Is alarm chiming?
  452.                JZ      CK_MINUTE
  453.                JMP     DO_BELL
  454.  
  455. CK_MINUTE:     MOV     AX,WORD PTR CLOCK + 3   ;Retrieve current minute.
  456.                CMP     AH,LAST_MIN             ;Same as last minute?
  457.                JNZ     CK_ALARM
  458.                JMP     TIMER_END               ;If yes, done.
  459. CK_ALARM:      CMP     AX,"1" SHL 8 + "0"      ;Else, is it :01?
  460.                JZ      CK_ROLLOVER             ;If yes, check if 12:01.
  461.                SUB     AX,"0" SHL 8 + "0"      ;Else, adjust to binary.
  462.                OR      AH,AH                   ;Minute zero?
  463.                JZ      ADJUST_TIME
  464. TIMER_LILLY:   JMP     TIMER_END               ;If no, done.
  465.  
  466. CK_ROLLOVER:   OR      BP,BP                   ;Is it 12:01am?
  467.                JNZ     TIMER_LILLY             ;If no, done.
  468.                MOV     REREAD_FLAG,1           ;Else, reread disk alarms.
  469.                CMP     PROGRAM_STATUS,0        ;Are we popped up?
  470.                JNZ     FIX_DATE                ;If yes, fix date now.
  471.                CMP     NOMIDNIGHT_FLAG,1       ;Else, ignore rollover?
  472.                JZ      TIMER_LILLY             ;If yes, done.
  473.                MOV     POPUP_FLAG,1            ;Else, popup request.
  474.                JMP     TIMER_LILLY
  475. FIX_DATE:      CALL    UPDATE_DATE             ;Fix date.
  476.                JMP     TIMER_LILLY
  477.  
  478. ADJUST_TIME:   SUB     BP,6                    ; 6:00am
  479.                JS      EXIT_TIMER
  480.                CMP     BP,15                   ; 9:00pm
  481.                JA      EXIT_TIMER
  482.                OR      AL,AL                   ; xx:00
  483.                JZ      CK_MATCH
  484.                CMP     AL,3                    ; xx:30
  485.                JNZ     EXIT_TIMER
  486.                AND     AL,1                    ;Convert to index.
  487.  
  488. CK_MATCH:      CMP     PROGRAM_STATUS,0        ;Popped up?
  489.                JNZ     EXIT_TIMER              ;If yes, no alarms.
  490.                CBW
  491.                SHL     BP,1                    ;Hour * 2.
  492.                ADD     AX,BP                   ; + half hour index.
  493.                MOV     DI,AX
  494.                CMP     BYTE PTR ALARMS[DI],1   ;Appointment?
  495.                JNZ     EXIT_TIMER              ;If no, done.
  496.  
  497.                CMP     NOPOPUP_FLAG,1          ;No pop up request by user?
  498.                JZ      CK_BELL_FLAG            ;If yes, check chime.
  499.                MOV     ALARM_FLAG,1            ;Else, flag no cursor change
  500.                MOV     APP_INDEX,APP_LEFT      ; when disk reread to today.
  501.                MOV     DX,DI
  502.                XCHG    DH,DL                   ;Place cursor on appointment.
  503.                MOV     DL,12
  504.                CMP     DH,16
  505.                JB      MOVE_CURSOR
  506.                MOV     APP_INDEX,APP_RIGHT
  507.                SUB     DH,16
  508.                MOV     DL,48
  509. MOVE_CURSOR:   ADD     DH,4                    ;Starts on fourth row.
  510.                MOV     APP_CURSOR,DX
  511.  
  512. CK_BELL_FLAG:  CMP     NOBELL_FLAG,1           ;No chime request by user?
  513.                JNZ     START_BELL
  514.                MOV     POPUP_FLAG,1            ;If yes, just pop up.
  515.                JMP     SHORT EXIT_TIMER
  516.  
  517. START_BELL:    MOV     BELL_CNT,14 * 2         ;14 chirps for chime.
  518.                MOV     BELL_FLAG,1
  519.                CALL    SETUP_BELL
  520. DO_BELL:       CALL    FLIP_BELL
  521.  
  522. EXIT_TIMER:    JMP     TIMER_END
  523.  
  524. TIMER          ENDP
  525.  
  526. ;-------------------------------------------------------------
  527. ; INPUT: SI = 0 not to suppress leading zero; SI = 1 suppress.
  528. STORE_NUMBER:  MOV     BH,10
  529.                DIV     BH
  530.                ADD     AX,"00"
  531.                OR      SI,SI
  532.                JNZ     STORE_IT
  533.                CMP     AL,"0"
  534.                JNZ     STORE_IT
  535.                MOV     AL,SPACE
  536. STORE_IT:      STOSB
  537.                XCHG    AH,AL
  538.                STOSB
  539.                INC     DI
  540.                RET
  541.  
  542. ;------------------------------------------------------------------------------
  543. ;Interrupt 10h handling routine.
  544. ;------------------------------------------------------------------------------
  545. VIDEO          PROC    NEAR
  546.                INC     CS:FLAG_10H             ;No popup while in a int 10h.
  547.                PUSHF
  548.                CLI
  549.                CALL    DWORD PTR CS:OLD10
  550.                DEC     CS:FLAG_10H
  551.                IRET
  552. VIDEO          ENDP
  553.  
  554. ;------------------------------------------------------------------------------
  555. ;Interrupt 13h handling routine.
  556. ;------------------------------------------------------------------------------
  557. BDISK          PROC    FAR
  558.                PUSHF
  559.                INC     CS:FLAG_13H             ;No popup while disk activity.
  560.                CLI
  561.                CALL    DWORD PTR CS:OLD13      ;Call BIOS routine
  562.                PUSHF
  563.                DEC     CS:FLAG_13H
  564.                POPF
  565.                STI
  566.                RET     2                       ;Preserve flags.
  567. BDISK          ENDP
  568.  
  569. ;------------------------------------------------------------------------------
  570. ;Interrupt 28h handling routine.
  571. ;------------------------------------------------------------------------------
  572. BACKPROC       PROC    NEAR
  573.                PUSH    AX
  574.                PUSH    DS
  575.                MOV     AX,CS
  576.                MOV     DS,AX
  577.                CLI
  578.                PUSHF
  579.                CALL    DWORD PTR OLD28
  580.                CMP     REQUEST_FLAG,0          ;Popup requested?
  581.                JZ      BP_EXIT
  582.                CMP     BACK_FLAGS,0            ;Save to popup?
  583.                JNZ     BP_EXIT
  584.                CMP     PROGRAM_STATUS,0        ;Already popped up?
  585.                JNZ     BP_EXIT
  586.  
  587.                INC     FLAG_28h
  588.                STI
  589.                CLD
  590.                PUSH    BX
  591.                PUSH    CX
  592.                PUSH    DX
  593.                PUSH    SI
  594.                PUSH    DI
  595.                PUSH    ES
  596.                PUSH    BP
  597.                CALL    TSR_STATE               ;Save to enter Dos?
  598.                JC      BP_DONE
  599.                CALL    MAIN
  600. BP_DONE:       POP     BP
  601.                POP     ES
  602.                POP     DI
  603.                POP     SI
  604.                POP     DX
  605.                POP     CX
  606.                POP     BX
  607.                DEC     FLAG_28h
  608. BP_EXIT:       POP     DS
  609.                POP     AX
  610.                IRET
  611. BACKPROC       ENDP
  612.  
  613. ;----------------------------------------------;
  614. TSR_STATE:     PUSH    AX
  615.                CMP     BUSY_FLAGS,0
  616.                JNZ     TSR_BUSY
  617.  
  618.                MOV     ES,DOS_SEGMENT          ;Check INDOS flag.
  619.                MOV     BX,INDOS_OFFSET
  620.                MOV     AL,ES:[BX]
  621.                MOV     BX,ERRFLAG_OFFSET       ;Check critical error flag.
  622.                MOV     AH,ES:[BX]
  623.                XOR     BX,BX
  624.                CMP     BL,FLAG_28h
  625.                RCL     BL,1
  626.                CMP     BX,AX
  627.                JC      TSR_END
  628.  
  629. ; Checking for hardware interrupts will avoid lost of chars in Async.
  630.                MOV     AX,00001011B
  631.                OUT     20H,AL
  632.                JMP     $ + 2
  633.                IN      AL,20H
  634.                CMP     AH,AL
  635.                JC      TSR_END
  636.  
  637. TSR_OK:        CLC
  638.                JMP     SHORT TSR_END
  639.  
  640. TSR_BUSY:      STC
  641. TSR_END:       POP     AX
  642.                RET
  643.  
  644. ;-----------------------------------------------;
  645. ; This is the new Critical Error interrupt 24h. ;
  646. ;-----------------------------------------------;
  647. ERR_CURSOR     DW      ?                       ; Current cursor position.
  648. ERR_CORNER     DW      ?                       ; Address for error message.
  649. ABORT          DB      0                       ; =1 if user chose to abort.
  650.  
  651. IOERR:         STI
  652.                PUSH    BX
  653.                PUSH    CX
  654.                PUSH    DX
  655.                PUSH    SI
  656.                PUSH    DI
  657.                PUSH    BP
  658.                PUSH    DS
  659.                PUSH    ES
  660.  
  661.                MOV     BX,CS
  662.                MOV     DS,BX
  663.                MOV     ES,BX
  664.                CLD
  665.                ADD     AL,"A"
  666.                MOV     DISK_NAME + 24,AL       ;Convert and save drive letter.
  667.  
  668.                MOV     SI,OFFSET DISK          ;Disk or printer critical error?
  669.                TEST    AH,10000000B
  670.                JZ      SAVE_IT
  671.                MOV     SI,OFFSET PRN
  672.  
  673. SAVE_IT:       PUSH    SI                      ;Save screen contents we are
  674.                MOV     BH,ACTIVE_PAGE          ; going to write over.
  675.                MOV     AH,3
  676.                INT     10H
  677.                MOV     ERR_CURSOR,DX           ;Save cursor position and
  678.                CALL    HIDE_CURSOR             ; hide it off screen.
  679.  
  680.                MOV     AX,ERR_ROW              ;Popup error message.
  681.                CALL    CALC_ADDR
  682.                ADD     AX,ERR_COL * 2
  683.                MOV     ERR_CORNER,AX
  684.  
  685.                MOV     SI,AX
  686.                MOV     DI,OFFSET ERR_SAVE
  687.                MOV     CX,ERR_HEIGHT + 1
  688.                MOV     BP,ERR_WIDTH + 2
  689.                CALL    DO_SAVE
  690.  
  691.                POP     SI
  692.                MOV     DI,ERR_CORNER
  693.                CALL    POP_WINDOW
  694.                MOV     DI,ERR_CORNER
  695.                MOV     AX,CRT_WIDTH
  696.                ADD     DI,AX
  697.                ADD     DI,AX
  698.                ADD     DI,AX
  699.                MOV     SI,OFFSET ERR_BOT
  700.                CALL    POP_WINDOW
  701.                CALL    BEEP
  702.  
  703. WAIT_KEY:      XOR     AH,AH                   ;Get a user response.
  704.                INT     16H
  705.                MOV     AL,1
  706.                CMP     AH,13H                  ;Was it scan code for "R"?
  707.                JZ      ERR_END
  708.                CMP     AH,1EH                  ;Was it "A"?
  709.                JNZ     WAIT_KEY                ;If no, wait until valid
  710.                MOV     ABORT,1                 ; response.
  711.                MOV     AL,3                    ;Fail.
  712.                CMP     DOS_VERSION,300H        ;DOS 2 can't handle fail request.
  713.                JAE     ERR_END
  714.                XOR     AL,AL
  715.  
  716. ERR_END:       PUSH    AX
  717.                MOV     DI,ERR_CORNER           ;Restore screen.
  718.                MOV     SI,OFFSET ERR_SAVE
  719.                MOV     CX,ERR_HEIGHT + 1
  720.                MOV     BP,ERR_WIDTH + 2
  721.                CALL    DO_RESTORE
  722.                MOV     DX,ERR_CURSOR
  723.                CALL    SET_CURSOR              ;Restore cursor position.
  724.                POP     AX
  725.  
  726.                POP     ES                      ;Restore registers.
  727.                POP     DS
  728.                POP     BP
  729.                POP     DI
  730.                POP     SI
  731.                POP     DX
  732.                POP     CX
  733.                POP     BX
  734. IOEXIT:        IRET
  735.  
  736. ;------------------------------------------------------------------------------
  737. ;MAIN is the routine called to pop up the window.
  738. ;------------------------------------------------------------------------------
  739. MAIN           PROC    NEAR
  740.                MOV     PROGRAM_STATUS,1        ;Flag in process of popping up.
  741.                MOV     REQUEST_FLAG,0          ;Reset request counter.
  742.                MOV     SS_REGISTER,SS          ;Setup own stack.
  743.                MOV     SP_REGISTER,SP
  744.                MOV     AX,CS
  745.                MOV     SS,AX
  746.                MOV     SP,OFFSET OUR_STACK
  747.                STI
  748.                MOV     ES,AX
  749.  
  750.                CALL    GET_BIOS_DATA
  751.                MOV     AL,CRT_MODE             ;Is it video mode BW80, CO80
  752.                CMP     AL,3                    ; or MONO?
  753.                JZ      MAIN1
  754.                CMP     AL,2
  755.                JZ      MAIN1
  756.                CMP     AL,7
  757.                JZ      MAIN1
  758. QUICK_EXIT:    CMP     POPUP_FLAG,1            ;If no, can't popup; beep to tell
  759.                JZ      EXIT                    ; user only if was hotkey popup.
  760.                CALL    BEEP
  761.  
  762. ;----------------------------------------------;
  763. ; MAIN exit.                                   ;
  764. ;----------------------------------------------;
  765. EXIT:          CLI
  766.                MOV     SS,SS_REGISTER          ;Restore stack.
  767.                MOV     SP,SP_REGISTER
  768.                MOV     PROGRAM_STATUS,0
  769.                RET
  770.  
  771. ;----------------------------------------------;
  772. MAIN1:         CMP     CRT_COLS,80             ;At least 80 columns?
  773.                JB      QUICK_EXIT
  774.  
  775. GET_COLORS:    CALL    GET_CUR_ADDR            ;Save cursor address.
  776.                CMP     MONO_FLAG,1             ;Forced Black and white?
  777.                JZ      DO_MONO
  778.                MOV     SI,OFFSET COLOR_ATTR    ;Select color or mono
  779.                CMP     CRT_MODE,3              ; attributes.
  780.                JZ      GOT_ATTR
  781. DO_MONO:       MOV     SI,OFFSET MONO_ATTR
  782. GOT_ATTR:      MOV     DI,OFFSET COLOR
  783.                MOV     CX,SIZE COLOR_ATTRIBS
  784.                REP     MOVSB
  785.  
  786. MAIN5:         MOV     AH,51H
  787.                CALL    INT21_PSP               ;Get PSP.
  788.                MOV     OLDPSP,BX
  789.                PUSH    CS
  790.                POP     BX
  791.                MOV     AH,50H                  ;Set PSP.
  792.                CALL    INT21_PSP
  793.  
  794.                MOV     AH,2FH
  795.                INT     21H
  796.                MOV     OLD_DTA[0],BX           ;Get DTA.
  797.                MOV     OLD_DTA[2],ES
  798.                MOV     DX,OFFSET DTA
  799.                MOV     AH,1AH                  ;Set DTA.
  800.                INT     21H
  801.  
  802.                MOV     AX,3300H                ;Get break.
  803.                INT     21H
  804.                MOV     BREAK,DL
  805.                XOR     DL,DL                   ;Break off.
  806.                MOV     AX,3301H
  807.                INT     21H
  808.  
  809. MAIN6:         PUSH    CS
  810.                POP     ES
  811.                CALL    IOSET                   ;Set up critical error handler.
  812.                CALL    UPDATE_DATE
  813.                CALL    SAVE_SCREEN
  814.                MOV     EXIT_FLAG,0
  815.                CMP     POPUP_FLAG,1            ;Alarm or rollover?
  816.                JNZ     READY
  817.                MOV     POPUP_FLAG,0
  818.                MOV     STATE,OFFSET APPOINTMENT  ;If yes, popup in appointments
  819.                CALL    CTODAY                    ; on today.
  820. READY:         MOV     PROGRAM_STATUS,2          ;Flag so clock displayed.
  821.  
  822. ;------------------------------;
  823. ;    M A I N    L O O P        ;
  824. ;------------------------------;
  825. NEXT_STATE:    CALL    HIDE_CURSOR
  826.                CALL    STATE
  827.                CMP     EXIT_FLAG,1             ;If Esc Calendar or Hotkey, exit.
  828.                JNZ     NEXT_STATE
  829.  
  830. ESCAPE:        MOV     PROGRAM_STATUS,1        ;Disable clock display.
  831.                CALL    RESTORE_SCREEN
  832.  
  833.                MOV     BX,OLDPSP               ;Restore PSP.
  834.                MOV     AH,50H
  835.                CALL    INT21_PSP
  836.  
  837.                PUSH    DS                      ;Restore DTA.
  838.                LDS     DX,DWORD PTR OLD_DTA
  839.                MOV     AH,1AH
  840.                INT     21H
  841.                POP     DS
  842.  
  843.                MOV     DL,BREAK                ;Restore BREAK.
  844.                MOV     AX,3301H
  845.                INT     21H
  846.  
  847.                CALL    IORESET                 ;Restore critical handler.
  848.  
  849.                MOV     BH,ACTIVE_PAGE          ;Restore cursor.
  850.                MOV     DX,CURSOR_POS
  851.                MOV     AH,2
  852.                INT     10H
  853.                MOV     DX,ADDR_6845            ;Recover CRTC base address
  854.                MOV     CX,CURSOR_ADDR
  855.                MOV     AL,14
  856.                OUT     DX,AL
  857.                INC     DX
  858.                MOV     AL,CH
  859.                OUT     DX,AL
  860.                DEC     DX
  861.                MOV     AL,15
  862.                OUT     DX,AL
  863.                INC     DX
  864.                MOV     AL,CL
  865.                OUT     DX,AL
  866.                JMP     EXIT
  867. MAIN           ENDP
  868.  
  869. ;----------------------------------------------;
  870. INT21_PSP:     CMP     DOS_VERSION,30AH        ;PSP call DOS 3 or above.
  871.                JB      INT21_PSP2
  872.                INT     21H
  873.                RET
  874.  
  875. INT21_PSP2:    PUSH    DS                      ;Else, fake via error.
  876.                MOV     DI,ERRFLAG_OFFSET
  877.                MOV     DS,DOS_SEGMENT
  878.                INC     BYTE PTR [DI]
  879.                INT     21H
  880.                DEC     BYTE PTR [DI]
  881.                POP     DS
  882.                RET
  883.  
  884. ;------------------------------------------;
  885. ; OUTPUT: ZF=1 if aborted.  CY=1 if failed ;
  886. ;------------------------------------------;
  887. ZR             EQU     1000000B                ;Bit for zero flag in register.
  888.  
  889. INT21_IO:      INT     21H
  890.                PUSH    AX                      
  891.                LAHF                            ;Save flag's results of DOS call.
  892.                AND     AH,NOT ZR               ;Assume zero flag zero.
  893.                CMP     ABORT,1                 ;Was there an abort from
  894.                JNZ     INT21_IO_END            ; critical error?
  895.                OR      AH,ZR                   ;If yes, turn zero bit on.
  896.                MOV     ABORT,0                 ;Reset abort flag.
  897. INT21_IO_END:  SAHF                            ;Return results in flags reg.
  898.                POP     AX
  899.                RET
  900.  
  901. ;----------------------------------------------;
  902.  
  903. UPDATE_DATE:   MOV     AH,2AH                  ;Get the date from DOS.
  904.                INT     21H
  905.                MOV     YEAR_TODAY,CX
  906.                MOV     DAY_MON_TODAY,DX
  907.                RET
  908.  
  909. ;**********************************************;
  910. ;       F U N C T I O N   C A L L S
  911. ;**********************************************;
  912. MONTHS         DB      "JanFebMarAprMayJunJulAugSepOctNovDec"
  913. NUMDAYS        DB       31,28,31,30,31,30,31,31,30,31,30,31
  914.  
  915. YEAR_CAL       DW      ?                       ;Year displayed.
  916. DAY_MON_CAL    LABEL   WORD
  917. DAY_CAL        DB      ?                       ;Day cursor is on.
  918. MONTH_CAL      DB      ?                       ;Month displayed.
  919.  
  920. YEAR_TODAY     DW      ?                       ;Current year.
  921. DAY_MON_TODAY  LABEL   WORD
  922. DAY_TODAY      DB      ?                       ;Current day.
  923. MONTH_TODAY    DB      ?                       ;Current month.
  924.  
  925. YEAR_CUR       DW      ?                       ;Last year displayed.
  926. DAY_MON_CUR    LABEL   WORD
  927. DAY_CUR        DB      ?                       ;Last day displayed.
  928. MONTH_CUR      DB      -1                      ;Last month displayed.
  929.  
  930. WEEKDAY        DB      ?                       ;Day of week for 1st.
  931. LAST_DAY       DB      ?                       ;Last day of month.
  932. DAY_COUNTER    DB      ?                       ;Day display counter.
  933. BLOCK_COUNTERS LABEL   WORD
  934. BLOCK_COUNTER  DB      ?,?                     ;Block display counters.
  935. BLOCK_ROW      DW      0                       ;Block row index.
  936.  
  937. CTABLE         DB  3CH,   3DH,    3EH,       3FH
  938.                DB  4BH,   4DH,    48H,       50H,       47H,       4FH
  939.                DB  49H,   51H,    84H,       76H,       77H,       75H
  940.                DB  73H,   74H
  941. CTABLE_LEN     EQU     $ - CTABLE
  942.                DW  SAVE,  CTODAY, PPURGE,    PRINT
  943.                DW  CLEFT, CRIGHT, CUP,       CDOWN,     CHOME,     CEND
  944.                DW  CPGUP, CPGDN,  CCTRLPGUP, CCTRLPGDN, CCTRLHOME, CCTRLEND
  945.                DW  CHOME, CEND
  946.  
  947. CALENDAR:      CALL    CK_DATE                 ;See if date changed.
  948.  
  949.                MOV     SI,OFFSET CAL_MENU      ;Pop up calendar screen.
  950.                CALL    POP_MENU
  951.  
  952.                MOV     DAY_COUNTER,0           ;Counters for day and
  953.                MOV     BLOCK_COUNTERS,0        ; cursor display.
  954.                MOV     SI,OFFSET CAL_MIDDLE
  955.                CALL    POP_WINDOW
  956.                MOV     CX,5
  957. NEXT_CALROW:   PUSH    CX
  958.                MOV     SI,OFFSET CAL_DUP
  959.                CALL    POP_WINDOW
  960.                POP     CX
  961.                LOOP    NEXT_CALROW
  962.                INC     SI
  963.                CALL    POP_WINDOW
  964.  
  965.                CALL    GETKEY                  ;Get a keystroke.
  966.                JC      CALENDAR_DONE           ;Exit if Esc or hotkey.
  967.                CMP     AL,ENTER_SCAN           ;If Enter, then go to
  968.                JZ      GOTO_APP                ; appointment screen.
  969.                CMP     AL,31H                  ;If "N" scan code.
  970.                JZ      GOTO_NOTE
  971.                CMP     AL,F6_SCAN              ; or F6, go directly
  972.                JNZ     CAL_DISPATCH            ; to Notepad.
  973. GOTO_NOTE:     MOV     STATE,OFFSET APPOINTMENT
  974.                CALL    CK_DATE
  975.                MOV     APP_CURSOR,A_NOTE_CURSOR
  976.                MOV     APP_INDEX,APP_NOTE
  977.                JMP     SHORT CALENDAR_END
  978.  
  979. GOTO_APP:      MOV     STATE,OFFSET APPOINTMENT
  980.                JMP     SHORT CALENDAR_END
  981.  
  982. CAL_DISPATCH:  MOV     SI,YEAR_CAL             ;Pass variables in registers
  983.                MOV     DL,DAY_CAL              ; to calendar keyboard
  984.                MOV     DH,MONTH_CAL            ; functions.
  985.                MOV     BL,WEEKDAY
  986.                MOV     BH,LAST_DAY
  987.                MOV     DI,OFFSET CTABLE
  988.                MOV     CX,CTABLE_LEN
  989.                CALL    DISPATCH
  990.                CMP     EXIT_FLAG,1
  991.                JZ      CALENDAR_END
  992.                JMP     CALENDAR
  993.  
  994. CALENDAR_DONE: MOV     EXIT_FLAG,1             ;Tell MAIN to exit.
  995. CALENDAR_END:  RET
  996.  
  997. ;----------------------------------------------;
  998. ; INPUT: SI=YEAR_CAL; DL=DAY_CAL; DH=MONTH_CAL; BL=WEEKDAY; BH=LAST_DAY
  999.  
  1000. CTODAY:        MOV     SI,YEAR_TODAY           ;Today's date.
  1001.                MOV     DX,DAY_MON_TODAY
  1002.                JMP     SHORT CFUNC_UPDATE
  1003.  
  1004. CPGDN:         INC     DH                      ;Next month.
  1005.                CMP     DH,12                   ;Past Dec?
  1006.                JBE     CFUNC_UPDATE
  1007.                MOV     DH,1                    ;Jan.
  1008.                INC     SI                      ;Next year.
  1009.                JMP     SHORT CK_YEAR
  1010.  
  1011. CPGUP:         DEC     DH                      ;Previous month.
  1012.                JNZ     CFUNC_UPDATE            ;Before Jan?
  1013.                MOV     DH,12                   ;Dec.
  1014.                DEC     SI                      ;Previous year.
  1015.                JMP     SHORT CK_YEAR
  1016.  
  1017. CCTRLPGDN:     INC     SI                      ;Next year.
  1018.                JMP     SHORT CK_YEAR
  1019.  
  1020. CCTRLPGUP:     DEC     SI                      ;Previous year.
  1021.  
  1022. CK_YEAR:       CMP     SI,10000                ;Stay within Gregorian
  1023.                JAE     CFUNC_END               ; calendar.
  1024.                CMP     SI,1582
  1025.                JA      CFUNC_UPDATE
  1026.                JMP     SHORT CFUNC_END
  1027.  
  1028. CLEFT:         DEC     DL                      ;Previous day.
  1029.                JNZ     CFUNC_UPDATE
  1030.                JMP     SHORT CFUNC_END
  1031.  
  1032. CRIGHT:        INC     DL                      ;Next day.
  1033.                CMP     DL,BH
  1034.                JBE     CFUNC_UPDATE
  1035.                JMP     SHORT CFUNC_END
  1036.  
  1037. CUP:           MOV     AL,7                    
  1038.                SUB     AL,BL                   ;Adjust for weekday.
  1039.                CMP     DL,AL                   ;If first week, ignore
  1040.                JBE     CFUNC_END
  1041.                SUB     DL,7                    ;Previous week.
  1042.                JA      CFUNC_UPDATE
  1043.                MOV     DL,1                    ;First day, if out of bounds.
  1044.                JMP     SHORT CFUNC_UPDATE
  1045.  
  1046. CDOWN:         MOV     CL,7
  1047.                MOV     AL,CL
  1048.                SUB     AL,BL
  1049. FIND_BOTTOM:   ADD     AL,CL                   ;Find last week row.
  1050.                CMP     AL,BH
  1051.                JBE     FIND_BOTTOM
  1052.                SUB     AL,CL                   
  1053.                CMP     DL,AL
  1054.                JA      CFUNC_END               ;Ignore if on last row.
  1055.                ADD     DL,7                    ;Next week.
  1056.                CMP     DL,BH
  1057.                JBE     CFUNC_UPDATE
  1058.                MOV     DL,BH                   ;Last day if out of bounds.
  1059.                JMP     SHORT CFUNC_UPDATE
  1060.  
  1061. CCTRLHOME:     MOV     DL,1                    ;First day.
  1062.                JMP     SHORT CFUNC_UPDATE
  1063.  
  1064. CCTRLEND:      MOV     DL,BH                   ;Last day.
  1065.  
  1066. CFUNC_UPDATE:  MOV     YEAR_CAL,SI             ;Store new day/year.
  1067.                MOV     DAY_MON_CAL,DX
  1068. CFUNC_END:     RET
  1069.  
  1070. CHOME:         MOV     AL,DL                   ;Adjust for weekday.
  1071.                ADD     AL,BL
  1072.                DEC     AL
  1073.                CBW
  1074.                MOV     CL,7
  1075.                DIV     CL
  1076.                MOV     DL,1                    ;First day if at start of row.
  1077.                OR      AH,AH
  1078.                JZ      CFUNC_UPDATE
  1079.                MUL     CL
  1080.                SUB     AL,BL
  1081.                INC     AL
  1082.                JBE     CFUNC_UPDATE
  1083.                MOV     DL,AL                   ;Else go to start of row.
  1084.                JMP     CFUNC_UPDATE
  1085.  
  1086. CEND:          MOV     AL,DL                   ;Adjust for weekday.
  1087.                ADD     AL,BL
  1088.                CBW
  1089.                MOV     CL,7
  1090.                DIV     CL
  1091.                MOV     DL,BH                   ;Last day if at end of row.
  1092.                OR      AH,AH
  1093.                JZ      CFUNC_UPDATE
  1094.                MUL     CL
  1095.                ADD     AL,CL
  1096.                SUB     AL,BL
  1097.                MOV     DL,AL                   ;Else, end of row.
  1098.                CMP     DL,BH
  1099.                JBE     CFUNC_UPDATE
  1100.                MOV     DL,BH
  1101.                JMP     CFUNC_UPDATE
  1102.  
  1103. ;----------------------------------------------;
  1104. CK_DATE:       MOV     AX,DAY_MON_CAL          ;Retrieve calendar day/year.
  1105.                MOV     BX,YEAR_CAL
  1106.                CMP     REREAD_FLAG,1           ;Forced reread?
  1107.                JZ      GET_CAL
  1108.                CMP     AH,MONTH_CUR            ;Has month changed?
  1109.                JNZ     GET_CAL
  1110.                CMP     BX,YEAR_CUR             ;Has year changed?
  1111.                JNZ     GET_CAL
  1112.                CMP     STATE,OFFSET APPOINTMENT
  1113.                JNZ     CK_DATE_END             ;If appointment screen,
  1114.                CMP     AL,DAY_CUR              ; has day changed?
  1115.                JZ      CK_DATE_END
  1116.  
  1117. GET_CAL:       MOV     REREAD_FLAG,0           ;Reset flag.
  1118.                PUSH    AX
  1119.                PUSH    BX
  1120.                CALL    PERMANENT               ;See if changes have been made
  1121.                POP     BX                      ; in appointment screen.
  1122.                POP     AX
  1123.                MOV     MONTH_CUR,AH            ;Store current day/year.
  1124.                MOV     YEAR_CUR,BX
  1125.                CALL    FIRSTDAY                ;Find first day of month.
  1126.                CALL    READ_DATA               ;Read data off of disk.
  1127.                CMP     ALARM_FLAG,1            ;Was this alarm?
  1128.                JZ      RESET_ALARM             ;If yes, leave cursor on app.
  1129.  
  1130.                MOV     A_LEFT.CURSOR,A_LEFT_CURSOR
  1131.                MOV     A_RIGHT.CURSOR,A_RIGHT_CURSOR
  1132.                MOV     A_NOTE.CURSOR,A_NOTE_CURSOR
  1133.                MOV     APP_INDEX,APP_LEFT
  1134.                MOV     APP_CURSOR,A_LEFT_CURSOR
  1135.  
  1136. RESET_ALARM:   MOV     ALARM_FLAG,0
  1137. CK_DATE_END:   RET
  1138.  
  1139. ;----------------------------------------------;
  1140. FIRSTDAY:      MOV     SI,YEAR_CAL             ;Year.
  1141.                MOV     NUMDAYS[1],28           ;Assume this isn't a leap year.
  1142.                TEST    SI,3                    ;Year divisible by 4?
  1143.                JNZ     GETDAY                  ;Assumed right.
  1144.                MOV     NUMDAYS[1],29           ;Leap year = 29 days.
  1145. GETDAY:        MOV     BX,6                    ;Saturday,(weekday of 1/1/1583)
  1146.                MOV     AX,SI                   ;Calendar year.
  1147.                SUB     AX,1583                 ;No. years since our base year.
  1148.                ADD     BX,AX                   ;Calendar advances 1 weekday per
  1149.                                                ;  year unless leap year.
  1150.                ADD     AX,2                    ;Adj diff, so even #, if year
  1151.                MOV     CX,4                    ;  was after a leap year.
  1152.                CWD
  1153.                DIV     CX                      ;No. leap years before this.
  1154.                ADD     BX,AX                   ;Add 1 day, for each leap yr.
  1155.                CMP     SI,1700                 ;Things work normally 'til 1700.
  1156.                JL      CNVRT                   ;Not a leap year.
  1157.                MOV     AX,SI
  1158.                SUB     AX,1600                 ;Get no. years since 1600.
  1159.                MOV     CL,100
  1160.                CWD                             ;Convert to number of centuries.
  1161.                DIV     CX
  1162.                OR      DX,DX                   ;If remain=0 this is centennial.
  1163.                JNZ     DEDUCT
  1164.                TEST    AX,3                    ;If century divisible by
  1165.                JZ      DECAX                   ; 400, it is also leap year.
  1166.                MOV     NUMDAYS[1],28           ;Other centennial years have 28.
  1167. DECAX:         DEC     AX                      ;If centennial, sub 1 from cent.
  1168. DEDUCT:        SUB     BX,AX                   ;Subtract 1 weekday per century.
  1169.                CWD
  1170.                MOV     CL,4
  1171.                DIV     CX                      ;Calculate centuries mod 400.
  1172.                ADD     BX,AX                   ;Add back 1 day per 400 years.
  1173. CNVRT:         MOV     SI,OFFSET NUMDAYS       ;Add in days per month, this yr.
  1174.                XOR     AH,AH
  1175.                MOV     CL,MONTH_CAL            ;Calendar month.
  1176.                DEC     CL
  1177.                MOV     DI,CX
  1178.                MOV     DL,NUMDAYS[DI]
  1179.                MOV     LAST_DAY,DL
  1180.                JCXZ    FINAL                   ;If Jan, ready for final calc.
  1181. ADDMNTH:       LODSB
  1182.                ADD     BX,AX                   ;Add to days count.
  1183.                LOOP    ADDMNTH                 ;Cont. until prior months added.
  1184. FINAL:         MOV     AX,BX                   ;Days advanced since 1/1/1583.
  1185.                CWD
  1186.                MOV     CL,7                    ;Find no. full weeks since 1583.
  1187.                DIV     CX                      ;Weekday of 1st of cal's month.
  1188.                MOV     WEEKDAY,DL              ;Result is first day of week.
  1189.  
  1190.                MOV     AL,DAY_CAL              ;Fix last day.
  1191. FIX_CURSOR:    CMP     AL,LAST_DAY
  1192.                JBE     STORE_CURSOR2
  1193.                DEC     AL
  1194.                JMP     FIX_CURSOR
  1195. STORE_CURSOR2: MOV     DAY_CAL,AL              ;Store fix.
  1196.                MOV     DAY_CUR,AL
  1197.                CALL    STORE_DATE
  1198.                RET
  1199.  
  1200. ;----------------------------------------------;
  1201. STORE_DATE:    MOV     BP,3                    ;Three places need dates.
  1202.                MOV     DI,OFFSET CAL_DATE      ;Calendar screen.
  1203. NEXT_DATE:     PUSH    DI
  1204.                MOV     AL,MONTH_CAL            ;Month
  1205.                DEC     AL
  1206.                MOV     CX,3
  1207.                MUL     CL
  1208.                ADD     AX,OFFSET MONTHS
  1209.                MOV     SI,AX
  1210.                REP     MOVSB
  1211.                INC     DI
  1212.                CMP     BP,3
  1213.                JZ      STORE_YEAR
  1214.  
  1215.                MOV     AL,DAY_CAL              ;Number of day.
  1216.                CBW
  1217.                CALL    STORE_NUM
  1218.                MOV     AL,SPACE
  1219.                STOSB
  1220. STORE_YEAR:    MOV     AX,YEAR_CAL             ;Year.
  1221.                CALL    STORE_NUM
  1222.                MOV     AL,SPACE
  1223.                STOSB
  1224.  
  1225.                POP     DI
  1226.                CMP     BP,3
  1227.                JZ      LOOP_DATE
  1228.                ADD     DI,12
  1229.                MOV     AL,WEEKDAY
  1230.                ADD     AL,DAY_CAL
  1231.                DEC     AL
  1232.                CBW
  1233.                MOV     CL,7
  1234.                DIV     CL
  1235.                MOV     AL,AH
  1236.                MOV     CL,11
  1237.                MUL     CL
  1238.                ADD     AX,OFFSET DAYS          ;Name of weekday; ie. Mon etc.
  1239.                MOV     SI,AX
  1240.                MOV     CX,3
  1241.                REP     MOVSB
  1242.  
  1243. LOOP_DATE:     DEC     BP
  1244.                JZ      STORE_DATE_END
  1245.                MOV     DI,OFFSET APP_DATE      ;Appointment screen.
  1246.                CMP     BP,2
  1247.                JZ      NEXT_DATE
  1248.                MOV     DI,OFFSET PUR_DATE      ;Purge window.
  1249.                JMP     NEXT_DATE
  1250. STORE_DATE_END:RET
  1251.  
  1252. ;----------------------------------------------;
  1253. STORE_NUM:     MOV     BX,10
  1254.                XOR     CX,CX                   ;Zero in counter.
  1255. NEXT_COUNT:    CWD                             ;Zero in high half.
  1256.                DIV     BX                      ;Divide by ten.
  1257.                ADD     DL,"0"                  ;Convert to ASCII.
  1258.                PUSH    DX                      ;Save results.
  1259.                INC     CX                      ;Also increment count.
  1260.                OR      AX,AX                   ;Are we done?
  1261.                JNZ     NEXT_COUNT              ;Continue until zero.
  1262. NEXT_NUMBER:   POP     AX                      ;Retrieve numbers.
  1263.                STOSB
  1264.                LOOP    NEXT_NUMBER
  1265.                RET
  1266.  
  1267. ;----------------------------------------------;
  1268. SCAN_DAY:      CALL    SCAN_APP                ;Find appointments.
  1269.                MOV     AL,DAY_CAL              ;Store small box char.
  1270.                CALL    STORE_BLOCKS            ; if appointment found.
  1271.                MOV     AX,YEAR_CAL
  1272.                CMP     AX,YEAR_TODAY
  1273.                JNZ     SCAN_DAY_END
  1274.                MOV     AX,DAY_MON_CAL
  1275.                CMP     AX,DAY_MON_TODAY
  1276.                JNZ     SCAN_DAY_END
  1277.                CALL    STORE_ALARMS            ;Store alarm if today.
  1278. SCAN_DAY_END:  RET
  1279.  
  1280. ;----------------------------------------------;
  1281. SCAN_APP:      PUSH    BP
  1282.                MOV     SI,OFFSET WORK_SPACE    ;Spaces in work space.
  1283.                MOV     AL,SPACE
  1284.                MOV     BP,OFFSET APP_LEFT_START   ;Scan appointments for
  1285.                MOV     CX,2                       ; non-space chars.
  1286. NEXT_COL:      PUSH    CX
  1287.                MOV     DX,APP_HEIGHT
  1288. NEXT_DAY:      MOV     DI,BP
  1289.                MOV     CX,APP_LEN
  1290.                XOR     AH,AH                   ;Mark with zero if no app.
  1291.                REP     SCASB
  1292.                JZ      TEMP_APP
  1293.                INC     AH                      ;Else, mark with one for alarm.
  1294. TEMP_APP:      MOV     [SI],AH
  1295.                INC     SI
  1296.                ADD     BP,APP_WIDTH
  1297.                DEC     DX
  1298.                JNZ     NEXT_DAY
  1299.                MOV     BP,OFFSET APP_RIGHT_START
  1300.                POP     CX
  1301.                LOOP    NEXT_COL
  1302.                POP     BP
  1303.                RET
  1304.  
  1305. ;----------------------------------------------;
  1306. ; INPUT: AL = Calendar day.
  1307. STORE_BLOCKS:  DEC     AL
  1308.                CBW
  1309.                MOV     CL,3
  1310.                SHL     AX,CL
  1311.                MOV     DI,AX
  1312.                ADD     DI,OFFSET APPOINTMENT_BLOCKS
  1313.                MOV     SI,OFFSET WORK_SPACE
  1314.                MOV     CX,2
  1315. NEXT_SET:      PUSH    CX
  1316.                MOV     DX,APP_HEIGHT / 2
  1317. NEXT_BLOCK2:   LODSW
  1318.                OR      AX,AX
  1319.                MOV     AL,SPACE                ;Store a space if no appointment.
  1320.                JZ      STORE_BLOCK
  1321.                MOV     AL,"■"                  ;Else, store little block char.
  1322. STORE_BLOCK:   STOSB
  1323.                DEC     DX
  1324.                JNZ     NEXT_BLOCK2
  1325.                ADD     DI,(BLOCK_COUNT / 2) - 8
  1326.                POP     CX
  1327.                LOOP    NEXT_SET
  1328.                RET
  1329.  
  1330. ;----------------------------------------------;
  1331. ALARMS         DB      APP_HEIGHT * 2 DUP (0)
  1332. WORK_SPACE     DB      APP_HEIGHT * 2 DUP (?)
  1333.  
  1334. STORE_ALARMS:  MOV     SI,OFFSET WORK_SPACE    ;Copy results of work space
  1335.                MOV     DI,OFFSET ALARMS        ; into alarm array.
  1336.                MOV     CX,SIZE ALARMS / 2
  1337.                REP     MOVSW
  1338.                RET
  1339.  
  1340. ;----------------------------------------------;
  1341. TODAY_FLAG     EQU     001B                    ;Data applies to today.
  1342. CAL_FLAG       EQU     010B                    ;Data applies to calendar.
  1343. APP_FLAG       EQU     100B                    ;Data applies to appointment.
  1344.  
  1345. READ_DATA:     MOV     DI,OFFSET APPOINTMENT_BLOCKS
  1346.                MOV     CX,BLOCK_COUNT / 2
  1347.                MOV     AX,SPACE SHL 8 + SPACE
  1348.                REP     STOSW                   ;Spaces in Appointment blocks.
  1349.  
  1350.                MOV     BP,APP_HEIGHT
  1351.                MOV     BX,APP_LEN
  1352.                MOV     DI,OFFSET APP_LEFT_START
  1353. NEXT_BLANK:    MOV     CX,BX
  1354.                REP     STOSB
  1355.                ADD     DI,APP_COL_SPACE
  1356.                MOV     CX,BX
  1357.                REP     STOSB                   ;Spaces in Appointment book.
  1358.                ADD     DI,APP_ROW_SPACE
  1359.                DEC     BP
  1360.                JNZ     NEXT_BLANK
  1361.  
  1362.                MOV     BP,3
  1363.                MOV     BX,NOTE_LEN
  1364.                MOV     DI,OFFSET NOTEPAD
  1365. NEXT_PAD:      MOV     CX,BX
  1366.                REP     STOSB                   ;Spaces in Notepad.
  1367.                ADD     DI,APP_NOTE_SPACE
  1368.                DEC     BP
  1369.                JNZ     NEXT_PAD
  1370.  
  1371.                MOV     DI,OFFSET ALARMS
  1372.                MOV     CX,SIZE ALARMS / 2
  1373.                REP     STOSW                   ;Spaces in Alarms.
  1374.  
  1375.                CALL    OPEN_TSR                ;Open data file.
  1376.                JBE     READ_DONE               ;If none, then done.
  1377.  
  1378. NEXT_READ:     CALL    READ_DATE               ;Read the date.
  1379.                JBE     READ_FAILED
  1380.                OR      AX,AX
  1381.                JZ      READ_END
  1382.  
  1383.                XOR     BP,BP                   ;Initialize date flag.
  1384.                CMP     CX,YEAR_TODAY           ;Data same day/month/year
  1385.                JNZ     CK_YEAR_CAL             ; as today?
  1386.                CMP     DX,DAY_MON_TODAY
  1387.                JNZ     CK_YEAR_CAL
  1388.                OR      BP,TODAY_FLAG           ;If yes, today.
  1389.  
  1390. CK_YEAR_CAL:   CMP     CX,YEAR_CAL             ;Same as day/month/year
  1391.                JNZ     CK_READ                 ; as calendar?
  1392.                CMP     DX,DAY_MON_CAL
  1393.                JNZ     CK_MON_CAL
  1394.                OR      BP,CAL_FLAG OR APP_FLAG ;If yes, then applies to
  1395.                JMP     SHORT DO_READ           ; calendar and appointment.
  1396.  
  1397. CK_MON_CAL:    CMP     DH,MONTH_CAL            ;Same as month/year only.
  1398.                JNZ     CK_READ
  1399.                OR      BP,CAL_FLAG             ;If yes, applies to calendar.
  1400.  
  1401. CK_READ:       OR      BP,BP                   ;Does data apply to anything?
  1402.                JNZ     DO_READ
  1403.                CALL    NEXT_RECORD             ;If no, bump file pointer
  1404.                JBE     READ_FAILED             ; to next record.
  1405.                JMP     NEXT_READ
  1406.  
  1407. DO_READ:       CALL    READ_APP                ;If applies, read in the data.
  1408.                JBE     READ_FAILED
  1409.  
  1410.                TEST    BP,APP_FLAG             ;Apply to appointments?
  1411.                JZ      CK_TODAY_CAL
  1412.                CALL    MOVE_APP                ;If yes, move data into app.
  1413.  
  1414. CK_TODAY_CAL:  CALL    SCAN_DTA                ;Scan the data for appointments.
  1415.                TEST    BP,TODAY_FLAG           ;Does it apply to today.
  1416.                JZ      CK_MON_CAL2
  1417.                CALL    STORE_ALARMS            ;If yes, store alarms.
  1418.  
  1419. CK_MON_CAL2:   TEST    BP,CAL_FLAG             ;Apply to calendar?
  1420.                JZ      NEXT_READ
  1421.                MOV     AL,BYTE PTR DTA.DATE_BINARY + 2
  1422.                CALL    STORE_BLOCKS            ;If yes, store small block chars.
  1423.                JMP     NEXT_READ
  1424.  
  1425. READ_END:      MOV     AH,3EH                  ;Close data file.
  1426.                CALL    INT21_IO
  1427. READ_DONE:     RET
  1428.  
  1429. READ_FAIL:     CALL    FAILED                  ;If failed, display message.
  1430.                RET
  1431. READ_FAILED:   CALL    FAILED_CLOSE
  1432.                RET
  1433.  
  1434. ;----------------------------------------------;
  1435. SCAN_DTA:      PUSH    BP
  1436.                MOV     SI,OFFSET WORK_SPACE
  1437.                MOV     AL,SPACE
  1438.                MOV     BP,OFFSET DTA.APPOINT_TEXT
  1439.                MOV     CX,2
  1440. NEXT_DTA:      PUSH    CX
  1441.                MOV     DX,APP_HEIGHT           ;Scan data read off disk
  1442. NEXT_DTA2:     MOV     DI,BP                   ; and store a 1 in work space
  1443.                MOV     CX,APP_LEN              ; if non-space char.
  1444.                XOR     AH,AH
  1445.                REP     SCASB
  1446.                JZ      TEMP_APP2
  1447.                INC     AH
  1448. TEMP_APP2:     MOV     [SI],AH
  1449.                INC     SI
  1450.                ADD     BP,APP_LEN * 2
  1451.                DEC     DX
  1452.                JNZ     NEXT_DTA2
  1453.                MOV     BP,OFFSET DTA.APPOINT_TEXT + APP_LEN
  1454.                POP     CX
  1455.                LOOP    NEXT_DTA
  1456.                POP     BP
  1457.                RET
  1458.  
  1459. ;----------------------------------------------;
  1460. MOVE_APP:      MOV     SI,OFFSET DTA.APPOINT_TEXT
  1461.                MOV     DI,OFFSET APP_LEFT_START
  1462.                MOV     DX,APP_HEIGHT
  1463. NEXT_MOVE:     MOV     CX,APP_LEN
  1464.                REP     MOVSB                   ;Move DTA appointments into
  1465.                ADD     DI,APP_COL_SPACE        ; screen app. storage space.
  1466.                MOV     CX,APP_LEN
  1467.                REP     MOVSB
  1468.                ADD     DI,APP_ROW_SPACE
  1469.                DEC     DX
  1470.                JNZ     NEXT_MOVE
  1471.  
  1472.                MOV     SI,OFFSET DTA.NOTEPAD_TEXT
  1473.                MOV     DI,OFFSET NOTEPAD       ;Move DTA Notepad into
  1474.                MOV     CX,NOTEPAD_LEN          ; screen Notepad space.
  1475.                REP     MOVSB
  1476.                RET
  1477.  
  1478. ;***************************************************************************;
  1479. APP_BOUNDS     STRUC                           ;Cursor bounds in 3 sections.
  1480. COL_HOME       DB      ?
  1481. COL_END        DB      ?
  1482. ROW_HOME       DB      ?
  1483. ROW_END        DB      ?
  1484. CURSOR         DW      ?
  1485. APP_BOUNDS     ENDS
  1486.  
  1487. APP_LEFT       EQU     0
  1488. APP_RIGHT      EQU     SIZE APP_BOUNDS
  1489. APP_NOTE       EQU     APP_RIGHT + SIZE APP_BOUNDS
  1490. APP_INDEX      DW      APP_LEFT                ;Section index.
  1491.  
  1492. A_LEFT_CURSOR  EQU     4 SHL 8 + 12            ;Home cursor positions.
  1493. A_RIGHT_CURSOR EQU     4 SHL 8 + 48
  1494. N_ROW          EQU     4 + APP_HEIGHT + 1
  1495. A_NOTE_CURSOR  EQU     N_ROW SHL 8 + 4
  1496.  
  1497. BOUNDS         LABEL   BYTE
  1498. A_LEFT  APP_BOUNDS < 12, 12 + APP_LEN, 4, 4 + APP_HEIGHT - 1, A_LEFT_CURSOR >
  1499. A_RIGHT APP_BOUNDS < 48, 48 + APP_LEN, 4, 4 + APP_HEIGHT - 1, A_RIGHT_CURSOR >
  1500. A_NOTE  APP_BOUNDS <4,4+NOTE_LEN,N_ROW,4+APP_HEIGHT+NOTE_HEIGHT,A_NOTE_CURSOR >
  1501.  
  1502. APP_CURSOR     LABEL   WORD
  1503. APP_CUR_COL    DB      12                      ;Appointment cursor position.
  1504. APP_CUR_ROW    DB       4
  1505.  
  1506. REPAINT_FLAG   DB      1                       ; 1 = Repaint the screen.
  1507.  
  1508.  
  1509. ATABLE         DB  3CH,        3DH,    3EH,    3FH,       40H,       59H
  1510.                DB  63H,        4BH,    4DH,    48H,       50H,       47H
  1511.                DB  4FH,        49H,    51H,    84H,       76H,       77H
  1512.                DB  75H,        73H,    74H,    0FH,       53H
  1513. ATABLE_LEN     EQU     $ - ATABLE
  1514.                DW  SAVE,       ATODAY, PPURGE, PRINT,     CLEAR,     SHIFT_CLEAR
  1515.                DW  CTRL_CLEAR, ALEFT,  ARIGHT, AUP,       ADOWN,     AHOME
  1516.                DW  AEND,       APGUP,  APGDN,  ACTRLPGUP, ACTRLPGDN, ACTRLHOME
  1517.                DW  ACTRLEND,   AHOME,  AEND,   SHIFT_TAB, ADEL
  1518.  
  1519. APPOINTMENT:   CALL    CK_DATE                 ;Check if date changed.
  1520.                CMP     REPAINT_FLAG,1
  1521.                JNZ     NEXT_APPOINT
  1522.  
  1523.                MOV     SI,OFFSET APP_MENU      ;Display appointment screen.
  1524.                CALL    POP_MENU
  1525.                MOV     REPAINT_FLAG,0
  1526.  
  1527. NEXT_APPOINT:  MOV     DX,APP_CURSOR
  1528.                CALL    SET_CURSOR
  1529.                CALL    GETKEY                  ;Get a keystroke.
  1530.                CMP     EXIT_FLAG,1             ;Exit if hotkey.
  1531.                JZ      APPOINT_END
  1532.                CMP     AL,ESC_SCAN             ;Back to calendar if Esc.
  1533.                JNZ     APP_DISPATCH
  1534.                MOV     STATE,OFFSET CALENDAR
  1535.                JMP     SHORT APPOINT_END
  1536. APP_DISPATCH:  CALL    CALC_APP_ADDR           ;Get cursor bounds.
  1537.                MOV     BP,APP_INDEX
  1538.                MOV     BX,WORD PTR BOUNDS[BP]
  1539.                OR      AH,AH                   ;Extended scan code?
  1540.                JZ      GOT_DISPATCH
  1541.                CALL    CK_ENTRY
  1542.                JMP     NEXT_APPOINT
  1543.  
  1544. GOT_DISPATCH:  MOV     DI,OFFSET ATABLE
  1545.                MOV     CX,ATABLE_LEN
  1546.                CALL    DISPATCH
  1547.                CMP     EXIT_FLAG,1
  1548.                JNZ     APPOINTMENT
  1549. APPOINT_END:   MOV     REPAINT_FLAG,1          ;Flag to repaint screen.
  1550.                CALL    PERMANENT               ;Check for changes.
  1551.                CALL    SCAN_DAY                ;Scan appointments.
  1552.                RET
  1553.  
  1554. ;----------------------------------------------;
  1555. ; INPUT:  DX = Cursor address; OUTPUT: SI -> Start of row.
  1556. CALC_APP_ADDR: PUSH    AX
  1557.                MOV     CX,DX
  1558.                SUB     CH,4                    ;Appointments start on line 4.
  1559.                MOV     AX,APP_WIDTH
  1560.                MUL     CH
  1561.                MOV     SI,AX
  1562.                XOR     CH,CH
  1563.                ADD     SI,CX
  1564.                ADD     SI,OFFSET APP_START
  1565.                POP     AX
  1566.                RET
  1567.  
  1568. ;----------------------------------------------;
  1569. ; INPUT: SI -> appointments; DX=Cursor; BP=APP_INDEX; BH=COL_END; BL=COL_HOME
  1570.  
  1571. CK_ENTRY:      XCHG    AH,AL
  1572.                CMP     AL,TAB                  ;Tab?
  1573.                JNZ     CK_BACKSPACE
  1574. SHIFT_TAB:     MOV     CX,SIZE APP_BOUNDS
  1575.                MOV     BX,BP                   ;Save index.
  1576.                MOV     AH,2
  1577.                INT     16H                     ;Get shift status.
  1578.                TEST    AL,11B                  ;Left or Right Shift?
  1579.                JZ      DO_TAB
  1580.                NEG     CX
  1581. DO_TAB:        MOV     AX,APP_NOTE
  1582.                ADD     BP,CX
  1583.                JNS     CK_HIGH
  1584.                MOV     BP,AX
  1585. CK_HIGH:       CMP     BP,AX
  1586.                JBE     NEW_FIELD
  1587.                XOR     BP,BP
  1588. NEW_FIELD:     MOV     APP_INDEX,BP            ;New section.
  1589.                MOV     BOUNDS.CURSOR[BX],DX    ;Save current cursor position.
  1590.                MOV     DX,BOUNDS.CURSOR[BP]    ;Get new cursor position.
  1591.                JMP     SHORT ENTRY_UPDATE
  1592.  
  1593. CK_BACKSPACE:  CMP     AL,8                    ;Backspace?
  1594.                JNZ     CK_PAD_CR
  1595.                CMP     DL,BL
  1596.                JZ      ENTRY_END
  1597.                DEC     SI                      ;Move back one space.
  1598.                DEC     DL
  1599.                MOV     APP_CURSOR,DX           ;Save cursor position.
  1600.                CALL    ADEL                    ;Delete that character.
  1601.                JMP     SHORT ENTRY_END
  1602.  
  1603. CK_PAD_CR:     CMP     AL,CR                   ;Carriage return?
  1604.                JNZ     APP_ASCII
  1605.                MOV     DL,BL
  1606.                CMP     DH,BOUNDS.ROW_END[BP]   ;Move to start of line.
  1607.                JZ      ENTRY_UPDATE
  1608.                INC     DH                      ;Next row if not at bottom.
  1609.                JMP     SHORT ENTRY_UPDATE
  1610.  
  1611. APP_ASCII:     CMP     AL,SPACE                ;Text character?
  1612.                JB      ENTRY_END
  1613.                INC     DL                      ;Next column.
  1614.                SUB     BH,DL
  1615.                JC      ENTRY_END               ;If last column, ignore.
  1616.                JZ      STORE_APP               ;If next to last column, store.
  1617.                MOV     CL,BH
  1618.                XOR     CH,CH                   
  1619.                ADD     SI,CX
  1620.                MOV     DI,SI
  1621.                DEC     SI
  1622.                STD
  1623.                REP     MOVSB                   ;Else, insert mode so shove
  1624.                CLD                             ; everything in front up one.
  1625.                INC     SI
  1626. STORE_APP:     MOV     [SI],AL                 ;Store character.
  1627.  
  1628. ENTRY_CHANGE:  MOV     MODIFY_FLAG,1           ;Flag that change made.
  1629. ENTRY_UPDATE:  MOV     APP_CURSOR,DX           ;Store new cursor position.
  1630.  
  1631.                CALL    DISPLAY_LINE            ;Display just that changed line
  1632.                                                ; for better response time.
  1633. ENTRY_END:     RET
  1634.  
  1635. ;----------------------------------------------;
  1636. ACTRLHOME:     MOV     DL,BL                   ;Beginning of field.
  1637.                JMP     SHORT DO_HOME
  1638.  
  1639. AHOME:         CMP     DL,BL                   ;Beginning of field unless
  1640.                MOV     DL,BL                   ; already there, then go
  1641.                JNZ     ENTRY_UPDATE            ; to section home.
  1642. DO_HOME:       MOV     DH,BOUNDS.ROW_HOME[BP]
  1643.                JMP     ENTRY_UPDATE
  1644.  
  1645. ACTRLEND:      MOV     DL,BH                   ;End of field
  1646.                JMP     SHORT DO_END
  1647.  
  1648. AEND:          CMP     DL,BH                   ;End of field unless
  1649.                MOV     DL,BH                   ; already there, then go
  1650.                JNZ     ENTRY_UPDATE            ; to section home.
  1651. DO_END:        MOV     DH,BOUNDS.ROW_END[BP]
  1652.                JMP     ENTRY_UPDATE
  1653.  
  1654. ALEFT:         CMP     DL,BL                   ;Left one space unless
  1655.                JNZ     DO_LEFT                 ; already column home.
  1656.                CMP     BP,APP_RIGHT
  1657.                JNZ     ENTRY_END
  1658.                MOV     APP_INDEX,APP_LEFT      ;If in col home of right section,
  1659.                SUB     DL,6                    ; go to left section.
  1660. DO_LEFT:       DEC     DL
  1661.                JMP     ENTRY_UPDATE
  1662.  
  1663. ARIGHT:        INC     DL                      ;Right on space unless
  1664.                CMP     DL,BH                   ; already column end.
  1665.                JBE     ENTRY_UPDATE
  1666.                CMP     BP,APP_LEFT
  1667.                JNZ     ENTRY_END
  1668.                MOV     APP_INDEX,APP_RIGHT     ;If in col end of left section,
  1669.                ADD     DL,6                    ; go to right section.
  1670.                JMP     ENTRY_UPDATE
  1671.  
  1672. ADOWN:         CMP     DH,BOUNDS.ROW_END[BP]   ;If at bottom, go and not
  1673.                JNZ     UPDATE_DOWN             ; in Notepad, go to Notepad.
  1674.                CMP     BP,APP_NOTE
  1675.                JZ      ENTRY_END
  1676.                INC     DH                      ;Else, next row.
  1677.                MOV     APP_INDEX,APP_NOTE
  1678. UPDATE_DOWN:   INC     DH
  1679.                JMP     ENTRY_UPDATE
  1680.  
  1681. AUP:           CMP     DH,BOUNDS.ROW_HOME[BP]  ;If in top row of NotePad
  1682.                JNZ     DO_UP                   ; go to either left or right
  1683.                CMP     BP,APP_NOTE             ; section.
  1684.                JNZ     ENTRY_END
  1685.                DEC     DH
  1686.                MOV     BP,APP_RIGHT
  1687.                CMP     DL,BOUNDS.COL_HOME[BP]
  1688.                JAE     UPDATE_UP
  1689.                MOV     BP,APP_LEFT
  1690.                MOV     BX,WORD PTR BOUNDS[BP]
  1691.                CMP     DL,BL
  1692.                JA      CK_UP_END
  1693.                MOV     DL,BL
  1694.                JMP     SHORT UPDATE_UP
  1695. CK_UP_END:     CMP     DL,BH
  1696.                JBE     UPDATE_UP
  1697.                MOV     DL,BH
  1698. UPDATE_UP:     MOV     APP_INDEX,BP
  1699. DO_UP:         DEC     DH                      ;Else, just decrement row.
  1700.                JMP     ENTRY_UPDATE
  1701.  
  1702. ADEL:          SUB     BH,DL                   ;Ignore if in last column.
  1703.                MOV     CL,BH
  1704.                XOR     CH,CH
  1705.                JCXZ    ADEL_END
  1706.                MOV     DI,SI
  1707.                INC     SI
  1708.                REP     MOVSB                   ;Else, move everything to right
  1709.                CALL    DISPLAY_LINE            ; of cursor left one space.
  1710.                MOV     MODIFY_FLAG,1
  1711. ADEL_END:      RET
  1712.  
  1713. ;----------------------------------------------;
  1714. ATODAY:        CALL    PERMANENT
  1715.                MOV     SI,YEAR_TODAY
  1716.                MOV     YEAR_CAL,SI             ;Go to today.
  1717.                MOV     DX,DAY_MON_TODAY
  1718.                MOV     DAY_MON_CAL,DX
  1719.                JMP     SHORT DAY_UPDATE
  1720.  
  1721. APGUP:         CALL    PERMANENT
  1722. PPGUP:         MOV     AL,-1                   ;Previous day.
  1723.                JMP     SHORT CK_DAY
  1724.  
  1725. APGDN:         CALL    PERMANENT
  1726. PPGDN:         MOV     AL,1                    ;Next day.
  1727. CK_DAY:        MOV     DL,DAY_CAL
  1728.                ADD     DL,AL
  1729.                JZ      NEW_MONTH
  1730.                CMP     DL,LAST_DAY             ;Past month bounds?
  1731.                JA      NEW_MONTH
  1732. UPDATE_MONTH:  MOV     DAY_CAL,DL              ;If no, OK.
  1733.                JMP     SHORT DAY_UPDATE
  1734.  
  1735. NEW_MONTH:     MOV     DAY_CAL,1               ;Move to new month.
  1736.                JA      PCTRLPGDN
  1737.                MOV     DAY_CAL,31
  1738.                JMP     SHORT PCTRLPGUP
  1739.  
  1740. ACTRLPGUP:     CALL    PERMANENT
  1741. PCTRLPGUP:     MOV     AX,-1                   ;Previous month.
  1742.                JMP     SHORT CK_MONTH
  1743.  
  1744. ACTRLPGDN:     CALL    PERMANENT
  1745. PCTRLPGDN:     MOV     AX,1                    ;Next month.
  1746. CK_MONTH:      MOV     DH,MONTH_CAL
  1747.                ADD     DH,AL
  1748.                JNZ     CK_MONTH2
  1749.                MOV     DH,12                   ;Past year bounds?
  1750.                JMP     SHORT CK_YEAR2
  1751. CK_MONTH2:     CMP     DH,12
  1752.                JBE     UPDATE_MONTH2
  1753.                MOV     DH,1
  1754.                JMP     SHORT CK_YEAR2
  1755. UPDATE_MONTH2: MOV     MONTH_CAL,DH
  1756.                JMP     SHORT DAY_UPDATE
  1757.  
  1758. CK_YEAR2:      MOV     MONTH_CAL,DH
  1759.                MOV     SI,YEAR_CAL
  1760.                ADD     SI,AX                   ;Next/Previous year.
  1761.                CMP     SI,10000
  1762.                JAE     DAY_END
  1763.                CMP     SI,1582                 ;Check bounds.
  1764.                JB      DAY_END
  1765.                MOV     YEAR_CAL,SI
  1766.  
  1767. DAY_UPDATE:    MOV     REPAINT_FLAG,1          ;Repaint the screen.
  1768. DAY_END:       RET
  1769.  
  1770. ;----------------------------------------------;
  1771. CLEAR:         MOV     DL,BL
  1772.                CALL    CALC_APP_ADDR
  1773.                MOV     DI,SI                   ;Appointment address line.
  1774.                MOV     CX,BX
  1775.                SUB     CH,CL
  1776.                MOV     CL,CH
  1777.                XOR     CH,CH
  1778.                MOV     AL,SPACE                ;Store spaces.
  1779.                REP     STOSB
  1780.                MOV     APP_CURSOR,DX           ;Home cursor.
  1781.                MOV     BOUNDS.CURSOR[BP],DX
  1782.                MOV     APP_INDEX,BP
  1783.                JMP     SHORT F6_END
  1784.  
  1785. SHIFT_CLEAR:   MOV     CX,WORD PTR BOUNDS.ROW_HOME[BP]
  1786.                MOV     DH,CH
  1787.                SUB     CH,CL
  1788.                MOV     CL,CH
  1789.                XOR     CH,CH
  1790.                INC     CX
  1791. NEXT_SHIFT_F6: PUSH    CX                      ;Rows in section.
  1792.                CALL    CLEAR                   ;Clear all rows.
  1793.                DEC     DH
  1794.                POP     CX
  1795.                LOOP    NEXT_SHIFT_F6
  1796.                JMP     SHORT F6_END
  1797.  
  1798. CTRL_CLEAR:    MOV     BP,APP_NOTE             ;Start with Notepad.
  1799.                MOV     CX,3                    ;Three sections to clear.
  1800. NEXT_CTRL_F6:  PUSH    CX
  1801.                MOV     BX,WORD PTR BOUNDS[BP]
  1802.                CALL    SHIFT_CLEAR             ;Clear section.
  1803.                SUB     BP,SIZE APP_BOUNDS
  1804.                POP     CX
  1805.                LOOP    NEXT_CTRL_F6
  1806.  
  1807. F6_END:        MOV     MODIFY_FLAG,1
  1808.                MOV     REPAINT_FLAG,1
  1809.                RET
  1810.  
  1811. ;----------------------------------------------;
  1812. ; INPUT: DX = Cursor position; SI -> Storage.
  1813. DISPLAY_LINE:  MOV     AL,DH
  1814.                SUB     AL,4                    ;Calc start of app. line
  1815.                MOV     CX,APP_WIDTH            ; to display.
  1816.                MUL     CL
  1817.                MOV     SI,AX
  1818.                ADD     SI,OFFSET APP_START
  1819.                MOV     AL,DH
  1820.                XOR     AH,AH
  1821.                CALL    CALC_ADDR               ;Calc corresponding display
  1822.                PUSH    ES                      ; address.
  1823.                MOV     DX,STATUS_REG
  1824.                MOV     ES,VIDEO_SEG
  1825.                MOV     BH,COLOR.B
  1826.                DEC     CX
  1827. NEXT_LINE:     LODSB                           ;Display line.
  1828.                CALL    WRITE_SCREEN
  1829.                LOOP    NEXT_LINE
  1830.                POP     ES
  1831.                RET
  1832.  
  1833. ;***************************************************************************;
  1834. DATEONLY_FLAG  DB      ?                       ; =1 if purge date only.
  1835.  
  1836. PTABLE         DB  49H,   51H,   84H,       76H,       3DH
  1837. PTABLE_LEN     EQU     $ - PTABLE
  1838.                DW  PPGUP, PPGDN, PCTRLPGUP, PCTRLPGDN, CTODAY
  1839.  
  1840. PPURGE:        PUSH    YEAR_CAL                ;Preserve calendar variables.
  1841.                PUSH    DAY_MON_CAL
  1842.                PUSH    YEAR_CUR
  1843.                PUSH    DAY_MON_CUR
  1844.                CALL    HIDE_CURSOR
  1845.  
  1846. NEXT_F4:       CALL    FIRSTDAY                ;Store purge date in window.
  1847.                MOV     AX,1
  1848.                CALL    CALC_ADDR
  1849.                ADD     DI,9 * 2
  1850.                MOV     SI,OFFSET PURGE_MSG
  1851.                CALL    POP_WINDOW              ;Display purge window.
  1852.                CALL    GETKEY                  ;Get a keystroke.
  1853.                JC      F4_DONE                 ;If Esc, exit.
  1854.                MOV     DATEONLY_FLAG,0         ;Assume F7.
  1855.                CMP     AL,F7_SCAN              ;Is it F7?
  1856.                JZ      CK_APPEND
  1857.                MOV     DATEONLY_FLAG,1         ;Assume F8.
  1858.                CMP     AL,F8_SCAN              ;Is it F8.
  1859.                JZ      CK_APPEND
  1860.  
  1861.                MOV     DI,OFFSET PTABLE
  1862.                MOV     CX,PTABLE_LEN
  1863.                CALL    DISPATCH
  1864.                CMP     EXIT_FLAG,1
  1865.                JNZ     NEXT_F4
  1866.                JMP     SHORT F4_DONE
  1867.  
  1868. F4_END:        MOV     REREAD_FLAG,1
  1869.  
  1870. F4_DONE:       POP     DAY_MON_CUR             ;Restore calendar variables.
  1871.                POP     YEAR_CUR
  1872.                POP     DAY_MON_CAL
  1873.                POP     YEAR_CAL
  1874.                CALL    FIRSTDAY                ;Fix calendar and appointment
  1875.                MOV     REPAINT_FLAG,1          ; ASCII date; repaint screen.
  1876.                RET
  1877.  
  1878. ;----------------------------------------------;
  1879. ARCHIVE_FLAG   DB      0                       ; =1 if archive.
  1880. READ_HANDLE    DW      -1                      ;File handles.
  1881. WRITE_HANDLE   DW      -1
  1882. ARCHIVE_HANDLE DW      -1
  1883.  
  1884. CK_APPEND:     MOV     ARCHIVE_FLAG,0          ;Reset archive flag.
  1885.                MOV     AX,6
  1886.                CALL    CALC_ADDR
  1887.                ADD     DI,40 * 2
  1888.                MOV     SI,OFFSET ARCHIVE_MSG
  1889.                CALL    POP_WINDOW              ;Display archive window.
  1890.  
  1891. NEXT_APPEND:   CALL    GETKEY                  ;Get a keystroke.
  1892.                JC      F4_DONE
  1893.                CMP     AL,N_SCAN
  1894.                JZ      DO_PURGE
  1895.                CMP     AL,Y_SCAN               ;"Y" = archive.
  1896.                JNZ     NEXT_APPEND
  1897.                MOV     ARCHIVE_FLAG,1
  1898.  
  1899. DO_PURGE:      CALL    OPEN_TSR                ;Open data file for reading.
  1900.                JBE     F4_DONE                 ;If doesn't exist, nothing to
  1901.                MOV     READ_HANDLE,AX          ; purge; else save handle.
  1902.  
  1903.                MOV     AX,8
  1904.                CALL    CALC_ADDR
  1905.                ADD     DI,50 * 2
  1906.                MOV     SI,OFFSET PURGING_MSG
  1907.                CALL    POP_WINDOW              ;Display purging window.
  1908.  
  1909.                CALL    OPEN_TSR                ;Open data file for writing.
  1910.                JBE     PURGE_FAIL
  1911.                MOV     WRITE_HANDLE,AX
  1912.                CMP     ARCHIVE_FLAG,1          ;Archive?
  1913.                JNZ     NEXT_PURGE
  1914.                MOV     DX,OFFSET ARCHIVE_PATH
  1915.                CALL    OPEN_TSR2               ;If yes, open archive file.
  1916.                JA      SAVE_HANDLE2
  1917.                XOR     CX,CX
  1918.                MOV     AH,3CH                  ;If doesn't exist, create one.
  1919.                CALL    INT21_IO
  1920.                JBE     PURGE_FAIL
  1921. SAVE_HANDLE2:  MOV     ARCHIVE_HANDLE,AX
  1922.                MOV     BX,AX
  1923.                XOR     CX,CX
  1924.                XOR     DX,DX
  1925.                MOV     AX,4202H                ;Move to end of archive file
  1926.                CALL    INT21_IO                ; to append.
  1927.                JA      NEXT_PURGE
  1928.  
  1929. PURGE_FAIL:    CALL    CLOSE_HANDLES           ;Failure exit.
  1930.                CALL    FAILED
  1931.                JMP     F4_END
  1932.  
  1933.  
  1934. NEXT_PURGE:    MOV     CX,SIZE DATA_RECORD
  1935.                MOV     BX,READ_HANDLE
  1936.                CALL    READ_RECORD             ;Read a record.
  1937.                JBE     PURGE_FAIL
  1938.                OR      AX,AX                   ;EOF?
  1939.                JZ      PURGE_DONE
  1940.                CMP     DATEONLY_FLAG,1         ;Purge everything < purge date.
  1941.                JZ      CK_THISDATE
  1942.                CMP     CX,YEAR_CAL             ;If no, year < purge date?
  1943.                JB      CK_ARCHIVE              ;If yes, purge.
  1944.                JA      WRITE_DATA              ;If above write data back.
  1945.                CMP     DX,DAY_MON_CAL          ;Else, day/month < purge date?
  1946.                JB      CK_ARCHIVE              ;Is yes, purge.
  1947.                JMP     SHORT WRITE_DATA        ;Else, write data back.
  1948.  
  1949. CK_THISDATE:   CMP     CX,YEAR_CAL             ;Purge date only.
  1950.                JNZ     WRITE_DATA
  1951.                CMP     DX,DAY_MON_CAL
  1952.                JZ      CK_ARCHIVE
  1953.  
  1954. WRITE_DATA:    MOV     DX,OFFSET DTA           ;Write data back to data file.
  1955.                MOV     CX,SIZE DATA_RECORD
  1956.                MOV     BX,WRITE_HANDLE
  1957.                CALL    WRITE_RECORD
  1958.                JBE     PURGE_FAIL
  1959.                JMP     NEXT_PURGE
  1960.  
  1961. CK_ARCHIVE:    CMP     ARCHIVE_FLAG,1          ;Archive?
  1962.                JNZ     NEXT_PURGE
  1963.                CALL    ARCHIVE
  1964.                JBE     PURGE_FAIL
  1965.                JMP     NEXT_PURGE
  1966.  
  1967. PURGE_DONE:    MOV     BX,WRITE_HANDLE
  1968.                XOR     CX,CX                   ;Truncate data file to
  1969.                CALL    WRITE_RECORD            ; current pointer location.
  1970.                JBE     PURGE_FAIL
  1971.                CALL    CLOSE_HANDLES           ;Close all file handles.
  1972.                JMP     F4_END
  1973.  
  1974. ;----------------------------------------------;
  1975. CLOSE_HANDLES: MOV     BX,READ_HANDLE
  1976.                CALL    CLOSE_SAVE
  1977.                MOV     BX,WRITE_HANDLE
  1978.                CALL    CLOSE_SAVE
  1979.                MOV     BX,ARCHIVE_HANDLE
  1980.                CALL    CLOSE_SAVE
  1981.                RET
  1982.  
  1983. ;----------------------------------------------;
  1984. ARCHIVE:       MOV     BX,ARCHIVE_HANDLE       
  1985.                MOV     DX,OFFSET DTA.DATE_ASCII
  1986.                MOV     CX,SIZE DATE_ASCII      ;Write date in ASCII.
  1987.                CALL    WRITE_RECORD
  1988.                JBE     ARCHIVE_END
  1989.                MOV     DTA,CR
  1990.                MOV     DTA + 1,LF
  1991.                CALL    WRITE_CRLF              ;Add Carriage return/linefeed.
  1992.                JBE     ARCHIVE_END
  1993.  
  1994.                MOV     BP,APP_HEIGHT           
  1995.                MOV     SI,OFFSET APP_START + 5
  1996.                MOV     DI,OFFSET DTA.APPOINT_TEXT
  1997. NEXT_ARCHIVE:  MOV     DX,SI
  1998.                MOV     CX,8
  1999.                CALL    WRITE_RECORD            ;Write times.
  2000.                JBE     ARCHIVE_END
  2001.                MOV     DX,DI
  2002.                MOV     CX,APP_LEN
  2003.                CALL    WRITE_RECORD            ;Write appointments.
  2004.                JBE     ARCHIVE_END
  2005.                ADD     SI,36
  2006.                ADD     DI,APP_LEN
  2007.                MOV     DX,SI
  2008.                MOV     CX,10
  2009.                CALL    WRITE_RECORD
  2010.                JBE     ARCHIVE_END
  2011.                MOV     DX,DI
  2012.                MOV     CX,APP_LEN
  2013.                CALL    WRITE_RECORD
  2014.                JBE     ARCHIVE_END
  2015.                CALL    WRITE_CRLF
  2016.                JBE     ARCHIVE_END
  2017.                ADD     SI,45
  2018.                ADD     DI,APP_LEN
  2019.                DEC     BP
  2020.                JNZ     NEXT_ARCHIVE
  2021.  
  2022.                MOV     BP,3
  2023.                MOV     SI,OFFSET DTA.NOTEPAD_TEXT
  2024. NEXT_NOTEPAD:  MOV     DX,SI
  2025.                MOV     CX,73
  2026.                CALL    WRITE_RECORD            ;Write Notepad.
  2027.                JBE     ARCHIVE_END
  2028.                CALL    WRITE_CRLF
  2029.                JBE     ARCHIVE_END
  2030.                ADD     SI,APP_WIDTH
  2031.                DEC     BP
  2032.                JNZ     NEXT_NOTEPAD
  2033.  
  2034.                OR      AL,1                    ;Indicate successful.
  2035.  
  2036. ARCHIVE_END:   RET
  2037.  
  2038. WRITE_CRLF:    MOV     DX,OFFSET DTA
  2039.                MOV     CX,2
  2040.                CALL    WRITE_RECORD
  2041.                RET
  2042.  
  2043. ;***************************************************************************;
  2044. SETUP_CODES    DB      10 DUP (0), 0           ;Printer setup codes.
  2045.  
  2046. PRINT:         CALL    HIDE_CURSOR
  2047.                MOV     AX,1
  2048.                CALL    CALC_ADDR
  2049.                ADD     DI,30 * 2
  2050.                MOV     SI,OFFSET PRINTER_NO
  2051.                CALL    POP_WINDOW              ;Display printer selection window.
  2052.  
  2053. NF5_KEY:       CALL    GETKEY                  ;Get a keystroke.
  2054.                JC      NF5_END                 ;If Esc, exit.
  2055.                XCHG    AH,AL
  2056.                SUB     AL,"1"                  ;Adjust to binary.
  2057.                JC      NF5_KEY
  2058.                CMP     AL,1
  2059.                JA      NF5_KEY
  2060.                MOV     DL,AL
  2061.                XOR     DH,DH
  2062.  
  2063.                PUSH    DX
  2064.                MOV     SI,OFFSET CAL_MENU
  2065.                CMP     STATE,OFFSET CALENDAR
  2066.                JZ      FIX_SCREEN
  2067.                MOV     SI,OFFSET APP_MENU
  2068. FIX_SCREEN:    CALL    POP_MENU                ;Fix screen cause that's where
  2069.                                                ; we're getting our data.
  2070.                MOV     AX,1
  2071.                CALL    CALC_ADDR               ;Printing starts with row 1.
  2072.                MOV     BX,DI
  2073.                MOV     BP,24
  2074.                POP     DX
  2075.  
  2076.                MOV     SI,OFFSET SETUP_CODES   ;Send printer setup codes.
  2077. NEXT_SETUP:    LODSB
  2078.                OR      AL,AL
  2079.                JZ      NEXT_PRINT
  2080.                CALL    PRINT_IT
  2081.                JNC     NEXT_SETUP
  2082.                JMP     SHORT NF5_END
  2083.  
  2084. NEXT_PRINT:    MOV     SI,BX
  2085.                MOV     CX,80                   ;80 characters/line.
  2086. NEXT_PRINT2:   CALL    GET_CHAR
  2087.                CALL    PRINT_IT
  2088.                JC      NF5_END
  2089.                LOOP    NEXT_PRINT2
  2090.                CALL    PRINT_CRLF
  2091.                JC      NF5_END
  2092.                ADD     BX,CRT_WIDTH
  2093.                DEC     BP
  2094.                JNZ     NEXT_PRINT
  2095.                MOV     CX,9
  2096. NEXT_CRLF:     CALL    PRINT_CRLF
  2097.                JC      NF5_END
  2098.                LOOP    NEXT_CRLF
  2099. NF5_END:       MOV     REPAINT_FLAG,1
  2100.                RET
  2101.  
  2102. ;----------------------------------------------;
  2103. IBM_FLAG       DB      0                       ; If 1, use line drawing chars.
  2104. IBM_CHARS      DB      "╞╡│╪┬─╤═╧■┌"
  2105. EPSON_CHARS    DB      "||||--===*+"           ;Replacements for line chars.
  2106. CHARS_LEN      EQU     $ - EPSON_CHARS
  2107.  
  2108.  
  2109. PRINT_IT:      PUSH    AX
  2110.                MOV     AH,2
  2111.                INT     17H
  2112.                TEST    AH,00101001B            ;Printer ready?
  2113.                JNZ     NOT_READY
  2114.                TEST    AH,11111001B
  2115.                JNZ     DO_PRINT
  2116. NOT_READY:     POP     AX
  2117.                CALL    BEEP                    ;If no, beep and exit.
  2118.                STC
  2119.                JMP     SHORT PRINT_END
  2120. DO_PRINT:      POP     AX
  2121.                TEST    AL,80H                  ;High bit char?
  2122.                JZ      DO_PRINT2               ;If no, print as is.
  2123.                CMP     IBM_FLAG,1              ;Else, print line drawing?
  2124.                JZ      DO_PRINT2               ;If yes, print as is.
  2125.                MOV     DI,OFFSET IBM_CHARS     ;Else, replace with appropriate
  2126.                PUSH    CX                      ; text char.
  2127.                MOV     CX,CHARS_LEN
  2128.                REPNZ   SCASB
  2129.                POP     CX
  2130.                ADD     DI,CHARS_LEN - 1
  2131.                MOV     AL,[DI]
  2132.  
  2133. DO_PRINT2:     XOR     AH,AH                   ;Print via BIOS.
  2134.                INT     17H
  2135.                CLC
  2136. PRINT_END:     RET
  2137.  
  2138. ;----------------------------------------------;
  2139. PRINT_CRLF:    MOV     AL,CR
  2140.                CALL    PRINT_IT
  2141.                JC      CRLF_END
  2142.                MOV     AL,LF
  2143.                CALL    PRINT_IT
  2144. CRLF_END:      RET
  2145. ;**********************************************;
  2146. ;       S U B R O U T I N E S                  ;
  2147. ;**********************************************;
  2148. ;INPUT: AL = Scan code; DI -> Valid scan codes table; CX = length of table
  2149. DISPATCH:      PUSH    AX
  2150.                PUSH    DX
  2151.                PUSH    BP
  2152.                MOV     BP,CX
  2153.                MOV     DX,DI
  2154.                ADD     DX,CX
  2155.                REPNZ   SCASB                   ;Scan for match.
  2156.                JZ      DO_DISPATCH
  2157.                POP     BP
  2158.                POP     DX
  2159.                JMP     SHORT NO_DISPATCH
  2160. DO_DISPATCH:   SUB     BP,CX
  2161.                DEC     BP
  2162.                SHL     BP,1
  2163.                ADD     BP,DX
  2164.                MOV     DI,BP                   ;Calc address of subroutine.
  2165.                POP     BP
  2166.                POP     DX
  2167.                CALL    [DI]                    ;Process the command.
  2168. NO_DISPATCH:   CLC
  2169. DISPATCH_END:  POP     AX
  2170.                RET
  2171.  
  2172. ;----------------------------------------------;
  2173. PERMANENT:     CMP     MODIFY_FLAG,1           ;Any changes been made?
  2174.                JNZ     PERMANENT_END           ;If no, done.
  2175.                MOV     MODIFY_FLAG,0
  2176.                CALL    HIDE_CURSOR
  2177.                MOV     AX,10
  2178.                CALL    CALC_ADDR
  2179.                ADD     DI,25 * 2
  2180.                MOV     SI,OFFSET PERMANENT_MSG
  2181.                CALL    POP_WINDOW              ;Display "Changes to disk?"
  2182.  
  2183. QUERY:         CALL    GETKEY
  2184.                JC      PERMANENT_END
  2185.                CMP     AL,N_SCAN
  2186.                JZ      PERMANENT_END
  2187.                CMP     AL,Y_SCAN               ;If "Y", then save.
  2188.                JNZ     QUERY
  2189.                JMP     SHORT SAVE2
  2190.  
  2191. PERMANENT_END: RET
  2192.  
  2193. ;----------------------------------------------;
  2194. SAVE:          CALL    SAVE2                   ;Save appointments.
  2195.                JC      F2_END
  2196.                MOV     AX,1
  2197.                CALL    CALC_ADDR
  2198.                ADD     DI,2
  2199.                MOV     SI,OFFSET SAVED_MSG
  2200.                CALL    POP_WINDOW              ;Display saved message.
  2201.                CALL    PAUSE                   ;Pause for keystroke.
  2202. F2_END:        RET
  2203.  
  2204.  
  2205. SAVE2:         MOV     MODIFY_FLAG,0
  2206.                CALL    OPEN_TSR                ;Open data file.
  2207.                JNC     SAVE_HANDLE
  2208.                XOR     CX,CX                   ;If doesn't exist, create one.
  2209.                MOV     AH,3CH
  2210.                CALL    INT21_IO
  2211.                JBE     FAILED
  2212.                MOV     BX,AX
  2213.  
  2214. SAVE_HANDLE:   MOV     BP,AX
  2215.  
  2216. CK_EOF:        CALL    READ_DATE               ;Read date of data.
  2217.                JBE     FAILED_CLOSE
  2218.                OR      AX,AX                   ;EOF?
  2219.                JNZ     MATCH_DATE              ;If yes, append data.
  2220.                CALL    GET_SPACE
  2221.                JBE     FAILED_CLOSE
  2222.                CMP     BX,2                    ;At least two clusters free?
  2223.                MOV     BX,BP                   ;Retrieve file handle.
  2224.                JAE     ENOUGH_ROOM
  2225.                CALL    CLOSE_SAVE
  2226.                MOV     SI,OFFSET DISK_FULL_MSG
  2227.                JMP     SHORT FAILED_MSG
  2228.  
  2229. ENOUGH_ROOM:   CALL    WRITE_APP               ;Write the data.
  2230.                JMP     SHORT CLOSE_SAVE        ;Done.
  2231.  
  2232. MATCH_DATE:    CMP     CX,YEAR_CUR             ;Date of data on disk
  2233.                JNZ     NO_MATCH                ; match appointment date?
  2234.                CMP     DX,DAY_MON_CUR
  2235.                JZ      GOT_DATE                ;If yes, write over.
  2236. NO_MATCH:      CALL    NEXT_RECORD             ;Else, search next record.
  2237.                JBE     FAILED_CLOSE
  2238.                JMP     CK_EOF
  2239.  
  2240. GOT_DATE:      CALL    WRITE_APP2
  2241.                JBE     FAILED_CLOSE
  2242.  
  2243. CLOSE_SAVE:    MOV     AH,3EH                  ;Close data file.
  2244.                CALL    INT21_IO
  2245.                MOV     REPAINT_FLAG,1
  2246. SAVE_END:      RET
  2247.  
  2248. FAILED_CLOSE:  MOV     AH,3EH
  2249.                CALL    INT21_IO
  2250. FAILED:        MOV     SI,OFFSET PERMANENT_FAIL
  2251. FAILED_MSG:    MOV     AX,10
  2252.                CALL    CALC_ADDR
  2253.                ADD     DI,25 * 2
  2254.  
  2255.                CALL    POP_WINDOW              ;If failed, display failed
  2256.                CALL    FLUSH_KEY               ; message.
  2257.                XOR     AH,AH                   ;Pause.
  2258.                INT     16H
  2259.                MOV     REPAINT_FLAG,1
  2260.                STC
  2261.                RET
  2262.  
  2263. ;----------------------------------------------;
  2264. OPEN_TSR:      MOV     DX,OFFSET DATA_PATH
  2265. OPEN_TSR2:     MOV     AX,3D02H                ;Open data file for reading
  2266.                CALL    INT21_IO                ; and writing.
  2267.                MOV     BX,AX                   ;Filehandle.
  2268.                RET
  2269.  
  2270. ;----------------------------------------------;
  2271. ; OUTPUT: CX = Year; DH = Month; DL = Day
  2272. READ_DATE:     MOV     CX,SIZE DATE_BINARY
  2273. READ_RECORD:   MOV     DX,OFFSET DTA
  2274.                MOV     AH,3FH                  ;Read first four bytes.
  2275.                CALL    INT21_IO
  2276.                MOV     CX,WORD PTR DTA.DATE_BINARY      ;Return binary date.
  2277.                MOV     DX,WORD PTR DTA.DATE_BINARY + 2
  2278.                RET
  2279.  
  2280. ;----------------------------------------------;
  2281. GET_SPACE:     MOV     DL,BYTE PTR DATA_PATH
  2282.                SUB     DL,"A" - 1
  2283.                MOV     AH,36H                  ;See if room to tack on app.
  2284.                CALL    INT21_IO
  2285.                RET
  2286.  
  2287. ;----------------------------------------------;
  2288. NEXT_RECORD:   XOR     CX,CX
  2289.                MOV     DX,SIZE DATE_ASCII+SIZE APPOINT_TEXT+SIZE NOTEPAD_TEXT
  2290.                MOV     AX,4201H
  2291.                CALL    INT21_IO                ;Bump pointer to next record.
  2292.                RET
  2293.  
  2294. ;----------------------------------------------;
  2295. ; OUTPUT: CY = 1 OR ZF = 1 if write failed.
  2296. WRITE_APP:     MOV     DX,OFFSET YEAR_CUR      ;Write binary date.
  2297.                MOV     CX,SIZE DATE_BINARY
  2298.                CALL    WRITE_RECORD
  2299.                JBE     WRITE_APP_END
  2300.  
  2301. WRITE_APP2:    MOV     DX,OFFSET APP_DATE      ;Write ASCII date.
  2302.                MOV     CX,DATE_LEN
  2303.                CALL    WRITE_RECORD
  2304.                JBE     WRITE_APP_END
  2305.  
  2306.                MOV     SI,APP_HEIGHT           ;16 Rows.
  2307.                MOV     DI,OFFSET APP_LEFT_START
  2308.                MOV     CX,APP_LEN
  2309. NEXT_WRITE:    MOV     DX,DI
  2310.                CALL    WRITE_RECORD            ;Write appointments.
  2311.                JBE     WRITE_APP_END
  2312.                ADD     DX,APP_LEN + APP_COL_SPACE
  2313.                CALL    WRITE_RECORD
  2314.                JBE     WRITE_APP_END
  2315.                ADD     DI,APP_WIDTH
  2316.                DEC     SI
  2317.                JNZ     NEXT_WRITE
  2318.  
  2319. WRITE_NOTEPAD: MOV     DX,OFFSET NOTEPAD
  2320.                MOV     CX,NOTEPAD_LEN
  2321.                CALL    WRITE_RECORD            ;Write Notepad.
  2322.                JBE     WRITE_APP_END
  2323.                INC     SI                      ;Flag as successful.
  2324.                CLC
  2325. WRITE_APP_END: RET
  2326.  
  2327. WRITE_RECORD:  MOV     AH,40H                  ;DOS write.
  2328.                CALL    INT21_IO
  2329.                RET
  2330.  
  2331. ;----------------------------------------------;
  2332. READ_APP:      MOV     DX,OFFSET DTA.DATE_ASCII
  2333.                MOV     CX,SIZE DATE_ASCII+SIZE APPOINT_TEXT+SIZE NOTEPAD_TEXT
  2334.                MOV     AH,3FH
  2335.                CALL    INT21_IO                ;Read data record.
  2336.                RET
  2337.  
  2338. ;----------------------------------------------;
  2339. BEEP:          PUSH    AX
  2340.                PUSH    BX
  2341.                PUSH    CX
  2342.                PUSH    DX
  2343.                CALL    SETUP_BELL
  2344.  
  2345.                MOV     CX,1                    ;One timer tick.
  2346.                CALL    DELAY                   ;Wait till clock rolls over.
  2347.                CALL    TOGGLE_BELL
  2348.  
  2349.                MOV     CX,1                    ;Number of seconds.
  2350.                CALL    DELAY                   ;Delay seconds.
  2351.                CALL    RESET_BELL
  2352.                POP     DX
  2353.                POP     CX
  2354.                POP     BX
  2355.                POP     AX
  2356.                RET
  2357.  
  2358. SETUP_BELL:    MOV     BX,CS:NOTE
  2359.                XOR     AX,AX
  2360.                MOV     DX,12H                  ;120000h dividend constant.
  2361.                DIV     BX                      ; Divide to get
  2362.                MOV     BX,AX                   ; 8253 countdown.
  2363.                CALL    RESET_BELL
  2364.                MOV     AL,0B6H                 ;Channel 2 speaker functions.
  2365.                OUT     43H,AL                  ;8253 Mode Control.
  2366.                JMP     $+2                     ;IO delay.
  2367.                MOV     AX,BX                   ;Retrieve countdown.
  2368.                OUT     42H,AL                  ;Channel 2 LSB.
  2369.                JMP     $+2
  2370.                MOV     AL,AH                   ;Channel 2 MSB.
  2371.                OUT     42H,AL
  2372.                RET
  2373.  
  2374. RESET_BELL:    IN      AL,PORT_B               ;Port B.
  2375.                AND     AL,NOT 3                ;Turn off speaker.
  2376.                JMP     $+2
  2377.                OUT     PORT_B,AL
  2378.                RET
  2379.  
  2380. FLIP_BELL:     DEC     BELL_CNT
  2381.                JNZ     TOGGLE_BELL
  2382.                CALL    RESET_BELL
  2383.                CMP     PROGRAM_STATUS,0        ;Are we popped up.
  2384.                JNZ     FLIP_END                ;If yes, done.
  2385.                CMP     NOPOPUP_FLAG,1          ;User requested no-popup?
  2386.                JZ      FLIP_END                ;If yes, done.
  2387.                MOV     POPUP_FLAG,1            ;Else, try to popup.
  2388. FLIP_END:      MOV     BELL_FLAG,0             ;Reset bell flag.
  2389.                RET
  2390.  
  2391. TOGGLE_BELL:   IN      AL,PORT_B
  2392.                XOR     AL,3
  2393.                JMP     $+2
  2394.                OUT     PORT_B,AL
  2395.                RET
  2396.  
  2397. ;----------------------------------------------;
  2398. ; INPUT: CX = 1/18 seconds.                    ;
  2399. DELAY:         PUSH    DS                      ;Preserve data segment.
  2400.                MOV     AX,40H                  ;Point to BIOS data segment.
  2401.                MOV     DS,AX
  2402. NEXT_TICK:     MOV     AX,DS:[6CH]             ;Retrieve timer low.
  2403. NEXT_DELAY:    MOV     DX,DS:[6CH]             ;Retrieve timer low.
  2404.                CMP     DX,AX                   ;Have we timed out?
  2405.                JZ      NEXT_DELAY              ;If not, wait until timer tick.
  2406.                LOOP    NEXT_TICK
  2407.                POP     DS                      ;Restore data segment.
  2408.                RET
  2409.  
  2410. ;----------------------------------------------;
  2411. SAVE_SCREEN:   XOR     AX,AX                   ;Top left of screen.
  2412.                CALL    CALC_ADDR
  2413.                MOV     SI,AX
  2414.                MOV     DI,OFFSET WIN_SAVE      ;Storage space.
  2415.                MOV     CX,25
  2416.                MOV     BP,80
  2417.                CALL    DO_SAVE                 ;Save entire screen.
  2418.                RET
  2419.  
  2420. DO_SAVE:       PUSH    DS
  2421.                MOV     DX,STATUS_REG
  2422.                MOV     DS,VIDEO_SEG
  2423.  
  2424. NEXT_SAVE:     PUSH    CX
  2425.                PUSH    SI
  2426.                MOV     CX,BP
  2427. NEXT_SAVE2:    IN      AL,DX                   ;Get status.
  2428.                RCR     AL,1                    ;Is it low?
  2429.                JC      NEXT_SAVE2              ;If not, wait until it is.
  2430.                CLI                             ;No more interrupts.
  2431.  
  2432. HWAIT3:        IN      AL,DX                   ;Get status.
  2433.                RCR     AL,1                    ;Is it high?
  2434.                JNC     HWAIT3                  ;If no, wait until it is.
  2435.                MOVSW
  2436.                STI
  2437.                LOOP    NEXT_SAVE2
  2438.                POP     SI
  2439.                ADD     SI,CS:CRT_WIDTH         ;Next row.
  2440.                POP     CX
  2441.                LOOP    NEXT_SAVE
  2442.                POP     DS
  2443.                RET
  2444.  
  2445. ;----------------------------------------------;
  2446. RESTORE_SCREEN:XOR     AX,AX                   ;Top left of screen.
  2447.                CALL    CALC_ADDR
  2448.                MOV     SI,OFFSET WIN_SAVE
  2449.                MOV     CX,25
  2450.                MOV     BP,80
  2451.                CALL    DO_RESTORE              ;Restore all 25 rows.
  2452.                RET
  2453.  
  2454. DO_RESTORE:    PUSH    ES
  2455.                MOV     ES,VIDEO_SEG
  2456.                MOV     DX,STATUS_REG
  2457.  
  2458. NEXT_SCREEN:   PUSH    CX
  2459.                PUSH    DI
  2460.                MOV     CX,BP
  2461. NEXT_SCREEN2:  IN      AL,DX                   ;Get status.
  2462.                RCR     AL,1                    ;Is it low?
  2463.                JC      NEXT_SCREEN2            ;If not, wait until it is.
  2464.                CLI                             ;No more interrupts.
  2465.  
  2466. HWAIT2:        IN      AL,DX                   ;Get status.
  2467.                RCR     AL,1                    ;Is it high?
  2468.                JNC     HWAIT2                  ;If no, wait until it is.
  2469.                MOVSW
  2470.                STI
  2471.                LOOP    NEXT_SCREEN2
  2472.  
  2473.                POP     DI
  2474.                ADD     DI,CRT_WIDTH            ;Next row.
  2475.                POP     CX
  2476.                LOOP    NEXT_SCREEN
  2477.                POP     ES
  2478.                RET
  2479.  
  2480. ;----------------------------------------------;
  2481. POP_MENU:      XOR     AX,AX                   ;Top left of screen.
  2482.                CALL    CALC_ADDR
  2483.  
  2484. ;--------------------------------------------------------;
  2485. ; INPUT: DI -> Video destination; SI -> Window to popup. ;
  2486. POP_WINDOW:    PUSH    ES
  2487.                MOV     DX,STATUS_REG
  2488.                MOV     ES,VIDEO_SEG
  2489.  
  2490. NEXT_POP:      PUSH    DI
  2491. NEXT_WIN:      LODSB
  2492.                CMP     AL,7                    ;Format code?
  2493.                JBE     CK_COMPRESS
  2494.                CALL    WRITE_SCREEN            ;If no, write to screen.
  2495.                JMP     NEXT_WIN
  2496.  
  2497. CK_COMPRESS:   DEC     AL                      ;Character to repeat?
  2498.                JNS     CK_DROP
  2499.                LODSW                           ;If yes, get count and char.
  2500.                MOV     CL,AL
  2501.                XOR     CH,CH
  2502.                XCHG    AL,AH
  2503.                CALL    REPEAT_CHAR             ;Repeat to screen.
  2504.                JMP     NEXT_WIN
  2505.  
  2506. CK_DROP:       DEC     AL                      ;Transparent black attribute?
  2507.                JNS     CK_COLOR
  2508.                MOV     CX,2
  2509.                CALL    DROP_SHADE              ;If yes, display drop shade.
  2510.                JMP     SHORT STRING_END
  2511.  
  2512. CK_COLOR:      DEC     AL                      ;New color?
  2513.                JNS     CK_STRING
  2514.                LODSB
  2515.                MOV     BL,AL
  2516.                XOR     BH,BH
  2517.                MOV     BH,BYTE PTR COLOR[BX]   ;If yes, look it up.
  2518.                JMP     NEXT_WIN
  2519.  
  2520. CK_STRING:     DEC     AL                      ;End of string?
  2521.                JNS     DROP_STRING
  2522. STRING_END:    POP     DI
  2523.                ADD     DI,CRT_WIDTH            ;If yes, go to next line.
  2524.                CMP     BYTE PTR [SI],-1        ;End of window?
  2525.                JNZ     NEXT_POP                ;If yes, done.
  2526.                JMP     SHORT POP_END
  2527.  
  2528. DROP_STRING:   DEC     AL                      ;Bottom drop shade?
  2529.                JNS     INSERT_DATE
  2530.                LODSB                           ;Get length of window.
  2531.                CBW
  2532.                MOV     CX,AX
  2533.                ADD     DI,4                    ;Shift right 2 columns.
  2534.                CALL    DROP_SHADE
  2535.                POP     DI
  2536.                JMP     SHORT POP_END
  2537.  
  2538. INSERT_DATE:   DEC     AL                      ;Special date insert?
  2539.                JNS     INSERT_APP
  2540.                CALL    DATE_INSERT
  2541.                JMP     NEXT_WIN
  2542.  
  2543. INSERT_APP:    DEC     AL                      ;Special small char. insert?
  2544.                JNS     SKIP
  2545.                CALL    APP_INSERT
  2546.                JMP     NEXT_WIN
  2547.  
  2548. SKIP:          LODSB                           ;Else, skip some characters.
  2549.                XOR     AH,AH
  2550.                ADD     DI,AX
  2551.                JMP     NEXT_WIN
  2552.  
  2553. POP_END:       POP     ES
  2554.                RET
  2555.  
  2556. ;----------------------------------------------;
  2557. DROP_SHADE:    MOV     BL,8
  2558.                INC     DI
  2559. ATTR:          IN      AL,DX                   ;Get status.
  2560.                RCR     AL,1                    ;Is it low?
  2561.                JC      ATTR                    ;If not, wait until it is.
  2562.                CLI                             ;No more interrupts.
  2563.  
  2564. HWAIT6:        IN      AL,DX                   ;Get status.
  2565.                RCR     AL,1                    ;Is it high?
  2566.                JNC     HWAIT6                  ;If no, wait until it is.
  2567.                MOV     AL,BL
  2568.                STOSB
  2569.                STI                             ;Interrupts back on.
  2570.                INC     DI
  2571.                LOOP    ATTR
  2572.                RET
  2573.  
  2574. ;----------------------------------------------;
  2575. DATE_INSERT:   PUSH    BX
  2576.                MOV     AH,WEEKDAY
  2577.                INC     DAY_COUNTER
  2578.                MOV     AL,DAY_COUNTER
  2579.                CMP     AL,AH                   ;Are we to first day of month?
  2580.                JBE     DO_BLANK                ;If no, blanks.
  2581.                SUB     AL,AH
  2582.                CBW
  2583.                CMP     AL,LAST_DAY             ;Are we past last day of month?
  2584.                JA      DO_BLANK                ;If yes, blanks.
  2585.                CMP     AL,DAY_TODAY
  2586.                JNZ     DO_DAY
  2587.                MOV     CL,MONTH_TODAY
  2588.                CMP     CL,MONTH_CAL
  2589.                JNZ     DO_DAY
  2590.                MOV     CX,YEAR_TODAY
  2591.                CMP     CX,YEAR_CAL
  2592.                JNZ     DO_DAY
  2593.                MOV     BH,COLOR.Y              ;Use highlight color if today.
  2594. DO_DAY:        CALL    DECIMAL_ASCII           ;Write the date.
  2595.                JMP     SHORT D_INSERT_END
  2596.  
  2597. DO_BLANK:      MOV     AL,SPACE
  2598.                CALL    WRITE_SCREEN
  2599.                MOV     AL,SPACE
  2600.                CALL    WRITE_SCREEN
  2601.  
  2602. D_INSERT_END:  POP     BX
  2603.                RET
  2604.  
  2605. ;----------------------------------------------;
  2606. APP_INSERT:    PUSH    BX
  2607.                MOV     BH,COLOR.A              ;Assume small block color.
  2608.                MOV     AH,WEEKDAY
  2609.                MOV     BP,BLOCK_ROW            ;Block row index (0 or 1).
  2610.                INC     BLOCK_COUNTER[BP]       ;Block day counter.
  2611.                MOV     AL,BLOCK_COUNTER[BP]
  2612.                CMP     AL,AH                   ;If before first day, blanks.
  2613.                JBE     DO_BLANK2
  2614.  
  2615.                PUSH    AX                      ;Save block counter.
  2616.                CBW
  2617.                MOV     CL,7
  2618.                DIV     CL
  2619.                OR      AH,AH
  2620.                JNZ     CALC_BLOCK
  2621.                XOR     BLOCK_ROW,1             ;Once a week flip block row index
  2622.  
  2623. CALC_BLOCK:    POP     AX
  2624.                SUB     AL,AH
  2625.                CMP     AL,LAST_DAY             ;Past last day?
  2626.                JA      DO_BLANK2               ;If so, blanks.
  2627.                CBW
  2628.                CMP     AL,DAY_CAL
  2629.                JNZ     CK_ROW
  2630.                MOV     BH,COLOR.C              ;If today, user cursor color.
  2631.  
  2632. CK_ROW:        MOV     CL,3
  2633.                DEC     AX
  2634.                SHL     AX,CL                   ;Index * 8 into array.
  2635.                TEST    BP,1
  2636.                JZ      GOT_INDEX
  2637.                ADD     AX,BLOCK_COUNT / 2      ; + Array size / 2 for odd rows.
  2638.  
  2639. GOT_INDEX:     MOV     BP,AX
  2640.                MOV     CX,8
  2641. NEXT_BLOCK:    MOV     AL,APPOINTMENT_BLOCKS[BP]
  2642.                CALL    WRITE_SCREEN            ;Write the 8 block chars.
  2643.                INC     BP
  2644.                LOOP    NEXT_BLOCK
  2645.                JMP     SHORT A_INSERT_END
  2646.  
  2647. DO_BLANK2:     MOV     AL,SPACE
  2648.                MOV     CX,8
  2649.                CALL    REPEAT_CHAR
  2650.  
  2651. A_INSERT_END:  POP     BX
  2652.                RET
  2653.  
  2654. ;----------------------------------------------;
  2655. CALC_ADDR:     MUL     CRT_WIDTH               ;Address = row * screen width
  2656.                ADD     AX,CRT_START            ; + start of screen buffer.
  2657.                MOV     DI,AX
  2658.                RET
  2659.  
  2660. ;----------------------------------------------;
  2661. ;INPUT: CX=char count; AX=character
  2662. REPEAT_CHAR:   PUSH    AX
  2663.                CALL    WRITE_SCREEN
  2664.                POP     AX
  2665.                LOOP    REPEAT_CHAR
  2666.                RET
  2667.  
  2668. ;----------------------------------------------;
  2669. WRITE_SCREEN:  MOV     BL,AL                   ;Store character in BL.
  2670. HORZ_RET:      IN      AL,DX                   ;Get status.
  2671.                RCR     AL,1                    ;Is it low?
  2672.                JC      HORZ_RET                ;If not, wait until it is.
  2673.                CLI                             ;No more interrupts.
  2674.  
  2675. HWAIT:         IN      AL,DX                   ;Get status.
  2676.                RCR     AL,1                    ;Is it high?
  2677.                JNC     HWAIT                   ;If no, wait until it is.
  2678.  
  2679.                MOV     AX,BX                   ;Retrieve character; now it's OK
  2680.                STOSW                           ; to write to screen buffer.
  2681.                STI                             ;Interrupts back on.
  2682.                RET                             ;Return
  2683.  
  2684. ;----------------------------------------------;
  2685. GET_CHAR:      PUSH    DS
  2686.                PUSH    DX
  2687.                MOV     DX,STATUS_REG
  2688.                MOV     DS,VIDEO_SEG
  2689.  
  2690. HORZ_RET2:     IN      AL,DX                  ;Get status.
  2691.                RCR     AL,1                   ;Is it low?
  2692.                JC      HORZ_RET2              ;If not, wait until it is.
  2693.                CLI                            ;No more interrupts.
  2694.  
  2695. HWAIT4:        IN      AL,DX                  ;Get status.
  2696.                RCR     AL,1                   ;Is it high?
  2697.                JNC     HWAIT4                 ;If no, wait until it is.
  2698.                LODSW
  2699.                STI
  2700.                POP     DX
  2701.                POP     DS
  2702.                RET
  2703.  
  2704. ;----------------------------------------------;
  2705. DECIMAL_ASCII: MOV     CL,10
  2706.                DIV     CL
  2707.                ADD     AX,"0" SHL 8 + "0"
  2708.                PUSH    AX
  2709.                CMP     AL,"0"
  2710.                JNZ     DO_DECIMAL
  2711.                MOV     AL,SPACE
  2712. DO_DECIMAL:    CALL    WRITE_SCREEN
  2713.                POP     AX
  2714.                MOV     AL,AH
  2715.                CALL    WRITE_SCREEN
  2716.                RET
  2717.  
  2718. ;------------------------------------------------------------------------------
  2719. ; OUTPUT: AL=scan code; AH=char; CY=1 if hotkey or Esc; EXIT_FLAG=1 if hotkey
  2720. GETKEY:        MOV     AH,1                    ;Keystroke waiting?
  2721.                INT     16H
  2722.                JNZ     GETKEY1
  2723.                INT     28H                     ;DOS idle interrupt.
  2724.                JMP     GETKEY
  2725. GETKEY1:       XOR     AH,AH                   ;Get keystroke.
  2726.                INT     16H
  2727.                XCHG    AL,AH
  2728.                CMP     AL,ESC_SCAN             ;Esc key?
  2729.                JZ      EXIT_KEY
  2730.  
  2731. CK_HOT:        CMP     AL,HOT_KEY_SCAN         ;Hotkey?
  2732.                JNZ     GETKEY_END
  2733.                PUSH    AX
  2734.                MOV     AH,2
  2735.                INT     16H
  2736.                TEST    AL,HOT_SHIFT_KEY
  2737.                POP     AX
  2738.                JZ      GETKEY_END
  2739.                MOV     EXIT_FLAG,1
  2740.  
  2741. EXIT_KEY:      STC
  2742.                RET
  2743.  
  2744. GETKEY_END:    CLC
  2745.                RET
  2746.  
  2747. ;----------------------------------------------;
  2748. FLUSH_IT:      XOR     AH,AH                   ;Flush keyboard buffer.
  2749.                INT     16H
  2750. FLUSH_KEY:     MOV     AH,1
  2751.                INT     16H
  2752.                JNZ     FLUSH_IT
  2753.                RET
  2754.  
  2755. ;----------------------------------------------;
  2756. PAUSE:         MOV     AH,1                    ;Wait till keystroke in buffer.
  2757.                INT     16H
  2758.                JZ      PAUSE
  2759.                RET
  2760.  
  2761. ;---------------------------------------------;
  2762. ; Move BIOS video data into our data segment. ;
  2763. ;---------------------------------------------;
  2764. GET_BIOS_DATA: PUSH    DS
  2765.                PUSH    ES
  2766.  
  2767.                MOV     AX,40H                  ;BIOS data area.
  2768.                MOV     DS,AX
  2769.                PUSH    CS
  2770.                POP     ES
  2771.  
  2772.                MOV     SI,BIOS_ACTIVE_PAGE     ;Start with active page.
  2773.                MOV     DI,OFFSET ACTIVE_PAGE
  2774.                MOVSB                           ;Retrieve active page
  2775.                MOVSW                           ; and address of 6845 port.
  2776.                MOV     SI,BIOS_CRT_MODE        ;Retrieve CRT mode, CRT columns,
  2777.                MOV     CX,CRT_DATA_LENGTH      ; CRT length, CRT start.
  2778.                REP     MOVSB
  2779.  
  2780.                XOR     BH,BH
  2781.                MOV     DL,24                   ;Assume 24 logical rows.
  2782.                MOV     AX,1130H                ;Get Information via BIOS.
  2783.                INT     10H
  2784. STORE_ROWS:    POP     ES
  2785.                POP     DS
  2786.                MOV     CRT_ROWS,DL             ;Store rows.
  2787.  
  2788.                MOV     BH,ACTIVE_PAGE
  2789.                MOV     AH,3
  2790.                INT     10H                     ;Get Cursor mode.
  2791.                MOV     CURSOR_MODE,CX
  2792.                MOV     CURSOR_POS,DX
  2793.                MOV     DX,ADDR_6845
  2794.                ADD     DX,6
  2795.                MOV     STATUS_REG,DX
  2796.                MOV     AX,0B000H
  2797.                CMP     DX,3BAH
  2798.                JZ      STORE_VIDEO
  2799.                ADD     AX,800H
  2800. STORE_VIDEO:   MOV     VIDEO_SEG,AX            ;Video address.
  2801.                MOV     AX,CRT_COLS
  2802.                SHL     AX,1
  2803.                MOV     CRT_WIDTH,AX            ;CRT width = columns * 2.
  2804.                RET
  2805.  
  2806. ;------------------------------------------------------------------------------;
  2807. ; Read port directly for programs like 123 that do not use BIOS to set address.;
  2808. ;------------------------------------------------------------------------------;
  2809. GET_CUR_ADDR:  MOV     DX,ADDR_6845
  2810.                MOV     AL,14
  2811.                OUT     DX,AL
  2812.                INC     DX
  2813.                IN      AL,DX
  2814.                MOV     AH,AL
  2815.                DEC     DX
  2816.                MOV     AL,15
  2817.                OUT     DX,AL
  2818.                INC     DX
  2819.                IN      AL,DX
  2820.                MOV     CURSOR_ADDR,AX
  2821.                RET
  2822.  
  2823. ;----------------------------------------------;
  2824. HIDE_CURSOR:   MOV     DH,CRT_ROWS
  2825.                INC     DH
  2826.                XOR     DL,DL
  2827.  
  2828. SET_CURSOR:    PUSH    AX
  2829.                MOV     BH,ACTIVE_PAGE
  2830.                MOV     AH,2
  2831.                INT     10H
  2832.                POP     AX
  2833.                RET
  2834.  
  2835. ;------------------------------------------------------------------------------
  2836. ;IOSET vectors interrupts 1Bh, 23h and 24h to internal handlers.  IORESET
  2837. ;restores the original vector values.
  2838. ;------------------------------------------------------------------------------
  2839. IOSET          PROC    NEAR
  2840.                PUSH    ES
  2841.                MOV     AX,351BH                ;BIOS Ctrl break interrupt.
  2842.                INT     21H
  2843.                MOV     OLD1B[0],BX
  2844.                MOV     OLD1B[2],ES
  2845.                MOV     DX,OFFSET IOEXIT        ;Ignore.
  2846.                MOV     AX,251BH
  2847.                INT     21H
  2848.  
  2849.                MOV     AX,3523H                ;DOS Ctrl break interrupt.
  2850.                INT     21H
  2851.                MOV     OLD23[0],BX
  2852.                MOV     OLD23[2],ES
  2853.                MOV     DX,OFFSET IOEXIT        ;Ignore.
  2854.                MOV     AX,2523H
  2855.                INT     21H
  2856.  
  2857.                MOV     AX,3524H                ;Critical error interrupt.
  2858.                INT     21H
  2859.                MOV     OLD24[0],BX
  2860.                MOV     OLD24[2],ES
  2861.                MOV     DX,OFFSET IOERR         ;Install ours.
  2862.                MOV     AX,2524H
  2863.                INT     21H
  2864.                POP     ES
  2865.                RET
  2866. IOSET          ENDP
  2867.  
  2868. ;-------------------------------------------;
  2869. IORESET        PROC    NEAR
  2870.                PUSH    DS
  2871.                MOV     DX,OLD24[0]
  2872.                MOV     DS,OLD24[2]
  2873.                MOV     AX,2524H                ;Restore Critical.
  2874.                INT     21H
  2875.  
  2876.                MOV     DX,CS:OLD23[0]
  2877.                MOV     DS,CS:OLD23[2]
  2878.                MOV     AX,2523H                ;Restore DOS Ctrl break.
  2879.                INT     21H
  2880.  
  2881.                MOV     DX,CS:OLD1B[0]
  2882.                MOV     DS,CS:OLD1B[2]
  2883.                MOV     AX,251BH                ;Restore BIOS Ctrl break.
  2884.                INT     21H
  2885.                POP     DS
  2886.                RET
  2887. IORESET        ENDP
  2888.  
  2889. ;------------------------------------------------------------------------------
  2890. ;INITIALIZE prepares the program for residency.
  2891. ;------------------------------------------------------------------------------
  2892. PATH_LEN       EQU     100
  2893. DATA_PATH      DB      PATH_LEN DUP (0)
  2894. ARCHIVE_PATH   DB      PATH_LEN DUP (0)
  2895.                DB      (256 / 8) DUP ("STACK   ")
  2896. OUR_STACK      =       $
  2897. ERR_SAVE       DB      (((ERR_WIDTH + 2) * 2) * (ERR_HEIGHT + 1)) DUP (?)
  2898. WIN_SAVE       DB      ((80 * 2) * 25) DUP (?)
  2899. RESIDENT_END   =       $
  2900.  
  2901. SYNTAX DB  "Syntax: Schedule [/I] [/U] [/Hn] [/Pn...n] [/G] [/A] [/C] [/M] [/B]",CR,LF
  2902.        DB  "/I = Install Memory-resident",CR,LF
  2903.        DB  "/U = Uninstall",CR,LF
  2904.        DB  "/H = Hotkey assignment; Ctrl or Alt plus new hotkey",CR,LF
  2905.        DB  "     eg. /H Ctrl Y or /H Alt 1;  default is Alt C",CR,LF
  2906.        DB  "/P = Printer setup string in decimal; 10 maximum.",CR,LF
  2907.        DB  "     eg. /P 27 40 115 66 is boldface on a LaserJet",CR,LF
  2908.        DB  "/G = Graphical characters in printing; Use appropriate /P",CR,LF
  2909.        DB  "     setup for your printer to switch to IBM character set",CR,LF
  2910.        DB  "/A = Appointment pop up OFF",CR,LF
  2911.        DB  "/C = Chime OFF",CR,LF
  2912.        DB  "/M = Midnight update pop up OFF",CR,LF
  2913.        DB  "/B = Black and white attributes"
  2914.        DB  CR,LF,LF,"$"
  2915.  
  2916. CANT_FIND      DB      "Can't find Schedule.com",CR,LF
  2917.                DB      "Change to Schedule's directory before running.",CR,LF,"$"
  2918. NOT_INSTALLED  DB      "Schedule not installed",CR,LF,"$"
  2919. ALREADY_MSG    DB      "Schedule already installed",CR,LF,"$"
  2920. UNLOAD_MSG     DB      "Schedule can't be uninstalled",CR,LF
  2921.                DB      "Uninstall resident programs in reverse order",CR,LF,"$"
  2922. NOT_ENOUGH     DB      "Not enough memory to install Schedule",CR,LF,"$"
  2923. ALLOCATE_MSG   DB      "Memory allocation error",CR,LF,BELL,"$"
  2924. INSTALL_MSG    DB      "Installed",CR,LF,"$"
  2925. UNINSTALL_MSG  DB      "Uninstalled",CR,LF,"$"
  2926. TSR            DB      "SCHEDULE.COM",0
  2927. TSR_LEN        EQU     $ - TSR
  2928. ARCHIVE_FILE   DB      "SCHEDULE.ASC",0
  2929. ARC_LEN        EQU     $ - ARCHIVE_FILE
  2930. DATA_FILE      DB      "SCHEDULE.DAT",0
  2931. DAT_LEN        EQU     $ - DATA_FILE
  2932.  
  2933. CRITICAL_MSG   DB      "DOS Critical Error Flag not found",CR,LF
  2934.                DB      "Can't install",CR,LF,"$"
  2935.  
  2936. HOTKEY_MSG     DB      "Press $"
  2937. HOTKEY_MSG2    DB      " to pop-up Schedule",CR,LF,"$"
  2938.  
  2939. SIDEKICK_MSG   DB      "SideKick must be loaded last.",CR,LF
  2940.                DB      "Uninstall SideKick and then install Schedule",CR,LF,"$"
  2941.  
  2942. WRONG_VERSION  DB      "Needs DOS 2.0 or later$"
  2943.  
  2944. SCAN_CODES LABEL BYTE
  2945.  
  2946. DB "1",2,"2",3,"3",4,"4",5,"5",6,"6",7,"7",8,"8",9,"9",0AH,"0",0BH,"-",0CH
  2947. DB "=",0DH,"Q",10H,"W",11H,"E",12H,"R",13H,"T",14H,"Y",15H,"U",16H,"I",17H
  2948. DB "O",18H,"P",19H,"[",1AH,"]",1BH,"A",1EH,"S",1FH,"D",20H,"F",21H,"G",22H
  2949. DB "H",23H,"J",24H,"K",25H,"L",26H,";",27H,39,28H,96,29H,"\",2BH,"Z",2CH
  2950. DB "X",2DH,"C",2EH,"V",2FH,"B",30H,"N",31H,"M",32H,",",33H,".",34H,"/",35H
  2951.  
  2952. SCAN_COUNT     EQU     ($ - SCAN_CODES) / 2
  2953.  
  2954. INSTALL_FLAG   DB      0                       ; =1 if /I found.
  2955. UNINSTALL_FLAG DB      0                       ; =1 if /U found.
  2956. ALT            DB      " Alt $"
  2957. CTRL           DB      "Ctrl $"
  2958. ALT_CAPS       DB      "ALT"
  2959. CTRL_CAPS      DB      "CTRL"
  2960.  
  2961. ;----------------------------------------------;
  2962. INITIALIZE     PROC    NEAR
  2963.                CLD                             ;All string operations forward.
  2964.                MOV     BX,OFFSET SIGNATURE     ;Point to start of code.
  2965.                NOT     BYTE PTR [BX]           ;Change a byte so no false match.
  2966.                XOR     DX,DX                   ;Start at segment zero.
  2967.                MOV     AX,CS                   ;Store our segment in AX.
  2968. NEXT_PARAG:    INC     DX                      ;Next paragraph.
  2969.                MOV     ES,DX
  2970.                CMP     DX,AX                   ;Is it our segment?
  2971.                JZ      ANNOUNCE                ;If yes, search is done.
  2972.                MOV     SI,BX                   ;Else, point to our signature.
  2973.                MOV     DI,BX                   ; and offset of possible match.
  2974.                MOV     CX,16                   ;Check 16 bytes for match.
  2975.                REP     CMPSB
  2976.                JNZ     NEXT_PARAG              ;If no match, keep looking.
  2977.  
  2978. ;----------------------------------------------;
  2979. ANNOUNCE:      MOV     TSR_SEGMENT,ES
  2980.                MOV     DX,OFFSET SIGNATURE + 1 ;Display our signature.
  2981.                CALL    PRINT_STRING
  2982.                MOV     DX,OFFSET SYNTAX        ;And syntax.
  2983.                CALL    PRINT_STRING
  2984.  
  2985.                MOV     SI,81H                  ;Point to command line.
  2986. NEXT_CAP:      LODSB                           ;Capitalize parameters.
  2987.                CMP     AL,CR
  2988.                JZ      PARSE
  2989.                CMP     AL,"a"
  2990.                JB      NEXT_CAP
  2991.                CMP     AL,"z"
  2992.                JA      NEXT_CAP
  2993.                AND     BYTE PTR [SI - 1],5FH
  2994.                JMP     SHORT NEXT_CAP
  2995.  
  2996. ;----------------------------------------------;
  2997. PARSE:         MOV     SI,81H                  ;Point to command line again.
  2998. NEXT_SWITCH:   LODSB
  2999.                CMP     AL,CR                   ;Is it carriage return?
  3000.                JNZ     CK_SPACE
  3001.                JMP     INSTALL                 ;If yes, done here.
  3002. CK_SPACE:      CMP     AL,SPACE                ;If space or below, ignore.
  3003.                JBE     NEXT_SWITCH
  3004.                CMP     AL,"/"                  ;Is it a switch character?
  3005.                JZ      GET_SWITCH              ;If yes, continue.
  3006.                JMP     TERMINATE               ;Else, error; exit.
  3007.  
  3008. GET_SWITCH:    LODSB
  3009.                CMP     AL,CR
  3010.                JZ      INSTALL
  3011.                CMP     AL,"U"                  ;Is it "U" ?
  3012.                JNZ     CK_I
  3013.                MOV     UNINSTALL_FLAG,1
  3014.                CALL    CK_INSTALLED            ;Else, see if installed.
  3015.                JZ      NO_TSR
  3016.                JMP     UNINSTALL               ;Else, uninstall.
  3017. NO_TSR:        MOV     DX,OFFSET NOT_INSTALLED ;If no, exit with error message.
  3018.                JMP     MSG_EXIT
  3019.  
  3020. CK_I:          CMP     AL,"I"                  ;Is it (I)nstall?
  3021.                JNZ     CK_G
  3022.                MOV     INSTALL_FLAG,1
  3023.                JMP     NEXT_SWITCH
  3024.  
  3025. CK_G:          CMP     AL,"G"                  ;Is it (G)raphic chars?
  3026.                JNZ     CK_P
  3027.                MOV     ES:IBM_FLAG,1
  3028.                JMP     NEXT_SWITCH
  3029.  
  3030. CK_P:          CMP     AL,"P"                  ;Is it (P)rinter setup codes?
  3031.                JNZ     CK_H
  3032.                CALL    GET_SETUP
  3033.                JMP     NEXT_SWITCH
  3034.  
  3035. CK_H:          CMP     AL,"H"                  ;Is it (H)otkey?
  3036.                JNZ     CK_C
  3037.                CALL    CHANGE_HOT
  3038.                JMP     NEXT_SWITCH
  3039.  
  3040. CK_C:          CMP     AL,"C"                  ;Is it (C)hime OFF?
  3041.                JNZ     CK_A
  3042.                MOV     ES:NOBELL_FLAG,1
  3043.                JMP     NEXT_SWITCH
  3044.  
  3045. CK_A:          CMP     AL,"A"                  ;Is it (A)ppointment popup OFF?
  3046.                JNZ     CK_M
  3047.                MOV     ES:NOPOPUP_FLAG,1
  3048.                JMP     NEXT_SWITCH
  3049.  
  3050. CK_M:          CMP     AL,"M"                  ;Is it (M)idnight rollover OFF?
  3051.                JNZ     CK_B
  3052.                MOV     ES:NOMIDNIGHT_FLAG,1
  3053.                JMP     NEXT_SWITCH
  3054.  
  3055. CK_B:          CMP     AL,"B"                  ;Is it (B)lack and white switch
  3056.                JZ      GOT_B
  3057.                JMP     TERMINATE
  3058. GOT_B:         MOV     ES:MONO_FLAG,1
  3059.                JMP     NEXT_SWITCH
  3060.  
  3061. ;----------------------------------------------;
  3062. INSTALL:       CALL    CK_INSTALLED            ;Check if already installed.
  3063.                JZ      CK_AVAILABLE            ;If no, see if enough memory.
  3064.                MOV     DX,OFFSET ALREADY_MSG   ;If yes, display "Already
  3065.                CALL    PRINT_STRING            ; installed" and
  3066.                CALL    DISP_HOTKEY             ; current hotkey.
  3067.                XOR     AL,AL                   ; EL = 0
  3068.                JMP     TERMINATE
  3069.  
  3070. ;----------------------------------------------;
  3071. CK_AVAILABLE:  MOV     BX,OFFSET RESIDENT_END
  3072.                ADD     BX,15                   ;Round up.
  3073.                MOV     CL,4
  3074.                SHR     BX,CL                   ;Convert to paragraphs.
  3075.                MOV     AH,4AH
  3076.                INT     21H                     ;Allocate memory.
  3077.                JNC     GET_VERSION
  3078.                MOV     DX,OFFSET NOT_ENOUGH    ;Exit if not enough
  3079.                JMP     MSG_EXIT                ; with message.
  3080.  
  3081. GET_VERSION:   MOV     AH,30H                  ;Get DOS version
  3082.                INT     21H
  3083.                XCHG    AL,AH
  3084.                MOV     DOS_VERSION,AX          ; and save.
  3085.                CMP     AH,2
  3086.                JAE     GET_PATH
  3087.                MOV     DX,OFFSET WRONG_VERSION ;If not DOS 2 or above, exit.
  3088.                JMP     MSG_EXIT
  3089.  
  3090. GET_PATH:      MOV     DX,OFFSET TSR           ;Open .COM file.
  3091.                MOV     AX,3D00H
  3092.                INT     21H
  3093.                JNC     FOUND_PATH
  3094. NOT_FOUND:     MOV     DX,OFFSET CANT_FIND     ;If can't find, exit
  3095.                JMP     MSG_EXIT                ; with message.
  3096.  
  3097. FOUND_PATH:    MOV     BX,AX                   ;Close .COM file.
  3098.                MOV     AH,3EH
  3099.                INT     21H
  3100.                MOV     AH,19H                  ;Get default drive.
  3101.                INT     21H
  3102.                ADD     AL,"A"
  3103.                MOV     DI,OFFSET DATA_PATH
  3104.                STOSB
  3105.                MOV     AL,":"                  ;Add delimiters.
  3106.                STOSB
  3107.                MOV     AL,"\"
  3108.                STOSB
  3109.                MOV     SI,DI
  3110.                XOR     DL,DL
  3111.                MOV     AH,47H                  ;Get default directory.
  3112.                INT     21H
  3113.                JC      NOT_FOUND
  3114.  
  3115. FIND_END:      LODSB                           ;Find end of path.
  3116.                OR      AL,AL
  3117.                JNZ     FIND_END
  3118.                MOV     DI,SI
  3119.                DEC     DI
  3120.                MOV     AL,"\"                  ;Add on delimiter if root.
  3121.                CMP     [DI-1],AL
  3122.                JZ      ADD_TSR
  3123.                STOSB
  3124. ADD_TSR:       PUSH    DI
  3125.                MOV     SI,OFFSET DATA_FILE
  3126.                MOV     CX,TSR_LEN
  3127.                REP     MOVSB                   ;Tack on data filename.
  3128.                MOV     SI,OFFSET DATA_PATH
  3129.                MOV     DI,OFFSET ARCHIVE_PATH
  3130.                MOV     CX,PATH_LEN
  3131.                REP     MOVSB                   ;Make a copy.
  3132.                POP     DI
  3133.                SUB     DI,OFFSET DATA_PATH
  3134.                ADD     DI,OFFSET ARCHIVE_PATH
  3135.                MOV     SI,OFFSET ARCHIVE_FILE
  3136.                MOV     CX,ARC_LEN
  3137.                REP     MOVSB                   ;Make this one archive filename
  3138.  
  3139. GET_INDOS:     MOV     AH,34H                  ;Undocumented INDOS call.
  3140.                INT     21H
  3141.                MOV     DOS_SEGMENT,ES
  3142.                MOV     INDOS_OFFSET,BX
  3143.  
  3144.                MOV     AX,3E80H                ;CMP opcode
  3145.                MOV     CX,2000H                ;Max search length
  3146.                MOV     DI,BX                   ;Look for Critical error address.
  3147. INIT4:         REPNZ   SCASW
  3148.                JCXZ    INIT5
  3149.                CMP     BYTE PTR ES:[DI+5],0BCH
  3150.                JZ      FOUND
  3151.                JMP     INIT4
  3152. INIT5:         MOV     CX,2000H
  3153.                INC     BX                      ;Odd addresses.
  3154.                MOV     DI,BX
  3155. INIT6:         REPNZ   SCASW
  3156.                JCXZ    NOTFOUND
  3157.                CMP     BYTE PTR ES:[DI+5],0BCH
  3158.                JZ      FOUND
  3159.                JMP     INIT6
  3160.  
  3161. NOTFOUND:      MOV     DX,OFFSET CRITICAL_MSG
  3162.                JMP     MSG_EXIT
  3163.  
  3164. FOUND:         MOV     AX,ES:[DI]
  3165.                MOV     ERRFLAG_OFFSET,AX
  3166.  
  3167.                CMP     INSTALL_FLAG,1          ;Install request?
  3168.                JZ      CK_SIDEKICK
  3169.                MOV     AH,0FH                  ;If no, change to text
  3170.                INT     10H                     ; video mode if necessary.
  3171.                CMP     AL,2
  3172.                JZ      GET_VECTORS
  3173.                CMP     AL,7
  3174.                JZ      GET_VECTORS
  3175.                CMP     AL,3
  3176.                JZ      GET_VECTORS
  3177.                MOV     AX,3
  3178.                INT     10H
  3179.                JMP     SHORT GET_VECTORS
  3180.  
  3181. CK_SIDEKICK:   XOR     AX,AX                   ;Check if SideKick installed.
  3182.                MOV     ES,AX
  3183.                MOV     ES,ES:[(9 * 4) + 2]     ;INT 9 segment
  3184.                CMP     WORD PTR ES:[16CH],"KS" ;SideKick signature.
  3185.                JNZ     GET_VECTORS
  3186.                MOV     DX,OFFSET SIDEKICK_MSG
  3187.                JMP     MSG_EXIT
  3188.  
  3189. GET_VECTORS:   PUSH    CS
  3190.                POP     ES
  3191.                CALL    UPDATE_DATE             ;Update calendar variables.
  3192.                MOV     YEAR_CAL,CX
  3193.                MOV     DAY_MON_CAL,DX
  3194.                CALL    GET_BIOS_DATA           ;Get BIOS variables.
  3195.                CALL    CK_DATE
  3196.  
  3197.                MOV     AX,3508H                ;INT 8
  3198.                INT     21H
  3199.                MOV     OLD8[0],BX
  3200.                MOV     OLD8[2],ES
  3201.                MOV     DX,OFFSET TIMER         ;Install new interrupt.
  3202.                MOV     AX,2508H
  3203.                INT     21H
  3204.  
  3205.                MOV     AX,3510H                ;Get INT 10 interrupt.
  3206.                INT     21H
  3207.                MOV     OLD10[0],BX             ;Save old interrupt.
  3208.                MOV     OLD10[2],ES
  3209.                MOV     DX,OFFSET VIDEO         ;Install new interrupt.
  3210.                MOV     AX,2510H
  3211.                INT     21H
  3212.  
  3213.                MOV     AX,3513H                ;Get INT 13 vector.
  3214.                INT     21H
  3215.                MOV     OLD13[0],BX             ;Save old interrupt.
  3216.                MOV     OLD13[2],ES
  3217.                MOV     DX,OFFSET BDISK         ;Install new interrupt.
  3218.                MOV     AX,2513H
  3219.                INT     21H
  3220.  
  3221.                MOV     AX,3528H                ;Get INT 28 interrupt.
  3222.                INT     21H
  3223.                MOV     OLD28[0],BX             ;Save old interrupt.
  3224.                MOV     OLD28[2],ES
  3225.                MOV     DX,OFFSET BACKPROC      ;Install new interrupt.
  3226.                MOV     AX,2528H
  3227.                INT     21H
  3228.  
  3229.                CMP     INSTALL_FLAG,1          ;Install request?
  3230.                JZ      INSTALL_INT9            ;If no, skip INT 9
  3231.                CALL    MAIN                    ; and just popup now.
  3232.                JMP     SHORT UNINSTALL         ;Uninstall vectors on return.
  3233.  
  3234. STAY_RESIDENT: CALL    PRINT_STRING
  3235. INSTALL_INT9:  MOV     AX,3509H                ;Get INT 9 vector.
  3236.                INT     21H
  3237.                MOV     OLD9[0],BX              ;Save old interrupt.
  3238.                MOV     OLD9[2],ES
  3239.                MOV     DX,OFFSET KEYBOARD      ;Install new interrupt.
  3240.                MOV     AX,2509H
  3241.                INT     21H
  3242.  
  3243.                MOV     AX,DS:[2CH]             ;Get environment segment.
  3244.                MOV     ES,AX
  3245.                MOV     AH,49H                  ;Free up environment.
  3246.                INT     21H
  3247.  
  3248.                MOV     DX,OFFSET INSTALL_MSG   ;Display install message.
  3249.                CALL    PRINT_STRING
  3250.                CALL    DISP_HOTKEY
  3251.  
  3252.                MOV     DX,OFFSET RESIDENT_END
  3253.                ADD     DX,15                   ;Round up.
  3254.                MOV     CL,4
  3255.                SHR     DX,CL                   ;Convert to paragraphs.
  3256.                MOV     AX,3100H                ;Return error code of zero.
  3257.                INT     21H                     ;Terminate but stay resident.
  3258.  
  3259. ;-------------------------------------------------------------------;
  3260. ; Exit.  Return ERRORLEVEL code 0 if successful, 1 if unsuccessful. ;
  3261. ;-------------------------------------------------------------------;
  3262. MSG_EXIT:      CALL    PRINT_STRING
  3263. ERROR_EXIT:    MOV     AL,1                    ;ERRORLEVEL = 1.
  3264. TERMINATE:     MOV     AH,4CH                  ;Terminate.
  3265.                INT     21H
  3266.  
  3267. ;---------------------------------------------------;
  3268. ; This subroutine uninstalls the resident TSR.      ;
  3269. ;---------------------------------------------------;
  3270. UNINSTALL:     MOV     CX,ES                   ;Save segment in CX.
  3271. DO_VECTORS:    MOV     AX,3508H                ;Get interrupt 8h.
  3272.                INT     21H
  3273.                CMP     BX,OFFSET TIMER         ;Has it been hooked by another?
  3274.                JNZ     UNINSTALL_ERR           ;If yes, exit with error message.
  3275.                MOV     BX,ES
  3276.                CMP     BX,CX                   ;Is the segment vector same?
  3277.                JNZ     UNINSTALL_ERR           ;If no, exit with error message.
  3278.  
  3279.                MOV     AX,3510H                ;Get interrupt 10h.
  3280.                INT     21H
  3281.                CMP     BX,OFFSET VIDEO         ;Has it been hooked by another?
  3282.                JNZ     UNINSTALL_ERR           ;If yes, exit with error message.
  3283.                MOV     BX,ES
  3284.                CMP     BX,CX                   ;Is the segment vector same?
  3285.                JNZ     UNINSTALL_ERR           ;If no, exit with error message.
  3286.  
  3287.                MOV     AX,3513H                ;Get interrupt 13h.
  3288.                INT     21H
  3289.                CMP     BX,OFFSET BDISK         ;Has it been hooked by another?
  3290.                JNZ     UNINSTALL_ERR           ;If yes, exit with error message.
  3291.                MOV     BX,ES
  3292.                CMP     BX,CX                   ;Is the segment vector same?
  3293.                JNZ     UNINSTALL_ERR           ;If no, exit with error message.
  3294.  
  3295.                MOV     AX,3528H                ;Get interrupt 28h.
  3296.                INT     21H
  3297.                CMP     BX,OFFSET BACKPROC      ;Has it been hooked by another?
  3298.                JNZ     UNINSTALL_ERR           ;If yes, exit with error message.
  3299.                MOV     BX,ES
  3300.                CMP     BX,CX                   ;Is the segment vector same?
  3301.                JNZ     UNINSTALL_ERR
  3302.  
  3303.                CMP     UNINSTALL_FLAG,1        ;Uninstall request?
  3304.                JNZ     DO_UNINSTALL            ;If no, skip INT 9.
  3305.  
  3306.                MOV     AX,3509H                ;Get interrupt 9h.
  3307.                INT     21H
  3308.                CMP     BX,OFFSET KEYBOARD      ;Has it been hooked by another?
  3309.                JNZ     UNINSTALL_ERR           ;If yes, exit with error message.
  3310.                MOV     BX,ES
  3311.                CMP     BX,CX                   ;Is the segment vector same?
  3312.                JZ      DEALLOCATE              ;If no, exit with error message.
  3313.  
  3314. UNINSTALL_ERR: MOV     DX,OFFSET UNLOAD_MSG    ;And exit with error message.
  3315.                CMP     UNINSTALL_FLAG,1        ;Uninstall request?
  3316.                JZ      LILLY_ERR               ;If yes, just exit.
  3317.                JMP     STAY_RESIDENT           ;Else, go resident.
  3318. LILLY_ERR:     JMP     MSG_EXIT
  3319.  
  3320. DEALLOCATE:    MOV     AH,49H                  ;Return memory to system pool.
  3321.                INT     21H
  3322.                MOV     DX,OFFSET ALLOCATE_MSG
  3323.                JC      LILLY_ERR               ;Display message if problem.
  3324.  
  3325.                MOV     DX,ES:OLD9[0]           ;Restore old INT 9.
  3326.                MOV     DS,ES:OLD9[2]
  3327.                MOV     AX,2509H
  3328.                INT     21H
  3329.  
  3330. DO_UNINSTALL:  MOV     DX,ES:OLD8[0]           ;Restore old INT 8.
  3331.                MOV     DS,ES:OLD8[2]
  3332.                MOV     AX,2508H
  3333.                INT     21H
  3334.  
  3335.                MOV     DX,ES:OLD10[0]          ;Restore old INT 10.
  3336.                MOV     DS,ES:OLD10[2]
  3337.                MOV     AX,2510H
  3338.                INT     21H
  3339.  
  3340.                MOV     DX,ES:OLD13[0]           ;Restore old INT 13.
  3341.                MOV     DS,ES:OLD13[2]
  3342.                MOV     AX,2513H
  3343.                INT     21H
  3344.  
  3345.                MOV     DX,ES:OLD28[0]          ;Restore old INT 28.
  3346.                MOV     DS,ES:OLD28[2]
  3347.                MOV     AX,2528H
  3348.                INT     21H
  3349.  
  3350.                PUSH    CS
  3351.                POP     DS                      ;Point to our data.
  3352.                CMP     UNINSTALL_FLAG,1
  3353.                JNZ     UNINSTALL_END
  3354.                MOV     DX,OFFSET UNINSTALL_MSG ;Display uninstall message.
  3355.                CALL    PRINT_STRING
  3356. UNINSTALL_END: XOR     AL,AL                   ;Exit with ERRORLEVEL = 0.
  3357.                JMP     TERMINATE
  3358.  
  3359. INITIALIZE     ENDP
  3360.  
  3361. ;-------------------------------------------------------;
  3362. ; OUTPUT: ZR = 1 if not installed; ZR = 0 if installed. ;
  3363. ;-------------------------------------------------------;
  3364. CK_INSTALLED:  MOV     AX,ES
  3365.                MOV     BX,CS
  3366.                CMP     AX,BX                   ;Compare segments.
  3367.                RET
  3368.  
  3369. ;----------------------------------------------;
  3370. CHANGE_HOT:    MOV     BP,ES                   ;Save segment.
  3371.                MOV     DX,CS
  3372.                CALL    FIND_START              ;Find start of parameter.
  3373.                CMP     AL,CR
  3374.                JZ      HOT_END
  3375.                MOV     BX,SI
  3376.                MOV     ES,DX
  3377.                MOV     DI,OFFSET ALT_CAPS      ;Is it "ALT"?
  3378.                MOV     CX,3
  3379.                REP     CMPSB
  3380.                JNZ     CK_CTRL
  3381.  
  3382.                MOV     ES,BP
  3383.                MOV     ES:HOT_SHIFT_KEY,ALT_STATE
  3384.                JMP     SHORT GET_HOT
  3385.  
  3386. CK_CTRL:       MOV     SI,BX
  3387.                MOV     DI,OFFSET CTRL_CAPS     ;Is it "CTRL"?
  3388.                MOV     CX,4
  3389.                REP     CMPSB
  3390.                JZ      GOT_CTRL
  3391.                MOV     SI,BX
  3392.                JMP     SHORT GET_HOT
  3393. GOT_CTRL:      MOV     ES,BP
  3394.                MOV     ES:HOT_SHIFT_KEY,CTRL_STATE
  3395.  
  3396. GET_HOT:       CALL    FIND_START              ;Find parameter start.
  3397.                CMP     AL,CR
  3398.                JZ      HOT_END
  3399.                LODSB
  3400.                MOV     CX,SCAN_COUNT           
  3401.                MOV     ES,DX
  3402.                MOV     DI,OFFSET SCAN_CODES
  3403. NEXT_HOT:      SCASB                           ;Look up hotkey.
  3404.                JZ      FOUND_HOT
  3405.                INC     DI
  3406.                LOOP    NEXT_HOT
  3407.                JMP     SHORT HOT_END
  3408.  
  3409. FOUND_HOT:     MOV     AH,[DI]
  3410.                MOV     ES,BP
  3411.                MOV     ES:COMBO,AL             ;Store hotkey ASCII
  3412.                MOV     ES:HOT_KEY_SCAN,AH      ; and scan code.
  3413. HOT_END:       MOV     ES,BP
  3414.                RET
  3415.  
  3416. ;----------------------------------------------;
  3417. FIND_START:    LODSB
  3418.                CMP     AL,CR
  3419.                JZ      START_END
  3420.                CMP     AL,SPACE
  3421.                JBE     FIND_START
  3422. START_END:     DEC     SI
  3423.                RET
  3424.  
  3425. ;----------------------------------------------;
  3426. GET_SETUP:     MOV     DI,OFFSET SETUP_CODES   ;Printer setup code storage.
  3427.                MOV     BP,10                   ;Ten codes maximum.
  3428. NEXT_SETUP2:   CALL    FIND_START              ;Find parameter.
  3429.                CMP     AL,CR
  3430.                JZ      SETUP_END
  3431.                CMP     AL,"/"
  3432.                JZ      SETUP_END
  3433.                XOR     BL,BL
  3434.                MOV     CL,10
  3435. NEXT_DECIMAL:  LODSB                           ;Get a character.
  3436.                CMP     AL,"/"
  3437.                JZ      STORE_SETUP
  3438.                CMP     AL,SPACE
  3439.                JBE     STORE_SETUP
  3440.                SUB     AL,"0"                  ;ASCII to binary.
  3441.                JC      SETUP_END               ;If not between 0 and 9, skip.
  3442.                CMP     AL,9
  3443.                JA      SETUP_END
  3444.                XCHG    AL,BL                   ;Swap old and new number.
  3445.                MUL     CL                      ; last entry by ten.
  3446.                ADD     BL,AL                   ;Add new number and store in BX.
  3447.                JMP     NEXT_DECIMAL
  3448.  
  3449. STORE_SETUP:   MOV     AL,BL
  3450.                STOSB                           ;Store printer code.
  3451.                DEC     SI
  3452.                DEC     BP
  3453.                JNZ     NEXT_SETUP2
  3454.  
  3455. SETUP_END:     XOR     AL,AL                   ;NULL terminate.
  3456.                STOSB
  3457.                RET
  3458.  
  3459. ;----------------------------------------------;
  3460. DISP_HOTKEY:   PUSH    DS
  3461.                MOV     DX,OFFSET HOTKEY_MSG    ;Display hotkey message.
  3462.                CALL    PRINT_STRING
  3463.                MOV     DS,TSR_SEGMENT
  3464.                MOV     BL,COMBO
  3465.                MOV     DX,OFFSET ALT
  3466.                CMP     HOT_SHIFT_KEY,ALT_STATE
  3467.                JZ      DISP_STATE
  3468.                MOV     DX,OFFSET CTRL
  3469. DISP_STATE:    POP     DS
  3470.                CALL    PRINT_STRING            ;And current hotkey.
  3471.                MOV     DL,BL
  3472.                MOV     AH,2
  3473.                INT     21H
  3474.                MOV     DX,OFFSET HOTKEY_MSG2
  3475.                CALL    PRINT_STRING
  3476.                RET
  3477.  
  3478. ;----------------------------------------------;
  3479. PRINT_CHAR:    MOV     DL,AL
  3480.                MOV     AH,2                    ;Print character via DOS.
  3481.                JMP     SHORT DOS_INT
  3482.  
  3483. PRINT_STRING:  MOV     AH,9                    ;Print string via DOS.
  3484. DOS_INT:       INT     21H
  3485.                RET
  3486.  
  3487. _TEXT          ENDS
  3488.                END     START
  3489.