advertisement moved to bottom of page to improve page loading time
11  Interesting Q&A from various newsgroups
unsorted, uncommented, simply copied from NG - mails (without written permission of the authors)
Please mail me if you do not agree - want to have removed your mail here.

last updated: Jan-27.2000    Index 1QA go to 1QA index page

   Subject: Re: Real Format
      Date: Sat, 12 Jun 1999 03:53:33 -0700
      From: <>
 Newsgroups: borland.public.turbopascal

Carlos Casado Garcia <> wrote in message
>     Could anyone tell me how the real number format are interpreted in
> Turbo Pascal internally?
>     Bits for exponent and mantisa?
>     Thank you very much
> Carlos

Program RealConv;

{  This program demonstrates the conversion of a 6 byte Pascal Real    }
{  real variable type by re-creating the exponent and Mantissa.        }
{  The temporary variable Mantissa accumulates the value stored in     }
{  bytes 2 through 6.                                                  }

  SixByteArray = array[1..6] of byte;

  r            : real;                    { this is a real48 type variable }
  s            : SixByteArray absolute r; { Allows access to individual real type bytes }
  i,j          : byte;
  PosFlag      : boolean;
  Mantissa     : double;

  p240         : double;

  Number       : double;

  function power (x,y : integer) : double;
    power := exp(y * ln(x));


  write('Enter floating point Number ');

{ Check if entry is positive from bit 7 of byte 6 }
  PosFlag := ($80 and s[6]) = 0;
{ Force bit 7 of byte 6 on }
  s[6] := s[6] or $80;
{ Initialize the Mantissa }
  Mantissa := 1.0;

  p240 :=power(2,40);

  for i := 2 to 6 do  { Check each byte of mantissa }

    for j := 0 to 7 do  { Check each bit }
      if ((s[i] shr j) and 1 ) = 1 then
        { Increment mantissa appropriately }
        Mantissa := Mantissa + power(2, (j + (i-2)*8));

  Number := Mantissa / p240;  { Normalize the number by dividing by 2^40 }

{ Get number by multiply Mantissa by the exponent }
  Number := Number * power(2, s[1] - $80);
  if not PosFlag then
     Number := Number * -1;

  writeln(Number);         { this is a double type variable }

   Subject: Re: Overlays save memory but slow down execution
      Date: Fri, 2 Jul 1999 00:17:57 GMT
      From: (Mike Copeland)
 Organization: Bull
 Newsgroups: comp.lang.pascal.borland

> I wrote a program in TP7 that uses about 50 units all declared as overlay
> in order to avoid an out-of-memory error. (The EXE-file plus OVR-file is
> about 400kB.)
> When I run this program, some procedures are far too slow. When I embed one
> such procedure (just for testing) in a new program, leaving out irrelevant
> things and all overlay declarations, it is about 10 times faster. (The
> resulting executable is about 200kB).
> Is this deceleration a known property of overlays and...
> can it be cured?

  Yes, this effect is entirely possible - if you don't carefully analyze
and restructure your code to make overlays for _for_ you.  As Pedt has
suggested, simply slapping the "overlay" template around all your Unit
sources and expecting any kind of reasonable execution performance is
naive...and dumb.  You have to package your overlayed Units in a manner
which follows the logical calls/uses within the program (all initialize
code logic in one overlay; termination/windup logic in another; discrete
menu functions in separate overlays; etc.).  This isn't a simple or easy
thing to do, and it requires great understanding of how the program
executes, what it does at each "function", all the while thinking "What
needs to be in memory while this executes?"
   Note that certain global functions/procedures shouldn't be overlayed,
particularly when 2 or more logical functions use them.  Doing so will
cause "overlay thrashing" (the situation you're experiencing, I'm sure),
as each overlay has to swap out to load another so that the common
subprogram can execute...followed by it swapping out so the caller
overlay can come back in to execute.  Thus, common subprograms should be
kept in a Unit which _isn't_ overlayed, so that they stay in program
memory and can be accessed by all overlays.
   Implementing overlays in a program is often a tedious "learning
