Category : Assembly Language Source Code
Archive   : ASM4.ZIP
Filename : SNAPSHOT.ASM

 
Output of file : SNAPSHOT.ASM contained in archive : ASM4.ZIP
INTERRUPTS SEGMENT AT 0H ;This is where the keyboard interrupt
ORG 9H*4 ;holds the address of its service routine
KEYBOARD_INT LABEL DWORD
INTERRUPTS ENDS

SCREEN SEGMENT AT 0B000H ;A dummy segment to use as the
SCREEN ENDS ;Extra Segment

ROM_BIOS_DATA SEGMENT AT 40H ;BIOS statuses held here, also keyboard buffer

ORG 1AH
HEAD DW ? ;Unread chars go from Head to Tail
TAIL DW ?
BUFFER DW 16 DUP (?) ;The buffer itself
BUFFER_END LABEL WORD

ROM_BIOS_DATA ENDS

CODE_SEG SEGMENT
ASSUME CS:CODE_SEG
ORG 100H ;ORG = 100H to make this into a .COM file
FIRST: JMP LOAD_SNAPSHOT ;First time through jump to initialize routine

COPY_RIGHT DB '(C) S. HOLZNER 1985' ;An Ascii signature
; KEYS DW 310EH,2106H,1E01H,3002H,2E03H ;A Sample: ^N,^F,^A,^B,^C
KEYS DW 5 DUP(0)
FLASHED DB 0 ;Have we flashed a screenful? 1=yes
SNAPSHOT_OFFSET DW 0 ;Chooses 1st 250 bytes or 2nd
SCREEN_SEG_OFFSET DW 0 ;0 for mono, 8000H for graphics
IO_CHAR DW ? ;Holds addr of Put or Get_Char
FILE_SIZE DW 0 ;Read in this many bytes
OLD_KEYBOARD_INT DD ? ;Location of old kbd interrupt
FILE DB 'A.DAT',0 ;Asciiz. Changed to B.Dat, etc.
WS_FLAG DB 0 ;<-- Set to 1 to strip WordStar
SNAPSHOT DB 10000 DUP (32) ;Storage for screens

SNAP PROC NEAR ;The keyboard interrupt will now come here.
ASSUME CS:CODE_SEG
PUSH AX ;Save the used registers for good form
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH SI
PUSH DS
PUSH ES
PUSHF ;First, call old keyboard interrupt
CALL OLD_KEYBOARD_INT

ASSUME DS:ROM_BIOS_DATA ;Examine the char just put in
MOV BX,ROM_BIOS_DATA
MOV DS,BX
MOV BX,TAIL ;Point to current tail
CMP BX,HEAD ;If at head, kbd int has deleted char
JE IN ;So leave
SUB BX,2 ;Point to just read in character
CMP BX,OFFSET BUFFER ;Did we undershoot buffer?
JAE NO_WRAP ;Nope
MOV BX,OFFSET BUFFER_END ;Yes -- move to buffer top
SUB BX,2 ;Point to just read in character
NO_WRAP:MOV DX,[BX] ;** Typed character in DX now **
LEA SI,KEYS ;Point to Keys for search
CMP FLASHED,1 ;Should we restore screen?
JE RESTORE ;Yes, jump there
CMP DX,CS:[SI] ;Compare to first key (Store screen)
JE STORE ;So Store
ADD SI,2 ;Point to next key
CMP DX,CS:[SI] ;Second key -- should we flash screen?
JE FLASH ;Yes
MOV CX,3 ;No -- check for .Dat keys (A.Dat,etc)
MOV SNAPSHOT_OFFSET,4000 ;Point to beginning of .Dats in memory
TEST: ADD SI,2 ;Increment to next key
CMP DX,CS:[SI] ;Is it right?
JE DATS ;Yes, flash a .Dat file on screen
ADD SNAPSHOT_OFFSET,2000 ;Point to next .Dat
LOOP TEST ;And go back until all three are done
JMP OUT ;No keys matched. Jump Out.
STORE: MOV TAIL,BX ;Delete character from buffer
MOV FLASHED,0 ;Switch Modes on Flashed
MOV SNAPSHOT_OFFSET,0 ;Point to screen storage part of pad
LEA AX,GET_CHAR ;Make IO use Get_char so current screen
MOV IO_CHAR,AX ;is stored
CALL IO ;Store Screen
IN: JMP OUT ;Done here, let's go.
FLASH: MOV TAIL,BX
MOV FLASHED,1 ;Switch Modes, next key will restore screen
MOV SNAPSHOT_OFFSET,2000 ;Point to screen storage part
LEA AX,GET_CHAR ;Make IO use Get_char so current screen
MOV IO_CHAR,AX ;is stored
CALL IO ;Store Screen
MOV SNAPSHOT_OFFSET,0 ;Use 1st 250 bytes of Snapshot memory
LEA AX,PUT_CHAR ;Make IO use Put-Char so it does
MOV IO_CHAR,AX
CALL IO ;Put result on screen
JMP OUT ;Done here.
RESTORE:
MOV FLASHED,0 ;Restore screen from memory
MOV TAIL,BX ;Delete character from buffer
MOV SNAPSHOT_OFFSET,2000 ;Point to storage part of memory
LEA AX,PUT_CHAR ;Make IO call Put_Char as it scans
MOV IO_CHAR,AX ;over all locations in screen
CALL IO ;Restore screen
JMP OUT ;And leave

