1
2SECTION code_clib
3SECTION code_l
4
5PUBLIC l_command_line_parse_in_place
6
7EXTERN asm_isspace
8
9l_command_line_parse_in_place:
10
11   ; * parse command line into words in place
12   ; * return argc and argv
13   ; * return pointer to redirector string if '>' or '<' found
14   ; * command line length capped at 255 chars
15   ;
16   ; enter : hl = & command line
17   ;         bc = number of chars in command line
18   ;              (limited to 255 chars here)
19   ;
20   ; note  : *(hl+bc) will be set to 0
21   ;
22   ; exit  : bc    = int argc
23   ;         hl    = char *argv[]
24   ;         hl'   = & redirector in command line (0 if none)
25   ;         bc'   = num chars remaining in redirector (0 if none)
26   ;         de'   = address of empty string
27   ;
28   ;         argv[] array is pushed onto the stack
29   ;
30   ; note  : on exit if there is a redirector, must 0 the
31   ;         redirector byte after examining it.
32   ;
33   ; uses  : af, bc, de, hl, bc', de', hl', ix
34
35   pop ix                      ; ix = return address
36
37   ; initialize redirector pointers
38
39   xor a
40
41   exx
42
43   ld c,a
44   ld b,a                      ; bc'= chars remaining in redirector
45
46   push bc                     ; argv[argc] = NULL
47
48   ld l,a
49   ld h,a
50   add hl,sp
51
52   ex de,hl                    ; de'= & ""
53
54   ld l,a
55   ld h,a                      ; hl'= & redirector in command line
56
57   exx
58
59   inc b
60   dec b
61
62   jr z, sz_cont
63
64   ld b,a
65   ld c,255
66
67sz_cont:
68
69   ; find end of command line
70
71   ; hl = & command line
72   ; bc = num chars remaining in command line < 256
73   ; hl'= & redirector
74   ; bc'= num chars remaining in redirector
75   ; de'= address of empty string
76   ; ix = return address
77
78   ld e,a
79   ld d,a                      ; d = quote indicator
80
81   inc c
82   dec c
83
84   jr z, argv_finished         ; if there is no command line
85
86find_end:
87
88   ld a,(hl)
89
90   inc d
91   dec d
92
93   jr z, outside_quote
94
95inside_quote:
96
97   cp d
98   jr nz, find_cont            ; if end quote not seen
99
100   ld d,b                      ; quote ended
101   jr find_cont
102
103outside_quote:
104
105   cp '"'
106   jr z, start_quote
107
108   cp '|'
109   jr z, redirector
110
111   cp '>'
112   jr z, redirector
113
114   cp '<'
115   jr nz, find_cont
116
117redirector:
118
119   push bc
120   push hl
121
122   exx
123
124   pop hl                      ; hl'= & redirector
125   pop bc                      ; bc'= num chars remaining in redirector
126
127   exx
128
129   jr found_end
130
131start_quote:
132
133   ld d,a
134
135find_cont:
136
137   inc e
138
139   cpi                         ; hl++, bc--
140   jp pe, find_end
141
142   ld (hl),b
143
144found_end:
145
146   ld c,e
147
148   ; hl = & last char in command line + 1
149   ; bc = number of chars in command line < 256
150   ;  d = quote indicator
151   ; hl'= & redirector
152   ; bc'= num chars remaining in redirector
153   ; de'= address of empty string
154   ; ix = return address
155
156   ; work command line backwords
157
158   ld e,b                      ; e = word_count = 0
159   inc bc
160
161   inc d
162   dec d
163
164   jr nz, word_found           ; if in an unterminated quote
165
166word_loop:
167
168   cpd                         ; hl--, bc--
169   jp po, argv_finished        ; if reached beginning of command line
170
171   ld a,(hl)
172
173   cp '"'
174   jr nz, word_ws_cont
175
176word_ws_quote:
177
178   ld d,a
179   ld (hl),b                   ; zero terminate over quote
180
181   jr word_found
182
183word_ws_cont:
184
185   call asm_isspace
186   jr c, word_found            ; not space, end of word found
187
188word_terminate:
189
190   ld (hl),b
191   jr word_loop
192
193word_found:
194
195   inc e                       ; word_count++
196
197word_begin_loop:
198
199   cpd                         ; hl--, bc--
200   jp po, generate_last_argv   ; if reached beginning of command line
201
202   ld a,(hl)
203
204   inc d
205   dec d
206
207   jr z, word_out_quote
208
209word_in_quote:
210
211   cp d
212   jr nz, word_begin_loop
213
214   ld d,b
215   jr word_end_quote
216
217word_out_quote:
218
219   cp '"'
220   jr nz, word_out_quote_cont
221
222   inc hl
223   push hl                     ; save start of word to argv[]
224   dec hl
225
226   jr word_ws_quote            ; quote indicates new woed starting
227
228word_out_quote_cont:
229
230   call asm_isspace
231   jr c, word_begin_loop       ; if next char is not space, word continues
232
233word_end_quote:
234
235   inc hl
236   push hl                     ; save start of word to argv[]
237   dec hl
238
239   jr word_terminate
240
241generate_last_argv:
242
243   inc hl
244   push hl                     ; save argv[]
245
246argv_finished:
247
248   ld c,e
249
250   ; bc = argc = word count
251   ; hl'= & redirector
252   ; bc'= num chars remaining in redirector
253   ; de'= address of empty string
254   ; ix = return address
255   ; stack = argv[]
256
257   ld l,b
258   ld h,b
259   add hl,sp                   ; hl = &argv[0]
260
261   jp (ix)
262