;*****************************************************************************
;*
;*                            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!
;*
;*****************************************************************************


include mdef.inc
include struct.inc

        modstart        i64tos

;
;
;       int _CmpBigInt( int sigdigits, int near *bigint )
;                              EAX             EDX
;
        xdefp   __CmpBigInt
        xdefp   __Rnd2Int
        xdefp   __Bin2String

        defpe   __CmpBigInt
        push    EDI             ; save EDI
        push    ECX             ; save ECX
        call    getpow10        ; get address of Power of 10 table
        inc     EAX             ; ++sigdigits
        lea     EDI,[EDI+EAX*8] ; point to Pow10Table[sigdigits+1]
        mov     ECX,[EDX]       ; get 64-bit integer
        mov     EDX,4[EDX]      ; ...(high part)
        sub     EAX,EAX         ; set adjustment to 0
        _loop                   ; loop
          cmp   EDX,cs:[EDI]    ; - check against 10**k
          _if   e               ; - if high parts equal
            cmp   ECX,cs:4[EDI] ; - - compare low part
          _endif                ; - endif
          _quif b               ; - quit if num < 10**k
          add   EDI,8           ; - set pointer to 10**(k+1)
          inc   EAX             ; - increment adjustment word
        _endloop                ; endloop
        sub     EDI,8           ; point at 10**(k-1)
        _loop                   ; loop
          cmp   EDX,cs:[EDI]    ; - check against 10**k
          _if   e               ; - if high parts equal
            cmp   ECX,cs:4[EDI] ; - - compare low part
          _endif                ; - endif
          _quif nb              ; - quit if num >= 10**(k-1)
          sub   EDI,8           ; - set pointer to 10**(k-2)
          dec   EAX             ; - increment adjustment word
        _endloop                ; endloop
        pop     ECX             ; restore ECX
        pop     EDI             ; restore EDI
        ret                     ; return to caller
        endproc __CmpBigInt

;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
;[]
;[] Rnd2int rounds the real pointed to by EAX to a 64 bit integer.
;[]
;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
;       void _Rnd2Int( double near *realnum, int near *bigint )
;                               EAX                 EDX
;
        defpe   __Rnd2Int
        push    EBX             ; save registers
        push    ECX             ; save ECX
        push    EDX             ; save EDX
        push    EBP             ; save EBP
        push    ESI             ; save ESI
        push    EDX             ; save address of bigint array
        mov     EBP,EAX         ; get address of realnum
        mov     ECX,[EBP]       ; load the number
        mov     EBX,4[EBP]      ; . . .
        mov     EBP,EBX         ; save high word
        and     EBP,0FFF00000h  ; isolate exponent in EBP
        xor     EBX,EBP         ; isolate mantissa in EDX
        xor     EBX,00100000h   ; turn on implied '1' bit in mantissa
        shr     EBP,20          ; move exponent to bottom part of word
        sub     EBP,0433h       ; calculate difference from 2**53
        _if     ne              ; if not already the right size
          _if   a               ; - if too big
            _loop               ; - - loop
              shl   ECX,1       ; - - - shift real left by one
              rcl   EBX,1       ; - - - . . .
              dec   EBP         ; - - - decrement count
            _until e            ; - - until count = 0
          _else                 ; - else
            sub EAX,EAX         ; - - clear remainder
            sub ESI,ESI         ; - - clear remainder bit bucket
            _loop               ; - - loop
              shr   EBX,1       ; - - - shift real right by one
              rcr   ECX,1       ; - - - . . .
              rcr   EAX,1       ; - - - save remainder
              adc   ESI,ESI     ; - - - remember if any bits fell off end
              inc   EBP         ; - - - increment count
            _until e            ; - - until e
            _guess rup          ; - - do we have to round up?
              cmp   EAX,80000000h;- - - compare remainder with .5000000
              _quif b,rup       ; - - - kick out if less than .5
              _if   e           ; - - - magical stuff if looks like a .5
                or      ESI,ESI ; - - - any bits dropped off the bottom
                _if     e       ; - - - if not
                  test  ECX,1   ; - - - - - is bottom digit even?
                  _quif e,rup   ; - - - - - kick out if it is
                _endif          ; - - - - endif
              _endif            ; - - - endif
              add   ECX,01      ; - - - round up the number
              adc   EBX,00      ; - - - . . .
            _endguess           ; - - endguess
          _endif                ; - endif
        _endif                  ; endif
        pop     EBP             ; get address of bigint array
        mov     [EBP],ECX       ; store 64-bit integer
        mov     4[EBP],EBX      ; . . .
        pop     ESI             ; restore ESI
        pop     EBP             ; restore EBP
        pop     EDX             ; restore EDX
        pop     ECX             ; restore ECX
        pop     EBX             ; restore EBX
        ret                     ; return
        endproc __Rnd2Int

