;Zadanie c.1
;	Napíšte program, ktorý najskor načíta z klávesnice retazec dlzky max.100 znakov a z 
;	daneho menu vykona tu cinnost, ktora je v ponuke. 
;	Po vykonaní a) alebo b) alebo d) program znovu vypise dane menu. 
;		a)vykonanie jednej ulohy
;		b)nacitanie noveho retazca
;		c)ukoncenie programu
;		d)vypisanie usporiadaneho retazca
;	Ponuka uloh:
;		10- nacita znak a zisti pocet jeho vyskytov v retazci
;Autor:  Tomáš Polák
;Termin odovzdania: 13.3.2006
;Rocnik 2, šk.rok 2005/2006


ZAS     SEGMENT STACK           	; direktiva pre assembler - zaciatok
                                	;                 zasobnikoveho segmentu
        DW      64 DUP(?)       	; definicia 64-och slov
ZAS     ENDS                    	; koniec zasobnikoveho segmentu
;----------------------------------------------------------------------------
DATA    SEGMENT                 	; zaciatok datoveho segmentu

NEWLINE DB	10,13,'$'		; definovany novy riadok
	
REQ1    DB	10,13,'Zadaj znak:$'	; definovanie vyzvy uzivatelovi
REQ2	DB	10,13,'Zadaj retazec:$'	; definovanie vyzvy uzivatelovi
MESSA1  DB	10,13,'Pocet vyskytov znaku v retazci:$'	; hlaska
MESSA2  DB	10,13,'Usporiadavam...$'			; hlaska
AUTHORITY DB	10,13,'@ Tomas Polak, PSS14, rocnik2, 20.3.2006, STU FIIT$' ; hlaska

MENU    DB      'MENU:'         	 ; definicia vypis menu
	DB	0AH, 0DH,'a) vykonanie ulohy - pocet vyskytov zadaneho znaku'
	DB	0AH, 0DH,'b) nacitanie noveho retazca'
 	DB	0AH, 0DH,'c) ukoncenie programu'
        DB	0AH, 0DH,'d) vypisanie usporiadaneho retazca'
	DB	0AH, 0DH,'e) vypisanie zadaneho retazca'
	DB	0AH, 0DH,'$'

VSTUP	DB	101
POCET	DB	0			; ur4enie aktualneho poctu znakov - doplni sluzba
STRING	DB	101 DUP (?)		; samotny retazec vyplnenie nasledujucich 101 pamatovych miest 
DATA    ENDS                    	; koniec datoveho segmentu


pam	MACRO t 			; definovanie makra na vypis textu
	MOV AH, 9			; presun 9 do registra AH, 9-systemova sluzba na vypis retazca
	mov DX, OFFSET t		; presun du reg. DX offsetovu cast t
	INT 21H				; prerusenie sluzba 21, vypis retazca
	endm				; koniec makra




;----------------------------------------------------------------------------
CODE    SEGMENT                 	; zaciatok kodoveho segmentu
        ASSUME  CS:CODE, DS:DATA, SS:ZAS        ;direktiva oznamuje
                                	;        assembleru pouzite segmenty
READSTR: MOV AX, SEG DATA        	; do AX vloz adresu segmentu DATA
         MOV DS, AX              	; segmentovu adresu presun do DS 
	 pam NEWLINE			; odriadkuj
	 pam REQ2			; vypis
	 	
	 MOV DX, OFFSET vstup		; nastav sa na zaciatok retazca
	 MOV AH, 0AH			; ziadost o vstup retazca  (volanie sluzby)
	 INT 21H

	 
	 JMP PONUKA

NORMVYP: pam NEWLINE			; odriadkuj

	 MOV AX, SEG DATA		; do registra AX vloz segmentovu cast adresy datoveho segmentu
	 MOV DS, AX			; segmentovu adresu presun do DS
	 MOV DX, [OFFSET POCET]		; register DX bude ukazovat na pocet nacitanych znakov (kvoli cyklu)			
	 MOV DX, OFFSET STRING		; nastavenie registra DX na offset retazca STRING
	 MOV SI, DX			; nastavenie registra SI
	 MOV CL, POCET			; vloz pocet znakov v retazci do registra CL

LUUP:	 MOV DL, [SI]			; presun do registra DL znak, na ktory ukazuje register SI
	 INC SI				; posun v retazci

	 MOV AH, 02H			; do registra AH vloz cislo sluzby 2
	 INT 21H			; samotny vypis (volanie sluzby) znaku z registra DL
	 LOOP	 LUUP			; opakuj cyklus kym je CX rozne od 0

	 JMP PONUKA			; navrat do menu

