--- trunk/mkinitrd-magellan/isolinux/getc.inc 2010/08/19 08:27:19 1132 +++ trunk/mkinitrd-magellan/isolinux/getc.inc 2010/08/19 09:50:43 1133 @@ -1,7 +1,7 @@ -;; $Id: getc.inc,v 1.1 2007-09-01 22:44:04 niro Exp $ ;; ----------------------------------------------------------------------- -;; -;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved +;; +;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved +;; Copyright 2009 Intel Corporation; author: H. Peter Anvin ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -16,80 +16,189 @@ ;; ;; Simple file handling library (open, getc, ungetc) ;; +;; WARNING: This interface uses the real_mode_seg/comboot_seg. +;; + +MAX_GETC_LG2 equ 4 ; Max number of file nesting +MAX_GETC equ (1 << MAX_GETC_LG2) +bytes_per_getc_lg2 equ 16-MAX_GETC_LG2 +bytes_per_getc equ (1 << bytes_per_getc_lg2) +secs_per_getc equ bytes_per_getc/SECTOR_SIZE +MAX_UNGET equ 9 ; Max bytes that can be pushed back + + struc getc_file +gc_file resw 1 ; File pointer +gc_bufbytes resw 1 ; Bytes left in buffer +gc_bufdata resw 1 ; Pointer to data in buffer +gc_unget_cnt resb 1 ; Character pushed back count +gc_unget_buf resb MAX_UNGET ; Character pushed back buffer + endstruc +getc_file_lg2 equ 4 ; Size of getc_file as a power of 2 + +%ifndef DEPEND +%if (getc_file_size != (1 << getc_file_lg2)) +%error "getc_file_size != (1 << getc_file_lg2)" +%endif +%endif ; ; open,getc: Load a file a character at a time for parsing in a manner -; similar to the C library getc routine. Only one simultaneous -; use is supported. Note: "open" trashes the trackbuf. +; similar to the C library getc routine. +; Up to MAX_GETC files can be open at the same time, +; they are accessed in a stack-like fashion. +; +; All routines assume CS == DS. ; ; open: Input: mangled filename in DS:DI ; Output: ZF set on file not found or zero length ; -; openfd: Input: file handle in SI -; Output: none +; openfd: Input: file handle in SI, file size in EAX +; Output: ZF set on getc stack overflow ; ; getc: Output: CF set on end of file ; Character loaded in AL ; +; close: Output: CF set if nothing open +; open: call searchdir jz openfd.ret openfd: - pushf - mov [FBytes],ax - mov [FBytes+2],dx - mov eax,[FBytes] - add eax,SECTOR_SIZE-1 - shr eax,SECTOR_SHIFT - mov [FSectors],eax ; Number of sectors - mov [FNextClust],si ; Cluster pointer - mov ax,[EndOfGetCBuf] ; Pointer at end of buffer -> - mov [FPtr],ax ; nothing loaded yet - popf ; Restore no ZF + push bx + + mov bx,[CurrentGetC] + sub bx,getc_file_size + cmp bx,GetCStack + jb .stack_full ; Excessive nesting + mov [CurrentGetC],bx + + mov [bx+gc_file],si ; File pointer + xor ax,ax + mov [bx+gc_bufbytes],ax ; Buffer empty + mov [bx+gc_unget_cnt],al ; ungetc buffer empty + + inc ax ; ZF <- 0 + pop bx .ret: ret +.stack_full: + call close_file + xor ax,ax ; ZF <- 1 + pop bx + ret + getc: - stc ; If we exit here -> EOF - mov ecx,[FBytes] - jecxz .ret - mov si,[FPtr] - cmp si,[EndOfGetCBuf] - jb .loaded - ; Buffer empty -- load another set - mov ecx,[FSectors] - cmp ecx,trackbufsize >> SECTOR_SHIFT - jna .oksize - mov ecx,trackbufsize >> SECTOR_SHIFT -.oksize: sub [FSectors],ecx ; Reduce remaining clusters - mov si,[FNextClust] - push es ; ES may be != DS, save old ES - push ds + push bx + push si + push di + push es + + mov di,[CurrentGetC] + movzx bx,byte [di+gc_unget_cnt] + and bx,bx + jnz .have_unget + + mov si,real_mode_seg ; Borrow the real_mode_seg + mov es,si + +.got_data: + sub word [di+gc_bufbytes],1 + jc .get_data ; Was it zero already? + mov si,[di+gc_bufdata] + mov al,[es:si] + inc si + mov [di+gc_bufdata],si +.done: + clc +.ret: pop es - mov bx,getcbuf + pop di + pop si + pop bx + ret +.have_unget: + dec bx + mov al,[di+bx+gc_unget_buf] + mov [di+gc_unget_cnt],bl + jmp .done + +.get_data: + pushad + ; Compute start of buffer + mov bx,di + sub bx,GetCStack + shl bx,bytes_per_getc_lg2-getc_file_lg2 + + mov [di+gc_bufdata],bx + mov si,[di+gc_file] + and si,si + mov [di+gc_bufbytes],si ; In case SI == 0 + jz .empty + mov cx,bytes_per_getc >> SECTOR_SHIFT + call getfssec + mov [di+gc_bufbytes],cx + mov [di+gc_file],si + jcxz .empty + popad + TRACER 'd' + jmp .got_data + +.empty: + TRACER 'e' + ; [di+gc_bufbytes] is zero already, thus we will continue + ; to get EOF on any further attempts to read the file. + popad + xor al,al ; Return a predictable zero + stc + jmp .ret + +; +; This is similar to getc, except that we read up to CX bytes and +; store them in ES:DI. Eventually this could get optimized... +; +; On return, CX and DI are adjusted by the number of bytes actually read. +; +readc: + push ax +.loop: + call getc + jc .out + stosb + loop .loop +.out: + pop ax + ret + +; +; close: close the top of the getc stack +; +close: push bx - call getfssec ; Load a trackbuf full of data - mov [FNextClust],si ; Store new next pointer - pop si ; SI -> newly loaded data - pop es ; Restore ES -.loaded: lodsb ; Load a byte, increment SI - mov [FPtr],si ; Update next byte pointer - dec dword [FBytes] ; Update bytes left counter - clc ; Not EOF -.ret: ret + push si + mov bx,[CurrentGetC] + mov si,[bx+gc_file] + call close_file + add bx,getc_file_size + mov [CurrentGetC],bx + pop si + pop bx + ret ; ; ungetc: Push a character (in AL) back into the getc buffer -; Note: if more than one byte is pushed back, this may cause -; bytes to be written below the getc buffer boundary. If there -; is a risk for this to occur, the getcbuf base address should -; be moved up. +; Note: if more than MAX_UNGET bytes are pushed back, all +; hell will break loose. ; ungetc: - mov si,[FPtr] - dec si - mov [si],al - mov [FPtr],si - inc dword [FBytes] + push di + push bx + mov di,[CurrentGetC] + movzx bx,[di+gc_unget_cnt] + mov [bx+di+gc_unget_buf],al + inc bx + mov [di+gc_unget_cnt],bl + pop bx + pop di ret ; @@ -134,14 +243,13 @@ .loaded: mov byte [di],0 mov si,NumBuf ; Fall through to parseint - ; ; parseint: Convert an integer to a number in EBX ; Get characters from string in DS:SI ; Return CF on error ; DS:SI points to first character after number ; -; Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+K, val+M +; Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+[KMG] ; parseint: push eax @@ -182,7 +290,7 @@ call unhexchar jc .km ; Not a (hex) digit cmp al,cl - jae .km ; Invalid for base + jae .km ; Invalid for base imul ebx,ecx ; Multiply accumulated by base add ebx,eax ; Add current digit lodsb @@ -195,6 +303,8 @@ je .isk cmp al,'m' je .ism + cmp al,'g' + je .isg dec si ; Back up .fini: and bp,bp jz .ret ; CF=0! @@ -206,20 +316,21 @@ ret .err: stc jmp short .ret -.isk: shl ebx,10 ; x 2^10 - jmp short .done -.ism: shl ebx,20 ; x 2^20 - jmp short .done +.isg: shl ebx,10 ; * 2^30 +.ism: shl ebx,10 ; * 2^20 +.isk: shl ebx,10 ; * 2^10 + jmp .fini - - section .bss + section .bss1 alignb 4 NumBuf resb 15 ; Buffer to load number NumBufEnd resb 1 ; Last byte in NumBuf -FBytes resd 1 ; Number of bytes left in getc file -FSectors resd 1 ; Number of sectors in getc file -FNextClust resw 1 ; Pointer to next cluster in d:o -FPtr resw 1 ; Pointer to next char in buffer + +GetCStack resb getc_file_size*MAX_GETC +.end equ $ + + section .data +CurrentGetC dw GetCStack.end ; GetCStack empty ; ; unhexchar: Convert a hexadecimal digit in AL to the equivalent number; @@ -240,7 +351,7 @@ ja .err sub al,'a'-10 ; CF <- 0 ret -.err: stc +.err: stc .ret: ret ; @@ -288,3 +399,17 @@ stosb .xret: popf ret + +; +; parseint_esdi: +; Same as parseint, but takes the input in ES:DI +; +parseint_esdi: + push ds + push es + pop ds + xchg si,di + call parseint + xchg si,di + pop ds + ret