edge cases and more commands
[sped.git] / repl.asm
1
2 extern printf
3 extern fflush
4 extern stdout
5 extern free
6
7 extern readLine
8 extern writeFile
9 extern shiftLeft
10 extern shiftRight
11
12 global repl
13
14 section .data
15     prompt_str db `sped > `, 0x00
16     invalidcmd_str db `invalid command\n`, 0x00
17     invalidaddr_str db `invalid address\n`, 0x00
18     oneline_str db `cannot delete line, as there is only one line\n`, 0x00
19     charcount_str db `read %i chars\n`, 0x00
20     currentline_str db `current line: %i\n`, 0x00
21     echo_str db `%s`, 0x00 ; print strings without format exploit
22
23 section .bss
24     buffer resb 4
25     buffer_lines resb 4
26     buffer_filename resb 4
27     cur_line resb 4
28
29 section .text
30
31 ; prompt for user
32 ; args: buffer, buffer_lines, buffer_filename
33 repl:
34
35     %define _BUFFER          16
36     %define _BUFFER_LINES    12
37     %define _BUFFER_FILENAME 8
38     %define CMDSTR           4 ; the previous line read from user
39
40     push ebp
41     mov ebp, esp
42
43     sub esp, 4
44     
45     ; set bss vars
46     mov eax, [ebp+_BUFFER]
47     mov [buffer], eax
48     mov eax, [ebp+_BUFFER_LINES]
49     mov [buffer_lines], eax
50     mov eax, [ebp+_BUFFER_FILENAME]
51     mov [buffer_filename], eax
52     mov DWORD [cur_line], 0x00
53
54     _repl_loop:
55     
56     ; print the prompt
57     push prompt_str
58     call printf
59     push DWORD [stdout]
60     call fflush
61
62     ; read line from stdin
63     push 0
64     call readLine
65
66     mov DWORD [ebp-CMDSTR], eax
67
68     ; commands are single char for now
69     cmp ecx, 1 
70     jne _repl_invalid_cmd
71
72     ; parse commands
73     mov eax, DWORD [ebp-CMDSTR]
74     mov eax, [eax]
75
76     ; q exists program =-=-=-=-=-=-=-=-=-=-=-=-=
77     mov eax, DWORD [ebp-CMDSTR]
78     cmp BYTE [eax], 'q'
79     jne _repl_cmd_quit_end
80     jmp _repl_exit
81     _repl_cmd_quit_end:
82
83     ; p prints current line =-=-=-=-=-=-=-=-=-=-=
84     mov eax, DWORD [ebp-CMDSTR]
85     cmp BYTE [eax], 'p'
86     jne _repl_cmd_print_end
87
88     mov eax, DWORD [cur_line]
89     mov ecx, 4
90     mul ecx
91     add eax, [buffer]
92     push DWORD [eax]
93     push echo_str
94     call printf
95     jmp _repl_continue
96     _repl_cmd_print_end:
97
98     ; n prints the current line number =-=-=-=-=-=-=-=
99     mov eax, DWORD [ebp-CMDSTR]
100     cmp BYTE [eax], 'n'
101     jne _repl_cmd_number_end
102
103     push DWORD [cur_line]
104     push currentline_str
105     call printf
106
107     jmp _repl_continue
108     _repl_cmd_number_end:
109
110     ; - goes to prev line =-=-=-=-=-=-=-=-=-=-=-=-=
111     mov eax, DWORD [ebp-CMDSTR]
112     cmp BYTE [eax], '-'
113     jne _repl_cmd_decline_end
114
115     ; make sure we are within bounds
116     mov eax, DWORD [cur_line] 
117     sub eax, 1
118     cmp eax, 0
119     jl _repl_invalid_addr
120     
121     sub DWORD [cur_line], 1
122
123     jmp _repl_continue
124     _repl_cmd_decline_end:
125
126     ; + goes to next line =-=-=-=-=-=-=-=-=-=-=-=-=
127     mov eax, DWORD [ebp-CMDSTR]
128     cmp BYTE [eax], '+'
129     jne _repl_cmd_incline_end
130
131     ; make sure we are within bounds 
132     mov eax, DWORD [cur_line] 
133     add eax, 1
134     cmp eax, [buffer_lines]
135     jge _repl_invalid_addr
136     
137     add DWORD [cur_line], 1
138
139     jmp _repl_continue
140     _repl_cmd_incline_end:
141
142     ; g goes to first line =-=-=-=-=-=-=-=-=-=-=-=-=
143     mov eax, DWORD [ebp-CMDSTR]
144     cmp BYTE [eax], 'g'
145     jne _repl_cmd_jumptop_end
146
147     mov DWORD [cur_line], 0x00
148
149     jmp _repl_continue
150     _repl_cmd_jumptop_end:
151
152     ; G goes to last line =-=-=-=-=-=-=-=-=-=-=-=-=
153     mov eax, DWORD [ebp-CMDSTR]
154     cmp BYTE [eax], 'G'
155     jne _repl_cmd_jumpbot_end
156
157     mov eax, DWORD [buffer_lines]
158     sub eax, 1
159     mov DWORD [cur_line], eax
160
161     jmp _repl_continue
162     _repl_cmd_jumpbot_end:
163
164     ; c changes the current line =-=-=-=-=-=-=-=-=-=
165     mov eax, DWORD [ebp-CMDSTR]
166     cmp BYTE [eax], 'c'
167     jne _repl_cmd_change_end
168
169     ; read a new line to use
170     push 0
171     call readLine
172
173     mov esi, eax
174
175     ; free old string
176     mov eax, [cur_line]
177     mov ecx, 4
178     mul ecx
179     add eax, [buffer]
180     push DWORD [eax]
181     call free
182
183     ; insert new string
184     mov eax, [cur_line]
185     mov ecx, 4
186     mul ecx
187     add eax, DWORD [buffer]
188     mov [eax], esi
189
190     jmp _repl_continue
191     _repl_cmd_change_end:
192
193     ; d delete line =-=-=-=-=-=-=-=-=-=-=-=-=
194     mov eax, DWORD [ebp-CMDSTR]
195     cmp BYTE [eax], 'd'
196     jne _repl_cmd_delete_end
197     
198     ; check to make sure we don't have only one line
199     cmp DWORD [buffer_lines], 1
200     jle _repl_oneline
201
202     ; delete the line
203     push DWORD [buffer]
204     push DWORD [buffer_lines]
205     push DWORD [cur_line]
206     call shiftLeft
207     mov [buffer], eax
208
209     sub DWORD [buffer_lines], 1
210
211     ; if it's the last line, move one down
212     mov eax, DWORD [buffer_lines]
213     cmp DWORD [cur_line], eax
214     jl _repl_continue
215     sub DWORD [cur_line], 1
216
217     jmp _repl_continue
218     _repl_cmd_delete_end:
219
220     ; o appends text after line =-=-=-=-=-=-=-=-=
221     mov eax, DWORD [ebp-CMDSTR]
222     cmp BYTE [eax], 'o'
223     jne _repl_cmd_appenddown_end
224
225     ; make room first
226     push DWORD [buffer]
227     push DWORD [buffer_lines]
228     mov eax, DWORD [cur_line]
229     add eax, 1
230     push eax
231     call shiftRight
232     mov [buffer], eax
233
234     ; input text
235     push 0
236     call readLine
237     mov esi, eax
238
239     ; insert new string
240     mov eax, [cur_line]
241     add eax, 1
242     mov ecx, 4
243     mul ecx
244     add eax, DWORD [buffer]
245     mov [eax], esi
246
247     add DWORD [buffer_lines], 1
248
249     jmp _repl_continue
250     _repl_cmd_appenddown_end:
251
252     ; O oppens text before line =-=-=-=-=-=-=-=
253     mov eax, DWORD [ebp-CMDSTR]
254     cmp BYTE [eax], 'O'
255     jne _repl_cmd_appendup_end
256
257     ; make room first
258     push DWORD [buffer]
259     push DWORD [buffer_lines]
260     push DWORD [cur_line]
261     call shiftRight
262     mov [buffer], eax
263
264     ; input text
265     push 0
266     call readLine
267     mov esi, eax
268
269     ; insert new string
270     mov eax, [cur_line]
271     mov ecx, 4
272     mul ecx
273     add eax, DWORD [buffer]
274     mov [eax], esi
275     
276     ; also move cursor down one
277     add DWORD [cur_line], 1
278
279     add DWORD [buffer_lines], 1
280
281     jmp _repl_continue
282     _repl_cmd_appendup_end:
283
284
285     ; w writes file =-=-=-=-=-=-=-=-=-=-=-=-=
286     mov eax, DWORD [ebp-CMDSTR]
287     cmp BYTE [eax], 'w'
288     jne _repl_cmd_write_end
289
290     push DWORD [buffer_filename]
291     push DWORD [buffer]
292     push DWORD [buffer_lines]
293     call writeFile
294
295     jmp _repl_continue
296     _repl_cmd_write_end:
297
298
299     ; if no commands were matched, it's an error
300     jmp _repl_invalid_cmd
301
302     ; some error messages
303     _repl_invalid_cmd:
304     push invalidcmd_str
305     call printf
306     jmp _repl_continue
307
308     _repl_invalid_addr:
309     push invalidaddr_str
310     call printf
311     jmp _repl_continue
312
313     _repl_oneline:
314     push oneline_str
315     call printf
316     jmp _repl_continue
317
318     _repl_continue:
319     jmp _repl_loop
320     
321     _repl_exit:
322
323     %undef _BUFFER
324     %undef _BUFFER_LINES
325     %undef _BUFFER_FILENAME
326     %undef CMDSTR
327
328     mov esp, ebp
329     pop ebp
330     ret
331