PONUKA: pam NEWLINE	   	; volanie makra na vypis retazca NEWLINE = odriadkuj
	pam AUTHORITY		; vypis
	pam NEWLINE	   	; volanie makra na vypis retazca NEWLINE = odriadkuj	
	pam NEWLINE	   	; volanie makra na vypis retazca NEWLINE = odriadkuj
	pam MENU	   	; volanie makra na vypis retazca MENU
	

	MOV AH, 1           	; volba znaku 
      	INT 21H		   	; prerusenie 21, zadanie znaku, znak sa bude nachadzat v registri AL

	CMP AL, 'a'	   	; porovnaj obsah registra AL so znakom 'a'
	JZ CLR1 	   	; ak sa rovnaju skoc na CLR1  - vykonaj funkciu - vpis poctu zadaneho znaku
     	CMP AL, 'b'	   	; porovnaj obsah registra AL so znakom 'b'	
      	JZ READSTR	   	; ak sa rovnaju skoc na READSTR- nacitaj novy retazec
      	CMP AL, 'c'         	; porovnaj obsah registra AL so znakom 'c'
      	JZ CLR3   	   	; ak sa rovnaju skoc na KONIEC - ukoncenie programu
	CMP AL, 'd'         	; porovnaj obsah registra AL so znakom 'd'
      	JZ CLR2   	   	; ak sa rovnaju skoc na CLR2 - triedenie
	CMP AL, 'e'	   	; porovnaj obsah registra AL so znakom 'e'
	JZ NORMVYP		; ak sa rovnaju skoc na NORMVYP- vypis aktualneho retazca

	JMP PONUKA		; v pripade akejkolvek inej volby vypis menu znova

CLR1:	call FUNCT		; vola proceduru FUNCT
	jmp PONUKA		; po jej skonceni navrat do menu

CLR2: 	call SORT		; vola proceduru SORT
	jmp PONUKA		; po jej skonceni navrat do menu

CLR3:	jmp ENDJMP		; skok na koniec

FUNCT	proc  			; zaciatok procedury
	 pam REQ1	 	; vypis hlasky
	
	 MOV AH, 1           	; volba znaku 
      	 INT 21H		; precitany znak sa bude nachadzat v registri AL
	
	 MOV DX, OFFSET VSTUP	; do registra DX presun offsetovu cast adresy VSTUP
	 ADD DX, 2		; presun sa na zaciatok retazca
	 MOV SI, DX		; v indexovom registri bude offset zaciatku registra
       	 MOV CL, POCET          ; do cl vloz pocet znakov v retazci
	 XOR AH, AH		; nuluj AH
	 XOR BL, BL		; nuluj BL  //register bude obsahovat aktualny znak z retazca
	 XOR DL, DL		; nuluj DL  //register bude obsahovat pocitadlo znakov

LUUP2:	 MOV BL, [SI]		; do BL presun znak na ktory ukazuje obsah registra SI
	 CMP BL, AL		; porovnaj zadany znak zo znakom na ktory ukazuje obsah registra SI
	 JNE NEXT		; ak sa nerovnaju skok na NEXT
	 INC DL			; ak sa rovnaju inkrementuj pocitadlo znakov DL

NEXT:	 INC SI			; presun register SI na dalsi znak retazca
	 LOOPNE  LUUP2		; skoc ak sa register CX(CL) nerovna nule
	 
	 XOR BH, BH		; nuluj CL,BL,BH priprava
	 XOR BL, BL		; do tychto registrov sa budu umiestnovat pocty
	 XOR CL, CL		; stoviek desiatok a jednotiek

STOVKY:  CMP DL, 100            ; porovnaj hodnotu DL zo 100
	 JB  DESIAT             ; ak je mensia, skoc na DESIAT
	 SUB DL, 100            ; od DL odpocitaj 100 
	 MOV CL, 1              ; do al vloz 1 //pocet stoviek (je mozny len jedna, kedze retazec ma dlzku max 100)

DESIAT:  CMP DL, 10             ; porovnaj hodnotu DL z 10
	 JB  JEDNOT             ; ak je mensia, skoc na JEDNOT
	 SUB DL, 10             ; od DL odpocitaj 10
	 INC BL                 ; inkrementuj hodnotu BL (hod. desiatok)
	 JMP DESIAT             ; skok na DESIAT

JEDNOT:  MOV BH, DL             ; do CL vloz hodnotu DL //po prechode cyklami ostal v DL pocet jednotiek       
	 ADD CL, 30H            ; do CL prirataj hexadecimalnu nulu 
	 ADD BL, 30H            ; do BL prirataj hexadecimalnu nulu        
	 ADD BH, 30H            ; do BH prirataj hexadecimalnu nulu 
	 
	 pam NEWLINE		; odriadkuj
	 pam MESSA1		; vypis hlasenie
	        
	 MOV AH, 2              ; funkcia vypis znaku na obrazovku
	 MOV DL, CL             ; do DL vloz pocet stoviek - AL
	 INT 21H                ; volanie funkcie dosu
	 MOV DL, BL             ; do DL vloz pocet desiatok - BL
	 INT 21H                ; volanie funkcie dosu
	 MOV DL, BH             ; do DL vloz pocet jednotiek - BH
	 INT 21H                ; volanie funkcie dosu
	ret
	endp

ENDJMP: jmp KONIEC
BCKJMP: jmp PONUKA


