;Zadanie c.2

;Text zadania:
;Vytvorte program, ktory zo vstupneho textoveho suboru nacita postup-
;nost celych cisiel so znamienkom v desiatkovej sustave (aspon 10),
;potom ich transformuje na cisla v dvojkovej ciselnej sustave v dopln-
;kovom kode a potom podla priania uzivatela
;a) vypocita sumu vsetkych cisiel a vypise ju
;b) usporiada cisla vzostupne a zapise usporiadanu postupnost cisiel
;   do noveho textoveho suboru
;c) vydeli dve vybrane cisla a vypise vysledok
;d) ukonci vykonavanie programu
;Na pracu so subormi mozete pouzit napr. sluzby 3dh, 3eh, 3fh, 40h.
;Vysledky operacii reba vypisovat v desiatkovej cisielnej sustave.
;Ak by pri vypocte sumy v pripade v desiatkovej ciselnej sustave.
;Ak by pri vypocte sumy a) doslo k preteceniu, oznamte prekrocenie ciselneho
;rozsahu
;Zdrojovy program musi byt podrobne okomentovany
;Termin odovzdania: na cviceni do 8.tyzdna semestra
;Hodnotenie: maximalne 10 bodov

;autor: Ludovit Fulop
;termin odovzdania: 12.11.1999
;2 roc., info b-9
;Skolsky rok: 1999/2000

zas segment stack 'stack'
	dw	100h	dup(?)	
zas ends

data segment
	vstup	db	'z2vstup.txt',0
	vystup	db	'z2vystup.txt',0
	znakov  db	0	; pocet nacitanych znakov
	buff	db	100h	dup(?)	; nacitane data zo suboru...max 256b
	pocet	dw	0			; pocet prevedenych cisel
	numbers dw	50h	dup(?)		; pole prevedenych cisel
	rad	dw	0		; desiatkovy rad, pouziva sa pri c->n
	pretecenie dw	0		; priznak pretecenia 
	tmp1	dw	0		; premenne v cykloch pre zoradnie
	tmp2	dw	0		; prvkov
	zapor	db	0	; pre delenie: 0bit=1 - podiel je zaporny
;-----------------
	inerr	db	10,13,'Chyba pri nacitavani dat zo vstupneho suboru',10,13,'$'
	menu	db	10,13,'1/Vypis suctu vsetkych prvkov',10,13
		db	'2/Usporiadanie prvkov',10,13
		db	'3/Delenie dvoch prvkov',10,13
		db	'4/Ukoncenie programu',10,13,'$'
	info0	db	'Nacitane prvky:',10,13,'$'
	info1	db	10,13,'Sucet prvkov je:',10,13,'$'
	info11	db	10,13,'Pri sucte nastalo pretecenie!',10,13,'$'
	info2	db	10,13,'Vzostupne usporiadanie prvkov:',10,13,'$'
	info21	db	10,13,'Pri zapise do suboru sa vyskytla chyba!',7,10,13,'$'
	info31	db	10,13,'Podiel zvolenych prvkov:',10,13,'$'
	info32	db	10,13,'Zvysok po deleni:',10,13,'$'
	info33	db	10,13,'Nulou delit nemozno!',7,10,13,'$'
	info34 	db	10,13,'Zvol si prvky:',10,13,'$'	
	info35	db	10,13,'Dany prvok neexistuje',10,13,'$'
	fh	dw	0			; file handle	
data ends

code segment
	assume DS:data,CS:code,SS:zas
pisret	proc				; procedura pre vypis retazca
	push ax
	mov ah,9			; ocakava pripravenost dat na DS:DX
	int 21h
	pop ax
	ret
pisret	endp

pisznak	proc				; procedura pre vypis znaku
	push ax
	mov ah,2			; ocakava pripravenost dat v DL
	int 21h
	pop ax
	ret
pisznak endp

citajznak proc				; procedura pre nacitanie 1 znaku
	mov ah,8			; nacitany znak vracia v AL
	int 21h
	ret
citajznak endp