experience", as one develops an understanding of what can be separated
into overlay Units, what cannot, and how to structure his/her program
logic to assure each overlay can do its own work without swapping in/out
for another.  Another thing to watch for is the _size_ of each overlay,
since TP will use a fixed overlay buffer of at least the size of the
largest overlay Unit - so it's best to keep the code of each overlayed
Unit about the same as all others, if possible (quite hard to do,
   Good luck...

   Subject: Re: Overlays save memory but slow down execution
      Date: Fri, 2 Jul 1999 05:50:35 +0100
      From: Pedt Scragg <>
Newsgroups: comp.lang.pascal.borland

Mike Copeland said:

>> I wrote a program in TP7 that uses about 50 units all declared as overlay

>  Yes, this effect is entirely possible - if you don't carefully analyze
>and restructure your code to make overlays for _for_ you.  As Pedt has
>suggested, simply slapping the "overlay" template around all your Unit
>sources and expecting any kind of reasonable execution performance is
>naive...and dumb.

<snip good advice>

One thing I forgot to mention, I've a program available via  that will give you the
size of each unit code within the overlay which might help.

There's also a unit that will allow the load the overlay file
into XMS memory - which memory I suspect people are more likely
to have than EMS.

Subject: Re: Detecting redirected output in DOS?
   Date: Thu, 26 Aug 1999 19:20:32 +0200
   From: Andreas Killer <>
Newsgroups: borland.public.turbopascal

Curtis Cameron schrieb:

> I'd like it to detect whether the output is being redirected or is going
> to the display, and turn off the paging feature if it's redirected. Is
> this possible?

Yes, use this routine with Output to detect if the output is redirected:

  function Redirect(var T : Text) : Boolean; Assembler;
    {-True wenn InPut/OutPut per DOS in auf eine Datei umgeleitet wurde.}
    { true if Input/Output was redirected via DOS to a file}
    les     di, T
    mov     ax, 4400h             {-IOCTL: Attribut lesen} {read attribute}
    mov     bx, es:[di]           {-BX = Handle}
    int     21h
    mov     al, False
    jc      @@Done                {-Fehler?}  {error?}
  DX enthält die Attribute des Treibers. Ein gesetztes Bit bedeutet:
     0    Treiber ist CON-Eingabe (Tastatur)
     1    Treiber ist CON-Ausgabe (Bildschirm)
     2    Treiber ist NUL
     3    Treiber ist ein Clock-Device
     5    Treiber ist im RAW-Modus, ansonsten COOKED-Modus
     7    Treiber ist ein Zeichentreiber, ansonsten eine Datei
    14    Treiber kann Steuerzeichen von AX=4402h/4403h INT 21 verarbeiten
  Alle anderen Bits sind reserviert.
  DX contains the attributes of the driver. A set bit represents:
     0    driver is CON-input {keyboard}
     1    driver is CON-output {CRT}
     2    driver is NUL
     3    driver is a clock device
     5    driver is in raw mode, else cooked mode
     7    driver is a character driver, else a file (block device)
    14    driver can work on control codes from AX=4402H/4403H Int 21H
  all remaining bits are reserved
/xlat by F.Glaser, Andreas Killer is not responsible!

    test    dl, 80h
    jnz     @@Done
    mov     al, True

Bye, Andreas.

Let me add my own workaround (not as clever as Andreas Killer's):
I wrote a space to the output and then checked the WhereX (of the CRT unit). If no CRT was in Uses, I looked for
the cursor location at 0040:00xx (I forgot where...). But it has the drawback that a space is on the file.

   Subject: Re: Turbo Pascal 6.0 und Windows 98 RTE200 on TP6
      Date: Wed, 08 Sep 1999 16:13:30 GMT
      From: (Horst Kraemer)
 Newsgroups: de.comp.lang.pascal.misc

On Wed, 08 Sep 1999 08:36:09 GMT, (Wilfried
Kramer) wrote:

> On Mon, 06 Sep 1999 22:54:16 +0200, "Ing. Franz Glaser"
> <> wrote:
> >Bernd Christoph Hartmann wrote:
> >>
> [ Details ... ]
> >> Der Rechner ist zu schnell und in der Unit CRT gibt es da ein Problem.
> >Nein, das glaub ich NICHT. Ich habe einen Haufen Programme, die
> >unter TP 6 compiliert sind, und die laufen unter DOS und WinNT
> >problemlos, auch auf 400ern. Win95 und 98 habe ich nicht.
> >Der RTE200 ist eine TP-7 - Sache, nicht TP 6.
> Soll ich das so verstehen, dass in der TP6 kein Ueberlauf auftritt?
> Und dass Borland das dann beim Uebergang zu TP7 verschlimmbessert hat?
> AFAIK trat das Ganze Problem doch frueher schon mal auf, als die
> Zaehler nur 8bit gross waren (TP3?).

Die Sache liegt so:

Beim Init von CRT wird eine "Eichschleife" durchlaufen und die Anzahl
der Schleifendurchlaeufe zwischen zwei Clock-Ticks, die als 55 ms
angesetzt wird, gezaehlt.

Zu Zeiten der TP6-Entwicklung ging man davon aus, dass diese Schleife
nie mehr als 65535 Mal durchlaufen wuerde. Daher spendierte man fuer
den Zaehler nur ein WORD und berechnete die Eichkonstante C:WORD per

        C := Zaehler div 55

Diese wird dann bei einem Delay-Aufruf mit der Anzahl der angegebenen
ms multipliziert und ergibt dann die Anzahl der fuer diesen Delay
auszufuehrenden Loops derselben Eichschleife.

Hier kann es keinen "Ueberlauf" im Sinne einer Prozessor-Exception
geben, da ein WORD1 DIV WORD2 in ASM nie einen DIV-Error produzieren

        mov bx, 55
        mov ax, C
        xor dx,dx
        div bx

Es gab aber im Laufe der Zeit immerhaeufiger einen "logischen"
Ueberlauf, da der WORD-Zaehler (vor der Division) ueberlief und auf 0
zurueckspang, weil ab 386 die Prozessoren erheblich schneller wurden.
Dadurch enthielt die Eichkonstante zwar unsinnige Resultate, die Delay
unbrauchbar macht, aber eine Hardware-Exception+RTE konnte es unter
TP6.0 beim Init von CRT nie geben.

Unter TP7.0 trug man diesem (wie sich spaeter herausstellte, zu
kurzsichtig, Rechnung). Man spendierte fuer die Zaehlvariable ein

Jetzt wurde die Division per

        mov bx, 55
        mov ax, C_lo
        mov dx, C_hi
        div bx

durchgefuehrt. Solange der Zaehler < 55*65536 ist, ist alles in
Butter. Aber die Entwickler rechneten nicht mit der rasanten
Entwicklung der Prozessoren. Auch eine ver-55-fachung des
hoechstzulaessigen Zaehlerwertes reichte nicht aus. Das Problem ist
nur, dass ein "logischer Ueberlauf" Zaehler>=55*65536 nun _auch_ durch
einen DIV-Ueberlauf (in Pascal RTE) bestraft wird, weil der
mathematische Quotient Zaehler div 55 nicht mehr in einen WORD passt.

In beiden Faellen kann man den Entwicklern maximal Kurzsichtigkeit
anlasten, da sie nie mit einem moeglichen Ueberlauf gerechnet haben.
Dass es nun bei Ueberlauf in TP6 zu keinem RTE200 und unter TP7 wohl
zu einem RTE200 kommt, ist in diesem Licht reiner Zufall, oder wie man
beim Schach sagt: Pech in der Stellung ;-)


   Subject: Re: UNIT problems   (unit decompilers...)
      Date: Sat, 02 Oct 1999 15:39:37 GMT
      From: Robert AH Prins <>
 Newsgroups: comp.lang.pascal.borland

In article <>,
  "Ing. Franz Glaser" <> wrote:
> Kim Hansen wrote:
> >
> > can someone please point me to
> > a program, that can disassemble
> > or some way alter the .TPUs,
> No! sorry.

Oi, oi, Franz, suffering from amnesia?     - William Peavy's program
(with full source!) to disassemble TP6 units - Norbert Juffa's TP6
replacement for SYSTEM.TPU   - Jim LeMay's TP6
replacement for SYSTEM.TPU - NJ's BP7 SYSTEM.TPU   - Morten Welinder's
TP/BP7 TPU peephole optimizer  - Duncan Murdoch's program
to extract SYSTEM.TPS from SYSTEM.TPU - Duncan Murdoch's TP6
unit disassembler (TWU1 is probably slightly better) - Duncan Murdoch's TP7
unit disassembler

Select "binaries" and at the bottom of the page you'll find three
entries for TPU, a newer version of DM's TP6 unit disassembler
(, the same and, TurboPower's
routines to extract TPU info.

Both TPL60N19 & BPL70N16 contain the full source of Norbert's improved
Borland 6-byte real routines and of his string routines.

Commercial TP/BP7 replacement unit? Look for references to Speedpack II

> > A compiler, that can build units
> > without including the system unit
> > will also do fine.
> Suggestion: Try to obtain Borland Pascal 7 (not Turbo Pascal 7). It
> has the source of the system units in ASM.
> I am using TP 6, and the source files were available for sale.

And if you really want to play, read some of my earlier postings in
comp.lang.pascal.borland (via deja), I've posted some useful (for me at
least) patches for TP6' TPC.EXE in the past, among them one to add
selected 386+ instructions to BASM, by, nothing for nothing, throwing
out some obsolete/duplicate instructions.



PS: Sorry if this appears more than once, Deja is playing up again...
Robert AH Prins

   Subject: Re: Real Numbers
      Date: Fri, 8 Oct 1999 14:55:27 +0200
      From: "B. Mahn" <>
 Newsgroups: borland.public.turbopascal



    Op1:=1.5;{stored in memory as $0081 0000 4000}
    Op2:=2.5;{stored in memory as $0082 0000 2000}
    Res:=Op1/Op2;{Res will later be stored as $9A80 9999 1999 (=0.6)}

    With {$N+,E-}
    The both REAL-Vars are first stored in AX:BX:DX and then pushed into
    The Calculation is done by CoProcessor.
    After Calculation the result will become popped from CoProcessor again
and stored in AX:BX:DX.
    The code line above will become this assembly code:
        mov     ax,WORD PTR [REALTEST.OP1]
        mov     bx,WORD PTR [REALTEST.OP1]+2
        mov     dx,WORD PTR [REALTEST.OP1]+4
        call    far SYSTEM.FREALEXT             ;Convert AX:BX:DX from Real
to Extended and push it into CoProcessor
        mov     ax,WORD PTR [REALTEST.OP2]
        mov     bx,WORD PTR [REALTEST.OP2]+2
        mov     dx,WORD PTR [REALTEST.OP2]+4
        call    far SYSTEM.FREALEXT             ;Convert AX:BX:DX from Real
to Extended and push it into CoProcessor
        fdivp   st(1),st                        ;divides st(1) through st(0)
(1.5/2.5) and pop st(0), the result is in st(0) now
        call    far SYSTEM.FEXTREAL             ;Convert Extended to Real
from CoProcessor and pop it into AX:BX:DX
        mov     WORD PTR [REALTEST.RES],ax
        mov     WORD PTR [REALTEST.RES]+2,bx
        mov     WORD PTR [REALTEST.RES]+4,dx

    With {$N-,E+}
    The REAL-Vars are stored in AX:BX:DX and CX:SI:DI.
    The line above will become this assembly code:
        mov     ax,[REALTEST.OP1]               ;save Op1 in AX:BX:DX
        mov     bx,[REALTEST.OP1]+2
        mov     dx,[REALTEST.OP1]+4
        mov     cx,[REALTEST.OP2]               ;save Op2 in CX:SI:DI
        mov     si,[REALTEST.OP2]+2
        mov     di,[REALTEST.OP2]+4
        call    far SYSTEM.RDIV                 ;Divides AX:BX:DX through
CX:SI:DI and save result in AX:BX:DX
        mov     [REALTEST.RES],ax               ;write result of calculation
into memory
        mov     [REALTEST.RES]+2,bx
        mov     [REALTEST.RES]+4,dx

   Subject: Re: Schnittpunkt zwischen Kreis und Strecke
              (intersection between circle and line)
      Date: Sat, 09 Oct 1999 12:27:00 +0200
      From: Florian Klaempfl <>
 Organization: Free-Net Erlangen Nuernberg Fuerth
 Newsgroups: de.comp.lang.pascal.misc

Christoph Burke wrote:
> Hallo!
> Gegeben sind zwei Punkte, die eine Strecke bilden.
> Gegeben ist ein Kreis, von dem der Mittelpunkt und der Radius bekannt sind.
> Ich suche nun eine fertige Procedure, die mir sagt, ob und wenn ja, wo sich
> die Figuren schneiden.
> Dieses Problem ist natürlich lösbar, jedoch habe ich nach den ersten
> Überlegungen gemerkt, daß es doch recht zeitaufwendig ist.
> Deswegen wollte ich das ganze Wissen des Internets nutzen; ohne Erfolg.
> Nun Versuche ich auf diesem Weg eine Lösung zu bekommen.
> Wer kann mir sagen, wo ich diese Procedure finde?


Die Gerade laesst sich in der Form
bringen, durch Loesen eines Gleichungssystema mit zwei Unbekannten:
(1) y1=m*x1+t
(2) y2=m*x2+t => t=y2-m*x2
(2) in (1) y1=m*x1+y2-m*x2 =>
m:=(y1-y2)/(x1-x2) und t:=y2-(y1-y2)*x2/(x1-x2);

Einsetzten der Geradengleichung:

Maple liefert dann:
mit D=-2*x0*m*t+2*x0*m*y0-t^2+2*t*y0-y0^2+r^2-m^2*x0^2+m^2*r^2
wenn D<0 kein Schnittpunkt
D=0 ein Schnittpunkt d.h. die Gerade ist eventuell eine Tagente
D>1 eventuell zwei Schnittpunkte

Wenn Du eine Strecke meinst, d.h. durch Endpunkte begrenzte Gerade,
dann muss Du noch die x-Werte der SChnittpunkte pruefen, ob sie
im "Definitionsbereich" der Streck liegen.

Nun hoffe ich noch, dass ich mich nicht vertippt habe ...

   Subject: Re: Number of days between two dates?
      Date: Sun, 10 Oct 1999 12:41:22 -0000
      From: "José Santos" <>

>I would like to calculate the number of days between two dates.
>The dates is from 1990 and on.
>Are there any units/code already written?

You are lucky, I've done a unit for precisely that.It also gives you the
ability to know what's the day of the week for a particular date.
I'm pasting it.

Unit Dates;
{Author: Jose Santos <>}


 TSmallInteger = Integer;
 TLongInteger  = Longint;

        Year  : TSmallInteger;
        Month : TSmallInteger;
        Day   : TSmallInteger;

 RefDate: TDate=
   Year  :  1000;
   Month :     1;
   Day   :     5
  ); {Reference date.It was a Sunday}

