summaryrefslogtreecommitdiffstats
path: root/setCase.asm
diff options
context:
space:
mode:
Diffstat (limited to 'setCase.asm')
-rw-r--r--setCase.asm167
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