cakaj proc				; caka na stlacenie klavesy
	push ax
	call citajznak
	pop ax
	ret
cakaj endp

koniec proc				; procedura pre ukoncenie programu
	mov ax,4c00h
	int 21h
	ret
koniec endp

;----------------------------------------------------------------------------

CitajData proc				; procedura pre nacitanie cisiel
	mov ax,seg vstup		
	mov ds,ax
	mov dx,offset vstup
	mov ah,3dh			; otvorenie vstupneho suboru
	mov al,0
	int 21h
	jnc exists			; prebehlo otvorenie uspesne?
	mov ax,seg inerr		; ak nie, vypis info a skonci
	mov ds,ax
	mov dx,offset inerr
	call pisret
	call koniec
exists:	mov fh,ax			; uloz do fh  file handler
	mov ax,seg buff
	mov ds,ax
	mov dx,offset buff
	mov ah,3fh			; dos fn 3h - citaj zo suboru
	mov bx,fh
	mov cx,100h
	int 21h				; pokus o nacitanie 256 znakov
	jnc close			; prebehlo citanie uspesne?
	mov ax,seg inerr		; ak nie, vypis info a skonci
	mov ds,ax
	mov dx,offset inerr
	call pisret
	call koniec
close:	mov znakov, al			; pocet nacitanych znakov	
	mov ah,3eh			; zatvorenie vstupneho suboru
	mov bx,fh
	int 21h	
	cmp znakov,0			; mal subor nulovu dlzku?
	jne kon1			; ak ano, vypis info a skonci
	mov ax,seg inerr
	mov ds,ax
	mov dx,offset inerr
	call pisret
	call koniec
kon1:	ret
CitajData endp

chars2num proc				; procedura pre konverziu retzca na
	push ax				; cislo
	push bx
	push cx
	push dx
	mov cx,0			; pocet prevedenych znakov
	xor dx,dx
	mov rad,1			; propocitavany desiatkovy rad
	dec bx
c2nlo1:	dec bx				; skok na predchadzajuci znak (rad)
	mov ax,offset buff		; si na zaziatku retazca?
	cmp ax,bx
	jg c2n1				; ak ano, zapis cislo do pola
	xor ax,ax
	mov al,[bx]			; naciatj znak z buffera
	cmp al,'0'			; je to este cislo?
	jl c2n1
	cmp al,'9'
	jg c2n1				; ak nie, zapis do pola
	sub al,'0'			; inak vyrataj hodnotu z ascii hodnoty
	cmp al,0			; je to 0?
	je c2n3				; ak ano, preskoc pripocitavanie radu
c2nlo2:	add dx,rad			; al-krat pripocitaj aktualny des. rad
	dec al
	jnz c2nlo2
c2n3:	mov ax,rad			; zvys rad 10x
	push bx
	mov bl,10
	mul bl
	pop bx
	cmp rad,1000
	jne c2n4
	mov ax,10000
c2n4:	mov rad,ax
	inc cx				; zvys pocitadlo prevednych cislic
	jmp c2nlo1			; dekoduj dalsi rad (cislo)
c2n1:	jcxz c2nEnd			; ak nebola prev. ziadna cislica, skonci
	cmp al,'-'			; je pred cislo znak - ?
	jne c2n2			; ak nie, preskoc...
	neg dx				; zmenu cisla na zaporne
c2n2:	mov bx,offset numbers		; zapis cisla do pola cisel
	add bx,pocet			; vyrataj adresu pridavaneho prvku
	add bx,pocet
	inc pocet			; zvys pocet cisiel
	mov [bx],dx			; uloz prevedene cislo do pola
c2nEnd:	pop dx
	pop cx
	pop bx
	pop ax
	ret
chars2num endp

KonvertujData proc		; procedura pre konverziu buffera na cisla
	mov bx,offset buff	; adresa bufferu - data nacitane zo suboru
	xor cx,cx
	mov cl,znakov		; pocet nacitanych znakov