Function Bissext(Year: TSmallInteger): Boolean;
Function DaysInMonth(Year, Month: TSmallInteger): TLongInteger;
Function DaysFromDateXToY(DateX, DateY: TDate): TLongInteger;
Function DayOfWeek(Date: TDate): TSmallInteger;


Function Bissext(Year: TSmallInteger): Boolean;
  Bissext:=(Year Mod 4=0)And(Year Mod 100>0)Or(Year Mod 400=0);

Function DaysInMonth(Year, Month: TSmallInteger): TLongInteger;
  If Month In [1,3,5,7,8,10,12] Then
   DaysInMonth:=31 Else
  If Month <> 2 Then
   DaysInMonth:=30 Else
  If Bissext(Year) Then
   DaysInMonth:=29 Else

Function DaysFromYearXToY(YearX, YearY: TSmallInteger): TLongInteger;
 ResTemp: TLongInteger;
 i: TSmallInteger;
  For i:=YearX To YearY Do
   If Bissext(i) Then
    ResTemp:=ResTemp+366 Else

Function DaysFromMonthXToY(Year, MonthX, MonthY: TSmallInteger):
 ResTemp: TLongInteger;
 i: TSmallInteger;
  For i:=MonthX To MonthY Do
   ResTemp:=ResTemp+DaysInMonth(Year, i);

