From ts@uwasa.fi Thu Jul 10 00:00:00 1997
Subject: FAQPAS5.TXT contents

                               Copyright (c) 1993-1997 by Timo Salmi
                                                 All rights reserved

FAQPAS5.TXT The fifth set of frequently (and not so frequently)
asked Turbo Pascal questions with Timo's answers. The items are in
no particular order.

You are free to quote brief passages from this file provided you
clearly indicate the source with a proper acknowledgment.

Comments and corrections are solicited. But if you wish to have
individual Turbo Pascal consultation, please post your questions to
a suitable Usenet newsgroup like news:comp.lang.pascal.borland. It
is much more efficient than asking me by email. I'd like to help,
but I am very pressed for time. I prefer to pick the questions I
answer from the Usenet news. Thus I can answer publicly at one go if
I happen to have an answer. Besides, newsgroups have a number of
readers who might know a better or an alternative answer. Don't be
discouraged, though, if you get a reply like this from me. I am
always glad to hear from fellow Turbo Pascal users.

....................................................................
Prof. Timo Salmi   Co-moderator of news:comp.archives.msdos.announce
Moderating at ftp:// & http://garbo.uwasa.fi archives  193.166.120.5
Department of Accounting and Business Finance  ; University of Vaasa
mailto:ts@uwasa.fi  <http://www.uwasa.fi/~ts>  ; FIN-65101,  Finland

--------------------------------------------------------------------
101) How do I detect if mouse hardware/driver is installed?
102) How can I read absolute sectors directly from a floppy?
103) How can I move a file to another directory in Turbo Pascal?
104) How can I get/set a disk volume label?
105) Is there a function to chop off the leading zero from 0.322?
106) How can I print a text file (and conclude sending a formfeed)?
107) How can I round 4.1256455 to two decimal places to give 4.13?
108) How can I list with paths all the files on a drive?
109) What are the formulas for ArcSin and ArcCos?
110) How can I determine how many bytes are allocated to a file?
111) How can I modify the colors of the VGA graphics palette?
112) How can I check if SMARTDRV has been installed? Which version?
113) Is there a way to make the text blink in the graphics mode?
114) How do I make writeln (15/18) give 0.83, not 8.3333333333E-01?
115) How do I get 256 colors instead of Turbo Pascal's normal 16?
116) How can I read a text character from the screen (e.g. xy 5,2)?
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:41 1997
Subject: Detecting mouse

101. *****
 Q: How do I detect if mouse hardware/driver is installed?

 A: The source code is given below. For more mouse related functions
please see ftp://garbo.uwasa.fi/pc/programming/inter54c.zip for
interrupt $33 functions.
  uses Dos;
  (* Detect if mouse hardware/driver is installed; initializes driver *)
  function MOUSDRFN : boolean;
  var regs : registers;
  begin
    FillChar (regs, SizeOf(regs), 0);  { Just to make sure }
    regs.ax := $0000;                  { Interrupt function number }
    Intr ($33, regs);                  { Call interrupt $33 }
    if regs.ax = $FFFF then
      mousdrfn := true
      else mousdrfn := false;
  end;  (* mousedrfn *)
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:42 1997
Subject: Reading absolute sectors

102. *****
 Q: How can I read absolute sectors directly from a floppy?

 A: Here is the source code for reading directly from a floppy disk.
For directly reading data from hard disk, please study the
information for interrupt $13 function $02 in Ralf Brown's list of
interrupts ftp://garbo.uwasa.fi/pc/programming/inter54a.zip.
  uses Dos;
  type readBufferType = array [1..1024] of byte;
  procedure READFLPY (drive  : char;
                      side   : byte;
                      track  : byte;
                      sector : byte;
                      var rb : readBufferType;
                      var ok : boolean);
  var regs : registers;
       i : byte;
  begin
    ok := false;
    for i := 1 to 3 do begin
      FillChar (regs, SizeOf(regs), 0);  { Just to make sure }
      regs.ah := $02;                    { Function }
      regs.al := 2;                      { Number of sectors to read }
      regs.dl := ord(Upcase(drive))-ord('A');
      if (regs.dl < 0) or (regs.dl > 1) then exit;   { For floppies only }
      regs.dh := side;
      regs.ch := track;
      regs.cl := sector;
      regs.es := Seg(rb);
      regs.bx := Ofs(rb);
      Intr ($13, regs);                  { Call interrupt $13 }
      if regs.flags and FCarry = 0 then begin   { Was it ok? }
        ok := true; exit;
      end; {if}
      { reset and try again a maximum of three times }
      FillChar (regs, SizeOf(regs), 0);  { Just to make sure }
      regs.ah := $00;                    { Function }
      regs.dl := ord(Upcase(drive))-ord('A');
    end; {for i}
  end;  (* readflpy *)
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:43 1997
Subject: Moving files

