summaryrefslogtreecommitdiffstats
path: root/setCase.asm
blob: ae3014a7d0f59ae038512716bac6a96c1e29722d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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