loop1:	mov al,[bx]		; natiahni znak z bufferu
	inc bx			; zvys adresu dalsieho znaku
	cmp al,'-'		; je to minus?
	je next1		; ak ano, testuj dalsi znak, inak...
kd2:	cmp al,'0'		; je to cislo?
	jl znak
	cmp al,'9'
	jg znak			; ak nie, dosli sme na koniec cisla, dekodujeme
	jmp next1		; ak ano, testuj dalsi znak
znak:	call chars2num		; prevedenie znakov na cislo a zapis do pola
next1:	loop loop1		; opakuj az do konca buffera
	inc bx
	call chars2num		; posledne volanie prevodu
	ret
KonvertujData endp

pisCislo proc				; procedura pre vypis cisla
	push ax				; ocakava cislo v AX
	push bx
	push cx
	push dx
	mov bx,offset buff	; do buff sa bude zapisovat prevedene cislo
	mov znakov,0		; pocet prevedenych cislic (dlzka cisla)
	cmp ax,0		; je zaporne?
	jge pc1			; ak nie, chod ho previest
	neg ax			; inak ho preved na kladne,
	mov dl,'-'		; vypis znak '-' na obrazovku
	call pisznak
	mov [bx],dl		; a zapis '-' aj do buff
	inc bx
	inc znakov		; zvys pocet znakov prevedeneho cisla
pc1:	mov dl,0
	cmp ax,10000		; 10 tisicovy rad
	jl tisic		; ak je mensie ako 10000, skoc na tisicovy rad
l1:	sub ax,10000		; inak odcituj 10000, pokym nebude ax<0
	inc dl
	cmp ax,0
	jg l1
	add ax,10000		; zrus posledne odictanie
	dec dl			; v dl je koeficient 10000-oveho radu
	add dl,'0'		; preved cislo v dl na jeho ascii hodnotu
	call pisznak		; vypis ho na obrazovku
	mov [bx],dl		; a zaroven zapis do buffera
	inc bx
	inc znakov
tisic:	mov dl,0		; tisicovy rad
	cmp ax,1000
	jl sto
l2:	sub ax,1000
	inc dl
	cmp ax,0
	jg l2
	add ax,1000
	dec dl
	add dl,'0'
	call pisznak
	mov [bx],dl
	inc bx
	inc znakov
sto:	mov dl,0		; stovkovy rad
	cmp ax,100
	jl desat
l3:	sub ax,100
	inc dl
	cmp ax,0
	jg l3
	add ax,100
	dec dl
	add dl,'0'
	call pisznak
	mov [bx],dl
	inc bx
	inc znakov
desat:	mov dl,0		; desiatkovy rad
	cmp ax,10
	jl jedna
l4:	sub ax,10
	inc dl
	cmp ax,0
	jg l4
	add ax,10
	dec dl
	add dl,'0'
	call pisznak
	mov [bx],dl
	inc bx
	inc znakov
jedna:	mov dl,al		; jednotkovy rad
	add dl,'0'
	call pisznak
	mov [bx],dl
	inc bx
	inc znakov
	mov dl,10		; odriadkuj
	mov [bx],dl
	inc bx
	inc znakov
	mov dl,13
	mov [bx],dl
	inc znakov
	pop dx
	pop cx
	pop bx
	pop ax
	ret
pisCislo endp

pisNumbers proc				; procedura pre vypis vsetkych cisiel
	push dx				; na obrazovku
	push bx
	push ax
	mov bx,offset numbers		; bx <- adresa pola cisiel
	mov cx,pocet			; cx <- pocet cisiel
pnlo1:	mov ax,[bx]			; natiahni cislo z pola
	add bx,2			; zvys adresu dalsieho cisla
	call piscislo			; vypis cislo
	mov dl,' '			
	call pisznak
	loop pnlo1			; skoc na dalsie cislo
	mov dl,10			; odriadkuj
	call pisznak
	mov dl,13
	call pisznak
	pop ax
	pop bx
	pop dx
	ret
pisNumbers endp

;----------------------------------------------------------------------------

