home *** CD-ROM | disk | FTP | other *** search
- page 60,132
-
- ;CARDFILE.COM for the IBM Personal Computer - 1987 by Jeff Prosise
- ;
- bios_data segment at 40h
- rs232_base dw 4 dup (?) ;UART base addresses
- org 4Ah
- crt_cols dw ? ;number of display columns
- org 4Eh
- crt_start dw ? ;video page offset address
- org 63h
- addr_6845 dw ? ;CRTC base address
- org 87h
- infobyte label word
- ega_info db ? ;EGA info byte
- bios_data ends
- ;
- code segment para public 'code'
- assume cs:code
- org 100h
- begin: jmp init1 ;goto initialization code
- ;
- program db "Cardfile 1.0 "
- copyright db "(c) 1987 Ziff Communications Co.",13,10
- db "Hotkey is ALT-RIGHT SHIFT$",1Ah
- author db "Jeff Prosise"
- ;
- dos_segment dw ? ;segment of internal DOS flags
- indos_offset dw ? ;offset of INDOS flag
- errflag_offset dw ? ;offset of critical error flag
- program_status db 0 ;popup status
- flag_10h db 0 ;status of interrupt 10h
- flag_13h db 0 ;status of interrupt 13h
- request_flag db 0 ;status of processing request
- ss_register dw ? ;SS register storage
- sp_register dw ? ;SP register storage
- oldpsp dw ? ;PSP segment storage
- ;
- maxrec db 255 ;maximum number of records
- recptr db 1 ;current record number
- numrec db 0 ;number of records
- adapter db ? ;0=MDA, 1=CGA, 2=EGA
- video_segment dw ? ;video segment address
- border_attr db ? ;window border attribute
- text_attr db ? ;window text attribute
- menu_attr db ? ;menu line attribute
- record_attr db ? ;record display attribute
- video_page db ? ;current video page
- cursor_mode dw ? ;cursor shape
- cursor_pos dw ? ;cursor position
- cursor_addr dw ? ;cursor CRTC address
- new_cursor dw ? ;Cardfile cursor shape
- dos_version db ? ;DOS version number
- slotno db ? ;record position
- reload db ? ;reload data file flag
- zflag db ? ;critical error flag change status
- fileflag db 0 ;filespec validity indicator
- record_length db 192 ;record length in bytes
- ;
- comport dw 0 ;COM1
- initstr db 10000011b ;1200 baud, N81 data format
- dialstr db "ATDT",0 ;Hayes Smartmodem dial string
- hangupstr db "ATH0",13,0 ;Hayes Smartmodem hangup string
- ;
- jump_table dw offset create ;vector dispatch table
- dw offset edit
- dw offset delete
- dw offset search
- dw offset save
- dw offset dial
- ;
- titles db 32,"Name",32,32,"Addr",14 dup (32),"Phone",32,"Note",32
- menuline1 db "F1-New F2-Ed F3-Del F4-Sch F5-Sv F6-Dial",0
- menuline2 db "Press ENTER to delete, ESC to abort",0
- menuline3 db "Press F1 to validate new entry",0
- menuline4 db "Find:",0
- menuline5 db "Press ENTER to continue, ESC to end",0
- menuline6 db "Search key not found. Press ESC",0
- menuline7 db "No room for additional records",0
- menuline8 db "Disk full",0
- menuline9 db "Press F1 to validate changes",0
- menuline10 db "Pick up phone and press spacebar",0
- menuline11 db "Error saving file",0
- menuline12 db "Modem not ready",0
- menuline13 db "File:",0
- ;
- timer_int label dword ;old interrupt 8 vector
- old8h dw 2 dup (?)
- keyboard_int label dword ;old interrupt 9 vector
- old9h dw 2 dup (?)
- video_int label dword ;old interrupt 10h vector
- old10h dw 2 dup (?)
- bdisk_int label dword ;old interrupt 13h vector
- old13h dw 2 dup (?)
- bp_int label dword ;old interrupt 28h vector
- old28h dw 2 dup (?)
- ;
- old1Bh_segment dw ? ;old interrupt 1Bh segment
- old1Bh_offset dw ? ;old interrupt 1Bh offset
- old23h_segment dw ? ;old interrupt 23h segment
- old23h_offset dw ? ;old interrupt 23h offset
- old24h_segment dw ? ;old interrupt 24h segment
- old24h_offset dw ? ;old interrupt 24h offset
- ;
- color_attr db 0,0B8h,1Fh,6Eh,6Eh,6Fh
- mono_attr db 0,0B0h,70h,07h,07h,07h
- enable_values db 2Ch,28h,2Dh,29h,2Ah,2Eh,1Eh
- key_table db "QWERTYUIOP",0,0,0,0
- db "ASDFGHJKL",0,0,0,0,0
- db "ZXCVBNM"
- ;
- ;------------------------------------------------------------------------------
- ;Execution comes here thru interrupt 9 every time a key is pressed or released.
- ;------------------------------------------------------------------------------
- keyboard proc near
- sti ;set interrupt enable flag
- pushf ;push flags to simulate INT
- call keyboard_int ;call keyboard handling routine
- push ax ;save AX
- mov ah,2 ;get keyboard shift status
- int 16h
- and al,0Fh ;mask off upper 4 bits
- cmp al,9 ;Alt/Rt-Shift pressed?
- pop ax ;restore AX
- jne kb_exit ;no, then exit
- cmp program_status,0 ;popup routine already active?
- jne kb_exit ;yes, then ignore keypress
- mov request_flag,18 ;set request flag
- kb_exit: iret
- keyboard endp
- ;
- ;------------------------------------------------------------------------------
- ;Interrupt 8 handling routine.
- ;------------------------------------------------------------------------------
- timer proc near
- pushf ;call BIOS routine
- call timer_int
- cmp request_flag,0 ;flag set?
- je timer_exit ;no, then exit
- cmp flag_10h,0 ;video flag set?
- jne dectime ;yes, then exit
- cmp flag_13h,0 ;disk flag set?
- jne dectime ;yes, then exit
- push es ;save ES and DI
- push di
- mov es,dos_segment ;check INDOS flag
- mov di,indos_offset
- cmp byte ptr es:[di],0
- jne poptime ;exit if it's set
- mov di,errflag_offset ;check critical error flag
- cmp byte ptr es:[di],0
- jne poptime ;exit if it's set
- pop di ;restore registers
- pop es
- mov request_flag,0 ;zero request flag
- call main ;call body of program
- timer_exit: iret
- poptime: pop di ;clean up the stack
- pop es
- dectime: dec request_flag ;decrement request flag
- iret
- timer endp
- ;
- ;------------------------------------------------------------------------------
- ;Interrupt 10h handling routine.
- ;------------------------------------------------------------------------------
- video proc near
- pushf ;push flags onto stack
- inc flag_10h ;increment flag
- call video_int ;call BIOS routine
- dec flag_10h ;decrement flag
- iret
- video endp
- ;
- ;------------------------------------------------------------------------------
- ;Interrupt 13h handling routine.
- ;------------------------------------------------------------------------------
- bdisk proc far
- pushf ;push flags onto stack
- inc flag_13h ;set 'busy' flag
- call bdisk_int ;call BIOS routine
- pushf ;save output flags
- dec flag_13h ;clear flag
- popf ;restore output flags
- ret 2 ;exit without destroying flags
- bdisk endp
- ;
- ;------------------------------------------------------------------------------
- ;Interrupt 28h handling routine.
- ;------------------------------------------------------------------------------
- backproc proc near
- pushf ;call original routine
- call bp_int
- cmp request_flag,0 ;request flag clear?
- je bp_exit ;yes, then exit
- cmp flag_10h,0 ;video flag set?
- jne bp_exit ;yes, then exit
- cmp flag_13h,0 ;disk flag set?
- jne bp_exit ;yes, then exit
- push es ;save ES and DI
- push di
- mov es,dos_segment ;check critical error flag
- mov di,errflag_offset
- cmp byte ptr es:[di],0
- pop di ;clean up the stack
- pop es
- jne bp_exit
- mov request_flag,0 ;clear request flag
- call main ;call main routine
- bp_exit: iret ;done - exit
- backproc endp
- ;
- ;------------------------------------------------------------------------------
- ;Interrupt 24h handling routine (DOS 3.X only).
- ;------------------------------------------------------------------------------
- ioerr proc near
- mov al,3 ;fail the call in progress
- ioexit: iret ;give control back to DOS
- ioerr endp
- ;
- ;------------------------------------------------------------------------------
- ;MAIN is the routine called to pop up and manipulate the CardFile window.
- ;------------------------------------------------------------------------------
- main proc near
- mov program_status,1 ;set program active flag
- cli ;make sure interrupts are off
- mov ss_register,ss ;save stack registers
- mov sp_register,sp
- push cs ;switch to internal stack
- pop ss
- mov sp,offset filespec
- sti ;enable interrupts
- push ax ;save other registers
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- push bp
- mov ah,15 ;get video mode and page
- int 10h
- cmp al,3 ;mode 0, 1, 2, or 3?
- jbe main1 ;yes, then continue
- cmp al,7 ;mode 7?
- je main1 ;yes, then continue
- ;
- ;Restore registers and stack before exit.
- ;
- exit: pop bp ;restore registers and exit
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- cli ;interrupts off
- mov ss,ss_register ;switch to original stack
- mov sp,sp_register
- sti ;interrupts on
- mov program_status,0 ;clear status flag
- ret
- ;
- ;Set DS and ES segment registers.
- ;
- main1: push cs ;set DS to code segment
- pop ds
- assume ds:code
- mov ax,bios_data ;point ES to BIOS data
- mov es,ax
- assume es:bios_data
- cmp crt_cols,80 ;at least 80 columns displayed?
- jb exit ;no, then exit
- ;
- ;Save needed video parameters.
- ;
- mov video_page,bh ;active video page
- mov ah,3 ;get cursor mode and location
- int 10h
- mov cursor_mode,cx
- mov cursor_pos,dx
- mov dx,addr_6845 ;get CRTC base address
- push dx ;save it for later
- mov al,14 ;specify register number
- out dx,al
- inc dx ;point DX to data port
- in al,dx ;read high byte of address
- mov ah,al ;save it
- dec dx ;back to index register
- mov al,15 ;specify register number
- out dx,al
- inc dx ;back to data port
- in al,dx ;read low byte of address
- mov cursor_addr,ax ;save cursor address
- ;
- ;Determine whether an EGA is present and active in the system.
- ;
- mov ah,12h ;see if EGA is present
- mov bl,10h
- int 10h
- cmp bl,10h ;did BL return unchanged?
- je main2 ;yes, then there's no EGA here
- test ega_info,8 ;is the EGA currently active?
- jnz main2 ;no, then branch
- mov adapter,2 ;set ADAPTER for EGA
- push bx ;save BX
- mov ax,1130h ;get number of scan lines per char
- int 10h
- dec cl ;form cursor definition in CX
- mov ch,cl
- sub ch,2
- mov new_cursor,cx ;save cursor definition
- mov si,offset color_attr ;point SI to color parms
- pop bx ;retrieve BX
- or bh,bh ;EGA attached to color monitor?
- je main4 ;yes, then branch
- mov si,offset mono_attr ;no, then point SI to mono parms
- jmp short main4
- ;
- ;Determine whether the active video adapter is a CGA or an MDA.
- ;
- main2: test addr_6845,40h ;is bit 6 of the CRTC address set?
- jz main3 ;no, then it's monochrome
- mov adapter,1 ;set ADAPTER for a CGA
- mov new_cursor,0607h ;define cursor shape
- mov si,offset color_attr ;point SI to color parms
- jmp short main4
- main3: mov adapter,0 ;set ADAPTER for an MDA
- mov new_cursor,0B0Ch ;define monochrome cursor
- mov si,offset mono_attr ;point SI to mono parms
- ;
- ;Set video parameters for color or monochrome.
- ;
- main4: push cs ;set ES to the code segment
- pop es
- assume es:nothing
- mov di,offset video_segment ;point DI to destination
- mov cx,3 ;3 words to move
- cld ;clear DF
- rep movsw ;transfer the values
- ;
- ;Save the current active PSP address and activate this PSP.
- ;
- push es ;save ES
- mov zflag,0 ;clear flag
- cmp dos_version,2 ;DOS version 2.X?
- jne main5
- mov es,dos_segment ;point ES:DI to INDOS
- mov di,indos_offset
- cmp byte ptr es:[di],0 ;INDOS clear?
- je main5 ;yes, then branch
- mov di,errflag_offset ;point ES:DI to error flag
- cmp byte ptr es:[di],0 ;critical error flag clear?
- jne main5 ;no, then branch
- mov byte ptr es:[di],1 ;set critical error flag manually
- mov zflag,1 ;set change flag
- main5: mov ah,51h ;get current PSP segment
- int 21h
- mov oldpsp,bx ;save it
- mov ah,50h ;make this the active PSP
- push cs
- pop bx
- int 21h
- cmp zflag,0 ;ZFLAG clear?
- je main6 ;yes, then branch
- mov di,errflag_offset ;point ES:DI to error flag
- mov byte ptr es:[di],0 ;restore error flag value
- main6: pop es ;restore ES
- ;
- ;Reset the interrupt 1Bh, 23h, and 24h vectors and open the CardFile window.
- ;
- call ioset ;reset interrupt vectors
- cmp adapter,1 ;disable CGA video
- jne main7
- call disable_cga
- main7: call save_screen ;save memory to be overwritten
- call make_screen ;open the CardFile window
- cmp adapter,1 ;enable CGA video
- jne main8
- call enable_cga
- main8: mov ah,1 ;hide the cursor
- mov ch,20h
- int 10h
- cmp numrec,0 ;any records in memory?
- je main10 ;no, then branch
- call show_record ;display current record
- ;
- ;Wait for a keystroke and exit when ESC is pressed.
- ;
- main10: call getkey ;wait for a keypress
- or al,al ;extended code entered?
- je main12 ;yes, then branch
- cmp al,13 ;ENTER pressed?
- jne main11 ;no, then branch around
- cmp numrec,2 ;at least 2 records?
- jb main10 ;no, then ignore keypress
- jmp short main20 ;yes, then do a PgDn
- main11: cmp al,27 ;ESC pressed?
- jne main10 ;no, then ignore keypress
- jmp short escape ;yes, then close window and exit
- ;
- ;An extended code was entered. Check for an Alt-character key combination.
- ;
- main12: cmp ah,16 ;scan code < 16 (Alt-Q)?
- jb main10 ;yes, then ignore it
- cmp ah,50 ;scan code > 50 (Alt-M)?
- ja main13 ;yes, then branch and continue
- call qsearch ;do quick search
- jmp main10 ;return for another keypress
- ;
- ;Check for a press of any function key F1 through F6.
- ;
- main13: cmp ah,59 ;scan code < 59 (F1)?
- jb main10 ;yes, then ignore it
- cmp ah,64 ;scan code > 64 (F6)?
- ja main14 ;yes, then branch and continue
- sub ah,59 ;normalize scan code
- mov bl,ah ;transfer result
- xor bh,bh ;byte to word in BX
- shl bx,1 ;double index in BX
- call word ptr cs:[offset jump_table+bx] ;call routine
- jmp main10 ;return
- ;
- ;Check for Home, End, PgUp, and PgDn.
- ;
- main14: cmp numrec,2 ;are there at least 2 records?
- jb main10 ;no, then ignore keypress
- cmp ah,71 ;Home key?
- jne main16 ;no, then branch
- mov recptr,1 ;set pointer to first record
- main15: call show_record ;display record
- jmp main10 ;return
- main16: cmp ah,79 ;End key?
- jne main18 ;no, then branch
- main17: mov al,numrec ;get number of records
- mov recptr,al ;set pointer to last record
- jmp main15 ;display record
- main18: cmp ah,73 ;PgUp key?
- jne main19 ;no, then branch
- dec recptr ;adjust pointer
- cmp recptr,0 ;wrap around if necessary
- jne main15
- jmp main17
- main19: cmp ah,81 ;PgDn key?
- jne main10 ;no, then ignore keypress
- main20: mov al,numrec ;presently showing last record?
- cmp al,recptr
- je main21 ;yes, then branch
- inc recptr ;no, then advance pointer
- jmp main15 ;display record
- main21: mov recptr,1 ;set pointer to first record
- jmp main15 ;display record
- ;
- ;Restore interrupt vectors and former active PSP.
- ;
- escape: mov ah,50h ;restore active PSP label
- mov bx,oldpsp
- int 21h
- call ioreset ;restore interrupt vectors
- ;
- ;Close the Cardfile window in preparation for exit.
- ;
- cmp adapter,1 ;disable CGA video
- jne esc1
- call disable_cga
- esc1: call restore_screen ;restore screen contents
- cmp adapter,1 ;enable CGA video
- jne esc2
- call enable_cga
- ;
- ;Restore the cursor's former position in the BIOS data area and the CRTC.
- ;
- esc2: mov ah,2 ;set cursor position thru BIOS
- mov bh,video_page
- mov dx,cursor_pos
- int 10h
- pop dx ;recover CRTC base address
- mov cx,cursor_addr ;restore cursor address
- mov al,14 ;CRTC register number
- out dx,al
- inc dx
- mov al,ch
- out dx,al ;write high byte of address
- dec dx
- mov al,15 ;CRTC register number
- out dx,al
- inc dx
- mov al,cl
- out dx,al ;write low byte
- ;
- ;Display the cursor, bypassing EGA cursor emulation logic, and exit.
- ;
- cmp adapter,2 ;EGA on board?
- jne esc3 ;no, then branch
- call show_cursor ;retain current shape
- jmp exit
- esc3: mov ah,1 ;restore cursor shape
- mov cx,cursor_mode
- int 10h
- jmp exit ;exit
- main endp
- ;
- ;------------------------------------------------------------------------------
- ;SAVE_SCREEN saves the contents of the screen that underlie the window.
- ;------------------------------------------------------------------------------
- linesum dw ?
- video_address dw ?
- ;
- save_screen proc near
- push ds ;save DS
- mov ax,bios_data ;point it to BIOS data area
- mov ds,ax
- assume ds:bios_data
- mov ax,crt_cols ;get number of display columns
- mov linesum,ax ;calculate distance from end of
- sub linesum,44 ; one line to start of next
- shl linesum,1
- mov bl,6 ;calculate starting address
- mul bl ;result in AX
- shl ax,1 ;double result for attr bytes
- add ax,36 ;add line offset
- mov si,ax ;transfer to SI
- add si,crt_start ;add page offset
- mov video_address,si ;save offset address
- mov ds,video_segment ;then set DS to the video segment
- mov di,offset screen_buffer ;point DI to storage buffer
- mov cx,10 ;10 lines to save
- save1: push cx ;save line count
- mov cx,44 ;44 characters per line
- rep movsw ;transfer one line to storage
- pop cx ;retrieve line count
- add si,linesum ;point SI to next video line
- loop save1 ;loop until all lines are saved
- pop ds ;restore DS
- assume ds:code
- ret ;exit
- save_screen endp
- ;
- ;------------------------------------------------------------------------------
- ;RESTORE_SCREEN writes the stored screen image to video memory.
- ;------------------------------------------------------------------------------
- restore_screen proc near
- push es ;save ES register value
- mov di,video_address ;point DI to starting video offset
- mov es,video_segment ;point ES to video memory
- mov si,offset screen_buffer ;point DS:SI to screen image
- mov cx,10 ;10 lines to restore
- restore1: push cx ;save line count
- mov cx,44 ;44 characters per line
- rep movsw ;restore one line
- pop cx ;retrieve line count
- add di,linesum ;set DI to next video line
- loop restore1 ;loop until done
- pop es ;restore ES
- ret
- restore_screen endp
- ;
- ;------------------------------------------------------------------------------
- ;MAKE_SCREEN writes an image of the CardFile window to video memory.
- ;------------------------------------------------------------------------------
- make_screen proc near
- push es ;save ES
- mov es,video_segment ;point ES:DI to video memory
- mov di,video_address
- mov al,218 ;line no. 1
- mov ah,border_attr
- stosw
- mov al,196
- mov cx,42
- rep stosw
- mov al,191
- stosw
- add di,linesum
- mov si,offset titles ;lines 2 thru 7
- mov cx,6 ;6 lines
- make1: push cx
- call formline
- add di,linesum
- pop cx
- loop make1
- mov al,179 ;line no. 8
- stosw
- push ax
- mov al,32
- mov ah,text_attr
- stosw
- push ax
- mov al,196
- mov cx,40
- rep stosw
- pop ax
- stosw
- pop ax
- stosw
- add di,linesum
- stosw ;line no. 9
- push ax
- mov al,32
- mov ah,menu_attr
- stosw
- push ax
- mov si,offset menuline1
- mov cx,40
- make2: lodsb
- stosw
- loop make2
- pop ax
- stosw
- pop ax
- stosw
- add di,linesum
- mov al,192 ;line no. 10
- stosw
- mov al,196
- mov cx,42
- rep stosw
- mov al,217
- stosw
- pop es ;restore ES
- ret
- make_screen endp
- ;
- ;------------------------------------------------------------------------------
- ;FORMLINE is called by MAKE_SCREEN to help with the dirty work.
- ;------------------------------------------------------------------------------
- formline proc near
- mov al,179 ;write border character
- mov ah,border_attr
- stosw
- push ax ;save it for later
- mov cx,6 ;do next 6 characters
- mov ah,text_attr
- form1: lodsb
- stosw
- loop form1
- mov al,32 ;add 2 blanks
- stosw
- stosw
- mov ah,record_attr ;then add 34 blank characters
- mov cx,34
- rep stosw
- pop ax ;finish with border character
- stosw
- ret
- formline endp
- ;
- ;------------------------------------------------------------------------------
- ;QSEARCH pages to the record whose first character matches the Alt key pressed.
- ;------------------------------------------------------------------------------
- qsearch proc near
- cmp numrec,2 ;at least 2 records to search?
- jb qs3 ;no, then exit
- mov al,ah ;transfer scan code to AL
- sub al,16 ;normalize it
- mov bx,offset key_table ;address table of equivalents
- xlat ;get corresponding ASCII code
- mov dl,al ;transfer it to DL
- mov cl,numrec ;get record count in CX
- xor ch,ch
- mov al,1 ;initialize record index
- qs1: push ax ;save index
- push cx ;save count
- call record_address ;get address of current record
- cmp [di],dl ;compare characters
- pop cx ;retrieve count and index
- pop ax
- jae qs2 ;end search
- inc al ;increment index
- loop qs1 ;loop back for next record
- dec al ;search exhausted
- qs2: cmp al,recptr ;record already showing?
- je qs3 ;yes, then exit
- mov recptr,al ;no, then change display
- call show_record
- qs3: ret
- qsearch endp
- ;
- ;------------------------------------------------------------------------------
- ;SEARCH searches data for occurrence of a string input by the user.
- ;------------------------------------------------------------------------------
- strlen db ? ;string length
- passes db ? ;number of search loops
- ;
- search proc near
- cmp numrec,0 ;any records to search?
- je search_exit ;no, then exit
- mov si,offset menuline4 ;prepare menu line for input
- call write_menu
- xor di,di ;read string from keyboard
- mov dx,0E1Ah
- mov cl,32
- call readln
- or cl,cl ;anything entered?
- jne search1 ;yes, then continue
- search_exit: mov si,offset menuline1 ;restore menu line and exit
- call write_menu
- ret
- ;
- ;Set search parameters and begin the scan.
- ;
- search1: mov strlen,cl ;save string length
- mov ch,33 ;determine no. of passes per line
- sub ch,cl
- mov passes,ch ;save it
- mov al,recptr ;start search at current record
- mov cl,numrec ;set max search length
- xor ch,ch
- search2: push ax ;save record number
- push cx ;save record count
- call record_address ;get address of current record
- mov cx,6 ;6 lines per record
- search3: push cx ;save line count
- push di ;save line address
- mov cl,passes ;set number of passes per line
- xor ch,ch
- search4: push cx ;save pass count
- push di ;save search address within line
- mov cl,strlen ;number of bytes to compare
- xor ch,ch
- xor si,si ;point SI to input buffer
- search5: lodsb ;get a byte from the input buffer
- and al,0DFh ;capitalize it
- mov bl,es:[di] ;get a byte from the record
- and bl,0DFh ;capitalize it
- inc di ;advance pointer
- cmp al,bl ;are the two bytes identical?
- jne nextpos ;no, then try next position
- loop search5 ;yes, then try next byte
- ;
- ;A match was found. Clean up the stack and display the record.
- ;
- add sp,10 ;delete last 5 words PUSHed
- pop ax ;retrieve current record number
- push ax ;push it back onto the stack
- mov cl,numrec ;restart the record counter
- xor ch,ch
- inc cx
- push cx ;shove it onto the stack
- mov recptr,al ;set current record to this one
- call show_record ;display new record
- mov si,offset menuline5 ;display new menu line
- call write_menu
- searchkey: call getkey ;wait for a keypress
- cmp al,13 ;ENTER key?
- je nextrec ;yes, then continue search
- cmp al,27 ;ESC key?
- jne searchkey ;no, then ignore the keypress
- pop cx ;clean up the stack
- pop ax
- jmp search_exit ;exit
- ;
- ;Advance to the next position and continue the string search.
- ;
- nextpos: pop di ;retrieve address
- pop cx ;retrieve pass count
- inc di ;advance to next position on line
- loop search4 ;loop back for another try
- nextline: pop di ;retrieve line address
- pop cx ;retrieve line count
- add di,32 ;advance pointer to next line
- loop search3 ;loop back
- nextrec: pop cx ;retrieve record count
- pop ax ;retrieve current record number
- cmp al,numrec ;currently on last record?
- je reset ;yes, then wrap around
- inc al ;no, then advance record pointer
- jmp short next1
- reset: mov al,1 ;reset record pointer
- next1: loop search2 ;reenter main loop
- ;
- ;All records were searched and no match was found.
- ;
- mov si,offset menuline6 ;print message
- call write_menu
- search6: call getkey ;wait for a press of ESC
- cmp al,27
- jne search6
- jmp search_exit ;exit
- search endp
- ;
- ;------------------------------------------------------------------------------
- ;DIAL dials the phone number currently displayed.
- ;------------------------------------------------------------------------------
- linectrl db ? ;Line Control Register value
- divlsb db ? ;baud rate divisor LSB
- divmsb db ? ;baud rate divisor MSB
- intreg db ? ;Interrupt Enable Register value
- ;
- dial proc near
- cmp numrec,0 ;any records in memory?
- jne dstart ;yes, then branch
- dial_exit: ret ;no, then exit
- ;
- ;Save the current state of the COM port.
- ;
- dstart: mov si,comport ;get UART base address
- shl si,1
- push es ;save ES
- mov ax,bios_data ;then point it to BIOS data area
- mov es,ax
- assume es:bios_data
- mov dx,rs232_base[si]
- pop es ;restore ES
- assume es:nothing
- or dx,dx ;is this port installed?
- je dial_exit ;no, then exit
- add dx,3 ;point DX to Line Control Register
- push dx ;save the address
- in al,dx ;read LCR
- mov linectrl,al ;store value for later
- or al,80h ;set DLAB
- out dx,al
- sub dx,3 ;point DX to Divisor LSB Register
- in al,dx ;read it
- mov divlsb,al ;save it
- inc dx ;point DX to Divisor MSB Register
- in al,dx ;read it
- mov divmsb,al ;save it
- mov al,linectrl ;recover Line Control setting
- and al,07Fh ;clear the high bit
- add dx,2 ;point DX back to Line Control
- out dx,al ;clear DLAB
- sub dx,2 ;address Interrupt Enable Register
- in al,dx ;read it
- mov intreg,al ;and save it
- ;
- ;Initialize the COM port.
- ;
- mov ah,0 ;initialize COM port
- mov al,initstr ;baud rate and data format
- mov dx,comport ;COM port identifier
- int 14h
- ;
- ;Dial the phone number.
- ;
- mov si,offset dialstr ;point DS:SI to 'ATDT' string
- call sendcom ;output string to COM port
- test ah,80h ;was the string sent?
- jnz time_out ;no, then modem isn't ready
- mov al,recptr ;get address of current record
- call record_address
- mov si,di
- add si,128 ;point SI to 'Phone' line
- mov cx,32 ;32 characters to check
- dial1: lodsb ;get one character
- cmp al,"," ;is it a comma?
- je dial2 ;yes, then send it
- cmp al,"0" ;less than ASCII zero?
- jb dial3 ;yes, then ignore it
- cmp al,"9" ;greater than ASCII 9?
- ja dial3 ;yes, then ignore it
- dial2: mov ah,1 ;output byte to COM port
- int 14h
- test ah,80h ;was the byte successfully output?
- jnz time_out ;no, then modem isn't ready
- dial3: loop dial1 ;loop until line is finished
- mov ax,013Bh ;terminate with semicolon and CR
- int 14h
- mov ax,010Dh
- int 14h
- test ah,80h ;were the bytes transmitted?
- jz dial5 ;yes, then continue
- ;
- ;Display 'Modem not ready' message and wait for ESC to be pressed.
- ;
- time_out: mov si,offset menuline12 ;print message
- call write_menu
- dial4: call getkey ;wait for a press of ESC
- cmp al,27
- jne dial4
- jmp dial8
- ;
- ;Wait for a press of the spacebar, then force the modem to hang up.
- ;
- dial5: mov si,offset menuline10 ;display 'Pick up phone...'
- call write_menu
- dial6: call getkey ;wait for a press of the spacebar
- cmp al,32
- jne dial6
- mov si,offset hangupstr ;point SI to 'ATH0' string
- mov dx,comport ;specify COM port
- call sendcom ;output it to the COM port
- mov cx,8000h ;I/O delay
- dial7: loop dial7
- ;
- ;Restore the COM port to its original state and exit.
- ;
- dial8: pop dx ;retrieve UART address
- mov al,80h ;set DLAB
- out dx,al
- sub dx,3 ;point DX to Divisor LSB
- mov al,divlsb ;reset it
- out dx,al
- inc dx ;point DX to MSB
- mov al,divmsb ;reset it
- out dx,al
- add dx,2 ;point DX to Line Control
- xor al,al ;clear DLAB
- out dx,al
- sub dx,2 ;point DX to Interrupt Enable
- mov al,intreg ;restore it
- out dx,al
- add dx,2 ;restore Line Control Register
- mov al,linectrl
- out dx,al
- mov si,offset menuline1 ;restore menu line and exit
- call write_menu
- ret
- dial endp
- ;
- ;------------------------------------------------------------------------------
- ;SENDCOM outputs an ASCIIZ string to the designated COM port.
- ;Entry: DS:SI - string address | Exit: AH bit 7 clear - string sent
- ; DX - 0 = COM1, 1 = COM2 | AH bit 7 set - time out
- ;------------------------------------------------------------------------------
- sendcom proc near
- lodsb ;get a byte
- or al,al ;zero terminator?
- je comexit ;yes, then exit
- mov ah,1 ;output byte
- int 14h
- test ah,80h ;was byte transmitted?
- jz sendcom ;yes, loop back for more
- comexit: ret ;exit
- sendcom endp
- ;
- ;------------------------------------------------------------------------------
- ;EDIT allows the current record to be edited.
- ;------------------------------------------------------------------------------
- edit proc near
- cmp numrec,0 ;any records to edit?
- je edit1 ;no, then exit
- mov al,recptr ;get current record number
- call record_address ;get its address and position
- mov slotno,al ;save position
- push di ;save address
- call delete_record ;delete it
- pop di ;recover address
- push di ;save it again
- mov si,offset menuline9 ;address menu line text
- call edit_record ;allow it to be edited
- pop si ;place address in SI
- jc no_entry ;branch if entry now blank
- call find_position ;determine logical position
- mov bl,slotno ;retrieve physical position
- call insert_record ;insert record into the stack
- mov recptr,cl ;modify current record number
- edit1: ret ;exit
- no_entry: cmp numrec,0 ;any records left after deletion?
- je edit1 ;no, then we're done
- mov al,numrec ;get number of records
- cmp al,recptr ;RECPTR in range?
- jae edit2 ;yes, then branch
- dec recptr ;no, then modify it
- edit2: call show_record ;display new current record
- ret
- edit endp
- ;
- ;------------------------------------------------------------------------------
- ;CREATE allows a new record to be created and inserted.
- ;------------------------------------------------------------------------------
- create proc near
- mov al,numrec ;retrieve number of records
- cmp al,maxrec ;room for another record?
- jne create1 ;yes, then branch
- mov si,offset menuline7 ;no, then print error message
- call write_menu
- create0: call getkey ;wait for a press of ESC
- cmp al,27
- jne create0
- mov si,offset menuline1 ;restore menu line
- call write_menu
- ret ;exit
- create1: call clear_window ;clear the current display
- xor al,al ;zero AL
- call record_address ;get address of empty record slot
- mov slotno,al ;save position
- mov al,32 ;blank the record
- mov cx,192
- rep stosb
- sub di,192 ;point DI back to start of record
- push di ;save address
- mov si,offset menuline3 ;set text address
- call edit_record ;allow record to be edited
- pop si ;get address in SI
- jc blank_entry ;branch if new entry is blank
- call find_position ;determine new record position
- mov bl,slotno ;retrieve its physical position
- call insert_record ;insert new record into stack
- mov recptr,cl ;point RECPTR to new record
- ret
- blank_entry: cmp numrec,0 ;any records?
- je blank1 ;no, then exit
- call show_record ;display current record
- blank1: ret
- create endp
- ;
- ;------------------------------------------------------------------------------
- ;DELETE deletes the current record.
- ;------------------------------------------------------------------------------
- delete proc near
- cmp numrec,0 ;any records to delete?
- je del_exit ;no, then exit
- mov si,offset menuline2 ;request verification
- call write_menu
- del1: call getkey ;get keyboard response
- cmp al,13 ;ENTER pressed?
- je del2 ;yes, then continue
- cmp al,27 ;ESC pressed?
- jne del1 ;no, then get another keypress
- del2: push ax ;save response
- mov si,offset menuline1 ;restore menu line
- call write_menu
- pop ax ;retrieve response
- cmp al,13 ;delete the record?
- jne del_exit ;no
- call delete_record ;delete current record
- cmp numrec,0 ;any records left?
- jne del3 ;yes, then branch
- call clear_window ;no, then clear display
- del_exit: ret ;exit
- del3: mov al,numrec ;get record count
- cmp al,recptr ;is RECPTR in range?
- jae del4 ;yes, then branch
- dec recptr ;no, then make sure it is
- del4: call show_record ;display new current record
- ret
- delete endp
- ;
- ;------------------------------------------------------------------------------
- ;SAVE writes the data in memory to disk.
- ;------------------------------------------------------------------------------
- save proc near
- cmp numrec,0 ;any records to save?
- jne fsave1 ;yes, then continue
- ret ;no, then exit
- fsave1: cmp fileflag,0 ;does a filespec exist?
- jne fsave2 ;yes, then branch
- ;
- ;Read a filespec input from the keyboard.
- ;
- getname: mov si,offset menuline13 ;print input prompt
- call write_menu
- xor di,di ;prepare for call to READLN
- mov dx,0E1Ah
- mov cl,34
- call readln ;read the filespec
- or cl,cl ;anything entered?
- je save_exit ;no, then exit
- mov fileflag,1 ;set filespec indicator
- xor si,si ;copy filespec into buffer
- mov di,offset filespec
- xor ch,ch
- rep movsb
- mov byte ptr es:[di],0 ;zero last byte
- ;
- ;Open the file and write record data out to it.
- ;
- fsave2: mov dx,offset filespec ;point DX to filespec
- mov ah,3Ch ;open/create file
- xor cx,cx ;normal attributes
- int 21h
- jc getname ;get new filespec if open failed
- fsave3: mov bx,ax ;transfer file handle to BX
- mov ah,40h ;write NUMREC byte to file
- mov cx,1
- mov dx,offset numrec
- int 21h
- jc save_error ;branch on error
- cmp ax,1 ;byte successfully written?
- jb diskfull ;no, then disk is full
- mov al,1 ;initialize record number
- mov cl,numrec ;get number of records to write
- xor ch,ch
- fsave4: push cx ;save count
- push ax ;save record number
- call record_address ;get address of current record
- mov dx,di ;transfer it to DX
- mov cx,192 ;192 bytes per record
- mov ah,40h ;write one record
- int 21h
- mov dx,ax ;transfer byte count to DX
- pop ax ;retrieve record number and count
- pop cx
- jc save_error ;branch on error
- cmp dx,192 ;entire record written?
- jb diskfull ;no, then disk is full
- inc al ;next record
- loop fsave4 ;loop until done
- closefile: mov ah,3Eh ;close file
- int 21h
- save_exit: mov si,offset menuline1 ;restore menu line
- call write_menu
- ret ;exit
- ;
- ;An error was encountered during the save.
- ;
- save_error: mov si,offset menuline11 ;print error message
- push bx ;save file handle
- call write_menu
- pop bx ;retrieve file handle
- error2: call getkey ;wait for a press of ESC
- cmp al,27
- jne error2
- jmp short closefile ;close file and resume
- ;
- ;No room left on the disk.
- ;
- diskfull: mov si,offset menuline8 ;print 'Disk full' message
- push bx ;save file handle
- call write_menu
- pop bx ;retrieve file handle
- full2: call getkey ;wait for a press of ESC
- cmp al,27
- jne full2
- jmp short closefile ;and exit
- save endp
- ;
- ;------------------------------------------------------------------------------
- ;DISABLE_CGA and ENABLE_CGA disable and enable CGA video output.
- ;------------------------------------------------------------------------------
- disable_cga proc near
- mov dx,3DAh ;address of Status Register
- disable1: in al,dx ;get status
- test al,8 ;vertical retrace active?
- je disable1 ;no, then wait
- sub dx,2 ;MSR address in DX
- mov al,25h ;value to disable video
- out dx,al ;disable video output
- ret
- disable_cga endp
- ;
- enable_cga proc near
- mov ah,15 ;get video mode
- int 10h
- mov bx,offset enable_values ;get value to enable display
- xlat ;value in AL
- mov dx,3D8h ;MSR address
- out dx,al ;enable video output
- ret
- enable_cga endp
- ;
- ;------------------------------------------------------------------------------
- ;GETKEY waits for a keypress and returns the keycode in AX.
- ;Exit: AX - keycode
- ;------------------------------------------------------------------------------
- getkey proc near
- mov ah,1 ;check keyboard buffer
- int 16h
- jne getkey1 ;jump if buffer contains a keycode
- int 28h ;no key pressed - issue int 28h
- jmp getkey ;loop back to try again
- getkey1: mov ah,0 ;get keycode from buffer
- int 16h
- ret ;exit with keycode in AX
- getkey endp
- ;
- ;------------------------------------------------------------------------------
- ;INSERT_RECORD inserts a record into the stack.
- ;Entry: BL - slot number
- ; CL - index number
- ;------------------------------------------------------------------------------
- insert_record proc near
- push cx ;save index number
- mov di,offset index_table ;point DI to index table
- mov al,cl ;get index number in AL for search
- mov cl,maxrec ;set counter
- xor ch,ch
- insert1: cmp [di],al ;index less than new index?
- jb insert2 ;yes, then branch
- inc byte ptr [di] ;increment index
- insert2: inc di ;advance DI to next index
- loop insert1 ;loop until all indexes examined
- pop cx ;retrieve new index number
- xor bh,bh ;byte to word in BX
- mov di,offset index_table ;point DI to index table
- mov [di+bx],cl ;deposit new index into table
- inc numrec ;increment record count by 1
- ret
- insert_record endp
- ;
- ;------------------------------------------------------------------------------
- ;DELETE_RECORD deletes the record indexed by RECPTR.
- ;------------------------------------------------------------------------------
- delete_record proc near
- mov al,recptr ;search for current record slot
- mov di,offset index_table
- mov cl,maxrec
- xor ch,ch
- repne scasb
- dec di ;back to matching byte
- mov byte ptr [di],0 ;zero current index
- mov al,recptr ;get current record number
- mov di,offset index_table ;point DI to index table
- mov cl,maxrec ;set counter
- xor ch,ch
- delrec1: cmp [di],al ;index less than current index?
- jb delrec2 ;yes, then branch
- dec byte ptr [di] ;no, decrement index
- delrec2: inc di ;advance to next index
- loop delrec1 ;loop until all records examined
- dec numrec ;decrement record count by 1
- ret
- delete_record endp
- ;
- ;------------------------------------------------------------------------------
- ;EDIT_RECORD allows the record addressed by ES:DI to be edited.
- ;Entry: ES:DI - record address | Exit: CF clear - record valid
- ; DS:SI - menu line text string | CF set - record blank
- ;------------------------------------------------------------------------------
- edit_record proc near
- push di ;save starting address
- call write_menu ;write new menu line
- mov bh,video_page ;set BH for video calls
- mov ah,2 ;set initial cursor position
- mov dx,071Bh
- int 10h
- call show_cursor ;display the cursor
- ;
- ;Wait for a keypress.
- ;
- editrec1: call getkey ;get a keypress
- or al,al ;extended code?
- jne editrec2 ;no, then branch
- jmp short extend ;goto extended code handler
- editrec2: cmp al,8 ;backspace key?
- je bspace
- cmp al,13 ;ENTER key?
- je enter
- cmp al,32 ;ASCII code less than 32?
- jb editrec1 ;yes, then ignore it
- ;
- ;Process a press of a character key.
- ;
- cmp dl,59 ;at the end of the line?
- je editrec1 ;yes, then ignore keypress
- stosb ;deposit character in record
- mov ah,10 ;then print it
- mov cx,1
- int 10h
- mov ah,2 ;advance the cursor
- inc dl
- int 10h
- jmp editrec1 ;return for more
- ;
- ;Process a press of the BACKSPACE key.
- ;
- bspace: cmp dl,27 ;any characters to delete?
- je editrec1 ;no, then ignore keypress
- mov ah,2 ;move cursor back one space
- dec dl
- int 10h
- mov ax,0A20h ;print a space character
- mov cx,1
- int 10h
- dec di ;decrement buffer pointer by 1
- mov byte ptr es:[di],32 ;insert an ASCII space
- jmp editrec1
- ;
- ;Process a press of the ENTER key.
- ;
- enter: mov al,dl ;reset DI to beginning of line
- xor ah,ah
- sub ax,27
- sub di,ax
- inc dh ;advance row number
- add di,32 ;advance pointer
- cmp dh,13 ;wrap around if necessary
- jne enter1
- mov dh,7
- sub di,192
- enter1: mov dl,27 ;home the cursor
- mov ah,2
- int 10h
- jmp editrec1 ;return to input loop
- ;
- ;Process a press of either Cursor-Left or Cursor-Right.
- ;
- extend: cmp ah,75 ;cursor left key?
- jne ext2 ;no, then branch
- cmp dl,27 ;already at left end of field?
- je ext1 ;yes, then ignore keypress
- mov ah,2 ;move cursor back one space
- dec dl
- int 10h
- dec di ;decrement buffer pointer
- ext1: jmp editrec1 ;return
- ext2: cmp ah,77 ;cursor right key?
- jne ext3 ;no, then branch
- cmp dl,59 ;cursor in last column?
- je ext1 ;yes, then ignore keypress
- mov ah,2 ;advance cursor
- inc dl
- int 10h
- inc di ;increment buffer pointer
- jmp editrec1 ;return
- ;
- ;Process a press of either Cursor-Up or Cursor-Down.
- ;
- ext3: cmp ah,72 ;cursor up key?
- jne ext5 ;no, then branch
- dec dh ;decrement row number
- sub di,32 ;set pointer to previous line
- cmp dh,6 ;wrap around if necessary
- jne ext4
- mov dh,12
- add di,192
- ext4: mov ah,2 ;move the cursor
- int 10h
- jmp editrec1 ;return for another keypress
- ext5: cmp ah,80 ;cursor down key?
- jne ext6 ;no, then branch
- inc dh ;increment row number
- add di,32 ;set pointer to next line
- cmp dh,13 ;wrap around if necessary
- jne ext4
- mov dh,7
- sub di,192
- jmp ext4 ;move cursor and return
- ;
- ;End the edit routine when F1 is pressed.
- ;
- ext6: cmp ah,59 ;F1 key?
- jne ext4 ;no, then ignore keypress
- mov ah,1 ;hide the cursor
- mov ch,20h
- int 10h
- mov si,offset menuline1 ;restore menu line
- call write_menu
- pop di ;recover starting address
- mov al,32 ;ASCII space character
- mov cx,192 ;192 bytes per record
- repe scasb ;check for non-space character
- jne ok ;OK if non-space found
- stc ;set CF to indicate blank entry
- ret
- ok: clc ;clear CF to indicate valid record
- ret
- edit_record endp
- ;
- ;------------------------------------------------------------------------------
- ;FIND_POSITION returns the new index of the record addressed by SI.
- ;Entry: SI - record address | Exit: CL - record number
- ;------------------------------------------------------------------------------
- find_position proc near
- mov cl,1 ;set index for first record
- cmp numrec,0 ;any records to examine?
- je find_exit ;no, then exit
- find1: mov al,cl ;get index in AL
- push cx ;save it
- call record_address ;get address of next record
- push si ;save new record address
- mov cx,32 ;32 bytes per record
- find2: cmpsb ;compare records
- ja next_record ;check next record
- jb slot_found ;alphabetical slot found
- loop find2 ;goto next byte if these are equal
- jmp short slot_found ;slot found if all equal
- next_record: pop si ;clean up the stack
- pop cx
- inc cl ;next record number
- cmp cl,numrec ;all records searched?
- jbe find1 ;no, then loop back for more
- find_exit: ret ;yes, then we're done
- slot_found: pop si ;clean up the stack
- pop cx
- ret
- find_position endp
- ;
- ;------------------------------------------------------------------------------
- ;SHOW_RECORD displays the record pointed to by RECPTR.
- ;------------------------------------------------------------------------------
- show_record proc near
- mov al,recptr ;get current record number
- call record_address ;get record address in DI
- mov si,di ;transfer it to SI
- mov bl,record_attr ;set attribute to be used
- mov dx,071Bh ;set initial cursor position
- mov cx,6 ;6 lines to display
- show1: push cx ;save line counter
- push dx ;save cursor position
- mov cx,32 ;32 characters per line
- call writeln ;display one line
- pop dx ;retrieve cursor address
- inc dh ;increment row number
- pop cx ;retrieve line counter
- loop show1 ;loop until done
- ret
- show_record endp
- ;
- ;------------------------------------------------------------------------------
- ;RECORD_ADDRESS returns the offset address and slot number of a record.
- ;Entry: AL - record number | Exit: DI - record address
- ; | AL - slot number
- ;------------------------------------------------------------------------------
- record_address proc near
- mov di,offset index_table ;point DI to index table
- mov cl,maxrec ;set counter
- xor ch,ch
- repne scasb ;search for current record number
- inc cx ;increment counter
- mov al,maxrec ;calculate offset address in AX
- sub al,cl
- push ax ;save slot number
- mul record_length
- add ax,offset data_buffer
- mov di,ax ;transfer address to DI
- pop ax ;recover slot number
- ret
- record_address endp
- ;
- ;------------------------------------------------------------------------------
- ;WRITE_MENU displays a line of text on the window's menu line.
- ;Entry: DS:SI - address of text
- ;------------------------------------------------------------------------------
- write_menu proc near
- mov ah,2 ;position the cursor
- mov dx,0E14h
- mov bh,video_page
- int 10h
- mov ax,0920h ;erase current menu line
- mov bl,menu_attr
- mov cx,40
- int 10h
- wm1: lodsb ;get a character
- or al,al ;exit if it's the delimiter
- je wm2
- mov ah,0Eh ;write the character
- int 10h
- jmp short wm1 ;loop until done
- wm2: ret
- write_menu endp
- ;
- ;------------------------------------------------------------------------------
- ;WRITELN displays a string.
- ;Entry: DS:SI - string address
- ; BL - attribute
- ; CX - string length
- ; DH,DL - starting row and column
- ;------------------------------------------------------------------------------
- writeln proc near
- mov bh,video_page ;set page number for output
- write1: mov ah,2 ;position cursor
- int 10h
- lodsb ;get one byte
- push cx ;save count
- mov cx,1 ;zero repetitions
- mov ah,9 ;int 10h function - write c/a
- int 10h ;write character/attribute
- inc dl ;advance cursor
- pop cx ;retrieve character count
- loop write1 ;loop until done
- ret
- writeln endp
- ;
- ;------------------------------------------------------------------------------
- ;READLN accepts input of a string entered from the keyboard.
- ;Entry: ES:DI - buffer address | Exit: CL - string length
- ; DH,DL - cursor start position |
- ; CL - max length accepted |
- ;------------------------------------------------------------------------------
- maxlen db ? ;maximum string length
- ;
- readln proc near
- mov maxlen,cl ;save max length
- mov ah,2 ;set cursor to start position
- mov bh,video_page
- int 10h
- call show_cursor ;display the cursor
- xor cl,cl ;initialize counter
- ;
- ;Wait for a keypress.
- ;
- read1: call getkey ;get a character
- cmp al,13 ;ENTER key?
- je read_exit ;yes, then exit
- cmp al,27 ;ESC key?
- jne read2 ;no, then branch
- xor cl,cl ;zero length
- jmp short read_exit ;exit
- read2: cmp al,8 ;backspace key?
- je backspace ;yes, then do backspace function
- cmp al,32 ;ASCII 32 or greater?
- jb read1 ;no, then ignore it
- cmp al,126 ;ASCII 126 or less?
- ja read1 ;no, then ignore keypress
- cmp cl,maxlen ;room for another entry?
- je read1 ;no, then ignore it
- ;
- ;Process the press of a character key.
- ;
- stosb ;deposit character in buffer
- push cx ;save character count
- mov ah,10 ;print the character
- mov cx,1
- int 10h
- inc dl ;advance the cursor
- mov ah,2
- int 10h
- pop cx ;retrieve count
- inc cl ;update count
- jmp read1 ;go back for more
- ;
- ;Process a press of the BACKSPACE key.
- ;
- backspace: or cl,cl ;any characters to delete?
- je read1 ;no, then ignore keystroke
- push cx ;save count
- dec dl ;move cursor back one space
- mov ah,2
- int 10h
- mov ah,10 ;print a space character
- mov al,32
- mov cx,1
- int 10h
- pop cx ;retrieve count
- dec cl ;decrement it
- dec di ;decrement buffer pointer
- jmp read1 ;go back for more
- ;
- ;Hide the cursor and return.
- ;
- read_exit: mov ah,1 ;hide the cursor
- mov ch,20h
- int 10h
- ret
- readln endp
- ;
- ;------------------------------------------------------------------------------
- ;SHOW_CURSOR displays the cursor and discounts EGA cursor emulation logic.
- ;Entry: NEW_CURSOR - starting and ending scan lines
- ;------------------------------------------------------------------------------
- show_cursor proc near
- cmp adapter,2 ;is an EGA currently active?
- jne cursor1 ;no, then branch
- push es ;save ES
- mov ax,bios_data ;point ES to BIOS data area
- mov es,ax
- assume es:bios_data
- push infobyte ;save EGA info byte
- or ega_info,1 ;disable EGA cursor emulation
- cursor1: mov ah,1 ;display the cursor
- mov cx,new_cursor
- int 10h
- cmp adapter,2 ;is an EGA active?
- jne cursor_exit ;no, then exit
- pop infobyte ;restore EGA info byte
- pop es ;restore ES
- assume es:nothing
- cursor_exit: ret
- show_cursor endp
- ;
- ;------------------------------------------------------------------------------
- ;CLEAR_WINDOW clears the record currently displayed in the window.
- ;------------------------------------------------------------------------------
- clear_window proc near
- mov ax,0600h ;interrupt 10h, function 6
- mov cx,071Bh
- mov dx,0C3Bh
- mov bh,record_attr
- int 10h
- ret
- clear_window endp
- ;
- ;------------------------------------------------------------------------------
- ;IOSET vectors interrupts 1Bh, 23h and 24h to internal handlers. IORESET
- ;restores the original vector values.
- ;------------------------------------------------------------------------------
- ioset proc near
- push es ;save ES
- mov ax,351Bh ;get interrupt 1Bh vector
- int 21h
- mov old1Bh_segment,es ;save it
- mov old1Bh_offset,bx
- mov ah,25h ;point it to an IRET instruction
- mov dx,offset ioexit
- int 21h
- mov ax,3523h ;get interrupt 23h vector
- int 21h
- mov old23h_segment,es ;save it
- mov old23h_offset,bx
- mov ah,25h ;point it to an IRET instruction
- mov dx,offset ioexit
- int 21h
- mov ax,3524h ;get interrupt 24h vector
- int 21h
- mov old24h_segment,es ;save it
- mov old24h_offset,bx
- mov ah,25h ;then set it to IOERR routine
- mov dx,offset ioerr
- int 21h
- pop es ;restore ES
- ret
- ioset endp
- ;
- ioreset proc near
- mov ax,2524h ;restore interrupt 24h vector
- mov dx,old24h_offset
- push ds
- assume ds:nothing
- mov ds,old24h_segment
- int 21h
- mov ax,2523h ;restore interrupt 23h vector
- mov dx,old23h_offset
- mov ds,old23h_segment
- int 21h
- mov ax,251Bh ;restore interrupt 1Bh vector
- mov dx,old1Bh_offset
- mov ds,old1Bh_segment
- int 21h
- pop ds
- assume ds:code
- ret
- ioreset endp
- ;
- ;------------------------------------------------------------------------------
- ;FINISH loads the data file, resets interrupt vectors, and terminates.
- ;------------------------------------------------------------------------------
- finish proc near
- ;
- ;Open the specified data file for reading.
- ;
- mov ax,3D00h ;open file for reading
- mov dx,offset filespec ;point DX to ASCIIZ filespec
- int 21h
- jnc finish3 ;branch if no error
- mov ah,9 ;print 'File not found'
- mov dx,offset errmsg1
- int 21h
- cmp reload,0 ;was this an attempted reload?
- je endfin ;no, then exit
- mov al,old_numrec ;yes, then restore parameters
- mov es:[numrec],al
- mov al,old_recptr
- mov es:[recptr],al
- mov al,old_fileflag
- mov es:[fileflag],al
- endfin: ret ;and exit
- ;
- ;Load the data file into memory.
- ;
- finish3: mov bx,ax ;transfer file handle to BX
- push ds ;exchange DS and ES
- push es
- pop ds
- pop es
- mov ah,3Fh ;read record count byte
- mov cx,1
- mov dx,offset numrec
- int 21h
- jc close ;branch on error
- mov al,ds:[maxrec] ;make sure NUMREC <= MAXREC
- cmp al,ds:[numrec]
- jae finish4
- mov ds:[numrec],al ;adjust if it isn't
- finish4: mov al,ds:[numrec] ;calculate number of bytes to read
- mul record_length
- mov cx,ax ;transfer number of bytes to CX
- mov ah,3Fh ;DOS function 3Fh - read file
- mov dx,offset data_buffer ;point DX to buffer area
- int 21h ;read all records from disk
- close: mov ah,3Eh ;close file
- int 21h
- mov ds:[fileflag],1 ;set filespec flag
- push ds ;swap DS and ES again
- push es
- pop ds
- pop es
- ;
- ;Initialize the record index table.
- ;
- finish5: mov di,offset index_table ;point DI to table area
- xor al,al ;zero AL
- mov cl,es:[maxrec] ;set counter
- xor ch,ch
- rep stosb ;zero all bytes
- mov cl,es:[numrec] ;set CX to number of records
- xor ch,ch
- jcxz finish7 ;exit if there are none
- mov di,offset index_table ;reset DI
- mov al,1 ;initialize AL
- finish6: stosb ;set one index byte
- inc al ;increment index
- loop finish6 ;loop until done
- ;
- ;Copy new filespec into old data space if this is a reload.
- ;
- finish7: cmp reload,0 ;is this a reload
- je finish8 ;no, then branch
- mov si,offset filespec ;point SI and DI to filespec areas
- mov di,si
- mov cx,126 ;set counter
- rep movsb ;transfer text
- ret ;done - exit
- ;
- ;Save and replace all required interrupt vectors.
- ;
- finish8: mov ax,3508h ;get interrupt 8 vector
- int 21h
- mov old8h,bx ;save it
- mov old8h[2],es
- mov ah,25h ;point it to the TIMER routine
- mov dx,offset timer
- int 21h
- mov ax,3509h ;get interrupt 9 vector
- int 21h
- mov old9h,bx ;save it
- mov old9h[2],es
- mov ah,25h ;point it to KEYBOARD routine
- mov dx,offset keyboard
- int 21h
- mov ax,3510h ;get interrupt 10h vector
- int 21h
- mov old10h,bx ;save it
- mov old10h[2],es
- mov ah,25h ;point it to VIDEO
- mov dx,offset video
- int 21h
- mov ax,3513h ;get interrupt 13h vector
- int 21h
- mov old13h,bx ;save it
- mov old13h[2],es
- mov ah,25h ;point it to BDISK
- mov dx,offset bdisk
- int 21h
- mov ax,3528h ;get interrupt 28h vector
- int 21h
- mov old28h,bx ;save it
- mov old28h[2],es
- mov ah,25h ;point it to BACKPROC
- mov dx,offset backproc
- int 21h
- ;
- ;Calculate amount of memory to reserve and terminate-but-stay-resident.
- ;
- mov dx,offset program ;display notice and hot key
- mov ah,9 ;with DOS function 9
- int 21h
- mov al,maxrec ;get max number of records
- mul record_length ;multiply by 192
- mov dx,ax ;transfer figure to DX
-
- add dx,(offset data_buffer - offset code + 15)
-
- mov cl,4 ;convert bytes to paragraphs
- shr dx,cl
- mov ax,3100h ;load function and return codes
- int 21h ;terminate-but-stay-resident
- finish endp
- ;
- ;-----------------------------------------------------------------------------
- ;Data space to be used after Cardfile is resident in memory.
- ;-----------------------------------------------------------------------------
- pc = $
- screen_buffer = pc ;video memory buffer
- pc = pc + 10 * 44 * 2
- index_table = pc ;record index table
- pc = pc + 512
- filespec = pc ;file specification
- pc = pc + 128
- data_buffer = pc ;record buffer
- ;
- ;------------------------------------------------------------------------------
- ;INITIALIZE prepares the program for residency.
- ;------------------------------------------------------------------------------
- initialize proc near
- assume ds:code
- errmsg1 db 13,10,"File not found",13,10,"$"
- errmsg2 db 13,10,"Critical Error Flag not found",13,10,"$"
- old_numrec db ?
- old_recptr db ?
- old_fileflag db ?
- ;
- ;See if the program is already resident in memory.
- ;
- init1: mov word ptr [begin],0 ;zero word to avoid false match
- xor bx,bx ;initialize search segment
- mov ax,cs ;record current segment in AX
- init2: inc bx ;increment search segment
- cmp ax,bx ;reached current segment?
- je init3 ;yes, then this is the first load
- mov es,bx ;point ES to search segment
- mov si,offset begin ;point SI and DI to ID offset
- mov di,si
- mov cx,16 ;check 16 characters
- cld ;clear DF
- repe cmpsb ;compare the strings
- jne init2 ;continue search if compare failed
- ;
- ;Cardfile is already installed. Set the reload flag and save parameters.
- ;
- mov reload,1 ;set flag
- mov al,es:[numrec] ;save parameters
- mov old_numrec,al
- mov al,es:[recptr]
- mov old_recptr,al
- mov al,es:[fileflag]
- mov old_fileflag,al
- mov es:[numrec],0 ;initialize counters and flags
- mov es:[recptr],1
- mov es:[fileflag],0
- jmp short parse ;branch to parsing code
- ;
- ;Determine which version of DOS is running.
- ;
- init3: mov ah,30h ;DOS function 30h
- int 21h
- mov dos_version,al ;major version number
- ;
- ;Get and save the address of the INDOS flag.
- ;
- mov ah,34h ;function 34h
- int 21h ;get address
- mov dos_segment,es ;save segment
- mov indos_offset,bx ;save offset
- ;
- ;Get and save the address of the critical error flag.
- ;
- mov ax,3E80h ;CMP opcode
- mov cx,2000h ;max search length
- mov di,bx ;start at INDOS address
- init4: repne scasw ;do the search
- jcxz init5 ;branch if search failed
- cmp byte ptr es:[di+5],0BCh ;verify this is it
- je found ;branch if it is
- jmp init4 ;resume loop if it's not
- init5: mov cx,2000h ;search again
- inc bx ;search odd addresses this time
- mov di,bx
- init6: repne scasw ;look for the opcode
- jcxz notfound ;not found if loop expires
- cmp byte ptr es:[di+5],0BCh ;verify this is it
- je found
- jmp init6
- notfound: mov ah,9 ;flag not found
- mov dx,offset errmsg2
- int 21h
- ret
- found: mov ax,es:[di] ;get flag offset address
- mov errflag_offset,ax ;save it
- push cs ;reset ES to the code segment
- pop es
- ;
- ;Parse the command line and create a complete filespec.
- ;
- parse: mov di,82h ;point DI to command line text
- cmp byte ptr [di-2],2 ;less than 2 characters entered?
- jnb parse0 ;no, then continue
- jmp finish5 ;yes, then skip load routine
- parse0: mov si,di ;point SI to command line text
- mov di,offset filespec ;point DI to buffer
- parse1: cmp byte ptr [si],32 ;advance to first non-space
- jne parse2
- inc si
- jmp parse1
- parse2: cmp byte ptr [si+1],":" ;leading drive specifier?
- je parse4 ;yes, then filespec is complete
- mov ah,19h ;get current drive
- int 21h
- add al,65 ;convert to ASCIIZ
- mov ah,":" ;complete drive specifier
- mov word ptr [di],ax ;write drive spec to buffer
- add di,2 ;advance DI
- cmp byte ptr [si],"\" ;leading backslash?
- je parse4 ;yes, then filespec is complete
- mov byte ptr [di],"\" ;fill in the backslash
- inc di
- push si ;save SI and DI
- push di
- mov ah,47h ;get current path
- mov si,di
- xor dl,dl ;default drive
- int 21h ;append path to drive spec
- pop di ;restore SI and DI
- pop si
- cmp byte ptr [di],0 ;anything returned?
- je parse4 ;no, then filespec is complete
- parse3: inc di ;advance to end of string
- cmp byte ptr [di],0
- jne parse3
- mov byte ptr [di],"\" ;insert trailing backslash
- inc di
- parse4: mov al,[si] ;append entry to filespec string
- cmp al,13
- je parse5
- mov [di],al
- inc si
- inc di
- jmp parse4
- parse5: mov byte ptr [di],0
- jmp finish ;load data file and exit
- initialize endp
- ;
- code ends
- end begin
-