; zadanie c.2
;---------------------------------------------------------------------------------------
; Vytvorte  program,  ktorý  načíta  z  textového súboru postupnost celých
; císel (viac ako 5) so znamienkom  v desiatkovej císelnej sústave.
; Precítané císla transformujte na císla v dvojkovej císelnej sústave v doplnkovom kóde,
; potom ich usporiadajte a VYPOCITA SUCET CISEL
;---------------------------------------------------------------------------------------
; Jozko Mrkvicka
; termin odovzdania: 2.12.2003
; 3.roc., 2003/2004


;-------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------

zas	segment	stack
	dw	256 dup(?)			; definovanie zasobnika
zas	ends

;-------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------

data	segment					; datovy segment

cisla	dw	2500 dup(?)		; buffer pre ciselne hodnoty (max. pocet cisel na vstupe...)
buffer	db	5000 dup(?)		; buffer pre obsah suboru
vstup	db	'zadanie2.in',0		; meno vstupneho suboru
vystup	db	'zadanie2.out',0	; meno vystupneho suboru
znakov  dw	0			; pocet skutocne nacitanych znakov
cisel	dw	0			; pocet nacitanych cisel

sucet	dw	0			; sucet cisel

rad	dw	0			; pomocne premenne pre proceduru String2Number
nemoze	db	0

tried_1	dw	0			; premenne na cyklus v triedeni
tried_2	dw	0

temp	dw	0			; premenne pre konvertovanie Number2String
bol	db	0

openERR	db	10,13,'Chyba pri citani vstupneho suboru',10,13,'$'
closERR	db	10,13,'Chyba pri ukladani do suboru',7,10,13,'$'
handle	dw	0			; file handler

pretec	db	10,13,'Sucet nie je spravny (pretecenie)',10,13,'$'
malo	db	10,13,'Malo vstupnych cisel (>5)',10,13,'$'


data	ends

;-------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------

code	segment				; kodovy segment
	assume DS:data,CS:code,SS:zas

;-------------------------------------------------------------------------------------

vypis	proc				; procedura na vypis retazca na obrazovku
	push ax				; data musia byt pripravene (DS:DX)
	mov ah,9			
	int 21h				; volanie DOSovskej sluzby pre vypis retazca
	pop ax
	ret
vypis	endp

;-------------------------------------------------------------------------------------

koniec	proc				; PROCEDURA, ktora ukonci program
	mov	ax,4c00h
	int	21h
	ret
koniec	endp

;-------------------------------------------------------------------------------------

load	proc				; procedura, ktora nacita vstupny subor du bufferu
	mov	ax,seg vstup		
	mov	ds,ax
	mov	dx,offset vstup
	mov	ax,3d00h		; otvorenie vstupneho suboru
	int	21h
	jnc	load01			; test, ci bol subor naozaj otvoreny

	mov	ax,seg openERR		; ako bolo otvorenie neuspesne, vypis chybove hlasenie
	mov	ds,ax
	mov	dx,offset openERR
	call	vypis
	call	koniec

load01:	mov	handle,ax		; File Handler

	mov	ax,seg buffer		; nacitanie obsahu suboru
	mov	ds,ax
	mov	dx,offset buffer
	mov	ah,3fh			; DOSovska funkcia na citanie zo suboru (3Fh)
	mov	bx,handle
	mov	cx,4985h		; nacitanie 64k znakov ; ak ich je menej, nacita menej...
	int	21h
	jnc	load02			; test, ci boli data nacitane

	mov	ax,seg openERR		; ak nie, vypis chybova hlasenie
	mov	ds,ax
	mov	dx,offset openERR
	call	vypis
	call	koniec

load02:	mov	znakov, ax		; subor bol nacitany uspesne -> ulozime pocet naozaj
					; nacitanych znakov
	mov	ah,3eh			; zavretie vstupneho suboru
	mov	bx,handle
	int	21h	

	cmp	znakov,0		; ak mal subor nulovu dlzku, pokladame to za chybu
	jne	load03			; ak nie, proceduru mozeme ukoncit

	mov	ax,seg openERR		; ak ano, vips chybova hlasenie
	mov	ds,ax
	mov	dx,offset openERR
	call	vypis
	call	koniec

load03:	ret

load	endp

;-------------------------------------------------------------------------------------

save	proc				; vypis vysledkov na obrazovku a do suboru

	mov	dx,seg buffer		; vypis vysledku na obrazovku
	mov	ds,dx
	mov	dx,offset buffer
	call	vypis

	mov	ah,3ch			; DOSovska funkcia na vytvorenie suboru
	mov	cx,20h
	mov	dx,seg vystup		; meno vystupneho suboru
	mov	ds,dx
	mov	dx,offset vystup
	int	21h

	jnc	save01			; ak vytvorenie suboru neprebehlo uspesne, vypiseme chybu

	mov	ax,0
	mov	dx,seg closERR
	mov	ds,dx
	mov	dx,offset closERR
	call	vypis
	call	koniec