Function DaysFromDateXToY(DateX, DateY: TDate): TLongInteger;
 ResTemp: TLongInteger;
  If DateX.Year<>DateY.Year Then
   ResTemp:=DaysInMonth(DateX.Year, DateX.Month)-DateX.Day+
            DaysFromMonthXToY(DateX.Year, DateX.Month+1, 12)+
            DaysFromYearXToY(DateX.Year+1, DateY.Year-1)+
            DaysFromMonthXToY(DateY.Year, 1, DateY.Month-1)+
            DateY.Day Else
  If DateX.Month<>DateY.Month Then
   ResTemp:=DaysInMonth(DateX.Year, DateX.Month)-DateX.Day+
            DaysFromMonthXToY(DateX.Year, DateX.Month+1, DateY.Month-1)+
            DateY.Day Else

Function DayOfWeek(Date: TDate): TSmallInteger;
{Returns the day of week.0 is for Sunday, 1 for Monday, etc}
  DayOfWeek:=DaysFromDateXToY(RefDate, Date) Mod 7;

 {No initialization required}

You can also easily do a calendar with this unit.But avoid using DayOfWeek
to calculate every day of the month.It takes time and is unnecessary.You
just need to know the first day of the month.
RefDate is only used to calculate weekdays.It's unnecessary if you won't use