DATS: MOV TAIL,BX
MOV FLASHED,1 ;Switch Modes, next key will restore screen
PUSH SNAPSHOT_OFFSET ;Save this while Offset set for storing
MOV SNAPSHOT_OFFSET,2000 ;Point to screen storage part
LEA AX,GET_CHAR ;Make IO use Get_char so current screen
MOV IO_CHAR,AX ;is stored
CALL IO ;Store Screen
POP SNAPSHOT_OFFSET ;Restore pointer to stored .Dat
LEA AX,PUT_CHAR ;Make IO use Put-Char so it does
MOV IO_CHAR,AX
CALL IO ;Put result on screen

OUT: POP ES ;Do the Pops of all registers.
POP DS
POP SI
POP DI
POP DX
POP CX
POP BX
POP AX
IRET ;An interrupt needs an IRET
SNAP ENDP

GET_CHAR PROC NEAR ;Gets a char from screen and advances position
PUSH DX
MOV SI,2 ;Loop twice, once for char, once for attribute
G_WAIT_LOW:
MOV AH,ES:[DI] ;Do the move from the screen, one byte at a time
INC DI ;Move to next screen location
DEC SI ;Decrement loop counter
CMP SI,0 ;Are we done?
JE LEAVE ;Yes
MOV SNAPSHOT[BX],AH ;No -- put char we got into snapshot
JMP G_WAIT_LOW ;Do it again
LEAVE: INC BX ;Update location
POP DX
RET
GET_CHAR ENDP

PUT_CHAR PROC NEAR ;Puts one char on screen and advances position
PUSH DX
MOV AH,SNAPSHOT[BX] ;Get the char to be put onto the screen
MOV SI,2 ;Loop twice, once for char, once for attribute
MOV ES:[DI],AH ;Move to screen, one byte at a time
ADD DI,2
SUB SI,2
INC BX ;Point to next char
POP DX
RET ;Exeunt
PUT_CHAR ENDP

IO PROC NEAR ;This scans over all screen positions
ASSUME ES:SCREEN ;Use screen as extra segment
MOV BX,SCREEN
MOV ES,BX

MOV DI,SCREEN_SEG_OFFSET ;DI will be pointer to screen postion
MOV BX,SNAPSHOT_OFFSET ;BX will be location pointer
MOV CX,25 ;There will be 10 lines
LINE_LOOP:
MOV DX,80 ;And 25 spaces across
CHAR_LOOP:
CALL IO_CHAR ;Call Put-Char or Get-Char
DEC DX ;Decrement character loop counter
JNZ CHAR_LOOP ;If not zero, scan over next character
LOOP LINE_LOOP ;And now go back to do next line
RET ;Finished
IO ENDP

