1 ;; -----------------------------------------------------------------------
3 ;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
4 ;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
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.
12 ;; -----------------------------------------------------------------------
17 ;; Simple file handling library (open, getc, ungetc)
19 ;; WARNING: This interface uses the real_mode_seg/comboot_seg.
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 MAX_UNGET equ 9 ; Max bytes that can be pushed back
29 gc_file resw 1 ; File pointer
30 gc_bufbytes resw 1 ; Bytes left in buffer
31 gc_bufdata resw 1 ; Pointer to data in buffer
32 gc_unget_cnt resb 1 ; Character pushed back count
33 gc_unget_buf resb MAX_UNGET ; Character pushed back buffer
35 getc_file_lg2 equ 4 ; Size of getc_file as a power of 2
38 %if (getc_file_size != (1 << getc_file_lg2))
39 %error "getc_file_size != (1 << getc_file_lg2)"
44 ; open,getc: Load a file a character at a time for parsing in a manner
45 ; similar to the C library getc routine.
46 ; Up to MAX_GETC files can be open at the same time,
47 ; they are accessed in a stack-like fashion.
49 ; All routines assume CS == DS.
51 ; open: Input: mangled filename in DS:DI
52 ; Output: ZF set on file not found or zero length
54 ; openfd: Input: file handle in SI, file size in EAX
55 ; Output: ZF set on getc stack overflow
57 ; getc: Output: CF set on end of file
58 ; Character loaded in AL
60 ; close: Output: CF set if nothing open
72 jb .stack_full ; Excessive nesting
75 mov [bx+gc_file],si ; File pointer
77 mov [bx+gc_bufbytes],ax ; Buffer empty
78 mov [bx+gc_unget_cnt],al ; ungetc buffer empty
97 movzx bx,byte [di+gc_unget_cnt]
101 mov si,real_mode_seg ; Borrow the real_mode_seg
105 sub word [di+gc_bufbytes],1
106 jc .get_data ; Was it zero already?
107 mov si,[di+gc_bufdata]
110 mov [di+gc_bufdata],si
121 mov al,[di+bx+gc_unget_buf]
122 mov [di+gc_unget_cnt],bl
127 ; Compute start of buffer
130 shl bx,bytes_per_getc_lg2-getc_file_lg2
132 mov [di+gc_bufdata],bx
135 mov [di+gc_bufbytes],si ; In case SI == 0
137 mov cx,bytes_per_getc
139 mov [di+gc_bufbytes],cx
148 ; [di+gc_bufbytes] is zero already, thus we will continue
149 ; to get EOF on any further attempts to read the file.
151 xor al,al ; Return a predictable zero
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...
159 ; On return, CX and DI are adjusted by the number of bytes actually read.
173 ; close: close the top of the getc stack
180 pm_call pm_close_file
181 add bx,getc_file_size
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.
196 movzx bx,[di+gc_unget_cnt]
197 mov [bx+di+gc_unget_buf],al
199 mov [di+gc_unget_cnt],bl
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.
209 ; Otherwise AL = first character after whitespace
221 .eof: cmp al,al ; Set ZF
224 .eoln: add al,0FFh ; Set CF, clear ZF
228 ; getint: Load an integer from the getc file.
229 ; Return CF if error; otherwise return integer in EBX
233 .getnum: cmp di,NumBufEnd ; Last byte in NumBuf
242 call ungetc ; Unget non-numeric
243 .loaded: mov byte [di],0
245 ; Fall through to parseint
247 ; parseint: Convert an integer to a number in EBX
248 ; Get characters from string in DS:SI
250 ; DS:SI points to first character after number
252 ; Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+[KMG]
258 xor eax,eax ; Current digit (keep eax == al)
259 mov ebx,eax ; Accumulator
261 xor bp,bp ; Used for negative flag
265 xor bp,1 ; Set unary minus flag
273 mov cl,10 ; Base = decimal
278 jb .km ; Value is zero
284 mov cl,8 ; Base = octal
287 mov al,'0' ; No numeric value accrued yet
288 mov cl,16 ; Base = hex
291 jc .km ; Not a (hex) digit
293 jae .km ; Invalid for base
294 imul ebx,ecx ; Multiply accumulated by base
295 add ebx,eax ; Add current digit
299 dec si ; Back up to last non-numeric
311 neg ebx ; Value was negative
319 .isg: shl ebx,10 ; * 2^30
320 .ism: shl ebx,10 ; * 2^20
321 .isk: shl ebx,10 ; * 2^10
326 NumBuf resb 15 ; Buffer to load number
327 NumBufEnd resb 1 ; Last byte in NumBuf
329 GetCStack resb getc_file_size*MAX_GETC
333 CurrentGetC dw GetCStack.end ; GetCStack empty
336 ; unhexchar: Convert a hexadecimal digit in AL to the equivalent number;
337 ; return CF=1 if not a hex digit
342 jb .ret ; If failure, CF == 1 already
347 .notdigit: or al,20h ; upper case -> lower case
349 jb .ret ; If failure, CF == 1 already
352 sub al,'a'-10 ; CF <- 0
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.
368 mov dl,1 ; Empty line -> empty string.
388 jnz .fillloop ; Ignore multiple spaces
389 mov al,' ' ; Ctrl -> space
392 .eoln: clc ; End of line is not end of file
395 .ret: pushf ; We want the last char to be space!
405 ; Same as parseint, but takes the input in ES:DI