Hope this is useful.
Regards, Jose Santos

    Subject: Re: Runtime error 200
       Date: 28 Oct 1999 17:19:35 +0300
      From: (Osmo Ronkanen)
 Organization: University of Helsinki
 Newsgroups: comp.lang.pascal.borland

In article <>, EDP  <> wrote:
>runtime error 200 at 037F:0091 on Pentium II and Celeron PC.
>any solution or patches?

Use RT200FIX as the first unit of the program. Use RT200DEL after
CRT.PAS in every module (main program/unit) that uses Delay(). There
is no need to use RT200SUB directly.

The fix is for TP 7.0 and real mode only. In pre-7.0 or PM there is
no fix, nor interference.

The execution first gets to the Initialization code of RT200Sub. It
hooks the int 0 handler. Then the execution goes to the CRT
initialization code. If it RTE200's then the int 0 handler in RT200Sub
is activated and DX:AX is divided by two and Dfix multiplied by 2. The
execution then returns to the division instruction. It can fail again
causing further division (and multiplication) by two until it does not
fail. After the CRT initialization the initialization code of RT200Fix
itself is executed. It just unhooks the int 0 handler of RT200Sub so that
further divisions by zero will directly trigger the TP int 0 handler
(That is established in the system unit initialization which always is
executed at the very beginning)

