RosettaCodeData/Task/Align-columns/8080-Assembly/align-columns.8080
2025-02-27 18:35:13 -05:00

212 lines
6.4 KiB
Text

putc equ 2
puts equ 9
fopen equ 15
fclose equ 16
fread equ 20
FCB1 equ 5Ch
FCB2 equ 6Ch
DTA equ 80h
COLSEP equ '$'
org 100h
;;; Check arguments
lxi d,argmsg
lda FCB1+1 ; Check file argument
cpi ' '
jz prmsg
lda FCB2+1 ; Check alignment argument
cpi 'L'
jz setal
cpi 'R'
jz setar
cpi 'C'
jnz prmsg
lxi h,center ; Set alignment function to run
jmp setfn
setal: lxi h,left
jmp setfn
setar: lxi h,right
setfn: shld alnfn+1
;;; Initialize column lengths to 0
xra a
lxi h,colw
inicol: mov m,a
inr l
jnz inicol
;;; Open file
lxi d,FCB1
mvi c,fopen
call 5
inr a
jz efile ; FF = error
;;; Process file
lxi h,maxw ; Find maximum widths
call rdlins
lxi h,alnlin ; Read lines and align columns
call rdlins
;;; Close file
lxi d,FCB1
mvi c,fclose
jmp 5
;;; Update maximum widths of columns, given line
maxw: lxi h,colw ; Column widths
lxi d,linbuf
mcol: mvi b,0FFh ; B = column width
mscan: inr b
ldax d ; Get current item
inx d ; Next item
call colend ; End of column?
jc mscan
push psw ; Keep column comparison
mov a,m ; Current width
cmp b ; Compare to new width
jnc mnxcol
mov m,b ; New one is bigger
mnxcol: inr l ; Next column
pop psw ; Restore column comparison
jz mcol ; Keep going if not end of line
ret
;;; Align and print columns of line
alnlin: lxi h,colw
lxi b,linbuf
alncol: lxi d,colbuf-1
alnscn: inx d ; Copy current column to buffer
ldax b
stax d
inx b
call colend
jc alnscn
push psw
push h
push b
alncal: xra a ; Zero-terminate the buffer
stax d
mov a,m ; Current max column length
sub e ; Minus length of this column
mov b,a ; Set B = current padding needed
alnfn: call 0 ; Call selected alignment
pop b
pop h
inr l
pop psw
jz alncol ; Next column, if any
lxi d,newlin ; End line
mvi c,puts
jmp 5
;;; Align column left and print
left: push b ; Save padding needed
lxi h,colbuf ; Print column
call print0
pop b ; Restore padding
inr b ; Plus one, for separator between columns
;;; Print B spaces as padding
pad: xra a
ora b
rz ; No padding
padl: push b
mvi e,' '
mvi c,putc
call 5
pop b
dcr b
jnz padl
ret
;;; Align column right and print
right: call pad ; Padding first
lxi h,colbuf
call print0 ; Then column
mvi b,1
jmp pad ; Separator space
;;; Align column in the center and print
center: mov a,b ; Split padding in half
rar
mov b,a
aci 0
mov c,a
push b ; Keep both parts
call pad ; Left padding
lxi h,colbuf ; Print column
call print0
pop b ; Restore padding
mov b,c ; Right padding
inr b ; Plus one for the separator
jmp pad
;;; Print 0-terminated string at HL
print0: mov a,m
ana a
rz
push h
mov e,m
mvi c,putc
call 5
pop h
inx h
jmp print0
;;; Does character in A end a column?
;;; C clear if so. Z clear if also end of line.
colend: cpi 32 ; End of line?
cmc
rnc
cpi COLSEP ; Separator?
rz
stc ; If neither, set carry and return
ret
;;; Process file in FCB1 line by line
;;; HL = line callback
rdlins: shld linecb+1 ; Set callback
xra a ; Start at beginning of file
sta FCB1+0Ch ; EX
sta FCB1+0Eh ; S2
sta FCB1+0Fh ; RC
sta FCB1+20h ; AL
lxi d,linbuf ; Start write pointer at line buffer
rdrec: push d ; Keep write pointer
lxi d,FCB1 ; Read next record
mvi c,fread
call 5
pop d ; Restore write pointer
dcr a ; 1 = EOF
rz
inr a
jnz efile ; Otherwise, <>0 = error
lxi h,DTA ; Reset read pointer to DTA
cpydat: mov a,m ; Copy byte to line buffer
stax d
inx d
cpi 26 ; EOF -> done
rz
cpi 10 ; (\r)\n -> EOL
jnz cnexb
push h ; Keep record pointer
linecb: call 0 ; Call callback routine
pop h ; Restore record pointer
lxi d,linbuf ; Reset line pointer
cnexb: inr l ; Next byte
jz rdrec ; Next record
jmp cpydat
efile: lxi d,filerr
prmsg: mvi c,puts
jmp 5
;;; Messages
argmsg: db 'ALIGN FILE.TXT L/R/C$'
filerr: db 'FILE ERROR$'
newlin: db 13,10,'$'
;;; Variables
colw equ ($/256+1)*256 ; Column widths (page-aligned)
colbuf equ colw+256 ; Column buffer
linbuf equ colbuf+256 ; Line buffer