103. *****
 Q: How can I move a file to another directory in Turbo Pascal?

 A: If the file and the target directory are on the same disk you
can use Turbo Pascal's rename command for the purpose. If they are
on separate disks you'll first have to copy the file as explained in
the item "How can I copy a file in a Turbo Pascal program?" and then
erase the original as explained in the item "Can you tell a beginner
how to delete files with Turbo Pascal?"
  var f : file;
  begin
    Assign (f, 'r:\faq.pas');
    {$I-} Rename (f, 'r:\cmand\faq.pas'); {$I+}
    if IOResult = 0 then
      writeln ('File moved') else writeln ('File not moved');
  end.
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:44 1997
Subject: Getting/setting volume label

104. *****
 Q: How can I get/set a disk volume label?

 A: Getting the volume label can be done in alternative ways. Below
is one of them
  Uses Dos;
  (* Get a disk's volume label *)
  function GETLABFN (device : char) : string;
  var FileInfo : SearchRec;
      fsplit_dir  : DirStr;
      fsplit_name : NameStr;
      fsplit_ext  : ExtStr;
      stash       : byte;
  begin
    getlabfn := '';
    device := UpCase (device);
    if (device < 'A') or (device > 'Z') then exit;
    {}
    stash := fileMode;
    FileMode := $40;
    FindFirst (device + ':\*.*', AnyFile, FileInfo);
    while DosError = 0 do
      begin
        if ((FileInfo.Attr and VolumeId) > 0) then
          begin
            FSplit (FExpand(FileInfo.Name),
                    fsplit_dir, fsplit_name, fsplit_ext);
            Delete (fsplit_ext, 1, 1);
            getlabfn := fsplit_name + fsplit_ext;
            FileMode := stash;
            exit;
          end;
        FindNext (FileInfo);
      end; {while}
    FileMode := stash;
  end; (* getlabfn *)

As for setting a disk volume label with Turbo Pascal that is a much
more complicated task. You'll need to manipulate the File Control
Block (FCB). This alternative is not taken further in here. If you
need the procedure it is available without the source code as
  "SETLABEL Set a disk's volume label"
  in TSUNTL.TPU in ftp://garbo.uwasa.fi/pc/ts/tspa3570.zip.
An alternative is shelling to Dos to call its own LABEL.EXE program
as follows
  {$M 2048, 0, 0}   (* <-- Important. Adjust if out of memory. *)
  Uses Dos;
  begin
    SwapVectors;
    Exec (GetEnv('comspec'), '/c label A:');  (* Execution *)
    SwapVectors;
  end.
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:45 1997
Subject: Omitting leading zero

105. *****
 Q: Is there a function to chop off the leading zero from 0.322?

 A: If you wish to output a real without the leading zero you can
use the following function
  function CHOPFN (x : real; dd : byte) : string;
  var s : string;
  begin
    Str (x:0:dd, s);
    if x >= 0 then
      chopfn := Copy (s,2,255)
    else
      chopfn := '-' + Copy (s,3,255);
  end;  (* chopfn *)
There are other options. What is below is more cumbersome than
CHOPFN, but it demonstrates the usage of the Move command rather
nicely.
  function CHOP2FN (x : real; dd : byte) : string;
  var s : string;
  begin
    Str (x:0:dd, s);
    if x >= 0 then begin
      Move (s[2],s[1],Length(s)-1);
      Dec(s[0]);
      chop2fn := s;
      end
    else begin
      Move (s[3],s[1],Length(s)-2);
      Dec(s[0],2);
      chop2fn := '-' + s;
    end;
  end;  (* chop2fn *)
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:46 1997
Subject: Printing a file and a formfeed

106. *****
 Q: How can I print a text file (and conclude sending a formfeed)?

 A: We can turn this beginner's question into some instructive
source code. Study carefully the many details included. For printer
handling you might also wish to see in my FAQ the separate item
number 15 "How can I test that the printer is ready?"
  Uses Printer;             { Associates lst with the LPT1 device }
  const formfeed = #12;     { The formfeed character }
  var s : string;           { A string for a single line }
      filename : string;    { A variable for the file name }
      f : text;             { Text-file variable }
      fmsave : byte;        { For storing the original filemode }
  begin
    if ParamCount > 0 then  { If there are parameters on the command line }
      filename := ParamStr(1)                     { get the first of them }
    else begin
      writeln ('Usage: ', ParamStr(0), ' [Filename]');
      halt(1);              { Sets errorlevel to 1 for batches }
    end;
    fmSave := FileMode;     { Save the current filemode }
    FileMode := $40;        { To handle also read-only and network files }
    Assign (f, filename);   { Associate file variable with file name }
    {$I-}                   { Input/Output-Checking temporarily off }
    Reset (f);              { Open the file }
    {$I+}
    if IOResult <> 0 then begin    { Check failure of opening the file }
      writeln ('Error opening ', filename);
      FileMode := fmSave;   { Restore original filemode }
      halt(2);              { Sets errorlevel to 2 for batches }
    end; {if}
    while not eof(f) do begin
      readln (f, s);        { Read a line, maximum length 255 characters }
      writeln (lst, s);     { Write the line to the printer }
    end; {while}
    Close (f);              { Close the file }
    FileMode := fmSave;     { Restore the original filemode }
    write (lst, formfeed);  { Eject the page from the printer }
  end.
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:47 1997
Subject: Rounding a value

107. *****
 Q: How can I round 4.1256455 to two decimal places to give 4.13?

 A: Here is the source code. Note the two alternatives. The trivial
one of just formulating the output, and the more complicated of
actually rounding the value of a variable.
  var x, y : real;
  {}
  (* Sign function, needed to round negative values correctly *)
  function SignFn (a : real) : real;
  begin
    if a > 0.0 then signfn := 1.0
      else if a < 0.0 then signfn := -1.0
        else signfn := 0.0;
  end; (* sgnfn *)
  {}
  (* Round a real variable to d decimal places *)
  function RoundRealFn (x : real; d : byte) : real;
  var a : real;
      i : byte;
  begin
    a := 1.0;
    for i := 1 to d do a := a*10.0;
    RoundRealFn := Int (a*x + SignFn(x)*0.5) / a;
  end;  (* RoundRealFn *)
  {}
  (* Test *)
  begin
    x := 4.1256455;
    {}
    { ... The case of actually rounding a variable ...}
    y := RoundRealFn (x, 2);
    writeln (x, ' ', y);
    {}
    {... The more common case case of rounding the output only ...}
    writeln (x:0:2);
  end.
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:48 1997
Subject: Recursing directories

108. *****
 Q: How can I list with paths all the files on a drive?

 A: Here is the example source code
  {$M 16384,0,0}
  Uses Dos;
  {... the top directory ...}
  procedure FindFiles (Path, FileSpec : string);
  var FileInfo : SearchRec;
  begin
    FindFirst (Path + FileSpec, AnyFile, FileInfo);
    while DosError = 0 do begin
      if ((FileInfo.Attr and Directory) = 0) and
         ((FileInfo.Attr and VolumeId) = 0) then begin
        writeln (Path+FileInfo.Name);
      end; {if}
      FindNext (FileInfo);
    end; {while}
    {}
    {... subdirectories ...}
    FindFirst (Path + '*.*', Directory, FileInfo);
    while DosError = 0 do
      begin
        if ((FileInfo.Attr and Directory) > 0) and
            (FileInfo.Name <> '.') and
            (FileInfo.Name <> '..') then
              FindFiles (Path + FileInfo.Name + '\', FileSpec);
        FindNext (FileInfo);
      end; {while}
  end;  (* findfiles *)
  {}
  begin
    FindFiles ('C:\', '*.*');  { Note the trailing \ }
  end.
For starting below the root, use e.g. FindFiles ('C:\DOS\', '*.*');
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:49 1997
Subject: Arcsin and ArcCos

109. *****
 Q: What are the formulas for ArcSin and ArcCos?

 A: Arcsin is the inverse function of the sine. Hence y = acrsin(x)
implies x = sin(y). The values of x range from -1 and to 1. The
square root of (1-x^2) will become zero at -1 and 1 which will cause
an error if those special cases are not taken into account. Thus
define
  function ArcSin (x : real) : real;
  const halfPi = pi/2.0;
  begin
    if (x < -1.0) or (x > 1.0) then begin
      writeln ('ArcSin argument ', x, ' out of range [-1,1]');
      halt;
    end;
    if x = 1.0 then arcsin := halfPi
    else if x = -1.0 then arcsin := -halfPi
    else arcsin := ArcTan(x/Sqrt(1.0-Sqr(x)));
  end; (* arcsin *)

For ArcCos we can use
  function ArcCos (x : real) : real;
  const halfPi = pi/2.0;
  begin
    arccos := halfPi - ArcSin(x);
  end; (* arccos *)
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:50 1997
Subject: File size allocation

110. *****
 Q: How can I determine how many bytes are allocated to a file?

 A: Disk space is allocated to files by clusters, not by individual
bytes. Therefore, (except when exact multiples of cluster size)
files take up more space than is shown on the MS-DOS dir command
file size. To find out the true number of bytes a file takes up
you'll find have to find out what is the cluster size for the device
where the file is located. The following function does that.
  (* Allocation of bytes per cluster for the files on a drive *)
  function CLUSIZFN (device : char) : longint;
  var regs : registers;
  begin
    FillChar (regs, SizeOf(regs), 0);  { Just a precaution }
    with regs do begin
      ax := $3600;    { Get drive allocation information }
      dx := ord (UpCase(device)) - 64;  { Default=0, A=1, B=2,.. }
      MsDos (regs);   { Call interrrupt $21 }
      if (ax = $FFFF) then           { $FFFF if drive is invalid }
         clusizfn := -1              { To indicate an error }
       else
         clusizfn := cx * ax; { bytes per sector * sectors per cluster }
    end; {with}
  end;  (* clusizfn *)

Next, the following function can be used to find out the number of
bytes a file takes up.
  (* The file's total allocated bytes. Don't apply on an open file *)
  function ALLSIZFN (filename : string) : longint;
  var SizeOfCluster : longint;
      fmSave : byte;
      fpoint : file of byte;
  begin
    filename := FExpand (filename); { Make sure the drive is first }
    SizeOfCluster := CLUSIZFN (filename[1]);
    if SizeOfCluster = -1 then
      allsizfn := -1                { In case of error }
    else
      begin
        fmSave := FileMode;  { Store the FileMode value }
        FileMode := $40;     { Also read-only and network files }
        Assign (fpoint, filename);
        {$I-} Reset (fpoint); {$I+}
        if IOResult <> 0 then
          allsizfn := -1            { In case of error }
        else begin
          allsizfn := ((FileSize(fpoint) + SizeOfCluster - 1) div
                        SizeOfCluster) * SizeOfCluster;
          Close (fpoint);
        end;
        FileMode := fmSave;  { Restore the original FileMode status }
      end;
  end;  (* allsizfn *)
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:51 1997
Subject: Modifying VGA palette

111. *****
 Q: How can I modify the colors of the VGA graphics palette?

 A: Below is a demo source code how to do it. Solving this problem
is not trivial, but it is not overly complicated either.
   The related task of selecting the RGB (Red Green Blue) color
values to your liking is, in fact, the most laborious task. The
color values for each color component for the adapter run from 0 to
255, but in Turbo Pascal only only the 6 most-significant bits of
the color byte are loaded in the palette. Thus the TP color
components run from 0 to 63 only. The correspondence between the 0
to 255 and the 0 to 63 items can be found using the formula
  ReducedColorItem := Full8bitColorItem shr 2;
The reduction to 6 significant bits means that TP will unfortunately
not be able to utilize all the color combinations your VGA adapter
should be capable of.

  uses Crt, Graph;

  type RGBRecordType = record
                         c       : byte;
                         r, g, b : byte;
                       end;

  type RGBArrayRecordType = array[0..MaxColors] of RGBRecordType;

  const
    DefaultPalette : RGBArrayRecordType = (
     (c:  0; r: 0; g: 0; b: 0),   { Black; }
     (c:  1; r: 0; g: 0; b:40),   { Blue; }
     (c:  2; r: 0; g:40; b: 0),   { Green; }
     (c:  3; r: 0; g:40; b:40),   { Cyan; }
     (c:  4; r:40; g: 7; b: 7),   { Red; }
     (c:  5; r:40; g: 0; b:40),   { Magenta; }
     (c: 20; r:40; g:30; b: 0),   { Brown; }
     (c:  7; r:49; g:49; b:49),   { LightGray; }
     (c: 56; r:26; g:26; b:26),   { DarkGray; }
     (c: 57; r: 0; g: 0; b:63),   { LightBlue; }
     (c: 58; r: 9; g:63; b: 9),   { LightGreen; }
     (c: 59; r: 0; g:63; b:63),   { LightCyan; }
     (c: 60; r:63; g:10; b:10),   { LightRed; }
     (c: 61; r:44; g: 0; b:63),   { LightMagenta; }
     (c: 62; r:63; g:63; b:18),   { Yellow; }
     (c: 63; r:63; g:63; b:63) ); { White; }

  const
    MyPalette : RGBArrayRecordType = (
     (c:  0; r: 0; g: 0; b: 0),   { Black; }
     (c:  1; r: 0; g: 0; b:32),   { Blue; }
     (c:  2; r: 0; g:32; b: 0),   { Green; }
     (c:  3; r: 0; g:48; b:48),   { Cyan; }
     (c:  4; r:32; g: 0; b: 0),   { Red; }
     (c:  5; r:32; g: 0; b:32),   { Magenta; }
     (c: 20; r:43; g:21; b: 0),   { Brown; }
     (c:  7; r:48; g:48; b:48),   { LightGray; }
     (c: 56; r:32; g:32; b:32),   { DarkGray; }
     (c: 57; r: 0; g: 0; b:63),   { LightBlue; }
     (c: 58; r: 0; g:63; b: 0),   { LightGreen; }
     (c: 59; r: 0; g:63; b:63),   { LightCyan; }
     (c: 60; r:63; g: 0; b: 0),   { LightRed; }
     (c: 61; r:63; g: 0; b:63),   { LightMagenta; }
     (c: 62; r:63; g:63; b: 0),   { Yellow; }
     (c: 63; r:63; g:63; b:63) ); { White; }

  const
    BlackPalette : RGBArrayRecordType = (
     (c:  0; r: 0; g: 0; b: 0),   { Black; }
     (c:  1; r: 0; g: 0; b: 0),   { Blue; }
     (c:  2; r: 0; g: 0; b: 0),   { Green; }
     (c:  3; r: 0; g: 0; b: 0),   { Cyan; }
     (c:  4; r: 0; g: 0; b: 0),   { Red; }
     (c:  5; r: 0; g: 0; b: 0),   { Magenta; }
     (c: 20; r: 0; g: 0; b: 0),   { Brown; }
     (c:  7; r:48; g:48; b:48),   { LightGray; }
     (c: 56; r: 0; g: 0; b: 0),   { DarkGray; }
     (c: 57; r: 0; g: 0; b: 0),   { LightBlue; }
     (c: 58; r: 0; g: 0; b: 0),   { LightGreen; }
     (c: 59; r: 0; g: 0; b: 0),   { LightCyan; }
     (c: 60; r: 0; g: 0; b: 0),   { LightRed; }
     (c: 61; r: 0; g: 0; b: 0),   { LightMagenta; }
     (c: 62; r: 0; g: 0; b: 0),   { Yellow; }
     (c: 63; r: 0; g: 0; b: 0) ); { White; }

  procedure UsePalette (palette : RGBArrayRecordType);
  var i : byte;
  begin
    for i := 0 to MaxColors do
      SetRGBPalette (palette[i].c,
                     palette[i].r, palette[i].g, palette[i].b);
  end; (* UsePalette *)

  procedure DisplayPalette (x0, y0 : integer);
  const hight = 20; width = 30; separation = 10;
  var i, j, k : integer;
  begin
    k := 0;
    for j := 0 to 1 do begin
      for i := 0 to 7 do begin
        SetFillStyle (SolidFill, k);
        Bar (x0+i*(width+separation), y0+j*(hight+separation),
             x0+i*(width+separation)+width, y0+j*(hight+separation)+hight);
        Inc(k);
      end; {for i}
    end; {for j}
  end;  (* DisplayPalette *)

  var grDriver        : integer;
      grMode          : integer;
      ErrCode         : integer;
  begin
    grDriver := VGA;
    grMode := VGAHi;
    InitGraph (grDriver, grMode, ' ');
    ErrCode := GraphResult;
    if ErrCode <> grOk then begin
      Writeln ('Graphics error:', GraphErrorMsg(ErrCode)); halt; end;
    ClearDevice;  { Clears and homes the current pointer }
    {}
    SetFillStyle (SolidFill, LightGray);
    Bar (0, 0, GetMaxX, GetMaxy);
    DisplayPalette (50, 50);
    repeat until KeyPressed;
    while KeyPressed do ReadKey;
    {}
    UsePalette (MyPalette);
    DisplayPalette (50, 150);
    repeat until KeyPressed;
    while KeyPressed do ReadKey;
    {}
    UsePalette (BlackPalette);
    DisplayPalette (50, 250);
    repeat until KeyPressed;
    while KeyPressed do ReadKey;
    {}
    UsePalette (DefaultPalette);
    DisplayPalette (50, 350);
    repeat until KeyPressed;
    {}
    RestoreCrtMode;
    CloseGraph;
  end.
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:52 1997
Subject: Detecting SMARTDRV

112. *****
 Q: How can I check if SMARTDRV has been installed? Which version?

 A: Below is the source code

  Uses Dos;

  (* Has SMARTDRV been installed *)
  function SMARTFN : boolean;  { For SMARTDRV v4.00+ }
  var regs : registers;
  begin
    FillChar (regs, SizeOf(regs), 0);
    regs.ah := $4A;   { function }
    regs.al := $10;   { subfunction }
    regs.bx := $0000; { See $0003 for cache status }
    regs.cx := $EBAB;
    Intr ($2F, regs);
    smartfn := regs.ax = $BABE;   { A sense of humor ? }
  end; (* smartfn *)

  (* Get the SMARTDRV version *)
  function SMRVERFN : string;  { For SMARTDRV v4.00+ }
    function HEXFN (decimal : word) : string;
    const hexDigit : array [0..15] of char = '0123456789ABCDEF';
    begin
      hexfn := hexDigit[(decimal shr 12)]
            + hexDigit[(decimal shr 8) and $0F]
            + hexDigit[(decimal shr 4) and $0F]
            + hexDigit[(decimal and $0F)];
    end;  (* hexfn *)
  var regs : registers;
  begin
    FillChar (regs, SizeOf(regs), 0);
    regs.ah := $4A;   { function }
    regs.al := $10;   { subfunction }
    regs.bx := $0000; { See $0003 for cache status }
    regs.cx := $EBAB;
    Intr ($2F, regs);
    if regs.ax = $BABE then
      smrverfn := HEXFN(regs.bp)
    else
      smrverfn := 'Error';
  end; (* smrverfn *)
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:53 1997
Subject: Blinking in graphics mode

113. *****
 Q: Is there a way to make the text blink in the graphics mode?

 A: Unlike the argument options for TextColor in the Crt unit for
text output there is no predefined blink attribute for the Graph
unit. If you wish to have something blinking in the graphics mode,
be it text or part of an image, you'll have to build blinking with
output of alternating colors. Below is a simple demo of doing this.
  uses Crt, Graph;
  var grDriver : integer;
      grMode   : integer;
      ErrCode  : integer;
  const wait = 250;
  {}
  begin
    grDriver := Detect;
    InitGraph (grDriver, grMode, ' ');
    ErrCode := GraphResult;
    if ErrCode <> grOk then begin
      Writeln ('Graphics error:', GraphErrorMsg(ErrCode)); halt; end;
    SetColor (LightCyan);
    SetBkColor (Black);
    SetTextStyle(DefaultFont, HorizDir, 2);
    {}
    {... this is the example's key line ...}
    OutTextXY (0, 0, 'Some text');
    {}
    repeat
      SetColor (LightCyan);
      OutTextXY (0, 20, 'Press any key');
      Delay (wait);
      SetColor (Black);
      OutTextXY (0, 20, 'Press any key');
      Delay (wait);
    until KeyPressed;
    RestoreCrtMode;
    CloseGraph;
  end.
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:54 1997
Subject: Formatting output

114. *****
 Q: How do I make writeln (15/18) give 0.83, not 8.3333333333E-01?

 A: This information is surprisingly hard to locate in the manuals.
You'll find it in your Turbo Pascal 7.0 Programmer's Reference on
pages 204-206. Furthermore, it is not presented in the most
instructive of manners. So let's consider some a few simple examples
starting from the question posed.

Basically the format of writeln for text output is
  writeln ( YourVariable [ : [MinimumWidth] [ : DecimalPlaces ] );
Thus, to answer the question, to obtain "  0.83" you would use e.g.
  writeln (15/18 : 6 : 2);

There are some useful tricks that can be done with the text
formatting. To make the output always left-justified set
MinimumWidth to zero. For example you might have
  var x : real;
  begin
    x := -4.0/7.0;
    writeln (x : 0 : 2);
  end.
Which gives "-0.57".

Naturally it is also possible to regulate the length of the
exponential presentation. For example, writeln (x : 10) would give
"-5.714E-01".

The OutExpr formatting can be applied to other variable types as
well, including the string type. This is convenient for
right-justifying output as in the example below.
  const ff = 20;
  begin
    writeln ('Scott Earnest' : ff);
    writeln ('Osmo Ronkanen' : ff);
    writeln ('Timo Salmi' : ff);
    writeln ('John Stockton' : ff);
  end.
This will output
       Scott Earnest
       Osmo Ronkanen
          Timo Salmi
       John Stockton

The formatting can also be applied in converting numerical values to
strings with the Str procedure. For an example see the item "How do
I format graphics output like in textmode writeln?" in this same FAQ
collection.
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:55 1997
Subject: 256 colors

115. *****
 Q: How do I get 256 colors instead of Turbo Pascal's normal 16?

 A: This is only possible in the graphics mode. You'll need a
special BGI driver for the purpose. You'll find the drive and an
example of usage in
 18135 May 31 1989 ftp://garbo.uwasa.fi/pc/turbopas/vga256.zip
 vga256.zip Borland's BGI driver for VGA 256 color with Turbo Pascal demo
--------------------------------------------------------------------

From ts@uwasa.fi Thu Jul 10 00:01:56 1997
Subject: Reading from the screen

116. *****
 Q: How can I read a text character from the screen (e.g. xy 5,2)?

 A: The code for the task is given below
  Uses Dos;
  (* Read an individual character from the screen *)
  function VDCHXYFN (column, row : byte) : char;
  var regs : registers;
      videocolumns : byte;
      videobase : word;
      offset : word;
  begin
    { Get the video base address }
    FillChar (regs, SizeOf(regs), 0);
    regs.ah := $0F;  Intr ($10, regs);
    if regs.al = 7 then videobase := $B000 else videobase := $B800;
    {}
    { Get the screen width }
    FillChar (regs, SizeOf(regs), 0);
    regs.ah := $0F;
    Intr ($10, regs);
    videocolumns := regs.ah;
    {}
    { Get the character }
    offset := (((row-1)*videocolumns)+(column-1))*2;
    vdchxyfn := chr(mem[videobase:offset]);
  end;  (* vdchxyfn *)

  begin
     writeln ('Character at 5, 2 is ascii ', Ord(VDCHXYFN(5,2)));
  end.
--------------------------------------------------------------------

