;*****************************************************************************
;*
;*                            Open Watcom Project
;*
;*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
;*
;*  ========================================================================
;*
;*    This file contains Original Code and/or Modifications of Original
;*    Code as defined in and that are subject to the Sybase Open Watcom
;*    Public License version 1.0 (the 'License'). You may not use this file
;*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
;*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
;*    provided with the Original Code and Modifications, and is also
;*    available at www.sybase.com/developer/opensource.
;*
;*    The Original Code and all software distributed under the License are
;*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
;*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
;*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
;*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
;*    NON-INFRINGEMENT. Please see the License for the specific language
;*    governing rights and limitations under the License.
;*
;*  ========================================================================
;*
;* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
;*               DESCRIBE IT HERE!
;*
;*****************************************************************************


; This module converts a string to long_double
;       void __ZBuf2LD( char *buf, long_double *value );
;
include mdef.inc
include struct.inc

        modstart bufld386

        xdefp   __ZBuf2LD

;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
;<>                                                                   <>
;<>   __ZBuf2LD - convert buffer of significant digits into floating  <>
;<>             void __ZBuf2LD( char *buf, long_double *value )       <>
;<>                                                                   <>
;<>   input:  EAX - address of buffer of significant digits           <>
;<>           EDX - place to store value                              <>
;<>   output: [EDX]        - floating-point number                    <>
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>

        defpe   __ZBuf2LD
        push    EBP             ; save EBP
        push    ESI             ; save ESI
        push    EDI             ; save EDI
        push    ECX             ; save ECX
        push    EBX             ; save EBX
        push    EDX             ; save pointer to result
        mov     ESI,EAX         ; get address of buffer
        sub     EDX,EDX         ; set 96-bit integer to 0
        sub     ECX,ECX         ; ...
        sub     EBP,EBP         ; ...
        sub     EAX,EAX         ; zero out EAX
        _loop                   ; loop (convert digits into 64-bit int)
          mov   AL,[ESI]        ; - get next digit
          cmp   AL,0            ; - quit if at end of buffer
          _quif e               ; - . . .

;[]  multiply current value in EDX:ECX:EBP by 10

          mov   EDI,EDX         ; - save current value
          mov   EBX,ECX         ; - ...
          mov   EAX,EBP         ; - ...
          _shl  EBP,1           ; - multiply number by 4
          _rcl  ECX,1           ; -   by shifting left 2 places
          _rcl  EDX,1           ; - ...
          _shl  EBP,1           ; - ...
          _rcl  ECX,1           ; - ...
          _rcl  EDX,1           ; - ...
          add   EBP,EAX         ; - add original value
          adc   ECX,EBX         ; -  (this will make it times 5)
          adc   EDX,EDI         ; - ...
          _shl  EBP,1           ; - shift left to make it times 10
          _rcl  ECX,1           ; - ...
          _rcl  EDX,1           ; - ...
          sub   EAX,EAX         ; - zero eax
          mov   AL,[ESI]        ; - get next digit
          and   AL,0Fh          ; - isolate binary digit
          add   EBP,EAX         ; - add in current digit
          adc   ECX,0           ; - ...
          adc   EDX,0           ; - ...
          inc   ESI             ; - point to next digit in buffer
        _endloop                ; endloop
        mov     EAX,ECX         ; get low order word into EAX

;[] Turn the integer in EDX:EAX:EBP into a real number

        mov     EDI,3FFFh+63+32 ; set exponent
        call    Norm            ; convert the 64 bit integer to a float
        pop     EBP             ; restore pointer to result
        mov     4[EBP],EDX      ; store result
        mov     0[EBP],EAX      ; ...
        mov     8[EBP],SI       ; ...
        pop     EBX             ; restore EBX
        pop     ECX             ; restore ECX
        pop     EDI             ; restore EDI
        pop     ESI             ; restore ESI
        pop     EBP             ; restore EBP
        ret                     ; return to caller
        endproc __ZBuf2LD


;[] Norm normalizes an unsigned real in EDX:EAX:EBP i.e grab top 64 bits
;[] expects the exponent to be in EDI.
;[]     SI contains the new exponent

Norm    proc    near            ; normalize floating point number
        sub     ESI,ESI         ; clear out SI
        or      ESI,EAX         ; see if the integer is zero
        or      ESI,EDX         ; ...
        or      ESI,EBP         ; ...
        _if     ne              ; if number is non-zero
          or    EDX,EDX         ; - see if high word is 0
          _if   e               ; - if high word is 0
            mov   EDX,EAX       ; - - shift by 32-bits
            mov   EAX,EBP       ; - - ...
            sub   EBP,EBP       ; - - ...
            sub   EDI,32        ; - - adjust exponent by 32
          _endif                ; - endif
          or    EDX,EDX         ; - see if high word is 0
          _if   e               ; - if high word is 0
            mov   EDX,EAX       ; - - shift by 32-bits
            mov   EAX,EBP       ; - - ...
            sub   EBP,EBP       ; - - ...
            sub   EDI,32        ; - - adjust exponent by 32
          _endif                ; - endif
          _loop                 ; - loop
            or    EDX,EDX       ; - - quit if high bit is on
            _quif s             ; - - ...
            dec   EDI           ; - - decrement exponent
            _shl  EBP,1         ; - - shift integer left by 1 bit
            _rcl  EAX,1         ; - - ...
            _rcl  EDX,1         ; - - ...
          _endloop              ; - endloop
          _shl  EBP,1           ; - get top bit of extra word
          adc   EAX,0           ; - round up
          adc   EDX,0           ; - ...
          _if   c               ; - if carry out the top
            rcr   EDX,1         ; - - shift fraction back 1
            inc   EDI           ; - - increment exponent
          _endif                ; - endif
          mov   ESI,EDI         ; - get exponent
        _endif                  ; endif
        ret                     ; return
        endproc Norm

        endmod
        end