; 128 line wide file viewer, requires 80186, EGA
; Written by Tylisha C. Andersen
o equ <offset>
b equ <byte ptr>
w equ <word ptr>
.model tiny
.186
;---------------------------------------------------------------------
.data
fontcomp equ this byte
dw 0,0,35584,47779,53757,49147,50525,20703,-3521,56,15904,14562
dw 29440,-2113,16,7537,4343,0,8,16,-2049,-4097,255,-6380,40,-5121
dw 55064,6655,23256,2128,40331,4119,19204,-2864,4128,53835,9461
dw 21520,17782,4368,15812,28876,12304,-7236,568,2417,31991,20996
dw 41108,2600,-9301,37970,18693,18836,3088,0,14343,28942,-2295,-7041
dw 2417,4338,8452,18184,1148,15904,2082,8192,33342,32,8192,16399
dw 0,41022,40,7200,47183,-2017,-3555,1080,0,0,16896,32784,2080,421
dw 64,20992,-2667,2684,6513,2062,8,1060,4624,11426,20618,8458,32768
dw 0,8513,16388,17412,17416,4112,15504,12489,8192,16958,16,0,256
dw 4,60,0,0,0,4104,17416,4128,11667,26665,49676,33808,7200,2195
dw 8233,37662,10520,3080,48977,2081,34562,51589,3080,14723,18441
dw 5900,9352,2064,6547,18473,37644,8477,3080,64,4,8192,512,2048
dw 40992,8322,2,-8191,120,1092,4164,37648,8200,1040,11667,22568
dw 37644,10557,4680,14743,18473,37660,2337,3136,9623,18473,34588
dw 2233,7744,47495,16392,37648,2349,3144,48532,18473,18194,33808
dw 7200,33809,18473,37900,18865,4688,8580,16392,-3042,10661,4680
dw 42452,18537,37650,10533,3144,14743,16424,37648,9765,1624,14743
dw 18473,37650,2329,3080,51239,4162,37892,10661,3144,42388,18474
dw 37896,12197,4680,39316,18473,37906,8857,1040,34839,8232,34590
dw 2081,7232,4224,4226,9986,16904,7184,147,0,0,0,7680,66,64,0,51460
dw 3640,9604,18633,28,51492,3136,42000,18665,14,51236,3192,14417
dw 8324,8,-6364,33353,9604,18633,530,33809,7200,33792,2401,33938
dw 10793,4704,4166,8324,28,10557,4680,9472,18633,18,51492,3144,9472
dw 19150,16,-6364,16968,9472,16584,16,-7904,7216,4418,8388,4,10533
dw 3656,9472,18474,8,12069,4680,9472,12329,18,10021,33353,1280,4324
dw 16670,33824,1056,66,8324,17416,33800,4128,16563,0,0,18708,7752
dw 41347,16647,1156,10661,3656,41985,30920,1804,51588,3640,33796
dw 14537,1550,51460,3640,1027,14537,14,-6368,33857,41991,30920,1036
dw 51364,3192,9222,30920,524,49800,3600,34823,4290,1550,49672,3600
dw 41988,30921,25362,51492,4728,41217,28904,30,-1527,8060,48547
dw 20554,1814,51620,3144,41988,18633,1548,51492,3144,42247,18473
dw 1550,10533,3656,42244,19239,1154,-5723,7752,42244,18473,8478
dw -6368,33856,14417,41092,21534,18268,1040,9623,23753,10257,17052
dw 5137,33793,14537,270,49800,3600,41985,18633,268,10661,3656,47266
dw 18441,41490,2980,4712,40017,96,20736,16412,0,4098,16521,12,2108
dw 64,15360,2049,37888,16661,1860,5012,52291,257,16904,1040,10280
dw 43170,40960,43530,40,658,4233,27684,9371,14041,30395,47067,8557
dw 16904,33808,2081,28738,8580,49673,33904,37970,27045,74,1280,19065
dw 2304,28866,21124,42373,19049,37970,10661,74,-6907,19049,34130
dw 30880,20992,41108,120,2337,28864,0,512,33904,2081,7232,8448,16392
dw 124,0,31746,8580,16904,33820,0,31744,8448,16904,33916,2081,7282
dw 21124,42388,18989,36946,15536,0,-2800,18989,33106,31920,0,-2815
dw 19053,36946,11701,74,-4095,124,33106,28085,8522,-4095,124,37970
dw 31904,0,-3583,33916,0,32005,21066,41108,60,2081,7280,0,29192
dw 33820,0,15621,21066,42388,19069,2337,31986,8580,16392,112,0,7170
dw -124,-1,-1,0,-241,-6145,52793,40051,52793,40051,-25,-3841,0,9544
dw 55396,-8192,10553,5194,8688,16424,16,-2795,2600,34967,8329,30
dw -2524,72,4608,9879,8,41512,2064,9456,18630,24606,10557,3144,9072
dw 10261,12315,35080,3176,10752,21735,4096,-6358,2132,14704,16392
dw 24590,10533,4680,15600,15,8448,-4087,7952,6244,16416,24606,153
dw 7688,34856,4178,8580,18952,2128,15904,2,20480,18945,40,2129,160
dw 0,8,16,0,4096,8448,18152,3152,5216,160,4864,16412,0,7168,14567
dw 0,0,0
;---------------------------------------------------------------------
nomem$ db 'not enough memory to load', 13, 10, '$'
syntax$ db 'syntax: VIEW <file>', 13, 10, '$'
notfound$ db 'file not found', 13, 10, '$'
null_str db 0
;---------------------------------------------------------------------
.data?
font db 2048 dup(?) ; the font buffer
max_lines dw ? ; maximum number of lines to load
num_lines dw ? ; number of lines in file
first_line dw ? ; pointer to first line
buf_size equ 8192 ; buffer size
db 2 dup(?) ; spaces to precede filename
filename db 128 dup(?) ; file name
buffer db buf_size dup(?) ; disk buffer
handle dw ? ; file handle
buffer_pos dw ? ; position in buffer
buffer_end dw ? ; end of data in buffer
;---------------------------------------------------------------------
.code
org 100h
start: jmp main
;---------------------------------------------------------------------
; exit conditions from main
;---------------------------------------------------------------------
m_error: mov ah, 9 ; print out string
int 21h
m_exit: mov ax, 4C00h ; exit to DOS
int 21h
m_nomem: mov dx, o nomem$ ; not enough memory
jmp m_error
m_syntax: mov dx, o syntax$ ; syntax error
jmp m_error
m_notfound: mov dx, o notfound$ ; file not found
jmp m_error
;---------------------------------------------------------------------
; main - main procedure
;---------------------------------------------------------------------
main: mov sp, o stack_top ; set new stack position
mov ah, 4Ah ; shrink memory to minimum
mov bx, o stack_top+15
shr bx, 4
int 21h
jc m_nomem ; out of memory?
mov ah, 48h ; get total memory free
mov bx, -1
int 21h
mov ah, 48h ; allocate all free memory
int 21h
mov first_line, ax ; set first line segment
shr bx, 3 ; get maximum line count
sub bx, 40
jle m_nomem ; out of memory?
mov max_lines, bx ; set maximum line count
lea cx, [bx+39] ; cx = total line count
m_cloop: mov es, ax ; set all lines to a null string
mov b es:[0], 0
add ax, 8
loop m_cloop
;-----------------------------------------------------------
push ds ; es = ds
pop es
mov cl, ds:[80h] ; cx = command line length
xor ch, ch
inc cx
mov di, 81h ; find first non-space
mov al, ' '
repe scasb
lea si, [di-1] ; si = pointer to filename
cmp b [si], 0Dh ; no file specified?
je m_syntax
repne scasb ; find next space
mov b [di-1], 0 ; add the null terminator
mov di, o filename ; di = filename buffer
mov ah, 60h ; convert to full path
int 21h
mov ax, 2020h ; set preceding bytes to spaces
mov w filename-2, ax
;-----------------------------------------------------------
mov dx, o filename ; open the file
mov ax, 3D00h
int 21h
jc m_notfound ; jump if error
mov handle, ax ; save handle
mov bp, first_line ; bp = segment of first line
mov ax, buf_size ; init buffer variables
mov buffer_pos, ax
mov buffer_end, ax
mov num_lines, 0 ; line counter = 0
m_lineloop: mov es, bp ; es:di = line
xor di, di
mov cx, 127 ; 127 max. chars
m_charloop: call getchar ; get character
jc m_chardone ; check for EOF
cmp al, 13 ; cr = done with line
je m_chardone
cmp al, 10 ; ignore line feeds
je m_charloop
jcxz m_charloop ; maxed out, don't store
stosb ; store char
dec cx ; decrement maximum
jmp m_charloop ; loop back
m_chardone: mov al, 0 ; make string null-terminated
stosb ; (doesn't affect flags)
inc num_lines ; increment line counter
jc m_cont ; jump if EOF
add bp, 8 ; next line
mov ax, num_lines ; too many lines?
cmp ax, max_lines
jb m_lineloop ; loop if not
;-----------------------------------------------------------
m_cont: mov bx, handle ; close the file
mov ah, 3Eh
int 21h
push ds ; es = ds
pop es
mov si, o fontcomp ; si = compressed font
mov di, o font ; di = font buffer
mov bp, 256 ; bp = size
jmp m_decloop ; jump to decloop
m_decstore: shr al, 3 ; shift al and mask to 5 bits
and ax, 1F1Fh
stosw ; store 2 bytes
ret ; return
m_decloop: lodsw ; bl:bh:cl:ch:dl = 5 byte font char
xchg bx,ax ; 8 x 5 bits per line
lodsw
xchg cx,ax
lodsb
xchg dx,ax
mov ah, bl ; ax = bytes 0 and 1
mov al, bh
shr ax, 3
call m_decstore ; store bytes 0 and 1
mov ah, bh ; ax = bytes 2 and 3
mov al, cl
shr ax, 1
call m_decstore ; store bytes 2 and 3
mov ah, cl ; ax = bytes 4 and 5
mov al, ch
shl ax, 1
call m_decstore ; store bytes 4 and 5
mov ah, ch ; ax = bytes 6 and 7
mov al, dl
shl ax, 3
call m_decstore ; store bytes 6 and 7
dec bp ; loop
jnz m_decloop
;---------------------------------------------------------------------
; main key loop handling starts here
;---------------------------------------------------------------------
mov ax, 10h ; set video mode 0Fh (640x350 mono)
int 10h
mov si, o null_str ; si = null string
mov al, -1 ; al = -1 for reverse video
mov dx, 42 ; clear line 42 to white
call putline
mov si, o filename-2 ; es:si = filename
mov dx, -1 ; title line
call putline ; put line to screen
mov bp, -1 ; impossible value
jmp k_home ; jump to 'home' key
;-----------------------------------------------------------
m_done: mov ax, 3 ; restore video mode
int 10h
jmp m_exit ; exit to DOS
;-----------------------------------------------------------
k_keyloop: xor ah, ah ; wait for a key
int 16h
cmp ah, 01h ; quit if ESC
je m_done
cmp ah, 48h ; key UP?
je k_up
cmp ah, 50h ; key DOWN?
je k_down
cmp ah, 49h ; key PGUP?
je k_pgup
cmp ah, 51h ; key PGDN?
je k_pgdn
cmp ah, 47h ; key HOME?
je k_home
cmp ah, 4Fh ; key END?
je k_end
jmp k_keyloop ; invalid key, loop
;-----------------------------------------------------------
k_up: test bp, bp ; already at top?
jz k_keyloop
call scrolldn ; scroll screen down
dec bp ; move current line up
imul ax, bp, 8 ; ax = first line of screen
add ax, first_line
mov es, ax ; es:si = line
xor si, si
mov dx, 2 ; screen line 2
xor al, al ; white on black
call putline ; put line to screen
jmp k_keyloop ; loop
;-----------------------------------------------------------
k_down: mov ax, num_lines ; ax = max line position
dec ax
dec ax
cmp bp, ax ; already at bottom?
jge k_keyloop
call scrollup ; scroll screen up
inc bp ; move current line down
imul ax, bp, 8 ; ax = first line of screen
add ax, first_line
add ax, 39*8 ; ax = last line of screen
mov es, ax ; es:si = line
xor si, si
mov dx, 41 ; screen line 41
xor al, al ; white on black
call putline ; put line to screen
jmp k_keyloop ; loop
;-----------------------------------------------------------
k_pgup: test bp, bp ; already at top?
jz k_keyjmp
sub bp, 40 ; move up 40 lines and redraw
jnc k_redraw
xor bp, bp
jmp k_redraw
;-----------------------------------------------------------
k_pgdn: mov ax, num_lines ; ax = max line position - 41
sub ax, 41
cmp bp, ax ; already at bottom?
jge k_keyjmp
add bp, 40 ; move down 40 lines and redraw
jmp k_redraw
;-----------------------------------------------------------
k_home: test bp, bp ; already at top?
jz k_keyjmp
xor bp, bp ; move to top and redraw
jmp k_redraw
;-----------------------------------------------------------
k_end: mov ax, num_lines ; ax = max line position - 40
sub ax, 40
cmp bp, ax ; already at bottom?
jge k_keyjmp
mov bp, ax ; move to end and redraw
jmp k_redraw
;-----------------------------------------------------------
k_redraw: imul di, bp, 8 ; di = first line of screen
add di, first_line
mov dx, 2 ; first line is line 2
xor si, si ; si = 0
xor al, al ; white on black
k_rloop: mov es, di ; es:si = line
call putline ; put line to screen
add di, 8 ; next line
inc dx
cmp dx, 42 ; done all 40 lines?
jb k_rloop ; loop if not
k_keyjmp: jmp k_keyloop ; jump to key loop
;---------------------------------------------------------------------
; getchar - read one character from the file, buffered
;---------------------------------------------------------------------
; in: assumes ds = cs
; out: al = character, carry = EOF
getchar: pusha ; save registers
mov si, buffer_pos ; ax = position in buffer
cmp si, buffer_end ; if not to end, then load char
jb g_load
cmp si, buf_size ; buffer not full = EOF
jb g_done ; carry flag set if we jump
mov ah, 3Fh ; try to read in next buffer
mov bx, handle
mov cx, buf_size
mov dx, o buffer
int 21h
jc g_done ; carry = EOF
mov buffer_end, ax ; set end position
xor si, si ; set buffer position
mov buffer_pos, si
g_load: mov al, buffer[si] ; load byte
inc buffer_pos ; increment buffer position
clc ; clear carry flag
g_done: mov bp, sp ; set al value on return
mov [bp+14], al
popa ; restore registers
ret
;---------------------------------------------------------------------
; putline - put a line of text on the screen
;---------------------------------------------------------------------
; in: es:si = string, dx = y-position, al = xor byte (0 or -1)
; y-position -1 = draw the title line
putline: pusha ; save all registers
push ds
push es
push es ; ds:si = string
pop ds
push 0A000h ; es = video memory
pop es
imul dx, 640 ; set up to clear the line
mov di, dx ; dx, di = offset
mov ah, al ; ax = xor-value
mov cx, 640/2 ; 8 lines of the screen
test dx, dx ; if dx was negative, then
jge p_clear
mov dx, 240 ; use title position & larger size
xor di, di ; for a 3-line border on each side
mov cx, 1120/2
p_clear: rep stosw ; clear the line
mov di, dx ; di = offset
mov bp, ax ; bp = xor value
xor bx, bx ; zero bx
p_yloop: push si ; save si, di
push di
xor dx, dx ; clear bit buffer
mov cl, 11 ; shift = 11 (16 - 5)
p_xloop: lodsb ; load byte
test al, al ; check for null
jz p_xdone
xor ah, ah ; bx = font byte pointer
shl ax, 3
add bx, ax
mov ch, cs:font[bx] ; ch = font byte
sub bx, ax ; fix bx
mov al, ch ; ax = font byte
xor ah, ah
shl ax, cl ; shift left
or dx, ax ; or into bit buffer
sub cl, 5 ; adjust shift value
jnc p_xloop ; if bit buffer full, then
mov al, dh ; shift 8 bits out of the
shl dx, 8 ; bit buffer into al
add cl, 8 ; adjust shift value
xor ax, bp ; xor with xor-value
stosb ; write to video memory
jmp p_xloop ; loop
p_xdone: mov al, dh ; flush bit buffer:
mov ah, dl ; ax = dx (bytes reversed)
xor ax, bp ; xor with xor-value
stosw ; write to video memory
pop di ; restore si, di
pop si
add di, 80 ; next scanline on screen
inc bx ; increment line counter
cmp bx, 8 ; done all 8 lines?
jb p_yloop ; loop if not
pop es ; restore registers
pop ds
popa
ret ; return
;---------------------------------------------------------------------
; scrolldn - scroll all but the top 2 & bottom 1 lines down by 1 line
;---------------------------------------------------------------------
scrolldn: pusha ; save all registers
push ds
push es
mov ax, 0A000h ; ds, es = video memory
mov ds, ax
mov es, ax
std ; moves are backwards
mov si, 2*640+24960-2 ; scroll the screen down
mov di, 3*640+24960-2
mov cx, 24960/2
rep movsw
cld ; fix direction flag
pop es ; restore registers
pop ds
popa
ret ; return
;---------------------------------------------------------------------
; scrollup - scroll all but the top 2 & bottom 1 lines up by 1 line
;---------------------------------------------------------------------
scrollup: pusha ; save all registers
push ds
push es
mov ax, 0A000h ; ds, es = video memory
mov ds, ax
mov es, ax
mov si, 3*640 ; scroll the screen up
mov di, 2*640
mov cx, 24960/2
rep movsw
pop es ; restore registers
pop ds
popa
ret ; return
;---------------------------------------------------------------------
.data?
stack_buf db 1024 dup(?) ; stack buffer
stack_top:
end start