sucet proc				; procedura na vypocet suctu cisel
	mov pretecenie,0		; priznak pretecenia, incializacia
	xor ax,ax			; vysledny sucet
	mov cx,pocet			; pocet cisiel
	mov bx,offset numbers		; adresa pola cisiel
sloop1:	add ax,[bx]			; pripocitaj cislo k ax (k suctu)
	jnc s1				; nastalo pretecenie?
	mov pretecenie,1		; ak ano, nastav priznak
s1:	add bx,2			
	loop sloop1			; skoc na dalsie cislo
	mov dx,seg info1		
	mov ds,dx
	mov dx,offset info1
	call pisret
	call piscislo			; vypis suctu
	mov dl,10
	call pisznak
	mov dl,13
	call pisznak
	cmp pretecenie,0		; test priznaku pretecenia
	je skon				; ak pocas vypoctu nastalo,
	mov dx,seg info11		; vypis info
	mov ds,dx
	mov dx,offset info11
	call pisret
skon:	call cakaj			; cakaj na klavesu
	ret
sucet endp

pisVystup proc				; procedura pre vypis prvkov
        push dx				; naobrazovku a do vyst.suboru
        push bx
        push ax
	mov ah,3ch			; vytvor subor
	xor cx,cx
	mov dx,seg vystup
	mov ds,dx
	mov dx,offset vystup
	int 21h
	jnc pv1				; ak vytvorenie nebolo uspesne, vypis
	mov ax,0			; info
	mov dx,seg info21
	mov ds,dx
	mov dx,offset info21
	call pisret
pv1:    mov fh,ax			; do fh uloz file handler
	mov bx,offset numbers
        mov cx,pocet
pvlo1:  mov ax,[bx]			; natiahni cisloz tabulky
        add bx,2
        call piscislo			; vypis ho na obrazovku
	mov ah,40h
	push bx
	mov bx,fh
	push cx
	xor cx,cx
	mov cl,znakov
	mov dx,seg buff
	mov ds,dx			; a zaroven zapis aj do suboru
	mov dx,offset buff		; ak sa nepodarilo, nevadi, uz som o
	int 21h				; tom vypisal info
	pop cx
	pop bx
        mov dl,' '
        call pisznak
        loop pvlo1			; opakuj pre vsetky cisla
        mov dl,10
        call pisznak
        mov dl,13
        call pisznak
	mov ah,3eh			; zatvor vystupny subor
	mov bx,fh
	int 21h
        pop ax
        pop bx
        pop dx
	ret
pisVystup endp

zorad proc				; procedura pre zoradenie prvkov pola
	mov dx,seg info2
	mov ds,dx
	mov dx,offset info2
	call pisret
	mov cx,pocet
	mov bx,offset numbers
	mov tmp1,0			; pouzity je bubble sort:
	mov tmp2,0			; for i:=1 to pocet do
z1:	push bx				;  for j:=i to pocet do
	add bx,tmp1			;   if pole[i] > pole[j] then
	mov ax,[bx]			;    begin
	pop bx				;     	tmp:=pole[i];
	push bx				; 	pole[i]:=pole[j];
	add bx,tmp2			;	pole[j]:=tmp;
	mov dx,[bx]			;    end;
	pop bx
	add tmp2,2
	cmp ax,dx
	jle z2
	push bx
	add bx,tmp1
	mov [bx],dx
	pop bx
	push bx
	add bx,tmp2
	sub bx,2
	mov [bx],ax
	pop bx
z2:	mov ax,pocet
	add ax,pocet
	cmp tmp2,ax
	jl z1
	add tmp1,2
	mov ax,tmp1
	mov tmp2,ax
	loop z1
	call pisVystup			; vypis zorad. pola na obr a do suboru
	call cakaj
	ret
zorad endp

delenie proc					; procedura pre delenie 2 cisel
	mov bx,offset numbers
	mov cx,pocet
	mov dl,'A'