;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
;[]
;[] Bin2string  converts a binary integer into a string
;[]
;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
;       void _Bin2String(
;               int near *bigint,       /* EAX */
;               char near *bufptr,      /* EDX */
;               int sigdigits )         /* EBX */
;
        defpe   __Bin2String
        push    EBP             ; save EBP
        push    EDI             ; save EDI
        push    ECX             ; save ECX
        push    EBX             ; save EBX
        mov     EBP,EAX         ; get address of bigint array
        mov     ECX,[EBP]       ; get 64-bit integer
        mov     EAX,4[EBP]      ; . . .
        mov     EBP,EDX         ; get buffer pointer
        add     EBP,EBX         ; point to end of buffer
        mov     byte ptr [EBP],0; put in null character
;
; input:
;       EAX:ECX - 64-bit integer
;       EBP - pointer to buffer for digits
;       EBX - digit count

        push    EAX             ; save high word of quotient
        _loop                   ; loop
          pop   EAX             ; - restore high word of quotient
          mov   EDI,10000       ; - divisor is 10000
          sub   EDX,EDX         ; - zero high word
          or    EAX,EAX         ; - check high word
          jne   div1            ; - do all divides
          or    ECX,ECX         ; - check low order word
          jne   div2            ; - skip first divide
          push  EAX             ; - save high word of quotient
          jmp   short div5      ; - result is 0
div1:     div   EDI             ; - divide EAX:ECX by 10000
div2:     xchg  ECX,EAX         ; - ...
          div   EDI             ; - ...

;   quotient is in ECX:EAX
;   remainder is in EDX

          xchg  ECX,EAX         ; - move quotient to EAX:ECX
          push  EAX             ; - save high word of quotient
          mov   EAX,EDX         ; - get remainder
          mov   DL,100          ; - get divisor
          div   DL              ; - split remainder into 2 parts
          mov   DL,AH           ; - save low order part
          mov   AH,0            ; - zero
          aam                   ; - split top part into 2 digits
          xchg  EDX,EAX         ; - DH, DL gets top 2 digits, AX gets low part
          mov   AH,0            ; - zero
          aam                   ; - split low part into 2 digits
div5:     add   AX,3030h        ; - make ASCII digits
          add   DX,3030h        ; - ...
          sub   EBP,4           ; - move back 4
          mov   3[EBP],AL       ; - put low order digit in buffer
          dec   EBX             ; - decrement digit count
          _quif e               ; - quit if done
          mov   2[EBP],AH       ; - ...
          dec   EBX             ; - decrement digit count
          _quif e               ; - quit if done
          mov   1[EBP],DL       ; - ...
          dec   EBX             ; - decrement digit count
          _quif e               ; - quit if done
          mov   [EBP],DH        ; - put high order digit in buffer
          dec   EBX             ; - decrement digit count
        _until  e               ; until done

        pop     EAX             ; remove high word of quotient
        pop     EBX             ; restore EBX
        pop     ECX             ; restore ECX
        pop     EDI             ; restore EDI
        pop     EBP             ; restore EBP
        ret                     ; return
        endproc __Bin2String

;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
;<>                                                                  <>
;<>     64-bit integer powers of 10 table                            <>
;<>                                                                  <>
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
getpow10 proc   near            ; get address of powers of 10 table
        call    pow10end        ; call around the table
pow10table:                     ; powers of 10 table
        dd      000000000h,000000000h ; 0
        dd      000000000h,000000001h ; 10**00
        dd      000000000h,00000000ah ; 10**01
        dd      000000000h,000000064h ; 10**02
        dd      000000000h,0000003e8h ; 10**03
        dd      000000000h,000002710h ; 10**04
        dd      000000000h,0000186a0h ; 10**05
        dd      000000000h,0000f4240h ; 10**06
        dd      000000000h,000989680h ; 10**07
        dd      000000000h,005f5e100h ; 10**08
        dd      000000000h,03b9aca00h ; 10**09
        dd      000000002h,0540be400h ; 10**10
        dd      000000017h,04876e800h ; 10**11
        dd      0000000e8h,0d4a51000h ; 10**12
        dd      000000918h,04e72a000h ; 10**13
        dd      000005af3h,0107a4000h ; 10**14
        dd      000038d7eh,0a4c68000h ; 10**15
        dd      0002386f2h,06fc10000h ; 10**16
        dd      001634578h,05d8a0000h ; 10**17
        dd      00de0b6b3h,0a7640000h ; 10**18
        dd      08ac72304h,089e80000h ; 10**19
        dd      0ffffffffh,0ffffffffh ; MAX

pow10end proc   near
        pop     EDI             ; get address of table
        ret                     ; return
        endproc pow10end
        endproc getpow10

        endmod
        end
