|
;; $Id: getc.inc,v 1.1 2007-09-01 22:44:04 niro Exp $ |
|
1 |
;; ----------------------------------------------------------------------- |
;; ----------------------------------------------------------------------- |
2 |
;; |
;; |
3 |
;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved |
;; 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 |
;; 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 |
;; it under the terms of the GNU General Public License as published by |
16 |
;; |
;; |
17 |
;; Simple file handling library (open, getc, ungetc) |
;; 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 |
; open,getc: Load a file a character at a time for parsing in a manner |
46 |
; similar to the C library getc routine. Only one simultaneous |
; similar to the C library getc routine. |
47 |
; use is supported. Note: "open" trashes the trackbuf. |
; 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 |
; open: Input: mangled filename in DS:DI |
53 |
; Output: ZF set on file not found or zero length |
; Output: ZF set on file not found or zero length |
54 |
; |
; |
55 |
; openfd: Input: file handle in SI |
; openfd: Input: file handle in SI, file size in EAX |
56 |
; Output: none |
; Output: ZF set on getc stack overflow |
57 |
; |
; |
58 |
; getc: Output: CF set on end of file |
; getc: Output: CF set on end of file |
59 |
; Character loaded in AL |
; Character loaded in AL |
60 |
; |
; |
61 |
|
; close: Output: CF set if nothing open |
62 |
|
; |
63 |
open: |
open: |
64 |
call searchdir |
call searchdir |
65 |
jz openfd.ret |
jz openfd.ret |
66 |
openfd: |
openfd: |
67 |
pushf |
push bx |
68 |
mov [FBytes],ax |
|
69 |
mov [FBytes+2],dx |
mov bx,[CurrentGetC] |
70 |
mov eax,[FBytes] |
sub bx,getc_file_size |
71 |
add eax,SECTOR_SIZE-1 |
cmp bx,GetCStack |
72 |
shr eax,SECTOR_SHIFT |
jb .stack_full ; Excessive nesting |
73 |
mov [FSectors],eax ; Number of sectors |
mov [CurrentGetC],bx |
74 |
mov [FNextClust],si ; Cluster pointer |
|
75 |
mov ax,[EndOfGetCBuf] ; Pointer at end of buffer -> |
mov [bx+gc_file],si ; File pointer |
76 |
mov [FPtr],ax ; nothing loaded yet |
xor ax,ax |
77 |
popf ; Restore no ZF |
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 |
.ret: ret |
83 |
|
|
84 |
|
.stack_full: |
85 |
|
call close_file |
86 |
|
xor ax,ax ; ZF <- 1 |
87 |
|
pop bx |
88 |
|
ret |
89 |
|
|
90 |
getc: |
getc: |
91 |
stc ; If we exit here -> EOF |
push bx |
92 |
mov ecx,[FBytes] |
push si |
93 |
jecxz .ret |
push di |
94 |
mov si,[FPtr] |
push es |
95 |
cmp si,[EndOfGetCBuf] |
|
96 |
jb .loaded |
mov di,[CurrentGetC] |
97 |
; Buffer empty -- load another set |
movzx bx,byte [di+gc_unget_cnt] |
98 |
mov ecx,[FSectors] |
and bx,bx |
99 |
cmp ecx,trackbufsize >> SECTOR_SHIFT |
jnz .have_unget |
100 |
jna .oksize |
|
101 |
mov ecx,trackbufsize >> SECTOR_SHIFT |
mov si,real_mode_seg ; Borrow the real_mode_seg |
102 |
.oksize: sub [FSectors],ecx ; Reduce remaining clusters |
mov es,si |
103 |
mov si,[FNextClust] |
|
104 |
push es ; ES may be != DS, save old ES |
.got_data: |
105 |
push ds |
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 |
pop es |
115 |
mov bx,getcbuf |
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 |
push bx |
177 |
call getfssec ; Load a trackbuf full of data |
push si |
178 |
mov [FNextClust],si ; Store new next pointer |
mov bx,[CurrentGetC] |
179 |
pop si ; SI -> newly loaded data |
mov si,[bx+gc_file] |
180 |
pop es ; Restore ES |
call close_file |
181 |
.loaded: lodsb ; Load a byte, increment SI |
add bx,getc_file_size |
182 |
mov [FPtr],si ; Update next byte pointer |
mov [CurrentGetC],bx |
183 |
dec dword [FBytes] ; Update bytes left counter |
pop si |
184 |
clc ; Not EOF |
pop bx |
185 |
.ret: ret |
ret |
186 |
|
|
187 |
; |
; |
188 |
; ungetc: Push a character (in AL) back into the getc buffer |
; ungetc: Push a character (in AL) back into the getc buffer |
189 |
; Note: if more than one byte is pushed back, this may cause |
; Note: if more than MAX_UNGET bytes are pushed back, all |
190 |
; bytes to be written below the getc buffer boundary. If there |
; hell will break loose. |
|
; is a risk for this to occur, the getcbuf base address should |
|
|
; be moved up. |
|
191 |
; |
; |
192 |
ungetc: |
ungetc: |
193 |
mov si,[FPtr] |
push di |
194 |
dec si |
push bx |
195 |
mov [si],al |
mov di,[CurrentGetC] |
196 |
mov [FPtr],si |
movzx bx,[di+gc_unget_cnt] |
197 |
inc dword [FBytes] |
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 |
ret |
203 |
|
|
204 |
; |
; |
243 |
.loaded: mov byte [di],0 |
.loaded: mov byte [di],0 |
244 |
mov si,NumBuf |
mov si,NumBuf |
245 |
; Fall through to parseint |
; Fall through to parseint |
|
|
|
246 |
; |
; |
247 |
; parseint: Convert an integer to a number in EBX |
; parseint: Convert an integer to a number in EBX |
248 |
; Get characters from string in DS:SI |
; Get characters from string in DS:SI |
249 |
; Return CF on error |
; Return CF on error |
250 |
; DS:SI points to first character after number |
; DS:SI points to first character after number |
251 |
; |
; |
252 |
; Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+K, val+M |
; Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+[KMG] |
253 |
; |
; |
254 |
parseint: |
parseint: |
255 |
push eax |
push eax |
290 |
call unhexchar |
call unhexchar |
291 |
jc .km ; Not a (hex) digit |
jc .km ; Not a (hex) digit |
292 |
cmp al,cl |
cmp al,cl |
293 |
jae .km ; Invalid for base |
jae .km ; Invalid for base |
294 |
imul ebx,ecx ; Multiply accumulated by base |
imul ebx,ecx ; Multiply accumulated by base |
295 |
add ebx,eax ; Add current digit |
add ebx,eax ; Add current digit |
296 |
lodsb |
lodsb |
303 |
je .isk |
je .isk |
304 |
cmp al,'m' |
cmp al,'m' |
305 |
je .ism |
je .ism |
306 |
|
cmp al,'g' |
307 |
|
je .isg |
308 |
dec si ; Back up |
dec si ; Back up |
309 |
.fini: and bp,bp |
.fini: and bp,bp |
310 |
jz .ret ; CF=0! |
jz .ret ; CF=0! |
316 |
ret |
ret |
317 |
.err: stc |
.err: stc |
318 |
jmp short .ret |
jmp short .ret |
319 |
.isk: shl ebx,10 ; x 2^10 |
.isg: shl ebx,10 ; * 2^30 |
320 |
jmp short .done |
.ism: shl ebx,10 ; * 2^20 |
321 |
.ism: shl ebx,20 ; x 2^20 |
.isk: shl ebx,10 ; * 2^10 |
322 |
jmp short .done |
jmp .fini |
323 |
|
|
324 |
|
section .bss1 |
|
section .bss |
|
325 |
alignb 4 |
alignb 4 |
326 |
NumBuf resb 15 ; Buffer to load number |
NumBuf resb 15 ; Buffer to load number |
327 |
NumBufEnd resb 1 ; Last byte in NumBuf |
NumBufEnd resb 1 ; Last byte in NumBuf |
328 |
FBytes resd 1 ; Number of bytes left in getc file |
|
329 |
FSectors resd 1 ; Number of sectors in getc file |
GetCStack resb getc_file_size*MAX_GETC |
330 |
FNextClust resw 1 ; Pointer to next cluster in d:o |
.end equ $ |
331 |
FPtr resw 1 ; Pointer to next char in buffer |
|
332 |
|
section .data |
333 |
|
CurrentGetC dw GetCStack.end ; GetCStack empty |
334 |
|
|
335 |
; |
; |
336 |
; unhexchar: Convert a hexadecimal digit in AL to the equivalent number; |
; unhexchar: Convert a hexadecimal digit in AL to the equivalent number; |
351 |
ja .err |
ja .err |
352 |
sub al,'a'-10 ; CF <- 0 |
sub al,'a'-10 ; CF <- 0 |
353 |
ret |
ret |
354 |
.err: stc |
.err: stc |
355 |
.ret: ret |
.ret: ret |
356 |
|
|
357 |
; |
; |
399 |
stosb |
stosb |
400 |
.xret: popf |
.xret: popf |
401 |
ret |
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 |