dloop1:	mov ax,[bx]			; priradeni pismen cislam
	add bx,2
	call pisznak
	mov dh,dl
	mov dl,'='
	call pisznak
	call piscislo
	mov dl,' '	
	call pisznak
	mov dl,dh
	inc dl
	loop dloop1
	mov dl,10
	call pisznak
	mov dl,13
	call pisznak
	mov dx,seg info34			; volba prvkov
	mov ds,dx
	mov dx,offset info34
	call pisret
	mov cx,2
dloop2:	call citajznak
	mov ah,0
	cmp al,90				; bolo stlacene povolene
	jng d2					; pismeno?
	sub al,'a'				; ak nie, skonci
	jmp d3					; inak ho uloz, a nacitaj
d2:	sub al,'A'				; dalsie
d3:	cmp al,0
	jl derr1
	cmp ax,pocet
	jge derr1			
	mov bx,offset numbers
	add bx,ax				; vyratanie adresy zvoleneneho
	add bx,ax				; cisla a jeho ulozenie
	mov ax,[bx]
	call piscislo
	cmp cx,2
	jne d1
	mov dl,'/'
	call pisznak
	mov dx,ax
d1:	loop dloop2
	jmp d10
derr2:  mov dx,seg info33               ; nulou delit nemozno
        mov ds,dx
        mov dx,offset info33
        call pisret
        jmp dkon
derr1:  mov dx,seg info35               ; zvolene cislo neexistuje /zla klavesa
        mov ds,dx
        mov dx,offset info35
        call pisret
        jmp dkon
d10:	xchg ax,dx
	cmp dx,0			; je delitel 0?
	je derr2			; ak ano,vypis ze nulou delit nemozno
	mov bx,dx
	xor dx,dx
	mov zapor,0			; zistovanie ci je niektore
	cmp ax,0			; z cisel zaporne, prip ci su zaporne
	jnl d4				; obe, a nastavenie priznaku
	mov zapor,1			; podla neho sa bude podiel a zvysok
	neg ax				; vypisovat ako kladne alebo ako
d4:	cmp bx,0			; zaporne cislo
	jnl d5
	cmp zapor,1
	jne d9
	mov zapor,0
	jmp d8
d9:	mov zapor,1
d8:	neg bx
d5:	div bx				; delenie ax/bx
	push dx				; dx-zvysok po deleni
	push ax				; ax-celocielny podiel
	mov dx,seg info31
	mov ds,dx
	mov dx,offset info31
	call pisret
	pop ax
	test zapor,1
	jz d6
	neg ax
d6:	call piscislo			; vypis podielu a zvysku
	mov dx, seg info32
	mov ds,dx
	mov dx,offset info32
	call pisret
	pop ax
	test zapor,1
	jz d7
	neg ax
d7:	call piscislo
dkon:	call cakaj	
	ret
delenie endp

;----------------------------------------------------------------------------

do_menu proc				; hlavna procedura - vypis menu,
NeverEndingLoop:			; cakanie na klavesu a
	mov ax,3			; vyvolanie prislusnej akcie
	int 10h
	mov dx,seg info0
	mov ds,dx
	mov dx,offset info0
	call pisret
	call pisNumbers			; vypis cisel zo vstupneho suboru
	mov ax,seg menu
	mov ds,ax
	mov dx, offset menu
	call pisret			; vypis menu
	call citajznak			; cakaj na volbu
	cmp al,49			; je to 1? ak nie, testuj dalej, inac
	jne cmp2			; vyvolaj akciu
	call sucet
	jmp NeverEndingLoop
cmp2:	cmp al,50			; je to 2?
	jne cmp3
	call zorad
	jmp NeverEndingLoop
cmp3:	cmp al,51			; je to 3?
	jne cmp4
	call delenie
	jmp NeverEndingLoop
cmp4:	cmp al,52			; je to 4?
	jne NeverEndingLoop		; ak nie, cakaj na volbu, inak skonci
	ret
do_menu endp	

start: 
	call CitajData			; nacitanie dat zo vstupneho suboru
	call KonvertujData		; konverzia retazca na pole znakov
	call do_menu			; hlavna procedura - menu
	call koniec			; ukoncenie programu
code ends
end start