;------------------------------------------------------------------------------; ; Pouzite konstanty ; ;------------------------------------------------------------------------------; ; - implementacni omezeni na delku nacteneho radku %define ROW_LEN 80 %defstr ROW_LEN_STR ROW_LEN ;------------------------------------------------------------------------------; ; Deklarace struktury ; ;------------------------------------------------------------------------------; struc Line .order: resd 1 .content: resb ROW_LEN alignb 4 .size: endstruc ;------------------------------------------------------------------------------; ; Datovy segment ; ;------------------------------------------------------------------------------; section .rodata ; - formatovaci retezce a retezec modu otevreni souboru file_mode db "r",0 count_format db "%u",0 input_format db "%u;%",ROW_LEN_STR,"[^",13,10,"]",0 output_format db "%s",13,10,0 ; - chybove vypisy err_input db "Usage: %s ",13,10,0 err_fopen db "Failed to open input file '%s'",13,10,0 err_fscanf db "Invalid file format",13,10,0 err_malloc db "Failed to allocate memory",13,10,0 ;------------------------------------------------------------------------------; ; Symboly z knihovny jazyka C ; ;------------------------------------------------------------------------------; ; - otevreni a uzavreni souboru extern _fopen extern _fclose ; - vypis na terminal extern _fprintf extern ___iob_func ; - nacteni a zpracovani dat extern _qsort extern _fscanf ; - dynamicka alokace pameti a jeji uvolneni extern _malloc extern _free ;------------------------------------------------------------------------------; ; Windows ziskani stdout, stderr ; ;------------------------------------------------------------------------------; section .text init_stdio: call ___iob_func add eax, 32 mov [stdout], eax add eax, 32 mov [stderr], eax ret section .bss stdout resd 1 stderr resd 1 ;------------------------------------------------------------------------------; ; Kodovy segment ; ;------------------------------------------------------------------------------; section .text ;------------------------------------------------------------------------------; ; Funkce main ; ;------------------------------------------------------------------------------; ; Funkce otevre soubor a nacte obsah do binarni struktury v dynamicky ; alokovane pameti. ; Nazev souboru je predan pomoci argumentu; na prvnim radku se nachazi pocet ; zbylych radku k nacteni. Tyto radky zacinaji cislem oddelenym znakem ';', ; ktery je nasledovan libovolnym textem do delky ROW_LEN. ; Funkce main vypise obsah tychto radku v poradi urcenym cislem, kterym radky ; zacinaji. ; ; Priklad vstupniho souboru: Zodpovedajici vystup: ; 2 bb ; 5;a a ; 3;bb ; global _main _main: ; vytvoreni zasobnikoveho ramce push ebp mov ebp, esp ; misto pro lokalni promenne ; [ebp-4] FILE* - input_file, stdlib deskriptor otevreneho souboru ; [ebp-8] unsigned - line_count, pocet radku ; [ebp-12] Line* - data, ukazatel na alokovanou pamet ; [ebp-16] int - ret, navratova hodnota sub esp, 16 mov dword [esp], 0 ; inicializace stdout, stderr call init_stdio ; zaloha nekterych registru dle cdecl push ebx push esi ;--------------------------------------------------------------------------; ; Test na dva argumenty ; ;--------------------------------------------------------------------------; ; int main(int argc, char* argv[]) mov eax, [ebp+8] mov esi, [ebp+12] cmp eax, 2 je .open_file push dword [esi] ; argv[0] push dword err_input ; err_input push dword [stderr] ; stderr call _fprintf add esp, 12 mov dword [ebp-16], 1 jmp .return ;--------------------------------------------------------------------------; ; Otevreni souboru ; ;--------------------------------------------------------------------------; ; FILE *fopen(const char *path, const char *mode) ; fopen(argv[1], file_mode) .open_file: push file_mode ; file_mode push dword [esi+4] ; argv[1] call _fopen add esp, 8 mov [ebp-4], eax ; ulozeni do lokalni promenne test eax, eax ; test na NULL jnz .read_line_count push dword [esi+4] ; argv[1] push dword err_fopen ; err_open push dword [stderr] ; stderr call _fprintf add esp, 12 mov dword [ebp-16], 1 jmp .return ;--------------------------------------------------------------------------; ; Nacteni poctu radku ; ;--------------------------------------------------------------------------; ; int fscanf(FILE *stream, const char *format, ...) ; fscanf(input_file, count_format, &line_count) .read_line_count: lea esi, [ebp-8] push esi ; &line_count push dword count_format ; count_format push dword [ebp-4] ; input_file call _fscanf add esp, 12 cmp eax, 1 je .allocate_memory push dword err_fscanf ; err_fscanf push dword [stderr] ; stderr call _fprintf add esp, 8 mov dword [ebp-16], 1 jmp .close_file ;--------------------------------------------------------------------------; ; Alokace pameti ; ;--------------------------------------------------------------------------; ; void *malloc(size_t size) ; malloc(line_count * Line.size) .allocate_memory: mov eax, Line.size mul dword [ebp-8] ; preteceni poctu potrebnych bajtov test edx, edx jnz .malloc_error push eax ; line_count * Line.size call _malloc add esp, 4 mov [ebp-12], eax test eax, eax jnz .read_file .malloc_error: push dword err_malloc ; err_malloc push dword [stderr] ; stderr call _fprintf add esp, 8 mov dword [ebp-16], 1 jmp .close_file ;--------------------------------------------------------------------------; ; Nacteni obsahu ; ;--------------------------------------------------------------------------; ; int fscanf(FILE *stream, const char *format, ...) ; fscanf(input_file, input_format, &order, &content) .read_file: ; <<<< Ukol 1: <<<<<< ; <<< ZDE DOPLNTE CYKLUS PRO NACTENI [ebp-8] RADKU <<< ; <<<<<< <<<<<< .file_read_error: push dword err_fscanf ; err_fscanf push dword [stderr] ; stderr call _fprintf add esp, 8 mov dword [ebp-16], 1 jmp .free_memory ;--------------------------------------------------------------------------; ; Serazeni radku ; ;--------------------------------------------------------------------------; ; void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) ; qsort(data, line_count, Line.size, compare_rows) .sort_lines: ; <<<< Ukol 2: <<<<<< ; <<< ZDE DOPLNTE VOLANI qsort <<< ; <<<<<< <<<<<< ;--------------------------------------------------------------------------; ; Vypis vysledku ; ;--------------------------------------------------------------------------; ; int fprintf(FILE *stream, const char *format, ...) ; fprintf(stdout, output_format, line.content) .print_lines: xor ebx, ebx ; pocitadlo cyklu mov esi, [ebp-12] ; ukazatel na pocatek alokovane pameti lea esi, [esi + Line.content] ; ukazatel na prvni radek .print_line: cmp ebx, [ebp-8] je .free_memory push esi ; line.content push dword output_format ; output_format push dword [stdout] ; stdout call _fprintf add esp, 12 lea esi, [esi + Line.size] inc ebx jmp .print_line ;--------------------------------------------------------------------------; ; Uvolneni pameti ; ;--------------------------------------------------------------------------; ; void free(void *ptr) ; free(data) .free_memory: push dword [ebp-12] ; data call _free ;--------------------------------------------------------------------------; ; Zavreni souboru ; ;--------------------------------------------------------------------------; ; int fclose(FILE *stream) ; fclose(input_file) .close_file: push dword [ebp-4] ; input_file call _fclose ;--------------------------------------------------------------------------; ; Ukonceni a vraceni spravne hodnoty ; ;--------------------------------------------------------------------------; .return: mov eax, [ebp-16] ; obnova nekterych registru dle cdecl pop esi pop ebx ; upratani ramce a navrat leave ret ;------------------------------------------------------------------------------; ; Funkce compare_rows ; ;------------------------------------------------------------------------------; ; Funkce implementujici porovnani dvou elementu struktury List. Prvky ; struktury jsou predany ukazatelem, funkce jej porovna pomoci cisla (polozky ; List.order). ; V jazyce C by prototyp funkce vypadal nasledovne: ; int compare_rows(const Line* lhs, const Line* rhs) ; ; Funkce dodrzuje konvenci cdecl a vraci 32 bitove cislo v EAX, ktere splnuje ; nasledujici: ; EAX < 0 <=> *lhs < *rhs ; EAX = 0 <=> *lhs == *rhs ; EAX > 0 <=> *lhs > *rhs ; compare_rows: ; <<<< Ukol 3: <<<<<< ; <<< DOPLNTE TELO FUNKCE compare_rows <<< ; <<<<<< <<<<<< ret