home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 April / Chip_1997-04_cd.bin / prezent / cb / data.z / STREXT.ASM < prev    next >
Assembly Source File  |  1997-01-16  |  8KB  |  453 lines

  1.  
  2. ; *******************************************************
  3. ; *                            *
  4. ; *     Delphi Runtime Library                          *
  5. ; *                            *
  6. ; *    Copyright (c) 1996 Borland International    *
  7. ; *                            *
  8. ; *******************************************************
  9.  
  10.     INCLUDE    SE.ASM
  11.  
  12.     .386
  13.     .MODEL    FLAT
  14.  
  15.     EXTRN    _Pow10:NEAR
  16.     PUBLIC    _Str0Ext, _Str1Ext, _Str2Ext
  17.  
  18.     .CODE
  19.  
  20. one    DQ    1.0
  21. ten    DQ    10.0
  22. tenE17    DQ    1E17
  23. tenE18    DQ    1E18
  24.  
  25. ;    PROCEDURE _Str0Ext( val: Extended; var s: String );
  26.  
  27. _Str0Ext PROC
  28.  
  29. ; ->    [ESP+4]    Extended value
  30. ;    EAX    Pointer to string
  31.  
  32.     MOV    ECX,EAX            ; pass string
  33.     MOV    EAX,23            ; pass default field width
  34.     OR    EDX,-1            ; pass precision -1
  35.     JMP    _Str2Ext
  36.  
  37. _Str0Ext ENDP
  38.  
  39.  
  40. ;    PROCEDURE _Str1Ext( val: Extended; width: Longint; var s: String );
  41.  
  42. _Str1Ext PROC
  43.  
  44. ; ->    [ESP+4]    Extended value
  45. ;    EAX    Field width
  46. ;    EDX    Pointer to string
  47.  
  48.     MOV    ECX,EDX
  49.     OR    EDX,-1            ; pass precision -1
  50.     JMP    _Str2Ext
  51.  
  52. _Str1Ext ENDP
  53.  
  54.  
  55. ;    PROCEDURE _Str2Ext( val: Extended; width, precision: Longint; var s: String );
  56.  
  57. _Str2Ext PROC
  58.  
  59. ; ->    [ESP+4]    Extended value
  60. ;    EAX    Width
  61. ;    EDX    Precision
  62. ;    ECX    Pointer to string
  63.  
  64.     FLD    tbyte ptr [ESP+4]
  65.  
  66.     PUSH    EBX
  67.     PUSH    ESI
  68.     PUSH    EDI
  69.     MOV    EBX,EAX
  70.     MOV    ESI,EDX
  71.     PUSH    ECX            ; save string pointer
  72.     SUB    ESP,40            ; VAR digBuf: array [0..39] of Char
  73.  
  74. ;    limit width to 255
  75.  
  76.     CMP    EBX,255            ; if width > 255 then width := 255;
  77.     JLE    @@1
  78.     MOV    EBX,255
  79. @@1:
  80.  
  81. ;    save sign bit in bit 0 of EDI, take absolute value of val, check for
  82. ;    Nan and infinity.
  83.  
  84.     FLD    ST(0)
  85.     FSTP    tbyte ptr [ESP]
  86.     XOR    EAX,EAX
  87.     MOV    AX,word ptr [ESP+8]
  88.     MOV    EDI,EAX
  89.     SHR    EDI,15
  90.     AND    AX,7FFFH
  91.     CMP    AX,7FFFH
  92.     JE    @@nanInf
  93.     FABS
  94.  
  95. ;    if precision < 0 then do scientific else do fixed;
  96.  
  97.     TEST    ESI,ESI
  98.     JGE    @@fixed
  99.  
  100. ;    the following call finds a decimal exponent and a reduced
  101. ;    mantissa such that val = mant * 10**exp
  102.  
  103.     CALL    _ScaleExt        ; val is FST(0), exp is EAX
  104.  
  105. ;    for scientific notation, we have width - 8 significant digits
  106. ;    however, we can not have less than 2 or more than 18 digits.
  107.  
  108. @@scientific:
  109.  
  110.     MOV    ESI,EBX            ; digCnt := width - 8;
  111.     SUB    ESI,8
  112.     CMP    ESI,2            ; if digCnt < 2 then digCnt := 2
  113.     JGE    @@2
  114.     MOV    ESI,2
  115.     JMP    @@3
  116. @@2:
  117.     CMP    ESI,18            ; else if digCnt > 18 then digCnt := 18;
  118.     JLE    @@3
  119.     MOV    ESI,18
  120. @@3:
  121.  
  122. ;    _EmitDigits( val, digCnt, digBuf )
  123.  
  124.     MOV    EDX,ESP            ; pass digBuf
  125.     PUSH    EAX            ; save exponent
  126.     MOV    EAX,ESI            ; pass digCnt
  127.     CALL    _EmitDigits        ; convert val to ASCII
  128.  
  129.     MOV    EDX,EDI            ; save sign in EDX
  130.     MOV    EDI,[ESP+40+4]        ; load result string pointer
  131.  
  132.     MOV    [EDI],BL        ; length of result string := width
  133.     INC    EDI
  134.  
  135.     MOV    AL,' '            ; prepare for leading blanks and sign
  136.  
  137.     MOV    ECX,EBX            ; blankCnt := width - digCnt - 8
  138.     SUB    ECX,ESI
  139.     SUB    ECX,8
  140.     JLE    @@4
  141.  
  142.     REP    STOSB            ; emit blankCnt blanks
  143. @@4:
  144.     SUB    [EDI-1],CL        ; if blankCnt < 0, adjust length
  145.  
  146.     TEST    DL,DL            ; emit the sign (' ' or '-')
  147.     JE    @@5
  148.     MOV    AL,'-'
  149. @@5:
  150.     STOSB
  151.  
  152.     POP    EAX
  153.  
  154.     MOV    ECX,ESI            ; emit digCnt digits
  155.  
  156.     MOV    ESI,ESP            ; point ESI to digBuf
  157.  
  158.     CMP    byte ptr [ESI],'0'
  159.     JE    @@5a            ; if rounding overflowed, adjust exponent and ESI
  160.     INC    EAX
  161.     DEC    ESI
  162. @@5a:
  163.     INC    ESI
  164.  
  165.     MOVSB                ; emit one digit
  166.     MOV    byte ptr [EDI],'.'    ; emit dot
  167.     INC    EDI            ; adjust dest pointer
  168.     DEC    ECX            ; adjust count
  169.  
  170.     REP    MOVSB
  171.  
  172.     MOV    byte ptr [EDI],'E'
  173.  
  174.     MOV    CL,'+'            ; emit sign of exponent ('+' or '-')
  175.     TEST    EAX,EAX
  176.     JGE    @@6
  177.     MOV    CL,'-'
  178.     NEG    EAX
  179. @@6:
  180.     MOV    [EDI+1],CL
  181.  
  182.     XOR    EDX,EDX            ; emit exponent
  183.     MOV    CX,10
  184.     DIV    CX
  185.     ADD    DL,'0'
  186.     MOV    [EDI+5],DL
  187.  
  188.     XOR    EDX,EDX
  189.     DIV    CX
  190.     ADD    DL,'0'
  191.     MOV    [EDI+4],DL
  192.  
  193.     XOR    EDX,EDX
  194.     DIV    CX
  195.     ADD    DL,'0'
  196.     MOV    [EDI+3],DL
  197.  
  198.     ADD    AL,'0'
  199.     MOV    [EDI+2],AL
  200.  
  201.     JMP    @@exit
  202.  
  203. @@fixed:
  204.  
  205. ;    FST(0)    = value >= 0.0
  206. ;    EBX    = width
  207. ;    ESI    = precision
  208. ;    EDI    = sign
  209.  
  210.     FCOM    ten
  211.     FSTSW    AX
  212.     SAHF
  213.     MOV    EAX,0
  214.     JB    @@7
  215.  
  216.     CALL    _ScaleExt        ; val is FST(0), exp is EAX
  217.  
  218.     CMP    EAX,35            ; if val is too large, use scientific
  219.     JG    @@scientific
  220.  
  221. @@7:
  222. ;    FST(0)    = scaled value, 0.0 <= value < 10.0
  223. ;    EAX    = exponent, 0 <= exponent
  224.  
  225. ;    intDigCnt := exponent + 1;
  226.  
  227.     INC    EAX
  228.  
  229. ;    _EmitDigits( value, intDigCnt + precision, digBuf );
  230.  
  231.     MOV    EDX,ESP
  232.     PUSH    EAX
  233.     ADD    EAX,ESI
  234.     CALL    _EmitDigits
  235.     POP    EAX
  236.  
  237. ;    Now we need to check whether rounding to the right number of
  238. ;    digits overflowed, and if so, adjust things accordingly
  239.  
  240.     MOV    EDX,ESI            ; put precision in EDX
  241.     MOV    ESI,ESP            ; point EDI to digBuf
  242.     CMP    byte ptr [ESI],'0'
  243.     JE    @@8
  244.     INC    EAX
  245.     DEC    ESI
  246. @@8:
  247.     INC    ESI
  248.  
  249.     MOV    ECX,EAX            ; numWidth := sign + intDigCnt;
  250.     ADD    ECX,EDI
  251.  
  252.     TEST    EDX,EDX            ; if precision > 0 then
  253.     JE    @@9
  254.     INC    ECX            ;   numWidth := numWidth + 1 + precision
  255.     ADD    ECX,EDX
  256.  
  257.     CMP    EBX,ECX            ; if width <= numWidth
  258.     JG    @@9
  259.     MOV    EBX,ECX            ;   width := numWidth
  260. @@9:
  261.     PUSH    EAX
  262.     PUSH    EDI
  263.  
  264.     MOV    EDI,[ESP+40+2*4]    ; point EDI to dest string
  265.  
  266.     MOV    [EDI],BL        ; store final length in dest string
  267.     INC    EDI
  268.  
  269.     SUB    EBX,ECX            ; width := width - numWidth
  270.     MOV    ECX,EBX
  271.     JLE    @@10
  272.  
  273.     MOV    AL,' '            ; emit width blanks
  274.     REP    STOSB
  275. @@10:
  276.     SUB    [EDI-1],CL        ; if blankCnt < 0, adjust length
  277.     POP    EAX
  278.     POP    ECX
  279.  
  280.     TEST    EAX,EAX
  281.     JE    @@11
  282.  
  283.     MOV    byte ptr [EDI],'-'
  284.     INC    EDI
  285.  
  286. @@11:
  287.     REP    MOVSB            ; copy intDigCnt digits
  288.  
  289.     TEST    EDX,EDX            ; if precision > 0 then
  290.     JE    @@12
  291.  
  292.     MOV    byte ptr [EDI],'.'    ;   emit '.'
  293.     INC    EDI
  294.     MOV    ECX,EDX            ;   emit precision digits
  295.     REP    MOVSB
  296.  
  297. @@12:
  298.  
  299. @@exit:
  300.     ADD    ESP,40
  301.     POP    ECX
  302.     POP    EDI
  303.     POP    ESI
  304.     POP    EBX
  305.     RET    12
  306.  
  307. @@nanInf:
  308. ;    here: EBX = width, ECX = string pointer, EDI = sign, [ESP] = value
  309.  
  310.     FSTP    ST(0)
  311.     CMP    [ESP+4],80000000H
  312.     MOV    ESI,offset nanStr
  313.     JNE    @@13
  314.     DEC    EDI
  315.     MOV    ESI,offset plusInfStr
  316.     JNZ    @@13
  317.     MOV    ESI,offset minInfStr
  318. @@13:
  319.     MOV    EDI,ECX
  320.     MOV    ECX,EBX
  321.     MOV    [EDI],CL
  322.     INC    EDI
  323.     SUB    CL,[ESI]
  324.     JBE    @@14
  325.     MOV    AL,' '
  326.     REP    STOSB
  327. @@14:
  328.     SUB    [EDI-1],CL
  329.     MOV    CL,[ESI]
  330.     INC    ESI
  331.     REP    MOVSB
  332.  
  333.     JMP    @@exit
  334.  
  335. nanStr        DB    3,'Nan'
  336. plusInfStr    DB    4,'+Inf'
  337. minInfStr    DB    4,'-Inf'
  338.  
  339. _Str2Ext ENDP
  340.  
  341.  
  342. _EmitDigits PROC
  343.  
  344. ; ->    FST(0)    Value, 0 <= value < 10.0
  345. ;    EAX    Count of digits to generate
  346. ;    EDX    Pointer to digit buffer
  347.  
  348.     PUSH    EDI
  349.     MOV    EDI,EDX
  350.     MOV    ECX,EAX
  351.  
  352.     SUB    ESP,10            ; VAR bcdBuf: array [0..9] of Byte
  353.     MOV    byte ptr [EDI],'0'    ; digBuf[0] := '0';
  354.     FMUL    tenE17            ; val := Round(val*1e17);
  355.     FRNDINT
  356.  
  357.     FCOM    tenE18            ; if val >= 1e18 then
  358.     FSTSW    AX
  359.     SAHF
  360.     JB    @@1
  361.  
  362.     FSUB    tenE18            ;   val := val - 1e18;
  363.     MOV    byte ptr [EDI],'1'    ;   digBuf[0] := '1';
  364. @@1:
  365.     FBSTP    [ESP]            ; store packed bcd digits in bcdBuf
  366.  
  367.     MOV    EDX,8
  368.     INC    EDI
  369.  
  370. @@2:
  371.     WAIT
  372.     MOV    AL,[ESP+EDX]        ; unpack 18 bcd digits in 9 bytes
  373.     MOV    AH,AL            ; into 9 words = 18 bytes
  374.     SHR    AL,4
  375.     AND    AH,0FH
  376.     ADD    AX,'00'
  377.     STOSW
  378.     DEC    EDX
  379.     JNS    @@2
  380.  
  381.     SUB    ECX,18            ; we need at least digCnt digits
  382.     JL    @@3            ; we have generated 18
  383.  
  384.     MOV    AL,'0'            ; if this is not enough, append zeroes
  385.     REP    STOSB
  386.     JMP    @@4            ; in this case, we don't need to round
  387.  
  388. @@3:
  389.     ADD    EDI,ECX            ; point EDI to the round digit
  390.     CMP    byte ptr [EDI],'5'
  391.     JL    @@4
  392. @@5:
  393.     DEC    EDI
  394.     INC    byte ptr [EDI]
  395.     CMP    byte ptr [EDI],'9'
  396.     JLE    @@4
  397.     MOV    byte ptr [EDI],'0'
  398.     JMP    @@5
  399.  
  400. @@4:
  401.     ADD    ESP,10
  402.     POP    EDI
  403.     RET
  404.  
  405. _EmitDigits ENDP
  406.  
  407.  
  408. _ScaleExt PROC
  409.  
  410. ; ->    FST(0)    Value
  411. ; <-    EAX    exponent (base 10)
  412. ;    FST(0)    Value / 10**eax
  413.  
  414.     PUSH    EBX
  415.     SUB    ESP,12
  416.  
  417.     XOR    EBX,EBX
  418.  
  419. @@normLoop:                ; loop necessary for denormals
  420.  
  421.     FLD    ST(0)
  422.     FSTP    tbyte ptr [ESP]
  423.     MOV    AX,[ESP+8]
  424.     TEST    AX,AX
  425.     JE    @@testZero
  426. @@cont:
  427.     SUB    AX,3FFFH
  428.     MOV    DX,4D10H    ; log10(2) * 2**16
  429.     IMUL    DX
  430.     MOVSX    EAX,DX        ; exp10 = exp2 * log10(2)
  431.     NEG    EAX
  432.     JE    @@exit
  433.     SUB    EBX,EAX
  434.     CALL    _Pow10
  435.     JMP    @@normLoop
  436.  
  437. @@exit:
  438.     ADD    ESP,12
  439.     MOV    EAX,EBX
  440.     POP    EBX
  441.     RET
  442.  
  443. @@testZero:
  444.     CMP     dword ptr [ESP+4],0
  445.     JNE    @@cont
  446.     CMP    dword ptr [ESP+0],0
  447.     JNE    @@cont
  448.     JMP    @@exit
  449.  
  450. _ScaleExt ENDP
  451.  
  452.     END
  453.