save01:
	mov	handle,ax		; File Handler

	mov	cx, znakov		; nastavenie poctu vystupnych znakov
	mov	ah,40h			; DOSovska funkcia na ukladanie do suboru
	mov	bx,handle
	mov	dx,seg buffer		; ukladat data z bufferu
	mov	ds,dx
	mov	dx,offset buffer
	int	21h

	mov	ah,3eh			; zatvorenie vystupneho suboru
	mov	bx,handle
	int	21h

	ret
save	endp

;-------------------------------------------------------------------------------------

str2num	proc				; konverziu retzca na cislo



	mov	bx, offset buffer
	add	bx, znakov
s2n_bgn:
	mov	nemoze, 0		; pomocna premenna pre zistenie pretecenia
	xor	dx, dx			; vysledne cislo
	xor	cx, cx			; pocet prevedenych cislic
	mov	rad, 1			; desiatkovy rad, s ktorym prave robime

s2n_nxt:dec	bx			; pohyb v bufferi na vyssi rad

	cmp	bx, offset buffer	; Ak som na zaciatku retazca (prehladavam ho odzadu), tak ak boli
	jl	s2n_t1			; prevedene nejake cislice, zapisem ich do pola cisel a ak nie, tak
	jmp	s2n_d1			; mozem proceduru ukoncit
s2n_t1:	jcxz	s2n_end
	jmp	s2n_pls

s2n_d1:	xor	ax, ax
	mov	al, [bx]		; naciatj znak z buffera
	cmp	al, '0'			; je to cislica?
	jl	s2n_wrt			; ak ano, vyhodnocuje sa dalej
	cmp	al, '9'			; ak nie, zapis do pola
	jg	s2n_wrt

	cmp	nemoze, 0
	jz	s2n_s2			; ak by bolo prevadzane cislo privelke, vynecham ho

s2n_skp:dec	bx			; SKIP cislo
	cmp	bx, offset buffer
	jl	s2n_end			; ak som vycerpal buffer, odchadzam
	mov	al, [bx]
	cmp	al, '0'			; ak som narazil na necislicu (koniec cisla, ktore
	jl	s2n_bgn			;  preskakujem), mozem konvertovat dalej
	cmp	al, '9'
	jg	s2n_bgn
	jmp	s2n_skp	

s2n_s2:	sub	al, '0'			; upravit char cislicu na cislo

	push	dx
	mul	rad			; pridaj do DX hodnotu cislice (podla aktualneho radu)
	cmp	dx, 0
	pop	dx
	jnz	s2n_skp			; ak je cislo privelke, preskocim ho
	add	dx, ax			; pricitanie cislice k cislu
	js	s2n_skp			; ak je cislo privelke, preskocim ho

	push	bx			; zvys rad 
	push	dx
	mov	ax, rad
	mov	bx, 10
	mul	bx
	cmp	dx, 0			; ak je rad uz 100 000, tak nasledujuci znak
	jz	s2n_s1			; nemoze byt cislo
	mov	nemoze, 1
s2n_s1:	mov	rad, ax			; inac ulozim hodnotu zvyseneho radu do "rad"
	pop	dx
	pop	bx

	inc	cx			; zvys pocitadlo prevednych cislic

	jmp	s2n_nxt			; chod dekodovat dalsi rad (cislicu)

s2n_wrt:jcxz	s2n_bgn			; ak nebola prev. ziadna cislica, skusam prevadzat dalsie cislo

	cmp	al,'-'			; Ak je cislo zaporne, upravim na doplnkovy kod, inac necham tak
	jne	s2n_pls
	neg	dx

s2n_pls:push	bx
	mov	bx,offset cisla		; zapis cisla do pola cisel na spravnu poziciu (pocet*2)
	add	bx,cisel
	add	bx,cisel
	mov	[bx],dx
	pop	bx

	add	sucet, dx		; pocita sucet vsetkych cisel

	inc	cisel			; zvys pocet cisiel

	jmp	s2n_bgn			; mozem prevadzat dalsie cislo z buffera

s2n_end:ret

str2num	endp

;-------------------------------------------------------------------------------------

