-
Notifications
You must be signed in to change notification settings - Fork 1
/
cli.z80
209 lines (200 loc) · 4.17 KB
/
cli.z80
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
include 'string.z80'
ParseLine:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; BC is a pointer to the argc/argv array
; (it gets pushed and popped around comparisons)
; DE is used by StrTok
; HL is a pointer to the line to parse
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Prepare to read arguments
; Set argc to 0
push hl ; Keep string pointer
push bc ; Keep start of argcv struct
inc bc ; Skip counter
ld a, 0
push af ; Keep arg count on stack
ParseLine00:
call StrTok
; If string ended in a null, we're done
cp "\0"
jr z, ParseLine01
; DE now points to the start of the first arg
; Load this into (BC) and increment
ld a, e
ld (bc), a
inc bc
ld a, d
ld (bc), a
inc bc
; Increment argc
pop af
inc a
push af
; Prepare for next StrTok...
ex de, hl
jr ParseLine00
ParseLine01:
pop af ; Get arg count
pop bc ; Set BC back to start of argcv
ld (bc), a ; Store argc
pop hl ; Get string pointer back
ret
MapString2Address:
; In:
; HL points to a string
; BC points to table of (string address, arb address) pairs
; The table MUST be terminated with a pointer to a null str,
; which acts as a default match
; This function writes the matching arb address into HL
ld a, (bc)
ld e, a
inc bc
ld a, (bc)
ld d, a
inc bc
push bc
push hl
call StrCmp
pop hl
pop bc
jr z, MapS2A01 ; We've matched!
inc bc
inc bc
jr MapString2Address
MapS2A01:
ld a, (bc)
ld l, a
inc bc
ld a, (bc)
ld h, a
ret
; Function which interprets the string pointed to by HL
; as a command and calls the appropriate function
Dispatch:
call MapString2Address
jp (hl)
HandleCommandLine:
; HL - command string pointer
; DE - dispatch table pointer
; BC - argc/argv structure
call SkipWhitespace
call ConvertToUpper
push de
call ParseLine
pop bc
call Dispatch
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; UTILITY FUNCTIONS
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ValidateValue:
call StrLen
cp 2
jr nz, ValidateValueError
call IsStrHex
jr nz, ValidateValueError
cp a ; Set zero flag
ret
ValidateValueError:
call PrintStringA
ld hl, IsNotAValidStr
call PrintStringA
ld hl, ValueErrorStr
call PrintStringA
or 1 ; Reset zero flag
ret
IsNotAValidStr:
defm " is not a valid \0"
ValueErrorStr:
defm "value (use 00-FF).\r\n\0"
ValidateAddress:
call StrLen
cp 4
jr nz, ValidateAddressError
call IsStrHex
jr nz, ValidateAddressError
cp a ; Set zero flag
ret
ValidateAddressError:
call PrintStringA
ld hl, IsNotAValidStr
call PrintStringA
ld hl, AddressErrorStr
call PrintStringA
or 1 ; Reset zero flag
ret
AddressErrorStr:
defm "address (use 0000-FFFF).\r\n\0"
ValidateSector:
call StrLen
cp 8
jr nz, ValidateSectorError
call IsStrHex
jr nz, ValidateSectorError
cp a ; Set zero flag
ret
ValidateSectorError:
call PrintStringA
ld hl, IsNotAValidStr
call PrintStringA
ld hl, SectorErrorStr
call PrintStringA
or 1 ; Reset zero flag
ret
SectorErrorStr:
defm "sector (use 8 digit hex).\r\n\0"
ValidateFilename:
push hl
; Must be less than 13 chars
call StrLen
cp 13
jr nc, ValidateFilenameBad ; filename too long!
; Must have only one period
pop hl
push hl
ld d, 0
ValidateFilenameCountPeriodLoop:
ld a, (hl)
inc hl
cp "."
jr z, ValidateFilenameCountPeriod
cp "\0"
jr z, ValidateFilenameCountPeriodEnd
jr ValidateFilenameCountPeriodLoop
ValidateFilenameCountPeriod:
inc d
jr ValidateFilenameCountPeriodLoop
ValidateFilenameCountPeriodEnd:
; d now contains period count
ld a, d
cp 2
jr nc, ValidateFilenameBad ; Too many periods!
; If no periods, no extension, so no need to check ext length
cp 0
jr z, ValidateFilenameAllGood
; Extension must be 3 chars or less
; If we're here we *know* there is a period
pop hl
push hl
ld a, "."
ld bc, 12
cpir
; Now we've advanced to the first char after the period.
call StrLen
cp 4
jr nc, ValidateFilenameBad ; Extension too long!
ValidateFilenameAllGood:
; All good!
pop hl ; Get rid of filename pointer
cp a ; Set zero flag
ret
ValidateFilenameBad:
ld hl, BadFilenameStr
call PrintStringA
pop hl ; Get rid of filename pointer
or 1 ; Reset zero flag
ret
BadFilenameStr:
defm "Bad filename (use 8.3)\r\n\0"