291 lines
7.0 KiB
PHP
291 lines
7.0 KiB
PHP
;; $Id: getc.inc,v 1.6 2004/12/17 06:42:01 hpa Exp $
|
|
;; -----------------------------------------------------------------------
|
|
;;
|
|
;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
|
|
;;
|
|
;; 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
|
|
;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
|
|
;; Boston MA 02111-1307, USA; either version 2 of the License, or
|
|
;; (at your option) any later version; incorporated herein by reference.
|
|
;;
|
|
;; -----------------------------------------------------------------------
|
|
|
|
;;
|
|
;; getc.inc
|
|
;;
|
|
;; Simple file handling library (open, getc, ungetc)
|
|
;;
|
|
|
|
;
|
|
; 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.
|
|
;
|
|
; 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
|
|
;
|
|
; getc: Output: CF set on end of file
|
|
; Character loaded in AL
|
|
;
|
|
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
|
|
.ret: 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
|
|
pop es
|
|
mov bx,getcbuf
|
|
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
|
|
|
|
;
|
|
; 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.
|
|
;
|
|
ungetc:
|
|
mov si,[FPtr]
|
|
dec si
|
|
mov [si],al
|
|
mov [FPtr],si
|
|
inc dword [FBytes]
|
|
ret
|
|
|
|
;
|
|
; skipspace: Skip leading whitespace using "getc". If we hit end-of-line
|
|
; or end-of-file, return with carry set; ZF = true of EOF
|
|
; ZF = false for EOLN; otherwise CF = ZF = 0.
|
|
;
|
|
; Otherwise AL = first character after whitespace
|
|
;
|
|
skipspace:
|
|
.loop: call getc
|
|
jc .eof
|
|
cmp al,1Ah ; DOS EOF
|
|
je .eof
|
|
cmp al,0Ah
|
|
je .eoln
|
|
cmp al,' '
|
|
jbe .loop
|
|
ret ; CF = ZF = 0
|
|
.eof: cmp al,al ; Set ZF
|
|
stc ; Set CF
|
|
ret
|
|
.eoln: add al,0FFh ; Set CF, clear ZF
|
|
ret
|
|
|
|
;
|
|
; getint: Load an integer from the getc file.
|
|
; Return CF if error; otherwise return integer in EBX
|
|
;
|
|
getint:
|
|
mov di,NumBuf
|
|
.getnum: cmp di,NumBufEnd ; Last byte in NumBuf
|
|
jae .loaded
|
|
push di
|
|
call getc
|
|
pop di
|
|
jc .loaded
|
|
stosb
|
|
cmp al,'-'
|
|
jnb .getnum
|
|
call ungetc ; Unget non-numeric
|
|
.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
|
|
;
|
|
parseint:
|
|
push eax
|
|
push ecx
|
|
push bp
|
|
xor eax,eax ; Current digit (keep eax == al)
|
|
mov ebx,eax ; Accumulator
|
|
mov ecx,ebx ; Base
|
|
xor bp,bp ; Used for negative flag
|
|
.begin: lodsb
|
|
cmp al,'-'
|
|
jne .not_minus
|
|
xor bp,1 ; Set unary minus flag
|
|
jmp short .begin
|
|
.not_minus:
|
|
cmp al,'0'
|
|
jb .err
|
|
je .octhex
|
|
cmp al,'9'
|
|
ja .err
|
|
mov cl,10 ; Base = decimal
|
|
jmp short .foundbase
|
|
.octhex:
|
|
lodsb
|
|
cmp al,'0'
|
|
jb .km ; Value is zero
|
|
or al,20h ; Downcase
|
|
cmp al,'x'
|
|
je .ishex
|
|
cmp al,'7'
|
|
ja .err
|
|
mov cl,8 ; Base = octal
|
|
jmp short .foundbase
|
|
.ishex:
|
|
mov al,'0' ; No numeric value accrued yet
|
|
mov cl,16 ; Base = hex
|
|
.foundbase:
|
|
call unhexchar
|
|
jc .km ; Not a (hex) digit
|
|
cmp al,cl
|
|
jae .km ; Invalid for base
|
|
imul ebx,ecx ; Multiply accumulated by base
|
|
add ebx,eax ; Add current digit
|
|
lodsb
|
|
jmp short .foundbase
|
|
.km:
|
|
dec si ; Back up to last non-numeric
|
|
lodsb
|
|
or al,20h
|
|
cmp al,'k'
|
|
je .isk
|
|
cmp al,'m'
|
|
je .ism
|
|
dec si ; Back up
|
|
.fini: and bp,bp
|
|
jz .ret ; CF=0!
|
|
neg ebx ; Value was negative
|
|
.done: clc
|
|
.ret: pop bp
|
|
pop ecx
|
|
pop eax
|
|
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
|
|
|
|
|
|
section .bss
|
|
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
|
|
|
|
;
|
|
; unhexchar: Convert a hexadecimal digit in AL to the equivalent number;
|
|
; return CF=1 if not a hex digit
|
|
;
|
|
section .text
|
|
unhexchar:
|
|
cmp al,'0'
|
|
jb .ret ; If failure, CF == 1 already
|
|
cmp al,'9'
|
|
ja .notdigit
|
|
sub al,'0' ; CF <- 0
|
|
ret
|
|
.notdigit: or al,20h ; upper case -> lower case
|
|
cmp al,'a'
|
|
jb .ret ; If failure, CF == 1 already
|
|
cmp al,'f'
|
|
ja .err
|
|
sub al,'a'-10 ; CF <- 0
|
|
ret
|
|
.err: stc
|
|
.ret: ret
|
|
|
|
;
|
|
;
|
|
; getline: Get a command line, converting control characters to spaces
|
|
; and collapsing streches to one; a space is appended to the
|
|
; end of the string, unless the line is empty.
|
|
; The line is terminated by ^J, ^Z or EOF and is written
|
|
; to ES:DI. On return, DI points to first char after string.
|
|
; CF is set if we hit EOF.
|
|
;
|
|
getline:
|
|
call skipspace
|
|
mov dl,1 ; Empty line -> empty string.
|
|
jz .eof ; eof
|
|
jc .eoln ; eoln
|
|
call ungetc
|
|
.fillloop: push dx
|
|
push di
|
|
call getc
|
|
pop di
|
|
pop dx
|
|
jc .ret ; CF set!
|
|
cmp al,' '
|
|
jna .ctrl
|
|
xor dx,dx
|
|
.store: stosb
|
|
jmp short .fillloop
|
|
.ctrl: cmp al,10
|
|
je .ret ; CF clear!
|
|
cmp al,26
|
|
je .eof
|
|
and dl,dl
|
|
jnz .fillloop ; Ignore multiple spaces
|
|
mov al,' ' ; Ctrl -> space
|
|
inc dx
|
|
jmp short .store
|
|
.eoln: clc ; End of line is not end of file
|
|
jmp short .ret
|
|
.eof: stc
|
|
.ret: pushf ; We want the last char to be space!
|
|
and dl,dl
|
|
jnz .xret
|
|
mov al,' '
|
|
stosb
|
|
.xret: popf
|
|
ret
|