tried	proc				; Zoradenie prvkov pola (bubble sort) [vzostupne]

	mov	cx, cisel		; for(i=1;i<pocet;i++){
	jcxz	tr_end
	add	cx, cisel
	sub	cx, 2
	mov	si, offset cisla

tri_c2:	mov	bx, si			;   for(j=i;j<=pocet;j++){
	add	bx, 2

tri_c1:	mov	ax, [si]
	mov	dx, [bx]
	cmp	ax, dx			;     if(cislo[i]<cislo[j])
	jle	tri_no			;       cislo[i]<=>cislo[j]
	mov	[bx], ax
	mov	[si], dx

tri_no:	add	bx, 2
	cmp	cx, bx
	jge	tri_c1			; navrat vnutorneho cyklu

	add	si, 2
	cmp	cx, si
	jg	tri_c2			; navrat vonkajsieho cyklu

tr_end: ret
tried	endp

;-------------------------------------------------------------------------------------

N2S_cis proc				; Podprogramik pre nasledujucu proceduru
	cmp	bol, 0			; ak uz bolo nejake cislo s predosleho radu zobrazene
	jne	n2s_c_1			; , musi sa tento rad zobrazit, aj keby bol nulovy...
	cmp	ax, temp	
	jl	n2s_c_e			; ak je tento rad nulovy, nevypisujeme ho
	mov	bol, 1
n2s_c_1:xor	dx, dx
	div	temp
	add	al, '0'
	mov	[bx], al
	inc	bx
	inc	znakov
	mov	ax, dx
n2s_c_e:ret
N2S_cis	endp

;------------

N2S	proc				; Pripise cislo, ktore je v AX do bufferu ako retazec + "enter"
	push	bx

	mov	bx, offset buffer	; priprava na ukladanie cisla v retazcovej podobe
	add	bx, znakov

	cmp	ax, 0			; ak to nie je zaporne cislo, skocim na n2s_men
	jge	n2s_men

	mov	dl, '-'
	mov	[bx], dl		; ak to je zaporne cislo, ulozim '-'
	inc	bx
	inc	znakov
	neg	ax

n2s_men:mov	bol, 0

n2s_10k:mov	temp, 10000		; prevod radu "10 000"
	call	N2S_cis

n2s_1k:	mov	temp, 1000		; prevod radu "1 000"
	call	N2S_cis
	
n2s_100:mov	temp, 100		; prevod radu "100"
	call	N2S_cis
	
n2s_10:	mov	temp, 10		; prevod radu "10"
	call	N2S_cis

n2s_1:	add	al, '0'			; prevod radu "1"
	mov	[bx], al
	inc	bx
	inc	znakov

	mov	al, 10
	mov	[bx], al		; pridanie "enteru"
	inc	bx
	mov	al, 13
	mov	[bx], al
	inc	bx
	add	znakov, 2

	pop	bx

	ret
N2S	endp

;------------

Num2Str	proc				; Konvertovat pole cisel naspat na retazcovy vystup...
	mov	znakov, 0		; velkost vystupneho retazca
	mov	cx, cisel		; priprava cyklu (pocet cisel)
	jcxz	n2s_suc			; ak na vstupe neboli cisla, oznamime len ich sucet (=0)
	mov	bx, offset cisla
	xor	dx, dx

n2s_nxt:mov	ax, [bx]		; nacitat cislo a posunut ukazovatel na dalsie
	add	bx, 2

	call	N2S			; cislo z AX do textovej podoby

	loop	n2s_nxt			; cyklus (opakuj tolkokrat, kolko je cisel)

n2s_suc:mov	bx, offset buffer
	add	bx, znakov

	mov	byte ptr[bx], 's'	; ulozenie textu "sucet: " do buffra
	mov	byte ptr[bx+1], 'u'	
	mov	byte ptr[bx+2], 'c'	
	mov	byte ptr[bx+3], 'e'	
	mov	byte ptr[bx+4], 't'	
	mov	byte ptr[bx+5], ':'	
	mov	byte ptr[bx+6], ' '	
	add	bx, 7
	add	znakov, 7

	mov	ax, sucet		; ulozenie suctu v textovej podobe do buffra
	call	N2S

	mov	bx, offset buffer
	add	bx, znakov
	mov	byte ptr[bx], '$'	; kvoli vypisu na obrazovku

	ret
Num2Str	endp


;-------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------
; HLAVNY PROGRAM


start: 	call	load		; nacitanie cisel zo vstupneho suboru

	call	Str2Num		; prevod nacitanych dat do cisel a vypocet suctu tychto cisel

	cmp	cisel, 6	; Ak bolo na vstupe menej ako 6 (platnych) cisel - podmienka zadania
	jb	dalej
	mov	ax,seg malo
	mov	ds,ax
	mov	dx,offset malo
	call	vypis
	call	koniec

dalej:	call	tried		; potriedit
	call	Num2Str		; prevod cisel na ich textovu formu
	call	save		; ulozenie ciesel do vystupneho suboru a na obrazovku
	call	koniec		; skoncit program

;-------------------------------------------------------------------------------------

code	ends
	end	start

;-------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------

; Program je plne funkcny (vykonava vsetky pozadovane operacie)
; bol programovany a testovany na pocitaci AMD Duron pod WindowsXP
; Nakolko vyuziva iba zakladnu sadu instrukcii, nema ziadne zvlastne naroky na procesor
;  a malo by byt mozne ho spustit na ktoromkolvek pocitaci radu x86

; Vstupne udaje (retazec) je obmedzeny na 5000 znakov
; Cisla na vstupe, ktore su (mensie)vacsie ako (-)32767 su ignorovane

; Pouzita metoda triedenie je bublinkova
