Contents of /tags/mkinitrd-6_3_4/isolinux/getc.inc
Parent Directory | Revision Log
Revision 1133 -
(show annotations)
(download)
Thu Aug 19 09:50:43 2010 UTC (14 years, 1 month ago) by niro
Original Path: trunk/mkinitrd-magellan/isolinux/getc.inc
File size: 9048 byte(s)
Thu Aug 19 09:50:43 2010 UTC (14 years, 1 month ago) by niro
Original Path: trunk/mkinitrd-magellan/isolinux/getc.inc
File size: 9048 byte(s)
-updated to isolinux-3.86
1 | ;; ----------------------------------------------------------------------- |
2 | ;; |
3 | ;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved |
4 | ;; Copyright 2009 Intel Corporation; author: H. Peter Anvin |
5 | ;; |
6 | ;; This program is free software; you can redistribute it and/or modify |
7 | ;; it under the terms of the GNU General Public License as published by |
8 | ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, |
9 | ;; Boston MA 02111-1307, USA; either version 2 of the License, or |
10 | ;; (at your option) any later version; incorporated herein by reference. |
11 | ;; |
12 | ;; ----------------------------------------------------------------------- |
13 | |
14 | ;; |
15 | ;; getc.inc |
16 | ;; |
17 | ;; Simple file handling library (open, getc, ungetc) |
18 | ;; |
19 | ;; WARNING: This interface uses the real_mode_seg/comboot_seg. |
20 | ;; |
21 | |
22 | MAX_GETC_LG2 equ 4 ; Max number of file nesting |
23 | MAX_GETC equ (1 << MAX_GETC_LG2) |
24 | bytes_per_getc_lg2 equ 16-MAX_GETC_LG2 |
25 | bytes_per_getc equ (1 << bytes_per_getc_lg2) |
26 | secs_per_getc equ bytes_per_getc/SECTOR_SIZE |
27 | MAX_UNGET equ 9 ; Max bytes that can be pushed back |
28 | |
29 | struc getc_file |
30 | gc_file resw 1 ; File pointer |
31 | gc_bufbytes resw 1 ; Bytes left in buffer |
32 | gc_bufdata resw 1 ; Pointer to data in buffer |
33 | gc_unget_cnt resb 1 ; Character pushed back count |
34 | gc_unget_buf resb MAX_UNGET ; Character pushed back buffer |
35 | endstruc |
36 | getc_file_lg2 equ 4 ; Size of getc_file as a power of 2 |
37 | |
38 | %ifndef DEPEND |
39 | %if (getc_file_size != (1 << getc_file_lg2)) |
40 | %error "getc_file_size != (1 << getc_file_lg2)" |
41 | %endif |
42 | %endif |
43 | |
44 | ; |
45 | ; open,getc: Load a file a character at a time for parsing in a manner |
46 | ; similar to the C library getc routine. |
47 | ; Up to MAX_GETC files can be open at the same time, |
48 | ; they are accessed in a stack-like fashion. |
49 | ; |
50 | ; All routines assume CS == DS. |
51 | ; |
52 | ; open: Input: mangled filename in DS:DI |
53 | ; Output: ZF set on file not found or zero length |
54 | ; |
55 | ; openfd: Input: file handle in SI, file size in EAX |
56 | ; Output: ZF set on getc stack overflow |
57 | ; |
58 | ; getc: Output: CF set on end of file |
59 | ; Character loaded in AL |
60 | ; |
61 | ; close: Output: CF set if nothing open |
62 | ; |
63 | open: |
64 | call searchdir |
65 | jz openfd.ret |
66 | openfd: |
67 | push bx |
68 | |
69 | mov bx,[CurrentGetC] |
70 | sub bx,getc_file_size |
71 | cmp bx,GetCStack |
72 | jb .stack_full ; Excessive nesting |
73 | mov [CurrentGetC],bx |
74 | |
75 | mov [bx+gc_file],si ; File pointer |
76 | xor ax,ax |
77 | mov [bx+gc_bufbytes],ax ; Buffer empty |
78 | mov [bx+gc_unget_cnt],al ; ungetc buffer empty |
79 | |
80 | inc ax ; ZF <- 0 |
81 | pop bx |
82 | .ret: ret |
83 | |
84 | .stack_full: |
85 | call close_file |
86 | xor ax,ax ; ZF <- 1 |
87 | pop bx |
88 | ret |
89 | |
90 | getc: |
91 | push bx |
92 | push si |
93 | push di |
94 | push es |
95 | |
96 | mov di,[CurrentGetC] |
97 | movzx bx,byte [di+gc_unget_cnt] |
98 | and bx,bx |
99 | jnz .have_unget |
100 | |
101 | mov si,real_mode_seg ; Borrow the real_mode_seg |
102 | mov es,si |
103 | |
104 | .got_data: |
105 | sub word [di+gc_bufbytes],1 |
106 | jc .get_data ; Was it zero already? |
107 | mov si,[di+gc_bufdata] |
108 | mov al,[es:si] |
109 | inc si |
110 | mov [di+gc_bufdata],si |
111 | .done: |
112 | clc |
113 | .ret: |
114 | pop es |
115 | pop di |
116 | pop si |
117 | pop bx |
118 | ret |
119 | .have_unget: |
120 | dec bx |
121 | mov al,[di+bx+gc_unget_buf] |
122 | mov [di+gc_unget_cnt],bl |
123 | jmp .done |
124 | |
125 | .get_data: |
126 | pushad |
127 | ; Compute start of buffer |
128 | mov bx,di |
129 | sub bx,GetCStack |
130 | shl bx,bytes_per_getc_lg2-getc_file_lg2 |
131 | |
132 | mov [di+gc_bufdata],bx |
133 | mov si,[di+gc_file] |
134 | and si,si |
135 | mov [di+gc_bufbytes],si ; In case SI == 0 |
136 | jz .empty |
137 | mov cx,bytes_per_getc >> SECTOR_SHIFT |
138 | call getfssec |
139 | mov [di+gc_bufbytes],cx |
140 | mov [di+gc_file],si |
141 | jcxz .empty |
142 | popad |
143 | TRACER 'd' |
144 | jmp .got_data |
145 | |
146 | .empty: |
147 | TRACER 'e' |
148 | ; [di+gc_bufbytes] is zero already, thus we will continue |
149 | ; to get EOF on any further attempts to read the file. |
150 | popad |
151 | xor al,al ; Return a predictable zero |
152 | stc |
153 | jmp .ret |
154 | |
155 | ; |
156 | ; This is similar to getc, except that we read up to CX bytes and |
157 | ; store them in ES:DI. Eventually this could get optimized... |
158 | ; |
159 | ; On return, CX and DI are adjusted by the number of bytes actually read. |
160 | ; |
161 | readc: |
162 | push ax |
163 | .loop: |
164 | call getc |
165 | jc .out |
166 | stosb |
167 | loop .loop |
168 | .out: |
169 | pop ax |
170 | ret |
171 | |
172 | ; |
173 | ; close: close the top of the getc stack |
174 | ; |
175 | close: |
176 | push bx |
177 | push si |
178 | mov bx,[CurrentGetC] |
179 | mov si,[bx+gc_file] |
180 | call close_file |
181 | add bx,getc_file_size |
182 | mov [CurrentGetC],bx |
183 | pop si |
184 | pop bx |
185 | ret |
186 | |
187 | ; |
188 | ; ungetc: Push a character (in AL) back into the getc buffer |
189 | ; Note: if more than MAX_UNGET bytes are pushed back, all |
190 | ; hell will break loose. |
191 | ; |
192 | ungetc: |
193 | push di |
194 | push bx |
195 | mov di,[CurrentGetC] |
196 | movzx bx,[di+gc_unget_cnt] |
197 | mov [bx+di+gc_unget_buf],al |
198 | inc bx |
199 | mov [di+gc_unget_cnt],bl |
200 | pop bx |
201 | pop di |
202 | ret |
203 | |
204 | ; |
205 | ; skipspace: Skip leading whitespace using "getc". If we hit end-of-line |
206 | ; or end-of-file, return with carry set; ZF = true of EOF |
207 | ; ZF = false for EOLN; otherwise CF = ZF = 0. |
208 | ; |
209 | ; Otherwise AL = first character after whitespace |
210 | ; |
211 | skipspace: |
212 | .loop: call getc |
213 | jc .eof |
214 | cmp al,1Ah ; DOS EOF |
215 | je .eof |
216 | cmp al,0Ah |
217 | je .eoln |
218 | cmp al,' ' |
219 | jbe .loop |
220 | ret ; CF = ZF = 0 |
221 | .eof: cmp al,al ; Set ZF |
222 | stc ; Set CF |
223 | ret |
224 | .eoln: add al,0FFh ; Set CF, clear ZF |
225 | ret |
226 | |
227 | ; |
228 | ; getint: Load an integer from the getc file. |
229 | ; Return CF if error; otherwise return integer in EBX |
230 | ; |
231 | getint: |
232 | mov di,NumBuf |
233 | .getnum: cmp di,NumBufEnd ; Last byte in NumBuf |
234 | jae .loaded |
235 | push di |
236 | call getc |
237 | pop di |
238 | jc .loaded |
239 | stosb |
240 | cmp al,'-' |
241 | jnb .getnum |
242 | call ungetc ; Unget non-numeric |
243 | .loaded: mov byte [di],0 |
244 | mov si,NumBuf |
245 | ; Fall through to parseint |
246 | ; |
247 | ; parseint: Convert an integer to a number in EBX |
248 | ; Get characters from string in DS:SI |
249 | ; Return CF on error |
250 | ; DS:SI points to first character after number |
251 | ; |
252 | ; Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+[KMG] |
253 | ; |
254 | parseint: |
255 | push eax |
256 | push ecx |
257 | push bp |
258 | xor eax,eax ; Current digit (keep eax == al) |
259 | mov ebx,eax ; Accumulator |
260 | mov ecx,ebx ; Base |
261 | xor bp,bp ; Used for negative flag |
262 | .begin: lodsb |
263 | cmp al,'-' |
264 | jne .not_minus |
265 | xor bp,1 ; Set unary minus flag |
266 | jmp short .begin |
267 | .not_minus: |
268 | cmp al,'0' |
269 | jb .err |
270 | je .octhex |
271 | cmp al,'9' |
272 | ja .err |
273 | mov cl,10 ; Base = decimal |
274 | jmp short .foundbase |
275 | .octhex: |
276 | lodsb |
277 | cmp al,'0' |
278 | jb .km ; Value is zero |
279 | or al,20h ; Downcase |
280 | cmp al,'x' |
281 | je .ishex |
282 | cmp al,'7' |
283 | ja .err |
284 | mov cl,8 ; Base = octal |
285 | jmp short .foundbase |
286 | .ishex: |
287 | mov al,'0' ; No numeric value accrued yet |
288 | mov cl,16 ; Base = hex |
289 | .foundbase: |
290 | call unhexchar |
291 | jc .km ; Not a (hex) digit |
292 | cmp al,cl |
293 | jae .km ; Invalid for base |
294 | imul ebx,ecx ; Multiply accumulated by base |
295 | add ebx,eax ; Add current digit |
296 | lodsb |
297 | jmp short .foundbase |
298 | .km: |
299 | dec si ; Back up to last non-numeric |
300 | lodsb |
301 | or al,20h |
302 | cmp al,'k' |
303 | je .isk |
304 | cmp al,'m' |
305 | je .ism |
306 | cmp al,'g' |
307 | je .isg |
308 | dec si ; Back up |
309 | .fini: and bp,bp |
310 | jz .ret ; CF=0! |
311 | neg ebx ; Value was negative |
312 | .done: clc |
313 | .ret: pop bp |
314 | pop ecx |
315 | pop eax |
316 | ret |
317 | .err: stc |
318 | jmp short .ret |
319 | .isg: shl ebx,10 ; * 2^30 |
320 | .ism: shl ebx,10 ; * 2^20 |
321 | .isk: shl ebx,10 ; * 2^10 |
322 | jmp .fini |
323 | |
324 | section .bss1 |
325 | alignb 4 |
326 | NumBuf resb 15 ; Buffer to load number |
327 | NumBufEnd resb 1 ; Last byte in NumBuf |
328 | |
329 | GetCStack resb getc_file_size*MAX_GETC |
330 | .end equ $ |
331 | |
332 | section .data |
333 | CurrentGetC dw GetCStack.end ; GetCStack empty |
334 | |
335 | ; |
336 | ; unhexchar: Convert a hexadecimal digit in AL to the equivalent number; |
337 | ; return CF=1 if not a hex digit |
338 | ; |
339 | section .text |
340 | unhexchar: |
341 | cmp al,'0' |
342 | jb .ret ; If failure, CF == 1 already |
343 | cmp al,'9' |
344 | ja .notdigit |
345 | sub al,'0' ; CF <- 0 |
346 | ret |
347 | .notdigit: or al,20h ; upper case -> lower case |
348 | cmp al,'a' |
349 | jb .ret ; If failure, CF == 1 already |
350 | cmp al,'f' |
351 | ja .err |
352 | sub al,'a'-10 ; CF <- 0 |
353 | ret |
354 | .err: stc |
355 | .ret: ret |
356 | |
357 | ; |
358 | ; |
359 | ; getline: Get a command line, converting control characters to spaces |
360 | ; and collapsing streches to one; a space is appended to the |
361 | ; end of the string, unless the line is empty. |
362 | ; The line is terminated by ^J, ^Z or EOF and is written |
363 | ; to ES:DI. On return, DI points to first char after string. |
364 | ; CF is set if we hit EOF. |
365 | ; |
366 | getline: |
367 | call skipspace |
368 | mov dl,1 ; Empty line -> empty string. |
369 | jz .eof ; eof |
370 | jc .eoln ; eoln |
371 | call ungetc |
372 | .fillloop: push dx |
373 | push di |
374 | call getc |
375 | pop di |
376 | pop dx |
377 | jc .ret ; CF set! |
378 | cmp al,' ' |
379 | jna .ctrl |
380 | xor dx,dx |
381 | .store: stosb |
382 | jmp short .fillloop |
383 | .ctrl: cmp al,10 |
384 | je .ret ; CF clear! |
385 | cmp al,26 |
386 | je .eof |
387 | and dl,dl |
388 | jnz .fillloop ; Ignore multiple spaces |
389 | mov al,' ' ; Ctrl -> space |
390 | inc dx |
391 | jmp short .store |
392 | .eoln: clc ; End of line is not end of file |
393 | jmp short .ret |
394 | .eof: stc |
395 | .ret: pushf ; We want the last char to be space! |
396 | and dl,dl |
397 | jnz .xret |
398 | mov al,' ' |
399 | stosb |
400 | .xret: popf |
401 | ret |
402 | |
403 | ; |
404 | ; parseint_esdi: |
405 | ; Same as parseint, but takes the input in ES:DI |
406 | ; |
407 | parseint_esdi: |
408 | push ds |
409 | push es |
410 | pop ds |
411 | xchg si,di |
412 | call parseint |
413 | xchg si,di |
414 | pop ds |
415 | ret |