As the Dfix is multiplied by two every time the DX:AX is divided by
two in the loop handler then the proper delays can be restored by
multiplying the ms count given to delay by Dfix. However, to avoid
overflows a loop is better choice. RT200Del does just that in its
Delay. The overhead caused by the loop is insignificant.


Unit RT200fix;


uses RT200Sub,crt,dos;


{$ifdef ver70}
{$ifdef msdos}
  SetIntVec(0,Int0Save);   { Restore the Int 0 handler }


Unit RT200Del;


uses RT200Fix,CRT,RT200Sub;

Procedure Delay(ms:word);


Procedure Delay(ms:word);
var i:word;
  for i:=1 to Dfix do CRT.Delay(ms);



Unit RT200Sub;


const dfix:word=1;       { call delay() dfix times }

Var int0Save:pointer;


{$ifdef msdos}
{$ifdef ver70}

uses dos;

Procedure Int0; assembler;
          shr dx,1        { divide dx:ax by 2 }
          rcr ax,1
          shl Dfix,1      { multiply Dfix by 2 }
          iret            { return to the DIV (286+) }


    Subject: Re: Win95/98 checking and reporting
       Date: 8 Jan 2000 14:51:05 GMT
       From: Andreas Killer <>
 Newsgroups: borland.public.turbopascal, comp.lang.asm.x86, comp.lang.pascal, comp.lang.pascal.borland,

LuK schrieb:

> I have some source code here but I cannot find how to detect what Windows
> evrsion a program is using.
> when running win98/95 the program only reports "Windows" and not Windows 95
> etc

        AX = 160Ah
Return: AX = 0000h if call supported
            BX = version (BH=major, BL=minor)
            CX = mode (0002h = standard, 0003h = enhanced)

  procedure GetWinVer(var Mayor, Minor, Mode : Byte); Assembler;
    mov     ax, 160Ah
    int     2fh
    or      ax, ax
    je      @@Supported
    {-Call is not supported, zero results}
    xor     bx, bx
    xor     cx, cx
    {-Return mayor version}
    mov     al, bh
    les     di, Mayor
    {-Return minor version}
    mov     al, bl
    les     di, Minor
    {-Return mode}
    mov     al, cl
    les     di, Mode

  Mayor, Minor, Mode : Byte;
  GetWinVer(Mayor, Minor, Mode);
  WriteLn('Windows95a returns version 3.95 mode 3');
  WriteLn('Windows98b returns version 4.10 mode 3');
  WriteLn('Version ', Mayor, '.', Minor, ' Mode ', Mode);

Bye, Andreas.

    Subject: Re: How can I see that more then one key is pressed?
      Date: Sat, 08 Jan 2000 10:52:21 +0100
      From: Andreas Killer <>
 Newsgroups: borland.public.turbopascal

KIM HANSEN schrieb:

> How can I see that more then one key is pressed and see which ones is?
> I know how to do with one key pressed something like this
> If keypressed Then
>  Begin
>    Ch := Readkey;
>    If Ch = #27 Then lala
>  End;
> But how to check all the keys hhmm dont no.
> Help me PLEASE
> Thanx you.
> wex@

