diff options
Diffstat (limited to 'setCase.asm')
-rw-r--r-- | setCase.asm | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/setCase.asm b/setCase.asm new file mode 100644 index 0000000..ae3014a --- /dev/null +++ b/setCase.asm @@ -0,0 +1,167 @@ +; Version : 1.00 +; Updated : 20/8/2021 +; Licence : GPLv3 +; Set the case of ASCII text to upper or lower case. + +default rel ; we always want this. +extern printf + +%define argv0 r12 +%define upper r13 ;make r13 the boolean +%define scratch r14 +%define file r15 + +section .rodata + Usage db `%s OPTION [filename]\n Option Description\n-u Make characters uppercase.\n-l Make characters lowercase.\n`,0 + OpenError: db `Could not open: %s\n`,0 + +section .text + global main + +usage: + push rbx ;align the stack if not already done + + mov rsi, [argv0] ;get argv[0] + lea rdi, [rel Usage] ;copy the usage to rdi + xor eax,eax ;al == 0 means no FP args in XMM registers + call printf wrt ..plt ;call printf with `wrt ..plt` so dynamic linking works + + pop rbx ;pop rbx off the stack + + mov eax, 1 ;exit with value 1 + ret + + + + +stdin: + xor edi, edi ; file descriptor = stdin = 0 + lea rsi, [scratch] ; buffer = address to store the bytes read + mov edx, 1 ; number of bytes to read + xor eax, eax ; syscall for read == 0 + syscall + + test eax, eax ; If syscall returns 0 in rax, the character is EOF + je exit ; if char is EOF: exit + + call process_char + jmp stdin + + +process_char: + test upper,upper + jz lower ;jump to lower if upper is false + + ;fall through if uppercase + + cmp byte[scratch],'a' ;check if read char is below 'a' + jl skip_modification ;if below 'a', it's not a lowercase char + + cmp byte[scratch],'z' ;check if read char is equal to or below z + ja skip_modification ;if not equal or above, it's not a lowercase char + + sub byte[scratch], 32 ;subtract 32 from ASCII char to capitalise it + jmp skip_modification ;skip lowercase + +lower: + cmp byte[scratch],'A' ;check if read char is below 'A' + jl skip_modification ;if below 'A', it's not a uppercase char + + cmp byte[scratch],'Z' ;check if read char is equal to or below 'Z' + ja skip_modification ;if not equal or above, it's not a lowercase char + + add byte[scratch], 32 ;add 32 to ASCII char to make it lowercase + +skip_modification: + mov edi, 1 ; file descriptor = stdout + lea rsi, [scratch] ; buffer = address to write to console + mov edx, 1 ; number of bytes to write + mov eax, 1 ; SYSCALL number for writing to STDOUT + syscall ; make the syscall + + ret ; read the next char + + + + +file_error: + push rbx ;align the stack if not already done + + mov rsi, scratch ;get argv[2] + lea rdi, [rel OpenError];copy the filename to rdi + xor eax,eax ;al == 0 means no FP args in XMM registers + call printf wrt ..plt ;call printf with `wrt ..plt` so dynamic linking works + + pop rbx ;pop rbx off the stack + + mov eax, 1 ;exit with value 1 + ret + +open_file: + add rsi, 8 ;get pointer-to-pointer to argv[2] + mov scratch,[rsi] ;get pointer to argv[2] and copy it to scratch + + mov eax, 2 ;syscall sys_open + mov rdi, scratch ;place pointer to filename string in rdi + xor esi, esi ;O_RDONLY + xor edx, edx ;don't need a mode + syscall + + test eax, eax + js file_error ;if nonzero, sys_open failed + + mov file, rax ;store fp in file + +read_file: + mov rdi, file ;file descriptor = rax from sys_open above + lea rsi, [scratch] ;read into scratch + mov edx, 1 ;number of bytes to read + xor eax, eax ;syscall for read == 0 + syscall + + test eax, eax ;If syscall returns 0 in rax, the character is EOF + je close_file ;if char is EOF, close the file and exit + + call process_char + jmp read_file + + + + + +main: +mov argv0, rsi ;save argv[0] for later + +cmp edi, 2 +jl usage ;show usage if not enough args are provided + +check_args: + add rsi, 8 ;get pointer-to-pointer to argv[1] + + mov scratch, [rsi] ;get pointer to argv[1] and copy it to scratch + cmp byte[scratch], '-' + jne usage ;show usage if there is no argument (missing -) + + + xor upper, upper ;assume lowercase by default + + cmp byte[scratch+1], 'u' + jne false ;fall through if argv[1][1] == 'u' and thus set upper boolean to true + mov upper,1 +false: + + cmp edi, 3 + jl stdin ;go to stdin mode if no filename is provided + jg usage ;go to usage if more that 3 args are provided + + jmp open_file ;jump to file opening + + +close_file: + mov rdi, file ;fp to close + mov eax, 3 ;sys_close + syscall + +exit: + xor eax, eax + ret |