| ;; $Id$ |
| ;; ----------------------------------------------------------------------- |
| ;; |
| ;; 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, |
| ;; Bostom 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 open_return |
| openfd: |
| pushf |
| mov [FBytes1],ax |
| mov [FBytes2],dx |
| add ax,[ClustSize] |
| adc dx,byte 0 |
| sub ax,byte 1 |
| sbb dx,byte 0 |
| div word [ClustSize] |
| mov [FClust],ax ; Number of clusters |
| mov [FNextClust],si ; Cluster pointer |
| mov ax,[EndOfGetCBuf] ; Pointer at end of buffer -> |
| mov [FPtr],ax ; nothing loaded yet |
| popf ; Restore no ZF |
| open_return: ret |
| |
| getc: |
| stc ; If we exit here -> EOF |
| mov ecx,[FBytes] |
| jecxz getc_ret |
| mov si,[FPtr] |
| cmp si,[EndOfGetCBuf] |
| jb getc_loaded |
| ; Buffer empty -- load another set |
| mov cx,[FClust] |
| cmp cx,[BufSafe] |
| jna getc_oksize |
| mov cx,[BufSafe] |
| getc_oksize: sub [FClust],cx ; 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 |
| getc_loaded: lodsb ; Load a byte, increment SI |
| mov [FPtr],si ; Update next byte pointer |
| dec dword [FBytes] ; Update bytes left counter |
| clc ; Not EOF |
| getc_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: |
| skipspace_loop: call getc |
| jc skipspace_eof |
| cmp al,1Ah ; DOS EOF |
| je skipspace_eof |
| cmp al,0Ah |
| je skipspace_eoln |
| cmp al,' ' |
| jbe skipspace_loop |
| ret ; CF = ZF = 0 |
| skipspace_eof: cmp al,al ; Set ZF |
| stc ; Set CF |
| ret |
| skipspace_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 |
| gi_getnum: cmp di,NumBufEnd ; Last byte in NumBuf |
| jae gi_loaded |
| push di |
| call getc |
| pop di |
| jc gi_loaded |
| stosb |
| cmp al,'-' |
| jnb gi_getnum |
| call ungetc ; Unget non-numeric |
| gi_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 |
| pi_begin: lodsb |
| cmp al,'-' |
| jne pi_not_minus |
| xor bp,1 ; Set unary minus flag |
| jmp short pi_begin |
| pi_not_minus: |
| cmp al,'0' |
| jb pi_err |
| je pi_octhex |
| cmp al,'9' |
| ja pi_err |
| mov cl,10 ; Base = decimal |
| jmp short pi_foundbase |
| pi_octhex: |
| lodsb |
| cmp al,'0' |
| jb pi_km ; Value is zero |
| or al,20h ; Downcase |
| cmp al,'x' |
| je pi_ishex |
| cmp al,'7' |
| ja pi_err |
| mov cl,8 ; Base = octal |
| jmp short pi_foundbase |
| pi_ishex: |
| mov al,'0' ; No numeric value accrued yet |
| mov cl,16 ; Base = hex |
| pi_foundbase: |
| call unhexchar |
| jc pi_km ; Not a (hex) digit |
| cmp al,cl |
| jae pi_km ; Invalid for base |
| imul ebx,ecx ; Multiply accumulated by base |
| add ebx,eax ; Add current digit |
| lodsb |
| jmp short pi_foundbase |
| pi_km: |
| dec si ; Back up to last non-numeric |
| lodsb |
| or al,20h |
| cmp al,'k' |
| je pi_isk |
| cmp al,'m' |
| je pi_ism |
| dec si ; Back up |
| pi_fini: and bp,bp |
| jz pi_ret ; CF=0! |
| neg ebx ; Value was negative |
| pi_done: clc |
| pi_ret: pop bp |
| pop ecx |
| pop eax |
| ret |
| pi_err: stc |
| jmp short pi_ret |
| pi_isk: shl ebx,10 ; x 2^10 |
| jmp short pi_done |
| pi_ism: shl ebx,20 ; x 2^20 |
| jmp short pi_done |
| |
| ; |
| ; unhexchar: Convert a hexadecimal digit in AL to the equivalent number; |
| ; return CF=1 if not a hex digit |
| ; |
| unhexchar: |
| cmp al,'0' |
| jb uxc_ret ; If failure, CF == 1 already |
| cmp al,'9' |
| ja uxc_1 |
| sub al,'0' ; CF <- 0 |
| ret |
| uxc_1: or al,20h ; upper case -> lower case |
| cmp al,'a' |
| jb uxc_ret ; If failure, CF == 1 already |
| cmp al,'f' |
| ja uxc_err |
| sub al,'a'-10 ; CF <- 0 |
| ret |
| uxc_err: stc |
| uxc_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 gl_eof ; eof |
| jc gl_eoln ; eoln |
| call ungetc |
| gl_fillloop: push dx |
| push di |
| call getc |
| pop di |
| pop dx |
| jc gl_ret ; CF set! |
| cmp al,' ' |
| jna gl_ctrl |
| xor dx,dx |
| gl_store: stosb |
| jmp short gl_fillloop |
| gl_ctrl: cmp al,10 |
| je gl_ret ; CF clear! |
| cmp al,26 |
| je gl_eof |
| and dl,dl |
| jnz gl_fillloop ; Ignore multiple spaces |
| mov al,' ' ; Ctrl -> space |
| inc dx |
| jmp short gl_store |
| gl_eoln: clc ; End of line is not end of file |
| jmp short gl_ret |
| gl_eof: stc |
| gl_ret: pushf ; We want the last char to be space! |
| and dl,dl |
| jnz gl_xret |
| mov al,' ' |
| stosb |
| gl_xret: popf |
| ret |