;Na triedenie som pouzil algoritmus vymeny prvkov SELECTSORT, tento algoritmus prechadza cez retazec POCET-krat
;a hlada vzdy najmensi prvok,ktory ulozi na zodpovedajuce miesto v retazci, jeho hodnotu ulozi do registra BL a 		;jeho poziciu do registra DI. Dolna cast registra AX - AL sluzi ako riadiaca premenna vonkajsieho cyklu, oznacuje
;aj riadiacu premennu vnutorneho cyklu CL, ktora od nej zavisi podla funkcie CL=POCET-AL

SORT 	proc
	 pam NEWLINE
	 pam MESSA2
	 XOR AX, AX			; nulovanie registra AX//AL - riadiaca premenna vonkajsieho cyklu
START:	 MOV DX, OFFSET STRING		; nastavenie registra DX na offset retazca STRING, 				|
					; zaciatok vonkajsieho cyklu							|
	 MOV SI, DX			; nastavenie registra SI na zaciatok retazca STRING				|
	 ADD SI, AX			; nastavenie registra na zaciatocnu poziciu podla riadiacej premennej AL	|
	 MOV CL, POCET			; vloz pocet znakov v retazci do registra CL, riadiaca 				|
	 SUB CL, AL			; premenna (vnutorneho) cyklu LOOP, odpocitaj AL			|	|
	 MOV BL, 255			; vlozi max hodnotu do registra, tento register bude uchovavat		|	|
					; ASCII hodnotu znaku, ktory je do aktualnej pozicie najmensi		|	|
LUUP3:	 MOV DL, [SI]			; presun do registra DL znak, na ktory ukazuje register SI		|	|
	 CMP DL, BL			; porovnanie "doteraz najmensieho znaku" s aktualnym			|	|
	 JB  INK			; ak DL<BL skok na INK							|	|
	 JMP NXT			; inak skok na NXT							|	|
INK:	 MOV BL, DL			; v BL mame hodnotu najmensieho prvku					|	|
	 MOV DI, SI			; v DI mame poziciu(offset) najmensieho prvku				|	|
NXT:	 INC SI	  			; posun v retazci 							|	|
	 LOOP	 LUUP3			; opakuj cyklus kym je CX rozne od 0				     ___|	|
														       ;|
	 XOR AH, AH			; nuluj register AH								|
	 MOV SI, OFFSET STRING		; nastav SI na zaciatok retazca							|
	 ADD SI, AX			; nastav SI na zodpovedajucu poziciu podla riadiacej premennej AL		|
	 				; 										|
	 MOV  DL, [SI]			; presun do registra DL miesto v pamati, kam odkazuje SI			|
	 MOV [DI], DL		 	; vymen najdeny najmensi znak so znakom na pozicii				|
         MOV [SI], BL			; urcenej riadiacou premennou AL						|
	 PUSH AX			; obsah registra AX prekopiruj do zasobnika,					|
					; musi sa urobit, pretoze hodnotu AL budeme v dalsich iteraciach		|
					; potrebovat a INT 21H by ju prepisal svojim navratovym kodom			|
	 MOV AH, 2			; priprava na vypis znaku, sluzba 2						|
	 MOV DL, BL			; vstup sluzby, znak z registra DL						|
	 int 21H			; vykonanie sluzby -> prepis registra AX					|
														       ;|
	 POP AX				; obnovenie stavu registra AX							|
														    ;	|
	 MOV CL, POCET			; do registra CL presun pocet znakov v retazci					|
	 INC AL				; inkrementuj register AL - riadiaca premenna vonkajsieho cyklu			|
	 CMP AL, CL			; porovnaj AL a CL								|
	 JB START			; pokial AL<CL skok na START						     ___|

	JMP BCKJMP			; inak navrat do menu

	ret
	endp				; koniec procedury



KONIEC: MOV AX, 4C00H           ; funkcia ukoncenie programu
        INT 21H                 ; prerusenie na vykonanie ukoncenia programu
CODE    ENDS                    ; koniec kodoveho segmentu
        END     READSTR         ; koniec suboru - pre assembler
                                ; program bude spusteny od navestia READSTR

;ZHODNOTENIE:	Program bol vypracovany v editoreGVim. Program vykonava zatial vsetky funkcie podla zadania
;        	pricom jednotlive operacie si voli uzivatel prostrednictvom menu. Triedenie a funkciu vyhladavania
;		som implementoval ako proceduru. Na vypisy hlasok a menu som pouzil makro.
;        	Po skonceni operacie sa program vrati do menu.
;		Oproti zadaniu som pridal do menu funkciu e.| vypis retazca
;		Program si hned po zapnuti vyziada zadanie retazca a nacita najviac 100 znakov retazca pomocou
;		funkcie dos-u 0AH. Tato funkcia zapise do pamatovej bunky POCET skutocny pocet nacitanych znakov
;		co je velmi uzitocna hodnota. 
; 		Neprazdny zadany retazec je nutnou podmienkou spravneho fungovania programu.
;		Vypis zotriedeneho retazca som implementoval tak, ze program prechadza po retazci a zapamata
;		si najmensi znak a jeho adresu. Tento znak vypise a na jeho adresu zapise znak s kodom 255(FFH)
;		Tato pozicia bude obsahovat maximalnu hodnotu ASCII znaku a pri dalsom prechode retazcom
;		nebude brana do uvahy.


