home *** CD-ROM | disk | FTP | other *** search
- {TOADCONV.INC}
- (* Copyright (C) 1988 David P Kirschbaum All Rights Reserved *)
-
- VAR
- radix : INTEGER; {for AnyNum_Str support}
- NrStr : Str12; {global Number working string}
-
-
- FUNCTION real_Mod(r1,r2 : REAL) : REAL;
- {Turbo's MOD doesn't work with REALs.
- WARNING: On some numbers (namely even divisors),
- we will get a mod that's not visibly different from the
- intuitive MOD, but WILL in fact be different!
- That's why I had to do the real mod "rounding".
- }
- VAR r3 : REAL;
- BEGIN
- IF r2 > r1 THEN real_Mod := r1 {divisor > dividend}
- ELSE if r2 = r1 THEN real_Mod := 0.0 {divisor = dividend}
- ELSE BEGIN
- r3 := Frac(r1 / r2); {mod's in the decimals}
- IF r3 <> 0.0 THEN r3 := r2 * r3; {nonzero, so get the mod}
-
- IF (r3 + 0.5) > Int(r3 + 0.5) {real mod rounding}
- THEN r3 := r3 + 0.5;
-
- real_Mod := Int(r3); {return the Mod}
- END;
- END; {of real_Mod}
-
-
- PROCEDURE Make_Long(hi,lo : INTEGER; VAR long : long_int);
- {Create a long integer from two integers}
- BEGIN
- Inline(
- $C4/$BE/>LONG { les di,>long[bp] ;get target long's address}
- /$FC { cld ;insure fwd}
- /$8B/$86/>LO { mov ax,>lo[bp] ;get the low word}
- /$AB { stosw ;stuff low word}
- /$8B/$86/>HI { mov ax,>hi[bp] ;get the high word}
- /$AB { stosw ;stuff it}
- );
- END; {of Make_Long}
-
-
- PROCEDURE Zero_Long(VAR long : long_int);
- {Zero a long integer's lo and hi words}
- BEGIN
- Inline(
- $C4/$BE/>LONG {les di,>long[bp] ;get target long's address}
- /$31/$C0 {xor ax,ax ;get a 0}
- /$FC {cld ;insure fwd}
- /$AB {stosw ; .lo}
- /$AB {stosw ; .hi}
- );
- END; {of Zero_Long}
-
-
- FUNCTION unsigned_To_Real(u : integer) : REAL;
- { v1.3 Convert unsigned integer to real
- Note: INT is a FUNCTION that returns a REAL!!!
- From DEARC.PAS package.
- NO SIGNS! This is part of UNSIGNED INTEGER MATH!
- }
- BEGIN
- IF u >= 0 THEN unsigned_To_Real := Int(u)
- ELSE IF u = $8000 then unsigned_To_Real := 32768.0
- ELSE unsigned_To_Real := 65536.0 + u;
- END; {of unsigned_To_Real}
-
-
- FUNCTION real_To_Int(r : REAL) : INTEGER;
- {Converts a REAL to an integer.
- Works like TRUNC, but avoids the overflow problems.
- NO SIGNS! This is part of UNSIGNED INTEGER MATH!
- }
- VAR
- i : INTEGER;
- r1 : REAL;
- BEGIN
- r1 := real_Mod(r,65536.0); {insure it's in integer range}
- IF r1 < 1.0 THEN BEGIN {nope, or negative}
- real_To_Int := 0; {no negatives}
- Exit;
- END;
-
- IF r1 > 32768.0 THEN real_To_Int := TRUNC(r1 - 65536.0)
- ELSE IF r1 = 32768.0 THEN real_To_Int := $8000
- ELSE real_To_Int := TRUNC(r1);
- END; {of real_To_Int}
-
-
- FUNCTION long_To_Real (VAR long : long_int) : REAL;
- {This function takes the high and low words of a long int
- and converts it to a REAL.
- }
- VAR r : REAL;
- BEGIN
- IF long.hi = 0 THEN r := 0.0
- ELSE r := unsigned_To_Real(long.hi) * 65536.0;
-
- IF long.lo <> 0
- THEN r := r + unsigned_To_Real(long.lo);
- long_To_Real := r;
- END; {of long_To_Real}
-
-
- PROCEDURE Real_To_Long(r : REAL; VAR long : long_int);
- {This procedure changes a REAL to a long integer.
- v1.3 }
- VAR
- r1,r2 : REAL;
- BEGIN
- long := LONG_ZERO; {assume zero}
- IF r <= 0.0 THEN Exit; {done, NO SIGNS!}
-
- IF r > MAXREALINT THEN BEGIN {max long int size}
- Stc; {set global Carry to show overflow}
- long := MAXLONGINT; {equivalent typed constant record}
- Exit;
- END;
-
- IF r >= 65536.0 {we have a long.hi}
- THEN long.hi := real_To_Int(Int(r / 65536.0)); {get its value}
-
- long.lo := real_To_Int(Int(real_Mod(r,65536.0)) );
- END; {of Real_To_Long}
-
-
- FUNCTION long_Kb(VAR long : long_int) : INTEGER;
- {Convert long int to Kb integer. Handy for
- simple file size conversion.
- v1.3 recoded in assembler
- }
- BEGIN
- (* In Turbo: 1.59 secs in a test vs assembler's 1.48 secs
- long_kb := (long.lo SHR 10) + (long.hi SHL 6);
- *)
- Inline(
- $8C/$DB {mov bx,DS ;save dx}
- /$C5/$B6/>LONG {lds si,>long[bp] ;get long address}
- /$B9/$0A/$06 {mov cx,$060A ;ch=shr, cl=shl values}
- /$AD {lodsw ;long.hi}
- /$8B/$14 {mov dx,[si] ;long.lo}
- /$D3/$E0 {shl ax,cl ;long.hi shl 6}
- /$88/$E9 {mov cl,ch ;10}
- /$D3/$E2 {shl dx,cl ;long.lo shr 10}
- /$01/$D0 {add ax,dx ;product in kb}
- /$89/$46/$08 {mov [bp+8],ax ;stuff function's integer}
- /$8E/$DB {mov DS,bx ;restore DS}
- );
- END; {of long_Kb1}
-
- (* long integer string conversions.
- I assume you wish number strings padded to a consistent length
- for easy screen or printer columns.
-
- That's reflected in the Str%% length returned from each of these
- functions. You can tweak the required padding as desired,
- OR run the strings through a Stripper function that strips out
- left-padding spaces.
- *)
-
- FUNCTION Long_Size_Str(VAR size : long_int) : Str12;
- {Returns a long int as a 6-digit left-padded number string,
- converted to Kb if above an arbitrary size (MAXINT),
- plus " Bytes" or "Kb" appended as appropriate.
- Handy for displaying file sizes.
- I use the global NrStr here as a working string for speed, tightness.
- Sooooo bad, I know ..... Just making sure you're paying attention.
- }
- BEGIN
- IF (size.hi = 0) AND (size.lo >= 0) { Small # or small enough }
- THEN BEGIN
- Str(size.lo:6,NrStr);
- Long_Size_Str := NrStr + ' Bytes';
- END
- ELSE BEGIN {too big, do in Kb}
- Str(long_Kb(size):6,NrStr);
- Long_Size_Str := NrStr + ' Kb ';
- END;
- END; {of Long_Size_Str}
-
-
- FUNCTION Long_Str(VAR long : long_int) : Str12;
- {Converts long int to a left-padded 8-character string
- if you just GOTTA have all them byte digits.
- Uses global working string NrStr for speed, tightness.
- }
- BEGIN
- Str(long_To_Real(long):12:0,NrStr);
- Long_Str := NrStr;
- END; {of Long_Str}
-
-
- FUNCTION Flashy_Long_Str(VAR long : long_int) : Str10;
- {Converts long int to a left-padded 10-char string,
- but this time with commas.
- Uses global working string NrStr for speed, tightness.
- }
- BEGIN
- NrStr := Long_Str(long); {returns up to 12345678,
- padded left with spaces}
- {12345678}
- IF NrStr[5] <> ' ' THEN BEGIN { ^ got at least 4 digits}
- Insert(',', NrStr, 6); {12345,678 stuff the comma}
- IF NrStr[2] <> ' ' { ^ still digits}
- THEN Insert(',', NrStr, 3); {12,345,678 that's it!}
- END;
- Flashy_Long_Str := NrStr; {return the string}
- END; {of Flashy_Long_Str}
-
-
- (* Hexifying routines, integer and long integer *)
-
-
- PROCEDURE Hexify(i : INTEGER; VAR NrStr : Str5);
- {Fills NrStr (somewhere out there) with x converted to Hex.
- Does NOT left-pad with spaces!
- We do this with a PROCEDURE and a VAR string rather than a FUNCTION
- returning a string because of speed and tightness.
-
- Naturally, NrStr does not HAVE to be a STRING[4];
- it could be any string TYPEd as 4 chars or more, but you'd better
- not use a smaller one! This routine does NOT check and could
- overwrite other adjacent variables if you try to stuff 4 characters
- into a STRING[2]!
- v1.3 tightened.
- }
- BEGIN
- Inline(
- $C4/$BE/>NRSTR { les di,>NrStr[bp] ;string offset, seg}
- /$B8/$04/$04 { mov ax,$0404}
- /$FC { cld ;insure fwd}
- /$AA { stosb ;force string len to 4}
- /$89/$C1 { mov cx,ax ;ch=loop cntr, cl=ROL const}
- /$BA/$0F/$30 { mov dx,$300F ;2 constants $30, $0F}
- /$8B/$9E/>I { mov bx,>i[bp] ;get the integer parm}
- {Rotate:}
- /$D3/$C3 { rol bx,cl ;get a nibble (4 bytes)}
- /$88/$D8 { mov al,bl ;asciify this nibble}
- /$20/$D0 { and al,dl ;mask (constant $0F)}
- /$00/$F0 { add al,dh ;asciify (constant $30)}
- /$3C/$3A { cmp al,$3A ;ran out of regs!}
- /$72/$02 { jb StuffIt ;<= '9'}
- /$04/$07 { add al,7 ;bump to 'A'..'F'}
- {StuffIt:}
- /$AA { stosb ;stuff char in string}
- /$FE/$CD { dec ch ;done yet?}
- /$75/$ED { jnz Rotate ;nope, loop until done}
- );
- END; {of Hexify}
-
-
- FUNCTION Hex(i : INTEGER) : Str5;
- {Returns integer as a hex string.
- Faster than table-driven hexify routines.
- v1.3 tightened
- }
- BEGIN
- Inline(
- $8C/$D0 { mov ax,SS}
- /$8E/$C0 { mov ES,ax ;ES=SS}
- /$89/$EF { mov di,bp ;stack offset}
- /$81/$C7/$06/$00 { add di,6 ;where string will begin}
- /$B8/$04/$04 { mov ax,$0404}
- /$89/$C1 { mov cx,ax ;loop cntr4, ROL constant}
- /$FC { cld ;insure fwd}
- /$AA { stosb ;force string len to 4}
- /$BA/$0F/$30 { mov dx,$300F ;2 constants $30, $0F}
- /$8B/$9E/>I { mov bx,>i[bp] ;get the integer parm}
- {Rotate:}
- /$D3/$C3 { rol bx,cl ;get a nibble (4 bytes)}
- /$88/$D8 { mov al,bl ;asciify this nibble}
- /$20/$D0 { and al,dl ;mask (constant $0F)}
- /$00/$F0 { add al,dh ;asciify (constant $30)}
- /$3C/$3A { cmp al,$3A ;ran out of regs!}
- /$72/$02 { jb StuffIt ;<= '9'}
- /$04/$07 { add al,7 ;bump to 'A'..'F'}
- {StuffIt:}
- /$AA { stosb ;stuff char in string}
- /$FE/$CD { dec ch ;done yet?}
- /$75/$ED { jnz Rotate ;nope, loop until done}
- );
- END; {of Hex3}
-
-
- PROCEDURE LStr_Hex(VAR long : long_int; VAR NrStr : Str12);
- {Converts a long integer into the Hexidecimal string NrStr.
- Format: 0000:0000 hi word, then lo word.
- v1.3 tightened.
- }
- BEGIN
- Inline(
- $1E { push DS}
- /$C4/$BE/>NRSTR { les di,>NrStr[bp] ;string offset, seg}
- /$C5/$B6/>LONG { lds si,>long[bp] ;long ofs}
- /$B0/$09 { mov al,9 ;9 digits for 32-bit}
- /$FC { cld ;from left to right}
- /$AA { stosb ;force string len to 9}
- /$B8/$04/$04 { mov ax,$0404 ;ah is constant}
- /$89/$C1 { mov cx,ax ;cl=ROL, ch=loop cntr}
- /$BA/$0F/$30 { mov dx,$300F ;2 constants $30, $0F}
- /$8B/$5C/$02 { mov bx,[si+2] ;long.hi}
- /$E8/$0C/$00 { call Rotate ;do first integer}
- /$B0/$3A { mov al,$3A ;":"}
- /$AA { stosb ;stuff in string}
- /$8B/$1C { mov bx,[si] ;long.lo}
- /$88/$E5 { mov ch,ah ;refresh loop cntr}
- /$E8/$02/$00 { call Rotate}
- /$EB/$14 { jmp short Exit ;done}
-
- {Rotate:}
- /$D3/$C3 { rol bx,cl ;get a nibble (4 bytes)}
- /$88/$D8 { mov al,bl ;asciify this nibble}
- /$20/$D0 { and al,dl ;mask (constant $0F)}
- /$00/$F0 { add al,dh ;asciify (constant $30)}
- /$3C/$3A { cmp al,$3A ;ran out of regs!}
- /$72/$02 { jb StuffIt ;<= '9'}
- /$04/$07 { add al,7 ;bump to 'A'..'F'}
- {StuffIt:}
- /$AA { stosb ;stuff char in string}
- /$FE/$CD { dec ch ;done yet?}
- /$75/$ED { jnz Rotate ;nope, loop until done}
- /$C3 { ret}
-
- {Exit:}
- /$1F { pop DS ;restore}
- );
- END; {of LStr_Hex}
-
-
- FUNCTION LHex(VAR long : long_int) : Str12;
- {Converts the long integer into a string, returns it
- as the function (in case you don't have a string variable
- handy to use LStr_Hex).
- Format: 0000:0000 (hi word, then lo word)
- v1.3 recoded in assembler.
- }
- BEGIN
- (* In Turbo, 7.9 secs vs assembler's 5.43 secs
- LStr_Hex(long, S);
- LHex := S;
- *)
- Inline(
- $1E { push DS}
- /$8C/$D0 { mov ax,SS}
- /$8E/$C0 { mov ES,ax ;ES=SS}
- /$89/$EF { mov di,bp ;stack offset}
- /$81/$C7/$08/$00 { add di,8 ;where string will begin}
- /$C5/$B6/>LONG { lds si,>long[bp] ;long ofs}
- /$FC { cld ;from left to right}
- /$B0/$09 { mov al,9 ;9 digits for 32-bit}
- /$AA { stosb ;force string len to 9}
- /$B8/$04/$04 { mov ax,$0404 ;ah is constant}
- /$89/$C1 { mov cx,ax ;cl=ROL, ch=loop cntr}
- /$BA/$0F/$30 { mov dx,$300F ;2 constants $30, $0F}
- /$8B/$5C/$02 { mov bx,[si+2] ;long.hi}
- /$E8/$0C/$00 { call Rotate ;do first integer}
- /$B0/$3A { mov al,$3A ;":"}
- /$AA { stosb ;stuff in string}
- /$8B/$1C { mov bx,[si] ;long.lo}
- /$88/$E5 { mov ch,ah ;refresh loop cntr}
- /$E8/$02/$00 { call Rotate}
- /$EB/$14 { jmp short Exit ;done}
-
- {Rotate:}
- /$D3/$C3 { rol bx,cl ;get a nibble (4 bytes)}
- /$88/$D8 { mov al,bl ;asciify this nibble}
- /$20/$D0 { and al,dl ;mask (constant $0F)}
- /$00/$F0 { add al,dh ;asciify (constant $30)}
- /$3C/$3A { cmp al,$3A ;ran out of regs!}
- /$72/$02 { jb StuffIt ;<= '9'}
- /$04/$07 { add al,7 ;bump to 'A'..'F'}
- {StuffIt:}
- /$AA { stosb ;stuff char in string}
- /$FE/$CD { dec ch ;done yet?}
- /$75/$ED { jnz Rotate ;nope, loop until done}
- /$C3 { ret}
-
- {Exit:}
- /$1F { pop DS ;restore}
- );
- END; {of LHex1}
-
-
- FUNCTION AnyNum_Str(VAR num; typ : numtype) : Str64;
- {Returns a string for ANY number (integer, real, long integer).
- Uses the global numtype (inttyp, realtyp, longtyp) to tell the
- function what kinda number you're dealing with.
- Only works with VARs, notice!
- Using global radix, you can set 10 bit or 16 bit (hex). Haven't set it
- up for any other number bases yet.
- }
- CONST
- BADRADIX = 'Unsupported Radix!';
- VAR
- tlong : long_int;
- S : Str64;
- answer : REAL;
- r : REAL absolute num;
- i : INTEGER absolute num;
- l : long_int absolute num;
- BEGIN {AnyNum_Str}
- S := BADRADIX; {assume the worst}
- CASE typ OF
- realtyp : CASE radix OF
- 10 : BEGIN
- IF r = 0 THEN S := '0'
- ELSE STR(r:20:0,S);
- END;
- 16 : BEGIN
- Real_To_Long(r,tlong); {convert to long}
- LStr_Hex(tlong,S); {and to hex string}
- END;
- ELSE; { S := 'Unsupported Radix!';}
- END; {case}
- inttyp : CASE radix OF
- 10 : STR(i:6,S);
- 16 : S := '0000:' + Hex(i);
- ELSE; { Writeln('Unsupported Radix!');}
- END; {case}
- longtyp : CASE radix OF
- 10 : BEGIN
- answer := long_To_Real(l);
- IF answer = 0.0 THEN S := '0'
- ELSE STR(answer:20:0,S);
- END;
- 16 : LStr_Hex(l, S);
- ELSE; { Writeln('Unsupported Radix!');}
- END; {case}
- END; {case}
- IF (LENGTH(S) > 0)
- THEN WHILE (S[1] = ' ') DO
- Delete(S,1,1); {delete any leading spaces}
- AnyNum_Str := S; {return the function}
- END; {of AnyNum_Str}
-
-
- (* Other handy number/string functions *)
-
-
- FUNCTION Zero_Padded(S : Str12) : Str12;
- {Pad a string with zeroes .. e.g., if a space, stuff in a '0'.
- The length here is purely arbitrary.
- Works good with left-padded numbers from Long_Str and
- Long_Size_Str.
- This routine won't ADD zeros beyond the length of the original
- left-padded string. Didn't bother with that since I always
- passed a string left-padded to the length (width) I wanted.
- }
- VAR
- p : INTEGER;
- BEGIN
- p := POS(' ', S); {any spaces?}
- WHILE p <> 0 DO BEGIN {yep, go for it}
- S[p] := '0'; {stuff a zero in the space}
- p := pos(' ', S); {and loop through the test again}
- END;
- Zero_Padded := S; {return the string}
- END; {of Zero_Padded}
-
-
- FUNCTION Byte32_Str(VAR long : long_int) : Str64;
- {Build a long string of 32 bits from a long integer.
- String is actually 36 chars long.
- v1.3 recoded in assembler
- }
- BEGIN
- Inline(
- $1E { push DS ;save DS}
- /$8C/$D0 { mov ax,SS}
- /$8E/$C0 { mov ES,ax ;ES=SS}
- /$89/$EF { mov di,bp ;point to heap}
- /$81/$C7/$08/$00 { add di,8 ;string start}
- /$B8/$24/$00 { mov ax,36 ;str length}
- /$26 { ES:}
- /$88/$05 { mov [di],al ;force length}
- /$01/$C7 { add di,ax ;point to end}
- /$C5/$B6/>LONG { lds si,>long[bp] ;get long addr}
- /$FC { cld ;insure fwd}
- /$AD { lodsw ;long.lo}
- /$8B/$14 { mov dx,[si] ;long.hi}
- /$52 { push dx ;save on stack}
- /$BA/$30/$3A { mov dx,$3A30 ;constants in dh,dh}
- /$FD { std ;go backwards}
- /$89/$C3 { mov bx,ax ;need int in bx}
- /$E8/$0A/$00 { call DoBin ;go do it}
- /$88/$F0 { mov al,dh ;":" separator}
- /$AA { stosb ;stuff}
- /$AA { stosb ;twice between words}
- /$5B { pop bx ;get long.hi}
- /$E8/$02/$00 { call DoBin ;go do it}
- /$EB/$17 { jmp short Done}
-
- {DoBin:}
- /$B9/$10/$00 { mov cx,16 ;16 chars}
- {ShLup:}
- /$89/$D8 { mov ax,bx ;ax=decint}
- /$D1/$EB { shr bx,1 ;result=decint shr 1}
- /$24/$01 { and al,1 ;remainder=decint AND 1}
- /$00/$D0 { add al,dl ;$30, asciify}
- /$AA { stosb ;stuff char}
- /$80/$F9/$08 { cmp cl,8 ;divider every 8 bits}
- /$75/$03 { jne Lup ;nope}
- /$88/$F0 { mov al,dh ; ":" divider}
- /$AA { stosb ;stuff}
- {Lup:}
- /$E2/$ED { loop ShLup}
- /$C3 { ret}
-
- {Done:}
- /$FC { cld ;neaten up}
- /$1F { pop DS ;restore DS}
- );
- END; {of Byte32_Str}