I wrote a demoprogram a few years ago about this:

  Dos, Crt;
  KeysDown : array[1..127] of Boolean;
  Int9Save : procedure;
  KeyPolling : Boolean;

  procedure Int9Handler; Interrupt;
    Key : Byte;
    if KeyPolling then begin
      {-Read a key from the port}
      Key := Port[$60];
      {-Say that we got it}
      if Key < $80 then begin
        Port[$61] := Port[$61] or $80;
        Port[$61] := Port[$61] and $7F;
      {-Store keystate in the array}
      KeysDown[Key and $7F] := Key and $80 = 0;
      {-Send EOI to PIC}
      Port[$20] := $20;
    else begin
      inline($9C);                {-PUSHF}

  I : Byte;
  GetIntVec($9, @Int9Save);
  SetIntVec($9, Addr(Int9Handler));
  KeyPolling:= True;
    gotoXY(1, 1);
    for I := 1 to High(KeysDown) do begin
      if KeysDown[I] then
        TextAttr := $F
        TextAttr := $7;
      Write(I:3, ' ', Byte(KeysDown[I]), '   ');
  until KeysDown[1];              {-Esc}
  SetIntVec($9, @Int9Save);
  {-Release shiftstate}
  Mem[$40:$17] := Mem[$40:$17] and $F0;
  Mem[$40:$18] := Mem[$40:$18] and $FC;

Bye, Andreas

    Subject: Re: HD's > 2 GB Re: Bios und Ramspeicher
       Date: Thu, 27 Jan 2000 21:33:54 +0100
       From: Vinzent Hoefler <>
 Newsgroups: de.comp.lang.pascal (Martin Max Huckenbeck) wrote:

>Mal ein ähnliches Problem: Hat schon mal wer eine Möglichkeit nieder-
>geschrieben, mit der man auch Platten größer 2 GB (Frei+Gesamtspace)
>inputs entlocken kann?

RBIL ist Dein Freund. Da Platten > 2GB nur unter FAT32 Sinn machen
(FAT16 kann nur max. 2GB), also eine der netten und teilweise
natuerlich buggy (mittlerweile erwartet man das ja schon)

        AX = 7303h
        DS:DX -> ASCIZ string for drive ("C:\" or "\\SERVER\Share")
        ES:DI -> buffer for extended free space structure (see #01789)
        CX = length of buffer for extended free space
Return: CF clear if successful
            ES:DI buffer filled
        CF set on error
            AX = error code
Notes:  this function reportedly returns a maximum of 2GB free space
even on an FAT32 partition larger than 2GB under some versions of
Win95, apparently by limiting the number of reported free clusters to
no more than 64K on DOS versions which do not support the FAT32 calls,
this function returns CF clear/AL=00h (which is the DOS v1+ method for
reporting unimplemented functions)

Format of extended free space structure:
Offset  Size    Description     (Table 01789)
 00h    WORD    (ret) size of returned structure
 02h    WORD    (call) structure version (0000h)
                (ret) actual structure version (0000h)
 04h    DWORD   number of sectors per cluster (with adjustment for
 08h    DWORD   number of bytes per sector
 0Ch    DWORD   number of available clusters
 10h    DWORD   total number of clusters on the drive
 14h    DWORD   number of physical sectors available on the drive,
without adjustment for compression
 18h    DWORD   total number of physical sectors on the drive, without
adjustment for compression
 1Ch    DWORD   number of available allocation units, without
adjustment for compression
 20h    DWORD   total allocation units, without adjustment for
 24h  8 BYTEs   reserved

>Ich dachte mal, man könne die vorhandenen ASM-Teile einfach mal so
>umschreiben, das sie statt Bytes gleich in KBytes DIVen, da dann ja der
>Wert wieder in ein LongInt passen würde. Schon mal probiert?

Ich jedenfalls nicht. Wenn die Platte voll ist, gibt's dann halt 'nen
RTE100. ;-)

Ausserdem habe ich sowieso nur FAT16 (und ext2fs), weil ich so'n
neumodischen Kram nicht brauche. :-)


To err is human, to forgive beyond the scope of the operating system.

tpqa index tpqa 10 back  tpqa_12 forward tp_index faq_page

Get your own FREE HOMEPAGE