home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / APOG / ASM1.ZIP / CARDFILE.ASM < prev    next >
Encoding:
Assembly Source File  |  1989-01-10  |  90.9 KB  |  1,906 lines

  1. page ,132
  2. ;*------------------------------------------------------
  3. ;*  modified from com1 to com2
  4. ;*  as of 12/21/88 - 07:30 pm
  5. ;*  by Bud Rasmussen
  6. ;*------------------------------------------------------
  7. ;
  8. ;CARDFILE.COM for the IBM Personal Computer - 1987 by Jeff Prosise
  9. ;
  10. bios_data     segment at 40h
  11. rs232_base    dw 4 dup (?)                  ;UART base addresses
  12.               org 4Ah
  13. crt_cols      dw ?                          ;number of display columns
  14.               org 4Eh
  15. crt_start     dw ?                          ;video page offset address
  16.               org 63h
  17. addr_6845     dw ?                          ;CRTC base address
  18.               org 87h
  19. infobyte      label word
  20. ega_info      db ?                          ;EGA info byte
  21. bios_data     ends
  22. ;
  23. code          segment para public 'code'
  24.               assume cs:code
  25.               org 100h
  26. begin:        jmp init1                     ;goto initialization code
  27. ;
  28. program            db "Cardfile 1.0 "
  29. copyright          db "(c) 1987 Ziff Communications Co.",13,10
  30.                    db "Hotkey is ALT-RIGHT SHIFT$",1Ah
  31. author             db "Jeff Prosise"
  32. ;
  33. dos_segment        dw ?                     ;segment of internal DOS flags
  34. indos_offset       dw ?                     ;offset of INDOS flag
  35. errflag_offset     dw ?                     ;offset of critical error flag
  36. program_status     db 0                     ;popup status
  37. flag_10h           db 0                     ;status of interrupt 10h
  38. flag_13h           db 0                     ;status of interrupt 13h
  39. request_flag       db 0                     ;status of processing request
  40. ss_register        dw ?                     ;SS register storage
  41. sp_register        dw ?                     ;SP register storage
  42. oldpsp             dw ?                     ;PSP segment storage
  43. ;
  44. maxrec             db 255                   ;maximum number of records
  45. recptr             db 1                     ;current record number
  46. numrec             db 0                     ;number of records
  47. adapter            db ?                     ;0=MDA, 1=CGA, 2=EGA
  48. video_segment      dw ?                     ;video segment address
  49. border_attr        db ?                     ;window border attribute
  50. text_attr          db ?                     ;window text attribute
  51. menu_attr          db ?                     ;menu line attribute
  52. record_attr        db ?                     ;record display attribute
  53. video_page         db ?                     ;current video page
  54. cursor_mode        dw ?                     ;cursor shape
  55. cursor_pos         dw ?                     ;cursor position
  56. cursor_addr        dw ?                     ;cursor CRTC address
  57. new_cursor         dw ?                     ;Cardfile cursor shape
  58. dos_version        db ?                     ;DOS version number
  59. slotno             db ?                     ;record position
  60. reload             db ?                     ;reload data file flag
  61. zflag              db ?                     ;critical error flag change status
  62. fileflag           db 0                     ;filespec validity indicator
  63. record_length      db 192                   ;record length in bytes
  64. ;
  65. comport            dw 1                     ;COM2 ( page 375 - jourdain )
  66. initstr            db 10000011b             ;1200 baud, N81 data format
  67. dialstr            db "ATDT",0              ;Hayes Smartmodem dial string
  68. hangupstr          db "ATH0",13,0           ;Hayes Smartmodem hangup string
  69. ;
  70. jump_table         dw offset create              ;vector dispatch table
  71.                    dw offset edit
  72.                    dw offset delete
  73.                    dw offset search
  74.                    dw offset save
  75.                    dw offset dial
  76. ;
  77. titles             db 32,"Name",32,32,"Addr",14 dup (32),"Phone",32,"Note",32
  78. menuline1          db "F1-New F2-Ed F3-Del F4-Sch F5-Sv F6-Dial",0
  79. menuline2          db "Press ENTER to delete, ESC to abort",0
  80. menuline3          db "Press F1 to validate new entry",0
  81. menuline4          db "Find:",0
  82. menuline5          db "Press ENTER to continue, ESC to end",0
  83. menuline6          db "Search key not found. Press ESC",0
  84. menuline7          db "No room for additional records",0
  85. menuline8          db "Disk full",0
  86. menuline9          db "Press F1 to validate changes",0
  87. menuline10         db "Pick up phone and press spacebar",0
  88. menuline11         db "Error saving file",0
  89. menuline12         db "Modem not ready",0
  90. menuline13         db "File:",0
  91. ;
  92. timer_int          label dword              ;old interrupt 8 vector
  93. old8h              dw 2 dup (?)
  94. keyboard_int       label dword              ;old interrupt 9 vector
  95. old9h              dw 2 dup (?)
  96. video_int          label dword              ;old interrupt 10h vector
  97. old10h             dw 2 dup (?)
  98. bdisk_int          label dword              ;old interrupt 13h vector
  99. old13h             dw 2 dup (?)
  100. bp_int             label dword              ;old interrupt 28h vector
  101. old28h             dw 2 dup (?)
  102. ;
  103. old1Bh_segment     dw ?                     ;old interrupt 1Bh segment
  104. old1Bh_offset      dw ?                     ;old interrupt 1Bh offset
  105. old23h_segment     dw ?                     ;old interrupt 23h segment
  106. old23h_offset      dw ?                     ;old interrupt 23h offset
  107. old24h_segment     dw ?                     ;old interrupt 24h segment
  108. old24h_offset      dw ?                     ;old interrupt 24h offset
  109. ;
  110. color_attr         db 0,0B8h,1Fh,6Eh,6Eh,6Fh
  111. mono_attr          db 0,0B0h,70h,07h,07h,07h
  112. enable_values      db 2Ch,28h,2Dh,29h,2Ah,2Eh,1Eh
  113. key_table          db "QWERTYUIOP",0,0,0,0
  114.                    db "ASDFGHJKL",0,0,0,0,0
  115.                    db "ZXCVBNM"
  116. ;
  117. ;            .xlist
  118. ;------------------------------------------------------------------------------
  119. ;Execution comes here thru interrupt 9 every time a key is pressed or released.
  120. ;------------------------------------------------------------------------------
  121. keyboard      proc near
  122.               sti                           ;set interrupt enable flag
  123.               pushf                         ;push flags to simulate INT
  124.               call keyboard_int             ;call keyboard handling routine
  125.               push ax                       ;save AX
  126.               mov ah,2                      ;get keyboard shift status
  127.               int 16h
  128.               and al,0Fh                    ;mask off upper 4 bits
  129.               cmp al,9                      ;Alt/Rt-Shift pressed?
  130.               pop ax                        ;restore AX
  131.               jne kb_exit                   ;no, then exit
  132.               cmp program_status,0          ;popup routine already active?
  133.               jne kb_exit                   ;yes, then ignore keypress
  134.               mov request_flag,18           ;set request flag
  135. kb_exit:      iret
  136. keyboard      endp
  137. ;
  138. ;------------------------------------------------------------------------------
  139. ;Interrupt 8 handling routine.
  140. ;------------------------------------------------------------------------------
  141. timer         proc near
  142.               pushf                         ;call BIOS routine
  143.               call timer_int
  144.               cmp request_flag,0            ;flag set?
  145.               je timer_exit                 ;no, then exit
  146.               cmp flag_10h,0                ;video flag set?
  147.               jne dectime                   ;yes, then exit
  148.               cmp flag_13h,0                ;disk flag set?
  149.               jne dectime                   ;yes, then exit
  150.               push es                       ;save ES and DI
  151.               push di
  152.               mov es,dos_segment            ;check INDOS flag
  153.               mov di,indos_offset
  154.               cmp byte ptr es:[di],0
  155.               jne poptime                   ;exit if it's set
  156.               mov di,errflag_offset         ;check critical error flag
  157.               cmp byte ptr es:[di],0
  158.               jne poptime                   ;exit if it's set
  159.               pop di                        ;restore registers
  160.               pop es
  161.               mov request_flag,0            ;zero request flag
  162.               call main                     ;call body of program
  163. timer_exit:   iret
  164. poptime:      pop di                        ;clean up the stack
  165.               pop es
  166. dectime:      dec request_flag              ;decrement request flag
  167.               iret
  168. timer         endp
  169. ;
  170. ;------------------------------------------------------------------------------
  171. ;Interrupt 10h handling routine.
  172. ;------------------------------------------------------------------------------
  173. video         proc near
  174.               pushf                         ;push flags onto stack
  175.               inc flag_10h                  ;increment flag
  176.               call video_int                ;call BIOS routine
  177.               dec flag_10h                  ;decrement flag
  178.               iret
  179. video         endp
  180. ;
  181. ;------------------------------------------------------------------------------
  182. ;Interrupt 13h handling routine.
  183. ;------------------------------------------------------------------------------
  184. bdisk         proc far
  185.               pushf                         ;push flags onto stack
  186.               inc flag_13h                  ;set 'busy' flag
  187.               call bdisk_int                ;call BIOS routine
  188.               pushf                         ;save output flags
  189.               dec flag_13h                  ;clear flag
  190.               popf                          ;restore output flags
  191.               ret 2                         ;exit without destroying flags
  192. bdisk         endp
  193. ;
  194. ;------------------------------------------------------------------------------
  195. ;Interrupt 28h handling routine.
  196. ;------------------------------------------------------------------------------
  197. backproc      proc near
  198.               pushf                         ;call original routine
  199.               call bp_int
  200.               cmp request_flag,0            ;request flag clear?
  201.               je bp_exit                    ;yes, then exit
  202.               cmp flag_10h,0                ;video flag set?
  203.               jne bp_exit                   ;yes, then exit
  204.               cmp flag_13h,0                ;disk flag set?
  205.               jne bp_exit                   ;yes, then exit
  206.               push es                       ;save ES and DI
  207.               push di
  208.               mov es,dos_segment            ;check critical error flag
  209.               mov di,errflag_offset
  210.               cmp byte ptr es:[di],0
  211.               pop di                        ;clean up the stack
  212.               pop es
  213.               jne bp_exit
  214.               mov request_flag,0            ;clear request flag
  215.               call main                     ;call main routine
  216. bp_exit:      iret                          ;done - exit
  217. backproc      endp
  218. ;
  219. ;------------------------------------------------------------------------------
  220. ;Interrupt 24h handling routine (DOS 3.X only).
  221. ;------------------------------------------------------------------------------
  222. ioerr         proc near
  223.               mov al,3                      ;fail the call in progress
  224. ioexit:       iret                          ;give control back to DOS
  225. ioerr         endp
  226. ;
  227. ;------------------------------------------------------------------------------
  228. ;MAIN is the routine called to pop up and manipulate the CardFile window.
  229. ;------------------------------------------------------------------------------
  230. main          proc near
  231.               mov program_status,1          ;set program active flag
  232.               cli                           ;make sure interrupts are off
  233.               mov ss_register,ss            ;save stack registers
  234.               mov sp_register,sp
  235.               push cs                       ;switch to internal stack
  236.               pop ss
  237.               mov sp,offset filespec
  238.               sti                           ;enable interrupts
  239.               push ax                       ;save other registers
  240.               push bx
  241.               push cx
  242.               push dx
  243.               push si
  244.               push di
  245.               push ds
  246.               push es
  247.               push bp
  248.               mov ah,15                     ;get video mode and page
  249.               int 10h
  250.               cmp al,3                      ;mode 0, 1, 2, or 3?
  251.               jbe main1                     ;yes, then continue
  252.               cmp al,7                      ;mode 7?
  253.               je main1                      ;yes, then continue
  254. ;
  255. ;Restore registers and stack before exit.
  256. ;
  257. exit:         pop bp                        ;restore registers and exit
  258.               pop es
  259.               pop ds
  260.               pop di
  261.               pop si
  262.               pop dx
  263.               pop cx
  264.               pop bx
  265.               pop ax
  266.               cli                           ;interrupts off
  267.               mov ss,ss_register            ;switch to original stack
  268.               mov sp,sp_register
  269.               sti                           ;interrupts on
  270.               mov program_status,0          ;clear status flag
  271.               ret
  272. ;
  273. ;Set DS and ES segment registers.
  274. ;
  275. main1:        push cs                       ;set DS to code segment
  276.               pop ds
  277.               assume ds:code
  278.               mov ax,bios_data              ;point ES to BIOS data
  279.               mov es,ax
  280.               assume es:bios_data
  281.               cmp crt_cols,80               ;at least 80 columns displayed?
  282.               jb exit                       ;no, then exit
  283. ;
  284. ;Save needed video parameters.
  285. ;
  286.               mov video_page,bh             ;active video page
  287.               mov ah,3                      ;get cursor mode and location
  288.               int 10h
  289.               mov cursor_mode,cx
  290.               mov cursor_pos,dx
  291.               mov dx,addr_6845              ;get CRTC base address
  292.               push dx                       ;save it for later
  293.               mov al,14                     ;specify register number
  294.               out dx,al
  295.               inc dx                        ;point DX to data port
  296.               in al,dx                      ;read high byte of address
  297.               mov ah,al                     ;save it
  298.               dec dx                        ;back to index register
  299.               mov al,15                     ;specify register number
  300.               out dx,al
  301.               inc dx                        ;back to data port
  302.               in al,dx                      ;read low byte of address
  303.               mov cursor_addr,ax            ;save cursor address
  304. ;
  305. ;Determine whether an EGA is present and active in the system.
  306. ;
  307.               mov ah,12h                    ;see if EGA is present
  308.               mov bl,10h
  309.               int 10h
  310.               cmp bl,10h                    ;did BL return unchanged?
  311.               je main2                      ;yes, then there's no EGA here
  312.               test ega_info,8               ;is the EGA currently active?
  313.               jnz main2                     ;no, then branch
  314.               mov adapter,2                 ;set ADAPTER for EGA
  315.               push bx                       ;save BX
  316.               mov ax,1130h                  ;get number of scan lines per char
  317.               int 10h
  318.               dec cl                        ;form cursor definition in CX
  319.               mov ch,cl
  320.               sub ch,2
  321.               mov new_cursor,cx             ;save cursor definition
  322.               mov si,offset color_attr      ;point SI to color parms
  323.               pop bx                        ;retrieve BX
  324.               or bh,bh                      ;EGA attached to color monitor?
  325.               je main4                      ;yes, then branch
  326.               mov si,offset mono_attr       ;no, then point SI to mono parms
  327.               jmp short main4
  328. ;
  329. ;Determine whether the active video adapter is a CGA or an MDA.
  330. ;
  331. main2:        test addr_6845,40h            ;is bit 6 of the CRTC address set?
  332.               jz main3                      ;no, then it's monochrome
  333.               mov adapter,1                 ;set ADAPTER for a CGA
  334.               mov new_cursor,0607h          ;define cursor shape
  335.               mov si,offset color_attr      ;point SI to color parms
  336.               jmp short main4
  337. main3:        mov adapter,0                 ;set ADAPTER for an MDA
  338.               mov new_cursor,0B0Ch          ;define monochrome cursor
  339.               mov si,offset mono_attr       ;point SI to mono parms
  340. ;
  341. ;Set video parameters for color or monochrome.
  342. ;
  343. main4:        push cs                       ;set ES to the code segment
  344.               pop es
  345.               assume es:nothing
  346.               mov di,offset video_segment   ;point DI to destination
  347.               mov cx,3                      ;3 words to move
  348.               cld                           ;clear DF
  349.               rep movsw                     ;transfer the values
  350. ;
  351. ;Save the current active PSP address and activate this PSP.
  352. ;
  353.               push es                       ;save ES
  354.               mov zflag,0                   ;clear flag
  355.               cmp dos_version,2             ;DOS version 2.X?
  356.               jne main5
  357.               mov es,dos_segment            ;point ES:DI to INDOS
  358.               mov di,indos_offset
  359.               cmp byte ptr es:[di],0        ;INDOS clear?
  360.               je main5                      ;yes, then branch
  361.               mov di,errflag_offset         ;point ES:DI to error flag
  362.               cmp byte ptr es:[di],0        ;critical error flag clear?
  363.               jne main5                     ;no, then branch
  364.               mov byte ptr es:[di],1        ;set critical error flag manually
  365.               mov zflag,1                   ;set change flag
  366. main5:        mov ah,51h                    ;get current PSP segment
  367.               int 21h
  368.               mov oldpsp,bx                 ;save it
  369.               mov ah,50h                    ;make this the active PSP
  370.               push cs
  371.               pop bx
  372.               int 21h
  373.               cmp zflag,0                   ;ZFLAG clear?
  374.               je main6                      ;yes, then branch
  375.               mov di,errflag_offset         ;point ES:DI to error flag
  376.               mov byte ptr es:[di],0        ;restore error flag value
  377. main6:        pop es                        ;restore ES
  378. ;
  379. ;Reset the interrupt 1Bh, 23h, and 24h vectors and open the CardFile window.
  380. ;
  381.               call ioset                    ;reset interrupt vectors
  382.               cmp adapter,1                 ;disable CGA video
  383.               jne main7
  384.               call disable_cga
  385. main7:        call save_screen              ;save memory to be overwritten
  386.               call make_screen              ;open the CardFile window
  387.               cmp adapter,1                 ;enable CGA video
  388.               jne main8
  389.               call enable_cga
  390. main8:        mov ah,1                      ;hide the cursor
  391.               mov ch,20h
  392.               int 10h
  393.               cmp numrec,0                  ;any records in memory?
  394.               je main10                     ;no, then branch
  395.               call show_record              ;display current record
  396. ;
  397. ;Wait for a keystroke and exit when ESC is pressed.
  398. ;
  399. main10:       call getkey                   ;wait for a keypress
  400.               or al,al                      ;extended code entered?
  401.               je main12                     ;yes, then branch
  402.               cmp al,13                     ;ENTER pressed?
  403.               jne main11                    ;no, then branch around
  404.               cmp numrec,2                  ;at least 2 records?
  405.               jb main10                     ;no, then ignore keypress
  406.               jmp short main20              ;yes, then do a PgDn
  407. main11:       cmp al,27                     ;ESC pressed?
  408.               jne main10                    ;no, then ignore keypress
  409.               jmp short escape              ;yes, then close window and exit
  410. ;
  411. ;An extended code was entered.  Check for an Alt-character key combination.
  412. ;
  413. main12:       cmp ah,16                     ;scan code < 16 (Alt-Q)?
  414.               jb main10                     ;yes, then ignore it
  415.               cmp ah,50                     ;scan code > 50 (Alt-M)?
  416.               ja main13                     ;yes, then branch and continue
  417.               call qsearch                  ;do quick search
  418.               jmp main10                    ;return for another keypress
  419. ;
  420. ;Check for a press of any function key F1 through F6.
  421. ;
  422. main13:       cmp ah,59                     ;scan code < 59 (F1)?
  423.               jb main10                     ;yes, then ignore it
  424.               cmp ah,64                     ;scan code > 64 (F6)?
  425.               ja main14                     ;yes, then branch and continue
  426.               sub ah,59                     ;normalize scan code
  427.               mov bl,ah                     ;transfer result
  428.               xor bh,bh                     ;byte to word in BX
  429.               shl bx,1                                     ;double index in BX
  430.               call word ptr cs:[offset jump_table+bx]      ;call routine
  431.               jmp main10                                   ;return
  432. ;
  433. ;Check for Home, End, PgUp, and PgDn.
  434. ;
  435. main14:       cmp numrec,2                  ;are there at least 2 records?
  436.               jb main10                     ;no, then ignore keypress
  437.               cmp ah,71                     ;Home key?
  438.               jne main16                    ;no, then branch
  439.               mov recptr,1                  ;set pointer to first record
  440. main15:       call show_record              ;display record
  441.               jmp main10                    ;return
  442. main16:       cmp ah,79                     ;End key?
  443.               jne main18                    ;no, then branch
  444. main17:       mov al,numrec                 ;get number of records
  445.               mov recptr,al                 ;set pointer to last record
  446.               jmp main15                    ;display record
  447. main18:       cmp ah,73                     ;PgUp key?
  448.               jne main19                    ;no, then branch
  449.               dec recptr                    ;adjust pointer
  450.               cmp recptr,0                  ;wrap around if necessary
  451.               jne main15
  452.               jmp main17
  453. main19:       cmp ah,81                     ;PgDn key?
  454.               jne main10                    ;no, then ignore keypress
  455. main20:       mov al,numrec                 ;presently showing last record?
  456.               cmp al,recptr
  457.               je main21                     ;yes, then branch
  458.               inc recptr                    ;no, then advance pointer
  459.               jmp main15                    ;display record
  460. main21:       mov recptr,1                  ;set pointer to first record
  461.               jmp main15                    ;display record
  462. ;
  463. ;Restore interrupt vectors and former active PSP.
  464. ;
  465. escape:       mov ah,50h                    ;restore active PSP label
  466.               mov bx,oldpsp
  467.               int 21h
  468.               call ioreset                  ;restore interrupt vectors
  469. ;
  470. ;Close the Cardfile window in preparation for exit.
  471. ;
  472.               cmp adapter,1                 ;disable CGA video
  473.               jne esc1
  474.               call disable_cga
  475. esc1:         call restore_screen           ;restore screen contents
  476.               cmp adapter,1                 ;enable CGA video
  477.               jne esc2
  478.               call enable_cga
  479. ;
  480. ;Restore the cursor's former position in the BIOS data area and the CRTC.
  481. ;
  482. esc2:         mov ah,2                      ;set cursor position thru BIOS
  483.               mov bh,video_page
  484.               mov dx,cursor_pos
  485.               int 10h
  486.               pop dx                        ;recover CRTC base address
  487.               mov cx,cursor_addr            ;restore cursor address
  488.               mov al,14                     ;CRTC register number
  489.               out dx,al
  490.               inc dx
  491.               mov al,ch
  492.               out dx,al                     ;write high byte of address
  493.               dec dx
  494.               mov al,15                     ;CRTC register number
  495.               out dx,al
  496.               inc dx
  497.               mov al,cl
  498.               out dx,al                     ;write low byte
  499. ;
  500. ;Display the cursor, bypassing EGA cursor emulation logic, and exit.
  501. ;
  502.               cmp adapter,2                 ;EGA on board?
  503.               jne esc3                      ;no, then branch
  504.               call show_cursor              ;retain current shape
  505.               jmp exit
  506. esc3:         mov ah,1                      ;restore cursor shape
  507.               mov cx,cursor_mode
  508.               int 10h
  509.               jmp exit                      ;exit
  510. main          endp
  511. ;
  512. ;------------------------------------------------------------------------------
  513. ;SAVE_SCREEN saves the contents of the screen that underlie the window.
  514. ;------------------------------------------------------------------------------
  515. linesum       dw ?
  516. video_address dw ?
  517. ;
  518. save_screen   proc near
  519.               push ds                       ;save DS
  520.               mov ax,bios_data              ;point it to BIOS data area
  521.               mov ds,ax
  522.               assume ds:bios_data
  523.               mov ax,crt_cols               ;get number of display columns
  524.               mov linesum,ax                ;calculate distance from end of
  525.               sub linesum,44                ;  one line to start of next
  526.               shl linesum,1
  527.               mov bl,6                      ;calculate starting address
  528.               mul bl                        ;result in AX
  529.               shl ax,1                      ;double result for attr bytes
  530.               add ax,36                     ;add line offset
  531.               mov si,ax                     ;transfer to SI
  532.               add si,crt_start              ;add page offset
  533.               mov video_address,si          ;save offset address
  534.               mov ds,video_segment          ;then set DS to the video segment
  535.               mov di,offset screen_buffer   ;point DI to storage buffer
  536.               mov cx,10                     ;10 lines to save
  537. save1:        push cx                       ;save line count
  538.               mov cx,44                     ;44 characters per line
  539.               rep movsw                     ;transfer one line to storage
  540.               pop cx                        ;retrieve line count
  541.               add si,linesum                ;point SI to next video line
  542.               loop save1                    ;loop until all lines are saved
  543.               pop ds                        ;restore DS
  544.               assume ds:code
  545.               ret                           ;exit
  546. save_screen   endp
  547. ;
  548. ;------------------------------------------------------------------------------
  549. ;RESTORE_SCREEN writes the stored screen image to video memory.
  550. ;------------------------------------------------------------------------------
  551. restore_screen proc near
  552.               push es                       ;save ES register value
  553.               mov di,video_address          ;point DI to starting video offset
  554.               mov es,video_segment          ;point ES to video memory
  555.               mov si,offset screen_buffer   ;point DS:SI to screen image
  556.               mov cx,10                     ;10 lines to restore
  557. restore1:     push cx                       ;save line count
  558.               mov cx,44                     ;44 characters per line
  559.               rep movsw                     ;restore one line
  560.               pop cx                        ;retrieve line count
  561.               add di,linesum                ;set DI to next video line
  562.               loop restore1                 ;loop until done
  563.               pop es                        ;restore ES
  564.               ret
  565. restore_screen endp
  566. ;
  567. ;------------------------------------------------------------------------------
  568. ;MAKE_SCREEN writes an image of the CardFile window to video memory.
  569. ;------------------------------------------------------------------------------
  570. make_screen   proc near
  571.               push es                       ;save ES
  572.               mov es,video_segment          ;point ES:DI to video memory
  573.               mov di,video_address
  574.               mov al,218                    ;line no. 1
  575.               mov ah,border_attr
  576.               stosw
  577.               mov al,196
  578.               mov cx,42
  579.               rep stosw
  580.               mov al,191
  581.               stosw
  582.               add di,linesum
  583.               mov si,offset titles          ;lines 2 thru 7
  584.               mov cx,6                      ;6 lines
  585. make1:        push cx
  586.               call formline
  587.               add di,linesum
  588.               pop cx
  589.               loop make1
  590.               mov al,179                    ;line no. 8
  591.               stosw
  592.               push ax
  593.               mov al,32
  594.               mov ah,text_attr
  595.               stosw
  596.               push ax
  597.               mov al,196
  598.               mov cx,40
  599.               rep stosw
  600.               pop ax
  601.               stosw
  602.               pop ax
  603.               stosw
  604.               add di,linesum
  605.               stosw                         ;line no. 9
  606.               push ax
  607.               mov al,32
  608.               mov ah,menu_attr
  609.               stosw
  610.               push ax
  611.               mov si,offset menuline1
  612.               mov cx,40
  613. make2:        lodsb
  614.               stosw
  615.               loop make2
  616.               pop ax
  617.               stosw
  618.               pop ax
  619.               stosw
  620.               add di,linesum
  621.               mov al,192                    ;line no. 10
  622.               stosw
  623.               mov al,196
  624.               mov cx,42
  625.               rep stosw
  626.               mov al,217
  627.               stosw
  628.               pop es                        ;restore ES
  629.               ret
  630. make_screen   endp
  631. ;
  632. ;------------------------------------------------------------------------------
  633. ;FORMLINE is called by MAKE_SCREEN to help with the dirty work.
  634. ;------------------------------------------------------------------------------
  635. formline      proc near
  636.               mov al,179                    ;write border character
  637.               mov ah,border_attr
  638.               stosw
  639.               push ax                       ;save it for later
  640.               mov cx,6                      ;do next 6 characters
  641.               mov ah,text_attr
  642. form1:        lodsb
  643.               stosw
  644.               loop form1
  645.               mov al,32                     ;add 2 blanks
  646.               stosw
  647.               stosw
  648.               mov ah,record_attr            ;then add 34 blank characters
  649.               mov cx,34
  650.               rep stosw
  651.               pop ax                        ;finish with border character
  652.               stosw
  653.               ret
  654. formline      endp
  655. ;
  656. ;------------------------------------------------------------------------------
  657. ;QSEARCH pages to the record whose first character matches the Alt key pressed.
  658. ;------------------------------------------------------------------------------
  659. qsearch       proc near
  660.               cmp numrec,2                  ;at least 2 records to search?
  661.               jb qs3                        ;no, then exit
  662.               mov al,ah                     ;transfer scan code to AL
  663.               sub al,16                     ;normalize it
  664.               mov bx,offset key_table       ;address table of equivalents
  665.               xlat                          ;get corresponding ASCII code
  666.               mov dl,al                     ;transfer it to DL
  667.               mov cl,numrec                 ;get record count in CX
  668.               xor ch,ch
  669.               mov al,1                      ;initialize record index
  670. qs1:          push ax                       ;save index
  671.               push cx                       ;save count
  672.               call record_address           ;get address of current record
  673.               cmp [di],dl                   ;compare characters
  674.               pop cx                        ;retrieve count and index
  675.               pop ax
  676.               jae qs2                       ;end search
  677.               inc al                        ;increment index
  678.               loop qs1                      ;loop back for next record
  679.               dec al                        ;search exhausted
  680. qs2:          cmp al,recptr                 ;record already showing?
  681.               je qs3                        ;yes, then exit
  682.               mov recptr,al                 ;no, then change display
  683.               call show_record
  684. qs3:          ret
  685. qsearch       endp
  686. ;
  687. ;------------------------------------------------------------------------------
  688. ;SEARCH searches data for occurrence of a string input by the user.
  689. ;------------------------------------------------------------------------------
  690. strlen        db ?                          ;string length
  691. passes        db ?                          ;number of search loops
  692. ;
  693. search        proc near
  694.               cmp numrec,0                  ;any records to search?
  695.               je search_exit                ;no, then exit
  696.               mov si,offset menuline4       ;prepare menu line for input
  697.               call write_menu
  698.               xor di,di                     ;read string from keyboard
  699.               mov dx,0E1Ah
  700.               mov cl,32
  701.               call readln
  702.               or cl,cl                      ;anything entered?
  703.               jne search1                   ;yes, then continue
  704. search_exit:  mov si,offset menuline1       ;restore menu line and exit
  705.               call write_menu
  706.               ret
  707. ;
  708. ;Set search parameters and begin the scan.
  709. ;
  710. search1:      mov strlen,cl                 ;save string length
  711.               mov ch,33                     ;determine no. of passes per line
  712.               sub ch,cl
  713.               mov passes,ch                 ;save it
  714.               mov al,recptr                 ;start search at current record
  715.               mov cl,numrec                 ;set max search length
  716.               xor ch,ch
  717. search2:      push ax                       ;save record number
  718.               push cx                       ;save record count
  719.               call record_address           ;get address of current record
  720.               mov cx,6                      ;6 lines per record
  721. search3:      push cx                       ;save line count
  722.               push di                       ;save line address
  723.               mov cl,passes                 ;set number of passes per line
  724.               xor ch,ch
  725. search4:      push cx                       ;save pass count
  726.               push di                       ;save search address within line
  727.               mov cl,strlen                 ;number of bytes to compare
  728.               xor ch,ch
  729.               xor si,si                     ;point SI to input buffer
  730. search5:      lodsb                         ;get a byte from the input buffer
  731.               and al,0DFh                   ;capitalize it
  732.               mov bl,es:[di]                ;get a byte from the record
  733.               and bl,0DFh                   ;capitalize it
  734.               inc di                        ;advance pointer
  735.               cmp al,bl                     ;are the two bytes identical?
  736.               jne nextpos                   ;no, then try next position
  737.               loop search5                  ;yes, then try next byte
  738. ;
  739. ;A match was found.  Clean up the stack and display the record.
  740. ;
  741.               add sp,10                     ;delete last 5 words PUSHed
  742.               pop ax                        ;retrieve current record number
  743.               push ax                       ;push it back onto the stack
  744.               mov cl,numrec                 ;restart the record counter
  745.               xor ch,ch
  746.               inc cx
  747.               push cx                       ;shove it onto the stack
  748.               mov recptr,al                 ;set current record to this one
  749.               call show_record              ;display new record
  750.               mov si,offset menuline5       ;display new menu line
  751.               call write_menu
  752. searchkey:    call getkey                   ;wait for a keypress
  753.               cmp al,13                     ;ENTER key?
  754.               je nextrec                    ;yes, then continue search
  755.               cmp al,27                     ;ESC key?
  756.               jne searchkey                 ;no, then ignore the keypress
  757.               pop cx                        ;clean up the stack
  758.               pop ax
  759.               jmp search_exit               ;exit
  760. ;
  761. ;Advance to the next position and continue the string search.
  762. ;
  763. nextpos:      pop di                        ;retrieve address
  764.               pop cx                        ;retrieve pass count
  765.               inc di                        ;advance to next position on line
  766.               loop search4                  ;loop back for another try
  767. nextline:     pop di                        ;retrieve line address
  768.               pop cx                        ;retrieve line count
  769.               add di,32                     ;advance pointer to next line
  770.               loop search3                  ;loop back
  771. nextrec:      pop cx                        ;retrieve record count
  772.               pop ax                        ;retrieve current record number
  773.               cmp al,numrec                 ;currently on last record?
  774.               je reset                      ;yes, then wrap around
  775.               inc al                        ;no, then advance record pointer
  776.               jmp short next1
  777. reset:        mov al,1                      ;reset record pointer
  778. next1:        loop search2                  ;reenter main loop
  779. ;
  780. ;All records were searched and no match was found.
  781. ;
  782.               mov si,offset menuline6       ;print message
  783.               call write_menu
  784. search6:      call getkey                   ;wait for a press of ESC
  785.               cmp al,27
  786.               jne search6
  787.               jmp search_exit               ;exit
  788. search        endp
  789. ;
  790. ;------------------------------------------------------------------------------
  791. ;DIAL dials the phone number currently displayed.
  792. ;------------------------------------------------------------------------------
  793. linectrl           db ?                     ;Line Control Register value
  794. divlsb             db ?                     ;baud rate divisor LSB
  795. divmsb             db ?                     ;baud rate divisor MSB
  796. intreg             db ?                     ;Interrupt Enable Register value
  797. ;
  798. dial          proc near
  799.               cmp numrec,0                  ;any records in memory?
  800.               jne dstart                    ;yes, then branch
  801. dial_exit:    ret                           ;no, then exit
  802. ;
  803. ;Save the current state of the COM port.
  804. ;
  805. dstart:       mov si,comport                ;get UART base address
  806.               shl si,1
  807.               push es                       ;save ES
  808.               mov ax,bios_data              ;then point it to BIOS data area
  809.               mov es,ax
  810.               assume es:bios_data
  811.               mov dx,rs232_base[si]
  812.               pop es                        ;restore ES
  813.               assume es:nothing
  814.               or dx,dx                      ;is this port installed?
  815.               je dial_exit                  ;no, then exit
  816.               add dx,3                      ;point DX to Line Control Register
  817.               push dx                       ;save the address
  818.               in al,dx                      ;read LCR
  819.               mov linectrl,al               ;store value for later
  820.               or al,80h                     ;set DLAB
  821.               out dx,al
  822.               sub dx,3                      ;point DX to Divisor LSB Register
  823.               in al,dx                      ;read it
  824.               mov divlsb,al                 ;save it
  825.               inc dx                        ;point DX to Divisor MSB Register
  826.               in al,dx                      ;read it
  827.               mov divmsb,al                 ;save it
  828.               mov al,linectrl               ;recover Line Control setting
  829.               and al,07Fh                   ;clear the high bit
  830.               add dx,2                      ;point DX back to Line Control
  831.               out dx,al                     ;clear DLAB
  832.               sub dx,2                      ;address Interrupt Enable Register
  833.               in al,dx                      ;read it
  834.               mov intreg,al                 ;and save it
  835. ;
  836. ;Initialize the COM port.
  837. ;
  838.               mov ah,0                      ;initialize COM port
  839.               mov al,initstr                ;baud rate and data format
  840.               mov dx,comport                ;COM port identifier
  841.               int 14h
  842. ;
  843. ;Dial the phone number.
  844. ;
  845.               mov si,offset dialstr         ;point DS:SI to 'ATDT' string
  846.               call sendcom                  ;output string to COM port
  847.               test ah,80h                   ;was the string sent?
  848.               jnz time_out                  ;no, then modem isn't ready
  849.               mov al,recptr                 ;get address of current record
  850.               call record_address
  851.               mov si,di
  852.               add si,128                    ;point SI to 'Phone' line
  853.               mov cx,32                     ;32 characters to check
  854. dial1:        lodsb                         ;get one character
  855.               cmp al,","                    ;is it a comma?
  856.               je dial2                      ;yes, then send it
  857.               cmp al,"0"                    ;less than ASCII zero?
  858.               jb dial3                      ;yes, then ignore it
  859.               cmp al,"9"                    ;greater than ASCII 9?
  860.               ja dial3                      ;yes, then ignore it
  861. dial2:        mov ah,1                      ;output byte to COM port
  862.               int 14h
  863.               test ah,80h                   ;was the byte successfully output?
  864.               jnz time_out                  ;no, then modem isn't ready
  865. dial3:        loop dial1                    ;loop until line is finished
  866.               mov ax,013Bh                  ;terminate with semicolon and CR
  867.               int 14h
  868.               mov ax,010Dh
  869.               int 14h
  870.               test ah,80h                   ;were the bytes transmitted?
  871.               jz dial5                      ;yes, then continue
  872. ;
  873. ;Display 'Modem not ready' message and wait for ESC to be pressed.
  874. ;
  875. time_out:     mov si,offset menuline12      ;print message
  876.               call write_menu
  877. dial4:        call getkey                   ;wait for a press of ESC
  878.               cmp al,27
  879.               jne dial4
  880.               jmp dial8
  881. ;
  882. ;Wait for a press of the spacebar, then force the modem to hang up.
  883. ;
  884. dial5:        mov si,offset menuline10      ;display 'Pick up phone...'
  885.               call write_menu
  886. dial6:        call getkey                   ;wait for a press of the spacebar
  887.               cmp al,32
  888.               jne dial6 
  889.               mov si,offset hangupstr       ;point SI to 'ATH0' string
  890.               mov dx,comport                ;specify COM port
  891.               call sendcom                  ;output it to the COM port
  892.               mov cx,8000h                  ;I/O delay
  893. dial7:        loop dial7
  894. ;
  895. ;Restore the COM port to its original state and exit.
  896. ;
  897. dial8:        pop dx                        ;retrieve UART address
  898.               mov al,80h                    ;set DLAB
  899.               out dx,al
  900.               sub dx,3                      ;point DX to Divisor LSB
  901.               mov al,divlsb                 ;reset it
  902.               out dx,al
  903.               inc dx                        ;point DX to MSB
  904.               mov al,divmsb                 ;reset it
  905.               out dx,al
  906.               add dx,2                      ;point DX to Line Control
  907.               xor al,al                     ;clear DLAB
  908.               out dx,al
  909.               sub dx,2                      ;point DX to Interrupt Enable
  910.               mov al,intreg                 ;restore it
  911.               out dx,al
  912.               add dx,2                      ;restore Line Control Register
  913.               mov al,linectrl
  914.               out dx,al
  915.               mov si,offset menuline1       ;restore menu line and exit
  916.               call write_menu
  917.               ret
  918. dial          endp
  919. ;
  920. ;------------------------------------------------------------------------------
  921. ;SENDCOM outputs an ASCIIZ string to the designated COM port.
  922. ;Entry:  DS:SI - string address        | Exit:  AH bit 7 clear - string sent
  923. ;        DX    - 0 = COM1, 1 = COM2    |        AH bit 7 set   - time out
  924. ;------------------------------------------------------------------------------
  925. sendcom       proc near
  926.               lodsb                         ;get a byte
  927.               or al,al                      ;zero terminator?
  928.               je comexit                    ;yes, then exit
  929.               mov ah,1                      ;output byte
  930.               int 14h
  931.               test ah,80h                   ;was byte transmitted?
  932.               jz sendcom                    ;yes, loop back for more
  933. comexit:      ret       ;exit
  934. sendcom       endp
  935. ;
  936. ;------------------------------------------------------------------------------
  937. ;EDIT allows the current record to be edited.
  938. ;------------------------------------------------------------------------------
  939. edit          proc near
  940.               cmp numrec,0                  ;any records to edit?
  941.               je edit1                      ;no, then exit
  942.               mov al,recptr                 ;get current record number
  943.               call record_address           ;get its address and position
  944.               mov slotno,al                 ;save position
  945.               push di                       ;save address
  946.               call delete_record            ;delete it
  947.               pop di                        ;recover address
  948.               push di                       ;save it again
  949.               mov si,offset menuline9       ;address menu line text
  950.               call edit_record              ;allow it to be edited
  951.               pop si                        ;place address in SI
  952.               jc no_entry                   ;branch if entry now blank
  953.               call find_position            ;determine logical position
  954.               mov bl,slotno                 ;retrieve physical position
  955.               call insert_record            ;insert record into the stack
  956.               mov recptr,cl                 ;modify current record number
  957. edit1:        ret                           ;exit
  958. no_entry:     cmp numrec,0                  ;any records left after deletion?
  959.               je edit1                      ;no, then we're done
  960.               mov al,numrec                 ;get number of records
  961.               cmp al,recptr                 ;RECPTR in range?
  962.               jae edit2                     ;yes, then branch
  963.               dec recptr                    ;no, then modify it
  964. edit2:        call show_record              ;display new current record
  965.               ret
  966. edit          endp
  967. ;
  968. ;------------------------------------------------------------------------------
  969. ;CREATE allows a new record to be created and inserted.
  970. ;------------------------------------------------------------------------------
  971. create        proc near
  972.               mov al,numrec                 ;retrieve number of records
  973.               cmp al,maxrec                 ;room for another record?
  974.               jne create1                   ;yes, then branch
  975.               mov si,offset menuline7       ;no, then print error message
  976.               call write_menu
  977. create0:      call getkey                   ;wait for a press of ESC
  978.               cmp al,27
  979.               jne create0
  980.               mov si,offset menuline1       ;restore menu line
  981.               call write_menu
  982.               ret                           ;exit
  983. create1:      call clear_window             ;clear the current display
  984.               xor al,al                     ;zero AL
  985.               call record_address           ;get address of empty record slot
  986.               mov slotno,al                 ;save position
  987.               mov al,32                     ;blank the record
  988.               mov cx,192
  989.               rep stosb
  990.               sub di,192                    ;point DI back to start of record
  991.               push di                       ;save address
  992.               mov si,offset menuline3       ;set text address
  993.               call edit_record              ;allow record to be edited
  994.               pop si                        ;get address in SI
  995.               jc blank_entry                ;branch if new entry is blank
  996.               call find_position            ;determine new record position
  997.               mov bl,slotno                 ;retrieve its physical position
  998.               call insert_record            ;insert new record into stack
  999.               mov recptr,cl                 ;point RECPTR to new record
  1000.               ret
  1001. blank_entry:  cmp numrec,0                  ;any records?
  1002.               je blank1                     ;no, then exit
  1003.               call show_record              ;display current record
  1004. blank1:       ret
  1005. create        endp
  1006. ;
  1007. ;------------------------------------------------------------------------------
  1008. ;DELETE deletes the current record.
  1009. ;------------------------------------------------------------------------------
  1010. delete        proc near
  1011.               cmp numrec,0                  ;any records to delete?
  1012.               je del_exit                   ;no, then exit
  1013.               mov si,offset menuline2       ;request verification
  1014.               call write_menu
  1015. del1:         call getkey                   ;get keyboard response
  1016.               cmp al,13                     ;ENTER pressed?
  1017.               je del2                       ;yes, then continue
  1018.               cmp al,27                     ;ESC pressed?
  1019.               jne del1                      ;no, then get another keypress
  1020. del2:         push ax                       ;save response
  1021.               mov si,offset menuline1       ;restore menu line
  1022.               call write_menu
  1023.               pop ax                        ;retrieve response
  1024.               cmp al,13                     ;delete the record?
  1025.               jne del_exit                  ;no
  1026.               call delete_record            ;delete current record
  1027.               cmp numrec,0                  ;any records left?
  1028.               jne del3                      ;yes, then branch
  1029.               call clear_window             ;no, then clear display
  1030. del_exit:     ret                           ;exit
  1031. del3:         mov al,numrec                 ;get record count
  1032.               cmp al,recptr                 ;is RECPTR in range?
  1033.               jae del4                      ;yes, then branch
  1034.               dec recptr                    ;no, then make sure it is
  1035. del4:         call show_record              ;display new current record
  1036.               ret
  1037. delete        endp
  1038. ;
  1039. ;------------------------------------------------------------------------------
  1040. ;SAVE writes the data in memory to disk.
  1041. ;------------------------------------------------------------------------------
  1042. save          proc near
  1043.               cmp numrec,0                  ;any records to save?
  1044.               jne fsave1                    ;yes, then continue
  1045.               ret                           ;no, then exit
  1046. fsave1:       cmp fileflag,0                ;does a filespec exist?
  1047.               jne fsave2                    ;yes, then branch
  1048. ;
  1049. ;Read a filespec input from the keyboard.
  1050. ;
  1051. getname:      mov si,offset menuline13      ;print input prompt
  1052.               call write_menu
  1053.               xor di,di                     ;prepare for call to READLN
  1054.               mov dx,0E1Ah
  1055.               mov cl,34
  1056.               call readln                   ;read the filespec
  1057.               or cl,cl                      ;anything entered?
  1058.               je save_exit                  ;no, then exit
  1059.               mov fileflag,1                ;set filespec indicator
  1060.               xor si,si                     ;copy filespec into buffer
  1061.               mov di,offset filespec
  1062.               xor ch,ch
  1063.               rep movsb
  1064.               mov byte ptr es:[di],0        ;zero last byte
  1065. ;
  1066. ;Open the file and write record data out to it.
  1067. ;
  1068. fsave2:       mov dx,offset filespec        ;point DX to filespec
  1069.               mov ah,3Ch                    ;open/create file
  1070.               xor cx,cx                     ;normal attributes
  1071.               int 21h
  1072.               jc getname                    ;get new filespec if open failed
  1073. fsave3:       mov bx,ax                     ;transfer file handle to BX
  1074.               mov ah,40h                    ;write NUMREC byte to file
  1075.               mov cx,1
  1076.               mov dx,offset numrec
  1077.               int 21h
  1078.               jc save_error                 ;branch on error
  1079.               cmp ax,1                      ;byte successfully written?
  1080.               jb diskfull                   ;no, then disk is full
  1081.               mov al,1                      ;initialize record number
  1082.               mov cl,numrec                 ;get number of records to write
  1083.               xor ch,ch
  1084. fsave4:       push cx                       ;save count
  1085.               push ax                       ;save record number
  1086.               call record_address           ;get address of current record
  1087.               mov dx,di                     ;transfer it to DX
  1088.               mov cx,192                    ;192 bytes per record
  1089.               mov ah,40h                    ;write one record
  1090.               int 21h
  1091.               mov dx,ax                     ;transfer byte count to DX
  1092.               pop ax                        ;retrieve record number and count
  1093.               pop cx
  1094.               jc save_error                 ;branch on error
  1095.               cmp dx,192                    ;entire record written?
  1096.               jb diskfull                   ;no, then disk is full
  1097.               inc al                        ;next record
  1098.               loop fsave4                   ;loop until done
  1099. closefile:    mov ah,3Eh                    ;close file
  1100.               int 21h
  1101. save_exit:    mov si,offset menuline1       ;restore menu line
  1102.               call write_menu
  1103.               ret                           ;exit
  1104. ;
  1105. ;An error was encountered during the save.
  1106. ;
  1107. save_error:   mov si,offset menuline11      ;print error message
  1108.               push bx                       ;save file handle
  1109.               call write_menu
  1110.               pop bx                        ;retrieve file handle
  1111. error2:       call getkey                   ;wait for a press of ESC
  1112.               cmp al,27
  1113.               jne error2
  1114.               jmp short closefile           ;close file and resume
  1115. ;
  1116. ;No room left on the disk.
  1117. ;
  1118. diskfull:     mov si,offset menuline8       ;print 'Disk full' message
  1119.               push bx                       ;save file handle
  1120.               call write_menu
  1121.               pop bx                        ;retrieve file handle
  1122. full2:        call getkey                   ;wait for a press of ESC
  1123.               cmp al,27
  1124.               jne full2
  1125.               jmp short closefile           ;and exit
  1126. save          endp
  1127. ;
  1128. ;------------------------------------------------------------------------------
  1129. ;DISABLE_CGA and ENABLE_CGA disable and enable CGA video output.
  1130. ;------------------------------------------------------------------------------
  1131. disable_cga   proc near
  1132.               mov dx,3DAh                   ;address of Status Register
  1133. disable1:     in al,dx                      ;get status
  1134.               test al,8                     ;vertical retrace active?
  1135.               je disable1                   ;no, then wait
  1136.               sub dx,2                      ;MSR address in DX
  1137.               mov al,25h                    ;value to disable video
  1138.               out dx,al                     ;disable video output
  1139.               ret
  1140. disable_cga   endp
  1141. ;
  1142. enable_cga    proc near
  1143.               mov ah,15                     ;get video mode
  1144.               int 10h
  1145.               mov bx,offset enable_values   ;get value to enable display
  1146.               xlat                          ;value in AL
  1147.               mov dx,3D8h                   ;MSR address
  1148.               out dx,al                     ;enable video output
  1149.               ret
  1150. enable_cga    endp
  1151. ;
  1152. ;------------------------------------------------------------------------------
  1153. ;GETKEY waits for a keypress and returns the keycode in AX.
  1154. ;Exit:  AX - keycode
  1155. ;------------------------------------------------------------------------------
  1156. getkey        proc near
  1157.               mov ah,1                      ;check keyboard buffer
  1158.               int 16h
  1159.               jne getkey1                   ;jump if buffer contains a keycode
  1160.               int 28h                       ;no key pressed - issue int 28h
  1161.               jmp getkey                    ;loop back to try again
  1162. getkey1:      mov ah,0                      ;get keycode from buffer
  1163.               int 16h
  1164.               ret                           ;exit with keycode in AX
  1165. getkey        endp
  1166. ;
  1167. ;------------------------------------------------------------------------------
  1168. ;INSERT_RECORD inserts a record into the stack.
  1169. ;Entry:  BL - slot number
  1170. ;        CL - index number
  1171. ;------------------------------------------------------------------------------
  1172. insert_record proc near
  1173.               push cx                       ;save index number
  1174.               mov di,offset index_table     ;point DI to index table
  1175.               mov al,cl                     ;get index number in AL for search
  1176.               mov cl,maxrec                 ;set counter
  1177.               xor ch,ch
  1178. insert1:      cmp [di],al                   ;index less than new index?
  1179.               jb insert2                    ;yes, then branch
  1180.               inc byte ptr [di]             ;increment index
  1181. insert2:      inc di                        ;advance DI to next index
  1182.               loop insert1                  ;loop until all indexes examined
  1183.               pop cx                        ;retrieve new index number
  1184.               xor bh,bh                     ;byte to word in BX
  1185.               mov di,offset index_table     ;point DI to index table
  1186.               mov [di+bx],cl                ;deposit new index into table
  1187.               inc numrec                    ;increment record count by 1
  1188.               ret
  1189. insert_record endp
  1190. ;
  1191. ;------------------------------------------------------------------------------
  1192. ;DELETE_RECORD deletes the record indexed by RECPTR.
  1193. ;------------------------------------------------------------------------------
  1194. delete_record proc near
  1195.               mov al,recptr                 ;search for current record slot
  1196.               mov di,offset index_table
  1197.               mov cl,maxrec
  1198.               xor ch,ch
  1199.               repne scasb
  1200.               dec di                        ;back to matching byte
  1201.               mov byte ptr [di],0           ;zero current index
  1202.               mov al,recptr                 ;get current record number
  1203.               mov di,offset index_table            ;point DI to index table
  1204.               mov cl,maxrec                 ;set counter
  1205.               xor ch,ch
  1206. delrec1:      cmp [di],al                   ;index less than current index?
  1207.               jb delrec2                    ;yes, then branch
  1208.               dec byte ptr [di]             ;no, decrement index
  1209. delrec2:      inc di                        ;advance to next index
  1210.               loop delrec1                  ;loop until all records examined
  1211.               dec numrec                    ;decrement record count by 1
  1212.               ret
  1213. delete_record endp
  1214. ;
  1215. ;------------------------------------------------------------------------------
  1216. ;EDIT_RECORD allows the record addressed by ES:DI to be edited.
  1217. ;Entry:  ES:DI - record address        | Exit:  CF clear - record valid
  1218. ;        DS:SI - menu line text string |        CF set   - record blank
  1219. ;------------------------------------------------------------------------------
  1220. edit_record   proc near
  1221.               push di                       ;save starting address
  1222.               call write_menu               ;write new menu line
  1223.               mov bh,video_page             ;set BH for video calls
  1224.               mov ah,2                      ;set initial cursor position
  1225.               mov dx,071Bh
  1226.               int 10h
  1227.               call show_cursor              ;display the cursor
  1228. ;
  1229. ;Wait for a keypress.
  1230. ;
  1231. editrec1:     call getkey                   ;get a keypress
  1232.               or al,al                      ;extended code?
  1233.               jne editrec2                  ;no, then branch
  1234.               jmp short extend              ;goto extended code handler
  1235. editrec2:     cmp al,8                      ;backspace key?
  1236.               je bspace
  1237.               cmp al,13                     ;ENTER key?
  1238.               je enter
  1239.               cmp al,32                     ;ASCII code less than 32?
  1240.               jb editrec1                   ;yes, then ignore it
  1241. ;
  1242. ;Process a press of a character key.
  1243. ;
  1244.               cmp dl,59                     ;at the end of the line?
  1245.               je editrec1                   ;yes, then ignore keypress
  1246.               stosb                         ;deposit character in record
  1247.               mov ah,10                     ;then print it
  1248.               mov cx,1
  1249.               int 10h
  1250.               mov ah,2                      ;advance the cursor
  1251.               inc dl
  1252.               int 10h
  1253.               jmp editrec1                  ;return for more
  1254. ;
  1255. ;Process a press of the BACKSPACE key.
  1256. ;
  1257. bspace:       cmp dl,27                     ;any characters to delete?
  1258.               je editrec1                   ;no, then ignore keypress
  1259.               mov ah,2                      ;move cursor back one space
  1260.               dec dl
  1261.               int 10h
  1262.               mov ax,0A20h                  ;print a space character
  1263.               mov cx,1
  1264.               int 10h
  1265.               dec di                        ;decrement buffer pointer by 1
  1266.               mov byte ptr es:[di],32       ;insert an ASCII space
  1267.               jmp editrec1
  1268. ;
  1269. ;Process a press of the ENTER key.
  1270. ;
  1271. enter:        mov al,dl                     ;reset DI to beginning of line
  1272.               xor ah,ah
  1273.               sub ax,27
  1274.               sub di,ax
  1275.               inc dh                        ;advance row number
  1276.               add di,32                     ;advance pointer
  1277.               cmp dh,13                     ;wrap around if necessary
  1278.               jne enter1
  1279.               mov dh,7
  1280.               sub di,192
  1281. enter1:       mov dl,27                     ;home the cursor
  1282.               mov ah,2
  1283.               int 10h
  1284.               jmp editrec1                  ;return to input loop
  1285. ;
  1286. ;Process a press of either Cursor-Left or Cursor-Right.
  1287. ;
  1288. extend:       cmp ah,75                     ;cursor left key?
  1289.               jne ext2                      ;no, then branch
  1290.               cmp dl,27                     ;already at left end of field?
  1291.               je ext1                       ;yes, then ignore keypress
  1292.               mov ah,2                      ;move cursor back one space
  1293.               dec dl
  1294.               int 10h
  1295.               dec di                        ;decrement buffer pointer
  1296. ext1:         jmp editrec1                  ;return
  1297. ext2:         cmp ah,77                     ;cursor right key?
  1298.               jne ext3                      ;no, then branch
  1299.               cmp dl,59                     ;cursor in last column?
  1300.               je ext1                       ;yes, then ignore keypress
  1301.               mov ah,2                      ;advance cursor
  1302.               inc dl
  1303.               int 10h
  1304.               inc di                        ;increment buffer pointer
  1305.               jmp editrec1                  ;return
  1306. ;
  1307. ;Process a press of either Cursor-Up or Cursor-Down.
  1308. ;
  1309. ext3:         cmp ah,72                     ;cursor up key?
  1310.               jne ext5                      ;no, then branch
  1311.               dec dh                        ;decrement row number
  1312.               sub di,32                     ;set pointer to previous line
  1313.               cmp dh,6                      ;wrap around if necessary
  1314.               jne ext4
  1315.               mov dh,12
  1316.               add di,192
  1317. ext4:         mov ah,2                      ;move the cursor
  1318.               int 10h
  1319.               jmp editrec1                  ;return for another keypress
  1320. ext5:         cmp ah,80                     ;cursor down key?
  1321.               jne ext6                      ;no, then branch
  1322.               inc dh                        ;increment row number
  1323.               add di,32                     ;set pointer to next line
  1324.               cmp dh,13                     ;wrap around if necessary
  1325.               jne ext4
  1326.               mov dh,7
  1327.               sub di,192
  1328.               jmp ext4                      ;move cursor and return
  1329. ;
  1330. ;End the edit routine when F1 is pressed.
  1331. ;
  1332. ext6:         cmp ah,59                     ;F1 key?
  1333.               jne ext4                      ;no, then ignore keypress
  1334.               mov ah,1                      ;hide the cursor
  1335.               mov ch,20h
  1336.               int 10h
  1337.               mov si,offset menuline1       ;restore menu line
  1338.               call write_menu
  1339.               pop di                        ;recover starting address
  1340.               mov al,32                     ;ASCII space character
  1341.               mov cx,192                    ;192 bytes per record
  1342.               repe scasb                    ;check for non-space character
  1343.               jne ok                        ;OK if non-space found
  1344.               stc                           ;set CF to indicate blank entry
  1345.               ret
  1346. ok:           clc                           ;clear CF to indicate valid record
  1347.               ret
  1348. edit_record   endp
  1349. ;
  1350. ;------------------------------------------------------------------------------
  1351. ;FIND_POSITION returns the new index of the record addressed by SI.
  1352. ;Entry:  SI - record address           | Exit:  CL - record number
  1353. ;------------------------------------------------------------------------------
  1354. find_position proc near
  1355.               mov cl,1                      ;set index for first record
  1356.               cmp numrec,0                  ;any records to examine?
  1357.               je find_exit                  ;no, then exit
  1358. find1:        mov al,cl                     ;get index in AL
  1359.               push cx                       ;save it
  1360.               call record_address           ;get address of next record
  1361.               push si                       ;save new record address
  1362.               mov cx,32                     ;32 bytes per record
  1363. find2:        cmpsb                         ;compare records
  1364.               ja next_record                ;check next record
  1365.               jb slot_found                 ;alphabetical slot found
  1366.               loop find2                    ;goto next byte if these are equal
  1367.               jmp short slot_found          ;slot found if all equal
  1368. next_record:  pop si                        ;clean up the stack
  1369.               pop cx
  1370.               inc cl                        ;next record number
  1371.               cmp cl,numrec                 ;all records searched?
  1372.               jbe find1                     ;no, then loop back for more
  1373. find_exit:    ret                           ;yes, then we're done
  1374. slot_found:   pop si                        ;clean up the stack
  1375.               pop cx
  1376.               ret
  1377. find_position endp
  1378. ;
  1379. ;------------------------------------------------------------------------------
  1380. ;SHOW_RECORD displays the record pointed to by RECPTR.
  1381. ;------------------------------------------------------------------------------
  1382. show_record   proc near
  1383.               mov al,recptr                 ;get current record number
  1384.               call record_address           ;get record address in DI
  1385.               mov si,di                     ;transfer it to SI
  1386.               mov bl,record_attr            ;set attribute to be used
  1387.               mov dx,071Bh                  ;set initial cursor position
  1388.               mov cx,6                      ;6 lines to display
  1389. show1:        push cx                       ;save line counter
  1390.               push dx                       ;save cursor position
  1391.               mov cx,32                     ;32 characters per line
  1392.               call writeln                  ;display one line
  1393.               pop dx                        ;retrieve cursor address
  1394.               inc dh                        ;increment row number
  1395.               pop cx                        ;retrieve line counter
  1396.               loop show1                    ;loop until done
  1397.               ret
  1398. show_record   endp
  1399. ;
  1400. ;------------------------------------------------------------------------------
  1401. ;RECORD_ADDRESS returns the offset address and slot number of a record.
  1402. ;Entry: AL - record number             | Exit:  DI - record address
  1403. ;                                      |        AL - slot number
  1404. ;------------------------------------------------------------------------------
  1405. record_address proc near
  1406.               mov di,offset index_table     ;point DI to index table
  1407.               mov cl,maxrec                 ;set counter
  1408.               xor ch,ch
  1409.               repne scasb                   ;search for current record number
  1410.               inc cx                        ;increment counter
  1411.               mov al,maxrec                 ;calculate offset address in AX
  1412.               sub al,cl
  1413.               push ax                       ;save slot number
  1414.               mul record_length
  1415.               add ax,offset data_buffer
  1416.               mov di,ax                     ;transfer address to DI
  1417.               pop ax                        ;recover slot number
  1418.               ret
  1419. record_address endp
  1420. ;
  1421. ;------------------------------------------------------------------------------
  1422. ;WRITE_MENU displays a line of text on the window's menu line.
  1423. ;Entry:  DS:SI - address of text
  1424. ;------------------------------------------------------------------------------
  1425. write_menu    proc near
  1426.               mov ah,2                      ;position the cursor
  1427.               mov dx,0E14h
  1428.               mov bh,video_page
  1429.               int 10h
  1430.               mov ax,0920h                  ;erase current menu line
  1431.               mov bl,menu_attr
  1432.               mov cx,40
  1433.               int 10h
  1434. wm1:          lodsb                         ;get a character
  1435.               or al,al                      ;exit if it's the delimiter
  1436.               je wm2
  1437.               mov ah,0Eh                    ;write the character
  1438.               int 10h
  1439.               jmp short wm1                 ;loop until done
  1440. wm2:          ret
  1441. write_menu    endp
  1442. ;
  1443. ;------------------------------------------------------------------------------
  1444. ;WRITELN displays a string.
  1445. ;Entry:  DS:SI - string address
  1446. ;        BL    - attribute
  1447. ;        CX    - string length
  1448. ;        DH,DL - starting row and column
  1449. ;------------------------------------------------------------------------------
  1450. writeln       proc near
  1451.               mov bh,video_page             ;set page number for output
  1452. write1:       mov ah,2                      ;position cursor
  1453.               int 10h
  1454.               lodsb                         ;get one byte
  1455.               push cx                       ;save count
  1456.               mov cx,1                      ;zero repetitions
  1457.               mov ah,9                      ;int 10h function - write c/a
  1458.               int 10h                       ;write character/attribute
  1459.               inc dl                        ;advance cursor
  1460.               pop cx                        ;retrieve character count
  1461.               loop write1                   ;loop until done
  1462.               ret
  1463. writeln       endp
  1464. ;
  1465. ;------------------------------------------------------------------------------
  1466. ;READLN accepts input of a string entered from the keyboard.
  1467. ;Entry:  ES:DI - buffer address        | Exit: CL - string length
  1468. ;        DH,DL - cursor start position |
  1469. ;        CL    - max length accepted   |
  1470. ;------------------------------------------------------------------------------
  1471. maxlen        db ?                          ;maximum string length
  1472. ;
  1473. readln        proc near
  1474.               mov maxlen,cl                 ;save max length
  1475.               mov ah,2                      ;set cursor to start position
  1476.               mov bh,video_page
  1477.               int 10h
  1478.               call show_cursor              ;display the cursor
  1479.               xor cl,cl                     ;initialize counter
  1480. ;
  1481. ;Wait for a keypress.
  1482. ;
  1483. read1:        call getkey                   ;get a character
  1484.               cmp al,13                     ;ENTER key?
  1485.               je read_exit                  ;yes, then exit
  1486.               cmp al,27                     ;ESC key?
  1487.               jne read2                     ;no, then branch
  1488.               xor cl,cl                     ;zero length
  1489.               jmp short read_exit           ;exit
  1490. read2:        cmp al,8                      ;backspace key?
  1491.               je backspace                  ;yes, then do backspace function
  1492.               cmp al,32                     ;ASCII 32 or greater?
  1493.               jb read1                      ;no, then ignore it
  1494.               cmp al,126                    ;ASCII 126 or less?
  1495.               ja read1                      ;no, then ignore keypress
  1496.               cmp cl,maxlen                 ;room for another entry?
  1497.               je read1                      ;no, then ignore it
  1498. ;
  1499. ;Process the press of a character key.
  1500. ;
  1501.               stosb                         ;deposit character in buffer
  1502.               push cx                       ;save character count
  1503.               mov ah,10                     ;print the character
  1504.               mov cx,1
  1505.               int 10h
  1506.               inc dl                        ;advance the cursor
  1507.               mov ah,2
  1508.               int 10h
  1509.               pop cx                        ;retrieve count
  1510.               inc cl                        ;update count
  1511.               jmp read1                     ;go back for more
  1512. ;
  1513. ;Process a press of the BACKSPACE key.
  1514. ;
  1515. backspace:    or cl,cl                      ;any characters to delete?
  1516.               je read1                      ;no, then ignore keystroke
  1517.               push cx                       ;save count
  1518.               dec dl                        ;move cursor back one space
  1519.               mov ah,2
  1520.               int 10h
  1521.               mov ah,10                     ;print a space character
  1522.               mov al,32
  1523.               mov cx,1
  1524.               int 10h
  1525.               pop cx                        ;retrieve count
  1526.               dec cl                        ;decrement it
  1527.               dec di                        ;decrement buffer pointer
  1528.               jmp read1                     ;go back for more
  1529. ;
  1530. ;Hide the cursor and return.
  1531. ;
  1532. read_exit:    mov ah,1                      ;hide the cursor
  1533.               mov ch,20h
  1534.               int 10h
  1535.               ret
  1536. readln        endp
  1537. ;
  1538. ;------------------------------------------------------------------------------
  1539. ;SHOW_CURSOR displays the cursor and discounts EGA cursor emulation logic.
  1540. ;Entry:  NEW_CURSOR - starting and ending scan lines
  1541. ;------------------------------------------------------------------------------
  1542. show_cursor   proc near
  1543.               cmp adapter,2                 ;is an EGA currently active?
  1544.               jne cursor1                   ;no, then branch
  1545.               push es                       ;save ES
  1546.               mov ax,bios_data              ;point ES to BIOS data area
  1547.               mov es,ax
  1548.               assume es:bios_data
  1549.               push infobyte                 ;save EGA info byte
  1550.               or ega_info,1                 ;disable EGA cursor emulation
  1551. cursor1:      mov ah,1                      ;display the cursor
  1552.               mov cx,new_cursor
  1553.               int 10h
  1554.               cmp adapter,2                 ;is an EGA active?
  1555.               jne cursor_exit               ;no, then exit
  1556.               pop infobyte                  ;restore EGA info byte
  1557.               pop es                        ;restore ES
  1558.               assume es:nothing
  1559. cursor_exit:  ret
  1560. show_cursor   endp
  1561. ;
  1562. ;------------------------------------------------------------------------------
  1563. ;CLEAR_WINDOW clears the record currently displayed in the window.
  1564. ;------------------------------------------------------------------------------
  1565. clear_window  proc near
  1566.               mov ax,0600h                  ;interrupt 10h, function 6
  1567.               mov cx,071Bh
  1568.               mov dx,0C3Bh
  1569.               mov bh,record_attr
  1570.               int 10h
  1571.               ret
  1572. clear_window  endp
  1573. ;
  1574. ;------------------------------------------------------------------------------
  1575. ;IOSET vectors interrupts 1Bh, 23h and 24h to internal handlers.  IORESET
  1576. ;restores the original vector values.
  1577. ;------------------------------------------------------------------------------
  1578. ioset         proc near
  1579.               push es                       ;save ES
  1580.               mov ax,351Bh                  ;get interrupt 1Bh vector
  1581.               int 21h
  1582.               mov old1Bh_segment,es         ;save it
  1583.               mov old1Bh_offset,bx
  1584.               mov ah,25h                    ;point it to an IRET instruction
  1585.               mov dx,offset ioexit
  1586.               int 21h
  1587.               mov ax,3523h                  ;get interrupt 23h vector
  1588.               int 21h
  1589.               mov old23h_segment,es         ;save it
  1590.               mov old23h_offset,bx
  1591.               mov ah,25h                    ;point it to an IRET instruction
  1592.               mov dx,offset ioexit
  1593.               int 21h
  1594.               mov ax,3524h                  ;get interrupt 24h vector
  1595.               int 21h
  1596.               mov old24h_segment,es         ;save it
  1597.               mov old24h_offset,bx
  1598.               mov ah,25h                    ;then set it to IOERR routine
  1599.               mov dx,offset ioerr
  1600.               int 21h
  1601.               pop es                        ;restore ES
  1602.               ret
  1603. ioset         endp
  1604. ;
  1605. ioreset       proc near
  1606.               mov ax,2524h                  ;restore interrupt 24h vector
  1607.               mov dx,old24h_offset
  1608.               push ds
  1609.               assume ds:nothing
  1610.               mov ds,old24h_segment
  1611.               int 21h
  1612.               mov ax,2523h                  ;restore interrupt 23h vector
  1613.               mov dx,old23h_offset
  1614.               mov ds,old23h_segment
  1615.               int 21h
  1616.               mov ax,251Bh                  ;restore interrupt 1Bh vector
  1617.               mov dx,old1Bh_offset
  1618.               mov ds,old1Bh_segment
  1619.               int 21h
  1620.               pop ds
  1621.               assume ds:code
  1622.               ret
  1623. ioreset       endp
  1624. ;
  1625. ;------------------------------------------------------------------------------
  1626. ;FINISH loads the data file, resets interrupt vectors, and terminates.
  1627. ;------------------------------------------------------------------------------
  1628. finish        proc near
  1629. ;
  1630. ;Open the specified data file for reading.
  1631. ;
  1632.               mov ax,3D00h                  ;open file for reading
  1633.               mov dx,offset filespec        ;point DX to ASCIIZ filespec
  1634.               int 21h
  1635.               jnc finish3                   ;branch if no error
  1636.               mov ah,9                      ;print 'File not found'
  1637.               mov dx,offset errmsg1
  1638.               int 21h
  1639.               cmp reload,0                  ;was this an attempted reload?
  1640.               je endfin                     ;no, then exit
  1641.               mov al,old_numrec             ;yes, then restore parameters
  1642.               mov es:[numrec],al
  1643.               mov al,old_recptr
  1644.               mov es:[recptr],al
  1645.               mov al,old_fileflag
  1646.               mov es:[fileflag],al
  1647. endfin:       ret                           ;and exit
  1648. ;
  1649. ;Load the data file into memory.
  1650. ;
  1651. finish3:      mov bx,ax                     ;transfer file handle to BX
  1652.               push ds                       ;exchange DS and ES
  1653.               push es
  1654.               pop ds
  1655.               pop es
  1656.               mov ah,3Fh                    ;read record count byte
  1657.               mov cx,1
  1658.               mov dx,offset numrec
  1659.               int 21h
  1660.               jc close                      ;branch on error
  1661.               mov al,ds:[maxrec]            ;make sure NUMREC <= MAXREC
  1662.               cmp al,ds:[numrec]
  1663.               jae finish4
  1664.               mov ds:[numrec],al            ;adjust if it isn't
  1665. finish4:      mov al,ds:[numrec]            ;calculate number of bytes to read
  1666.               mul record_length
  1667.               mov cx,ax                     ;transfer number of bytes to CX
  1668.               mov ah,3Fh                    ;DOS function 3Fh - read file
  1669.               mov dx,offset data_buffer     ;point DX to buffer area
  1670.               int 21h                       ;read all records from disk
  1671. close:        mov ah,3Eh                    ;close file
  1672.               int 21h
  1673.               mov ds:[fileflag],1           ;set filespec flag
  1674.               push ds                       ;swap DS and ES again
  1675.               push es
  1676.               pop ds
  1677.               pop es
  1678. ;
  1679. ;Initialize the record index table.
  1680. ;
  1681. finish5:      mov di,offset index_table     ;point DI to table area
  1682.               xor al,al                     ;zero AL
  1683.               mov cl,es:[maxrec]            ;set counter
  1684.               xor ch,ch
  1685.               rep stosb                     ;zero all bytes
  1686.               mov cl,es:[numrec]            ;set CX to number of records
  1687.               xor ch,ch
  1688.               jcxz finish7                  ;exit if there are none
  1689.               mov di,offset index_table     ;reset DI
  1690.               mov al,1                      ;initialize AL
  1691. finish6:      stosb                         ;set one index byte
  1692.               inc al                        ;increment index
  1693.               loop finish6                  ;loop until done
  1694. ;
  1695. ;Copy new filespec into old data space if this is a reload.
  1696. ;
  1697. finish7:      cmp reload,0                  ;is this a reload
  1698.               je finish8                    ;no, then branch
  1699.               mov si,offset filespec        ;point SI and DI to filespec areas
  1700.               mov di,si
  1701.               mov cx,126                    ;set counter
  1702.               rep movsb                     ;transfer text
  1703.               ret                           ;done - exit
  1704. ;
  1705. ;Save and replace all required interrupt vectors.
  1706. ;
  1707. finish8:      mov ax,3508h                  ;get interrupt 8 vector
  1708.               int 21h
  1709.               mov old8h,bx                  ;save it
  1710.               mov old8h[2],es
  1711.               mov ah,25h                    ;point it to the TIMER routine
  1712.               mov dx,offset timer
  1713.               int 21h
  1714.               mov ax,3509h                  ;get interrupt 9 vector
  1715.               int 21h
  1716.               mov old9h,bx                  ;save it
  1717.               mov old9h[2],es
  1718.               mov ah,25h                    ;point it to KEYBOARD routine
  1719.               mov dx,offset keyboard
  1720.               int 21h
  1721.               mov ax,3510h                  ;get interrupt 10h vector
  1722.               int 21h
  1723.               mov old10h,bx                 ;save it
  1724.               mov old10h[2],es
  1725.               mov ah,25h                    ;point it to VIDEO
  1726.               mov dx,offset video
  1727.               int 21h
  1728.               mov ax,3513h                  ;get interrupt 13h vector
  1729.               int 21h
  1730.               mov old13h,bx                 ;save it
  1731.               mov old13h[2],es
  1732.               mov ah,25h                    ;point it to BDISK
  1733.               mov dx,offset bdisk
  1734.               int 21h
  1735.               mov ax,3528h                  ;get interrupt 28h vector
  1736.               int 21h
  1737.               mov old28h,bx                 ;save it
  1738.               mov old28h[2],es
  1739.               mov ah,25h                    ;point it to BACKPROC
  1740.               mov dx,offset backproc
  1741.               int 21h
  1742. ;
  1743. ;Calculate amount of memory to reserve and terminate-but-stay-resident.
  1744. ;
  1745.               mov dx,offset program         ;display notice and hot key
  1746.               mov ah,9                      ;with DOS function 9
  1747.               int 21h
  1748.               mov al,maxrec                 ;get max number of records
  1749.               mul record_length             ;multiply by 192
  1750.               mov dx,ax                     ;transfer figure to DX
  1751.  
  1752.               add dx,(offset data_buffer - offset code + 15)
  1753.  
  1754.               mov cl,4                      ;convert bytes to paragraphs
  1755.               shr dx,cl
  1756.               mov ax,3100h                  ;load function and return codes
  1757.               int 21h                       ;terminate-but-stay-resident
  1758. finish        endp
  1759. ;
  1760. ;-----------------------------------------------------------------------------
  1761. ;Data space to be used after Cardfile is resident in memory.
  1762. ;-----------------------------------------------------------------------------
  1763. pc            = $
  1764. screen_buffer = pc                          ;video memory buffer
  1765. pc            = pc + 10 * 44 * 2
  1766. index_table   = pc                          ;record index table
  1767. pc            = pc + 512
  1768. filespec      = pc                          ;file specification
  1769. pc            = pc + 128
  1770. data_buffer   = pc                          ;record buffer
  1771. ;
  1772. ;------------------------------------------------------------------------------
  1773. ;INITIALIZE prepares the program for residency.
  1774. ;------------------------------------------------------------------------------
  1775. initialize    proc near
  1776.               assume ds:code
  1777. errmsg1       db 13,10,"File not found",13,10,"$"
  1778. errmsg2       db 13,10,"Critical Error Flag not found",13,10,"$"
  1779. old_numrec    db ?
  1780. old_recptr    db ?
  1781. old_fileflag  db ?
  1782. ;
  1783. ;See if the program is already resident in memory.
  1784. ;
  1785. init1:        mov word ptr [begin],0        ;zero word to avoid false match
  1786.               xor bx,bx                     ;initialize search segment
  1787.               mov ax,cs                     ;record current segment in AX
  1788. init2:        inc bx                        ;increment search segment
  1789.               cmp ax,bx                     ;reached current segment?
  1790.               je init3                      ;yes, then this is the first load
  1791.               mov es,bx                     ;point ES to search segment
  1792.               mov si,offset begin           ;point SI and DI to ID offset
  1793.               mov di,si
  1794.               mov cx,16                     ;check 16 characters
  1795.               cld                           ;clear DF
  1796.               repe cmpsb                    ;compare the strings
  1797.               jne init2                     ;continue search if compare failed
  1798. ;
  1799. ;Cardfile is already installed.  Set the reload flag and save parameters.
  1800. ;
  1801.               mov reload,1                  ;set flag
  1802.               mov al,es:[numrec]            ;save parameters
  1803.               mov old_numrec,al
  1804.               mov al,es:[recptr]
  1805.               mov old_recptr,al
  1806.               mov al,es:[fileflag]
  1807.               mov old_fileflag,al
  1808.               mov es:[numrec],0             ;initialize counters and flags
  1809.               mov es:[recptr],1
  1810.               mov es:[fileflag],0
  1811.               jmp short parse                     ;branch to parsing code
  1812. ;
  1813. ;Determine which version of DOS is running.
  1814. ;
  1815. init3:        mov ah,30h                    ;DOS function 30h
  1816.               int 21h
  1817.               mov dos_version,al            ;major version number
  1818. ;
  1819. ;Get and save the address of the INDOS flag.
  1820. ;
  1821.               mov ah,34h                    ;function 34h
  1822.               int 21h                       ;get address
  1823.               mov dos_segment,es            ;save segment
  1824.               mov indos_offset,bx           ;save offset
  1825. ;
  1826. ;Get and save the address of the critical error flag.
  1827. ;
  1828.               mov ax,3E80h                  ;CMP opcode
  1829.               mov cx,2000h                  ;max search length
  1830.               mov di,bx                     ;start at INDOS address
  1831. init4:        repne scasw                   ;do the search
  1832.               jcxz init5                    ;branch if search failed
  1833.               cmp byte ptr es:[di+5],0BCh   ;verify this is it
  1834.               je found                      ;branch if it is
  1835.               jmp init4                     ;resume loop if it's not
  1836. init5:        mov cx,2000h                  ;search again
  1837.               inc bx                        ;search odd addresses this time
  1838.               mov di,bx
  1839. init6:        repne scasw                   ;look for the opcode
  1840.               jcxz notfound                 ;not found if loop expires
  1841.               cmp byte ptr es:[di+5],0BCh   ;verify this is it
  1842.               je found
  1843.               jmp init6
  1844. notfound:     mov ah,9                      ;flag not found
  1845.               mov dx,offset errmsg2
  1846.               int 21h
  1847.               ret
  1848. found:        mov ax,es:[di]                ;get flag offset address
  1849.               mov errflag_offset,ax         ;save it
  1850.               push cs                       ;reset ES to the code segment
  1851.               pop es
  1852. ;
  1853. ;Parse the command line and create a complete filespec.
  1854. ;
  1855. parse:        mov di,82h                    ;point DI to command line text
  1856.               cmp byte ptr [di-2],2         ;less than 2 characters entered?
  1857.               jnb parse0                    ;no, then continue
  1858.               jmp finish5                   ;yes, then skip load routine
  1859. parse0:       mov si,di                     ;point SI to command line text
  1860.               mov di,offset filespec        ;point DI to buffer
  1861. parse1:       cmp byte ptr [si],32          ;advance to first non-space
  1862.               jne parse2
  1863.               inc si
  1864.               jmp parse1
  1865. parse2:       cmp byte ptr [si+1],":"       ;leading drive specifier?
  1866.               je parse4                     ;yes, then filespec is complete
  1867.               mov ah,19h                    ;get current drive
  1868.               int 21h
  1869.               add al,65                     ;convert to ASCIIZ
  1870.               mov ah,":"                    ;complete drive specifier
  1871.               mov word ptr [di],ax          ;write drive spec to buffer
  1872.               add di,2                      ;advance DI
  1873.               cmp byte ptr [si],"\"         ;leading backslash?
  1874.               je parse4                     ;yes, then filespec is complete
  1875.               mov byte ptr [di],"\"         ;fill in the backslash
  1876.               inc di
  1877.               push si                       ;save SI and DI
  1878.               push di
  1879.               mov ah,47h                    ;get current path
  1880.               mov si,di
  1881.               xor dl,dl                     ;default drive
  1882.               int 21h                       ;append path to drive spec
  1883.               pop di                        ;restore SI and DI
  1884.               pop si
  1885.               cmp byte ptr [di],0           ;anything returned?
  1886.               je parse4                     ;no, then filespec is complete
  1887. parse3:       inc di                        ;advance to end of string
  1888.               cmp byte ptr [di],0
  1889.               jne parse3
  1890.               mov byte ptr [di],"\"         ;insert trailing backslash
  1891.               inc di
  1892. parse4:       mov al,[si]                   ;append entry to filespec string
  1893.               cmp al,13
  1894.               je parse5
  1895.               mov [di],al
  1896.               inc si
  1897.               inc di
  1898.               jmp parse4
  1899. parse5:       mov byte ptr [di],0
  1900.               jmp finish                    ;load data file and exit
  1901. initialize    endp
  1902. ;
  1903. code          ends
  1904.               end begin
  1905.