global _start %define STDIN 0 %define STDOUT 1 %define STDERR 2 %define RD_ONLY 00 %define FILE_BUF_SIZE 1024 section .data buffer_tail_ptr dq file_buffer ; stores pointer to the end of the buffer for file is_eof db 0 ; indicates if file ended count dq 0 ; сколько имен нашлось section .bss name resb 128 real_name_len resb 1 name_size equ $-name file_descriptor resq 1 file_buffer resb FILE_BUF_SIZE section .text %macro PRINT_STR 1 jmp %%run ; we define data right in code. It's not good, but ok for prototype %%string db %1 %%string_len equ $-%%string %%run: mov rax, 1 mov rdi, STDOUT mov rsi, %%string mov rdx, %%string_len syscall %endmacro %macro MPUSH 1-* %rep %0 push %1 %rotate 1 %endrep %endmacro %macro MPOP_R 1-* %rotate -1 %rep %0 pop %1 %rotate -1 %endrep %endmacro is_alpha: ; dl - symbol in ascii xor al, al cmp dl, 'A' jl .exit cmp dl, 'z' jg .exit ; dl < 'Z' or dl > 'a' cmp dl, 'Z' jl .true cmp dl, 'a' jg .true jmp .exit .true: mov al, 1 .exit: ret fill_buf: ; read bytes from file to buffer MPUSH rdi, rsi, rcx, r11, rdx mov rdi, [buffer_tail_ptr] call buffer_left mov rdx, rax mov rax, 0 mov rdi, [file_descriptor] mov rsi, [buffer_tail_ptr] ; mov rdx, FILE_BUF_SIZE syscall cmp rax, 0 jl file_read_error add [buffer_tail_ptr], rax cmp rax, FILE_BUF_SIZE jg .exit mov byte [is_eof], 1 .exit: MPOP_R rdi, rsi, rcx, r11, rdx ret read_name: ; ask user for name he is searching for MPUSH rax, rdi, rsi, rdx, rcx mov rax, 0 mov rdi, STDIN mov rsi, name mov rdx, name_size syscall ; returns number of read bytes cmp rax, 0 jl read_error test rax, rax jz no_name_error ; if no bytes were read mov [real_name_len], al ; if user didn't end output with CTRL+D, there will be one extra symbol mov dl, [name + rax - 1] call is_alpha ; check if last symbol is alpha test al, al jnz .exit ; if last symbol is \n or something simmilar, erase it xor rdx, rdx mov dl, byte [real_name_len] mov byte [name + rdx - 1], 0 ; clear last char if non alpha dec byte [real_name_len] .exit: MPOP_R rax, rdi, rsi, rdx, rcx ret are_names_equal: ; takes first fullname from buff and compares MPUSH rcx, rsi, rdi ; jump to second word mov rdi, file_buffer mov rcx, FILE_BUF_SIZE mov al, ' ' repne scasb ; Теперь мы указываем на символ второго слова mov r8, rdi ; store for later repne scasb ; Ищем второй пробел, чтобы определить границы второго слова dec rdi ; Нашелся второй пробел. убавляем 1 чтобы указывать именно на него sub rdi, r8 ; len mov rax, rdi cmp al, [real_name_len] jnz .false ; if lenghts are different - already false mov rdi, r8 ; return to pointer on second word mov rsi, name xor rcx, rcx mov cl, [real_name_len] repe cmpsb jnz .false .true: mov rax, 1 jmp .exit .false: mov rax, 0 .exit: MPOP_R rcx, rsi ,rdi ret buffer_left: ; counts free part of buffer push rdi mov rax, FILE_BUF_SIZE sub rdi, file_buffer sub rax, rdi pop rdi ret pop_from_addr: ; frees buffer from one name until \n, takes 1 addr push rbp mov rbp, rsp MPUSH rdx, rax sub rsp, 24 mov [rbp-24], rdi ; char* start call buffer_left mov [rbp-16], rax ; * count mov QWORD [rbp-8], 0 ; i ;loop .loop: ; read byte from start[i] mov rdx, [rbp-24] mov rax, [rbp-8] add rax, rdx mov al, [rax] ; place to buffer[i] mov rdx, [rbp-8] add rdx, file_buffer mov [rdx], al ; move zero to read position mov rdx, [rbp-24] mov rax, [rbp-8] add rax, rdx mov byte [rax], 0 inc qword [rbp-8] ; .cond: mov rax, [rbp-8] cmp rax, [rbp-16] jb .loop ; update buffer_tail_ptr mov rax, [rbp-24] sub rax, file_buffer sub [buffer_tail_ptr], rax add rsp, 24 MPOP_R rcx, rax pop rbp ret free_fullname: MPUSH rcx, rdi, rax mov rcx, FILE_BUF_SIZE mov rdi, file_buffer mov al, `\n` repne scasb call pop_from_addr MPOP_R rcx, rdi, rax ret _start: ; --parse command_line arguments push rbp mov rbp, rsp ; --check if there is any args mov rax, [rbp + 8] cmp rax, 2 jl no_filepath ; --if argument specified, try to read path mov rdi, [rbp + 8*3] mov rax, 0x2 ; open file mov rsi, RD_ONLY xor rdx, rdx syscall ; filepath already should be in rdi mov [file_descriptor], rax cmp rax, 0 jl file_open_error ; --asking user what name we are looking for PRINT_STR `Input name you are looking for: ` call read_name ; -- find number of occurenses. HARDEST PART .fill_buff_prefix: call fill_buf .name_cmp_loop: mov rdi, name call are_names_equal test rax, rax jz .no_increment inc qword [count] .no_increment: call free_fullname ; iseof && buffer_tail_ptr == file_buffer mov rax, [buffer_tail_ptr] cmp rax, file_buffer jne .name_cmp_loop mov al, [is_eof] test al, al jz .fill_buff_prefix ;formatted output mov rax, 1 ; write mov rdi, STDOUT mov rsi, name mov rdx, [real_name_len] syscall PRINT_STR " ............... " ; printing number mov rax, [count] mov rbx, 10 xor rcx, rcx .number_converting_loop: xor rdx, rdx div rbx ; push 1 byte to stack add dl, '0' ; convert to ascii dec rsp mov [rsp], dl inc rcx test rax, rax jnz .number_converting_loop mov rax, 1 mov rdi, STDOUT mov rsi, rsp mov rdx, rcx syscall PRINT_STR `\n` jmp exit read_error: PRINT_STR `Error while reading the name\n` jmp exit no_name_error: PRINT_STR `No propper name given\n` jmp exit file_open_error: PRINT_STR `Failed to open the file\n` jmp exit file_read_error: PRINT_STR `Error while reading the file\n` jmp exit no_filepath: PRINT_STR `You haven't specified a file to read from\n` jmp exit exit: mov rax, 60 mov rdi, 0 syscall