READ_FILE PROC NEAR ;Reads .Dats and formats in memory.
PUSH CX ;Save used registers
PUSH DX
PUSH DI
ASSUME DS:CODE_SEG,ES:CODE_SEG
MOV BX,AX ;Put passed file handle in BX
MOV CX,2000 ;Ask for 2000 bytes (Tops)
LEA DX,DATA ;Point DS:DX at Data area at end
MOV AH,3FH ;Ask for reading service
INT 21H ;And go get 'em
MOV CX,AX ;Store number of bytes read
MOV AH,3EH ;Now close file
INT 21H
CALL WS ;Strip high bit if necessary
LEA SI,DATA ;Transfer from CS:[SI] to DS:[BX] now
CMP CX,2000 ;Make sure on number of bytes read in.
JBE THE_LOOP
MOV CX,2000 ;Format file into Snapshot area now
THE_LOOP: ;Loop over character by character
CMP BYTE PTR [SI],9 ;Is it a tab?
JNE NOTAB ;Add 8 spaces for tabs
ADD DI,8
INC SI ;And point to next character
JMP CONT
NOTAB: CMP BYTE PTR [SI],13 ;Is it a carriage return?
JNE OK ;No, store the character
FILL: INC SI ;Found a . Fill to end of line
DEC CX ;Get rid of line feeds
CMP BYTE PTR [SI],13 ;Treat additional s as new lines
JE CR
CMP BYTE PTR [SI],' ' ;Bona Fide character?
JB FILL ;No, keep going past all linefeeds
CR: CMP CX,0 ;Yes, start to fill to end of line here
JLE FIN ;Check on loop index
INC CX ;And readjust it from skipping lf.s
MOV AX,DI ;AH will check if we're at end of line
SUB AX,OFFSET SNAPSHOT+4000 ;Get distance into screen
MOV DL,80 ;Divide by 80 to find columns
DIV DL
CHECK: CMP AH,79 ;Remainder of 79?
JA CONT ;If more, have begun a new line.
ADD: INC DI ;Add a space by incrementing DI
INC AH ;And keep track by incrementing AH too.
JMP CHECK ;At edge of screen?
OK: CMP DI,OFFSET SNAP ;Past end of storage area? (Many tabs and CRs)
JAE FIN ;Yes, don't move byte into it
MOVSB ;No, safe to move byte from [SI] to [DI]
CONT: LOOP THE_LOOP ;And keep going for all bytes in file
FIN: POP DI
POP DX
POP CX
RET ;Exit here.
READ_FILE ENDP

WS PROC NEAR ;This will strip high bits from the
CMP WS_FLAG,1 ; read-in file if WS_Flag = 1
JNE RETWS ;IF WS_Flag is not 1, exit
PUSH SI ;Store used registers
PUSH CX
LEA SI,DATA ;Point to read-in file
MOV CX,2000 ;Do 2000 bytes
ALOOP: AND BYTE PTR CS:[SI],127 ;Strip top bit
INC SI ;Point to next one.
LOOP ALOOP ;And keep going
POP CX ;Pops
POP SI
RETWS: RET ;And Exit.
WS ENDP

LOAD_SNAPSHOT PROC NEAR ;This procedure intializes everything
ASSUME DS:INTERRUPTS ;The data segment will be the Interrupt area
MOV AX,INTERRUPTS
MOV DS,AX

MOV AX,word ptr KEYBOARD_INT ;Get the old interrupt service routine
MOV word ptr OLD_KEYBOARD_INT,AX ;address, put it into our location
MOV AX,word ptr KEYBOARD_INT[2] ;OLD_KEYBOARD_INT so we can call it.
MOV word ptr OLD_KEYBOARD_INT[2],AX

MOV word ptr KEYBOARD_INT,OFFSET SNAP ;Load address of our program
MOV word ptr KEYBOARD_INT[2],CS ;routine into the keyboard interrupt
MOV AH,15 ;Ask for service 15 of INT 10H
INT 10H ;This tells us how display is set up
TEST AL,4 ;Is it?
JNZ READ ;Yes - jump out
MOV SCREEN_SEG_OFFSET,8000H ;No - set up for graphics display
READ: PUSH CS ;Now read in A.Dat, B.Dat etc.
POP DS ;Set DS correctly
MOV CX,3 ;Loop over three files
LEA DI,SNAPSHOT+4000 ;Store starting in this area
LOOP: ASSUME DS:CODE_SEG ;Loop over files
LEA DX,FILE ;Point to file name
MOV AX,3D00H ;Service 3DH, attribute 0 for file
INT 21H ;Open file
JC EXIT ;If not found, exit
; PUSH DI ;Store
CALL READ_FILE ;Pass file handle in AX to Read_File
; POP DI
ADD DI,2000 ;Point to next storage area
MOV BX,DX ;Change A.Dat into B.Dat etc.
INC BYTE PTR CS:[BX] ;A.DAT-->B.DAT etc.
LOOP LOOP ;Keep going over all files.
EXIT: MOV DX,OFFSET LOAD_SNAPSHOT ;Set up everything but LOAD_SNAPSHOT to
INT 27H ;stay and attach itself to DOS
LOAD_SNAPSHOT ENDP
DATA:
CODE_SEG ENDS

END FIRST ;END "FIRST" so 8088 will go to FIRST first.



  3 Responses to “Category : Assembly Language Source Code
Archive   : ASM4.ZIP
Filename : SNAPSHOT.ASM

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

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

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