From ts@uwasa.fi Sat Mar 30 00:00:00 1996
Subject: FAQPAS.TXT contents

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

FAQPAS.TXT 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.

If you are an experienced Turbo Pascal programmer with Turbo Pascal
material you would like to circulate publicly world-wide, you are
welcome to submit your material to the Garbo MS-DOS archives at the
University of Vaasa. To do that you *FIRST* must *CAREFULLY* read
the uploading instructions and the formal requirements in the file
ftp://garbo.uwasa.fi/pc/UPLOAD.INF. You are also welcome to contact
me by email for these instructions if you are not familiar with
downloading them from the Garbo archives.

....................................................................
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
ts@uwasa.fi http://uwasa.fi/~ts BBS 961-3170972; FIN-65101,  Finland

--------------------------------------------------------------------
 1) How do I disable or capture the break key in Turbo Pascal?
 2) How do I get a printed documentation of my students' TP runs?
 3) What is the code for the weekday of a given date?
 4) Need a program to format Turbo Pascal source code consistently
 5) Can someone give me advice for writing a tsr program?
 6) Why can't I read / write the com ports?
 7) What are interrupts and how to use them in Turbo Pascal?
 8) Should I upgrade my Turbo Pascal version?
 9) How do I execute an MS-DOS command from within a TP program?
10) How is millisecond timing done?
11) How can I customize the text characters to my own liking?
12) How to find the files in a directory and subdirectories?
13) I need a power function but there is none in Turbo Pascal.
14) How can I create arrays that are larger than 64 kilobytes?
15) How can I test that the printer is ready?
16) How can I clear the keyboard type-ahead buffer?
17) How can I utilize expanded memory (EMS) in my programs?
18) How can I obtain the entire command line?
19) How do I redirect text from printer to file in my TP program?
20) Turbo Pascal is for wimps. Use standard Pascal or C instead?
21) How do I turn the cursor off?
22) How to find all roots of a polynomial?
23) What is all this talk about "Pascal homework on the net"?
24) How can I link graphics drivers directly into my executable?
25) How can I trap a runtime error?
--------------------------------------------------------------------

Unless otherwise stated the answers cover versions 4.0, 5.0, 5.5,
6.0 and 7.0 (real mode). The Q&As are not for Turbo Pascal version 3
or earlier. Objects, TVision, Windows, Delphi, etc are not covered.
(I do not use them myself.)
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:01 1996
Subject: Disabling or capturing the break key

1. *****
 Q: I don't want the Break key to be able to interrupt my TP
programs. How is this done?
 Q2: I want to be able to capture the Break key in my TP program.
How is this done?
 Q3: How do I detect if a certain key has been pressed? (Often, how
do I detect, for example, if the CursorUp key has been pressed?)
 Q4: How do I detect if a cursor key or a function key has been
pressed?

 A: This set of frequently asked questions is basically a case of
RTFM (read the f*ing manual). But this feature is, admittedly, not
very prominently displayed in the Turbo Pascal reference. (As a
general rule we should not use the newsgroups as a replacement for
our possibly missing manuals, but enough of this line.)
   I'll only explain Q and Q2. The other two, Q3 and Q4 should be
evident from the example code.
   There is a CheckBreak variable in the Crt unit, which is true by
default. To turn it off use
     uses Crt;
     :
     CheckBreak := false;
     :
Besides turning off break checking this enables you to capture the
pressing of the break key as you would capture pressing ctrl-c. In
other words you can use e.g.
     :
  procedure TEST;
  var key : char;
  begin
    repeat
      if KeyPressed then
        begin
          key := ReadKey;
          case key of
             #0 : begin
                    key := ReadKey;
                    case key of
                      #59 : write ('F1 ');
                      #72 : write ('CursUp ');   { Detecting these }
                      #75 : write ('CursLf ');   { is often asked! }
                      #77 : write ('CursRg ');
                      #80 : write ('CursDn ');
                      else write ('0 ', ord(key), ' ');
                    end; {case}
                  end;
             #3 : begin    {ctrl-c or break}
                    writeln ('Break');
                    halt(1);
                  end;     { Terminate the program, or whatever }
            #27 : begin
                    write ('<esc> ');
                    exit;  { Exit test, continue program }
                  end;
            else write (key, ' ');
          end; {case}
        end; {if}
    until false;
  end;  (* test *)
     :
IMPORTANT: Don't test the ctrl-break feature just from within the TP
IDE, because it has ctlr-break handler ("interceptor") of its own
and may confuse you into thinking that ctrl-break cannot be
circumvented by the method given above.
  The above example has a double purpose. It also shows the
rudiments how you can detect if a certain key has been pressed. This
enables you to give input without echoing it to the screen, which is
a later FAQ in this collection.
  This is, however, not all there can be to break checking, since
the capturing is possible only at input time. It is also possible to
write a break handler to interrupt a TP program at any time. For
more details see Ohlsen & Stoker, Turbo Pascal Advanced Techniques,
Chapter 7. (For the bibliography, see FAQPASB.TXT in this same FAQ
collection).

 A2: This frequent question also elicits one of the most frequent
false answers. It is often suggested erroneously that the relevant
code would be
  uses dos;
  SetCBreak(false);
This is not so. It confuses MS-DOS and TP break checking with each
other. SetCBreak(false) will _*NOT*_ disable the Ctrl-Break key for
your Turbo Pascal program. What it does is "Sets the state of
Ctrl-Break checking in DOS". SetCBreak sets the state of Ctrl+Break
checking in DOS. When off (False), DOS only checks for Ctrl+Break
during I/O to console, printer, or communication devices. When on
(True), checks are made at every system call."
   This item goes to shows how important it is carefully to check
one's code and facts before claiming something.

 A3: Using the "CheckBreak := false;" method is not the only
alternative, however. Here is an example code for disabling
Ctrl-Break and Ctrl-C with interrupts
  uses Dos;
  var OldIntr1B : pointer;  { Ctrl-Break address }
      OldIntr23 : pointer;  { Ctrl-C interrupt handler }
      answer    : string;   { For readln test }
  {$F+}
  procedure NewIntr1B (flags,cs,ip,ax,bx,cx,dx,si,di,ds,es,bp : word);
            Interrupt;
  {$F-} begin end;
  {$F+}
  procedure NewIntr23 (flags,cs,ip,ax,bx,cx,dx,si,di,ds,es,bp : word);
            Interrupt;
  {$F-} begin end;
  begin
    GetIntVec ($1B, OldIntr1B);
    SetIntVec ($1B, @NewIntr1B);   { Disable Ctrl-Break }
    GetIntVec ($23, OldIntr23);
    SetIntVec ($23, @NewIntr23);   { Disable Ctrl-C }
    writeln ('Try breaking, disabled');
    readln (answer);
    SetIntVec ($1B, OldIntr1B);    { Enable Ctrl-Break }
    SetIntVec ($23, OldIntr23);    { Enable Ctrl-C }
    writeln ('Try breaking, enabled');
    readln (answer);
    writeln ('Done');
  end.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:02 1996
Subject: Directing output also to printer

2. *****
 Q: I want to have a printed documentation of my students' Turbo
Pascal program exercises. How is all input and output directed also
to the printer?

 A1: Use a screen capturing program to put everything that comes
onto the screen into a file, and print the file. See FAQPROGS.TXT in
ftp://garbo.uwasa.fi/pc/ts/tsfaqn43.zip (or whatever version number
is the current) for more about these programs. Available by
anonymous FTP or mail server from garbo.uwasa.fi.

 A2: See the code in TSPAS.NWS (item: Redirecting writes to the
printer) in the ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip (or whatever
is the current version number) Turbo Pascal units package (70 = 40,
50, 55, 60, or 70 depending on your TP version). Alternatively use
USECON and USEPRN routines in the TSUNTG unit of the same package.

     +------------------------------------------+
     ! To get these and other packages given as !
     !   /dir/subdir/name                       !
     ! see the instructions in PD2ANS.TXT       !
     +------------------------------------------+

 A3: But the really elegant solution to the problem of getting a
logfile (or a printed list) of a Turbo Pascal run is to rewrite the
write(ln) and read(ln) device driver functions. In itself writing
such driver redirections is very advanced Turbo Pascal programming,
but when the programming has once been done, the system is extremely
easy to use as many times as you like. It goes like this. The driver
redirections are programmed into a unit (say, tpulog or tpuprn). All
that is needed after that is to include the following uses statement
into the program (the target program) which has to be logged:
      uses TPULOG;    ( or )    uses TPUPRN;
This is all there is to it. Just adding one simple line to the
target program. (If you call any other units, "uses tpulog" must
come AFTER the system units (e.g. Dos), but BEFORE any which you may
define yourself!)
   The reason that I have named two units here instead of just one
in the above example is that the preferred log for the target
program may be a logfile or the printer. The better solution of
these two is to use the logfile option, and then print it. The
reason is simple. If the target program itself prints something,
your printout will look confused.
   The logging also has obvious limitations. It works for standard
input and output (read(ln) and write(ln)) only. 1) It does not
support graphics, in other words it is for the textmode. 2) It does
not support direct (Crt) screen writes. 3) And, naturally it only
shows the input and output that comes to the screen. Not any other
input or output, such as from or to a file. 4) Furthermore, you are
not allowed to reassign input or output. Statements like assign
(output, '') will result in a crash, because the rewritten output
device redirections are invalidated by such statements. 5) The
device on the default drive must not be write protected, since else
the logfile cannot be written to it. 6) It does not work for Turbo
Pascal 4.0. Despite these restrictions, the method is perfectly
suited for logging students' Turbo Pascal escapades.
   It is advisable first to test and run your target program without
"tpulog", so that if you get any strange errors you'll know whether
they are caused by the logging.
   Where to get such a unit. The code can be found in Michael
Tischer (1990), Turbo Pascal Internals, Abacus, Section 4.2. Next a
few of my own tips on this unit Tischer calls Prot. 1) The code is
in incorrect order. The code that is listed on pages 142 - 145 goes
between pages 139 and 140. 2) You can change the logfile name (const
prot_name) to lpt1 for a printed list of the target program run. In
that case it is advisable to include a test for the online status of
the printer within Tischer's unit. 3) I see no reason why the two
lines in Tischer's interface section couldn't be transferred to the
implementation section. Why have any global definitions?  But all in
all, it works like magic!

 A4: From: abcscnuk@csunb.csun.edu (Naoto Kimura (ACM))
Subject: Re: Printing a log of students' exercises revisited
To: ts@uwasa.fi
Date: Fri, 2 Nov 90 20:52:03 pdt
[Reproduced with Naoto's kind permission]
By the way, several months ago, I had submitted a file (nktools.zip)
file on SimTel that contains sources to a unit (LOGGER), which
allows logging of I/O going through the standard input and output
files, while still being able to use the program interactively.  I
believe that I also submitted a copy to your site.  It was something
I put together for use by students here at California State
University at Northridge.  The source works equally well in all
presently available versions of Turbo Pascal.
The only requirements are that
 * you place it as one of the last entries in the USES clause.  If
   there is anything that redirects the standard input and output
   file variables, you should put that unit before my unit in the
   USES clause, so that it can see the I/O stream.
 * Don't use the GotoXY and similar screen display control
   procedures in the Crt unit and expect it to come out the same way
   you had it on the display.  Since all my unit does is just
   capture the I/O stream to send it through the normal channels and
   also to the log file, all screen control information is not sent
   to the log file.
 * All I/O you want logged should go through the standard input and
   output file variables.
 * Don't close the standard input and output file variables, because
   it will cause problems.  Basically, as far as I have checked, it
   just causes the logging to stop at that point.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:03 1996
Subject: Code to give the weekday of a date

3. *****
 Q: I want code that gives the weekday of the given date.

 A1: There is a WKDAYFN function in my Turbo Pascal units collection
ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip (or whatever version number
is the latest, and where 70 is 40 50 55 60 and 70) Turbo Pascal
units collection to give the modern weekday based on Zeller's
congruence. Available by anonymous FTP or mail server from
garbo.uwasa.fi. Also you can find a more extensive Julian and
Gregorian weekday algorithm with source code in Dr.Dobb's Journal,
June 1989, p. 148. Furthermore Press & Flannery & al (1986),
Numerical Recipes, Cambridge University Press, present a weekday
code. The Numerical Recipes codes are available as
ftp://garbo.uwasa.fi/pc/turbopas/nrpas13.zip (big, 404k!).

 A2: Some will recommend the following kludge. Store the current
date, change it, and let MS-DOS get you the weekday. Don't use it!
It is a bad suggestion. On top of being sloppy programming, there
are several snags.  The trick works only for years 1980-2079. A
crash the program may leave the clock at a wrong date. And even if
multitasking is rare, in a multitasking environment havoc may result
for the other tasks. And you may have a TSR that requires the
correct date, etc.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:04 1996
Subject: Pretty printers (or uniform code)

4. *****
 Q: Where can I find a program that formats my (or my students')
Turbo Pascal code in a consistent matter.

 A: What you are asking for is often called "a pretty printer".
TurboPower Software's (the usual disclaimer applies) commercial
Turbo Analyst has a facility for this with many options. There are
also PD and shareware pretty printers, such as
 :
 16830 Nov 28 1989 ftp://garbo.uwasa.fi/pc/turbopas/ppdk50.zip
 ppdk50.zip Pascal Prettypringting Program, tweak, D.Kirschbaum
 :
 10015 Mar 29 1991 ftp://garbo.uwasa.fi/pc/turbopas/ppp.zip
 ppp.zip Pretty Print Pascal, with Turbo Pascal 5+ source, M.Bless
 :
 38021 Nov 5 1994 ftp://garbo.uwasa.fi/pc/turbopas/bp7sb104.zip
 bp7sb104.zip Borland and TP Source Beautifier, crippleware, J.Ferincz
 :
 25100 Jul 4 1992 ftp://garbo.uwasa.fi/pc/turbopas/epb232.zip
 epb232.zip Ed's Pascal Beautifier, E.Lee
 :
and others at garbo.uwasa.fi available by anonymous FTP or mail
server. See ftp://garbo.uwasa.fi/pc/INDEX.ZIP for the list of the
files.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:05 1996
Subject: How to write TSR programs

5. *****
 Q: Can someone give me advice for writing a tsr program?

 A: Writing a terminate and stay resident program can be considered
advanced programming and is beyond the scope of an electronic
message with limited space. Instead, here are some references to
Turbo Pascal books and papers which have a coverage of the subject.
Stephen O'Brien, Turbo Pascal, The Complete Reference, Chapter 16;
Stephen O'Brien, Turbo Pascal, Advanced Programmer's Guide, Chapter
6; Michael Tischer, Turbo Pascal Internals, Chapter 11 (a definite
bible of TP programming!); Michael Tischer (1992), PC Intern System
Programming, Chapter 32; Michael Yester, Using Turbo Pascal, Chapter
19; Kent Pottebaum, "Creating TSR Programs with Turbo Pascal", Dr.
Dobb's Journal, May 1989 and June 1989; Kris Jamsa, Dos Power User's
Guide, pp. 649-; Edward Mitchell (1993), Borland Pascal Developer's
Guide, Section "Writing TSRs", pp. 370-400, with 778 lines of sample
code.
   Also see example code files like
ftp://garbo.uwasa.fi/pc/turboobj/tsrhelp.zip,
ftp://garbo.uwasa.fi/pc/turbopa45/tess-5.zip,
ftp://garbo.uwasa.fi/pc/turbopa45/tsrunit.zip,
ftp://garbo.uwasa.fi/pc/turbopa7/pptsr10.zip,
ftp://garbo.uwasa.fi/pc/turbopa7/tsrsrc35.zip,
ftp://garbo.uwasa.fi/pc/turbopas/deltsr.zip,
ftp://garbo.uwasa.fi/pc/turbopas/tp4_tsr.zip.
   Furthermore, you should see the TSR.SWG examples in the fine SWAG
(SourceWare Archival Group's) collection of TP sources. Available
from the /pc/turbopas directory at Garbo. For the current references
to the SWAG files see ftp://garbo.uwasa.fi/pc/INDEX.ZIP.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:06 1996
Subject: Programming com ports

6. *****
 Q: Why can't I read / write the com ports.

 A: Com port programming (most often writing telecommunication
programs) is much much more complicated than simply trying to use
  write (com, whatever);
  read  (com, whatever);
This is a very advanced subject (frankly, beyond me), and the best
way to learn is to try to obtain some code to show you how. One
place to look at is Turbo Pascal text-books (I have a long list of
them at garbo.uwasa.fi archives in my collection of Turbo Pascal
units ftp://garbo.uwasa.fi/pc/ts/tsfaqp3470.zip. There also is an
example by David Rind in ftp://garbo.uwasa.fi/pc/pd2/faquote.zip.
Another source is International FidoNet pascal conference at some
bulletin board near you. The conference has had some very good
discussions in it. (No, I don't have them stored for distribution,
nor any further information.) Some files you might wish to look at:
ftp://garbo.uwasa.fi/pc/turbopas/comm_tp5.zip and comtty30.zip.
   Furthermore, you should see the COMM.SWG examples in the fine
SWAG (SourceWare Archival Group's) collection of TP sources.
Available from the /pc/turbopas directory at Garbo. For the current
references to the SWAG files see ftp://garbo.uwasa.fi/pc/INDEX.ZIP.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:07 1996
Subject: Primers to interrupt programming

7. *****
 Q: What are interrupts and how to use them in Turbo Pascal?

 A: An interrupt is a signal to the processor from a program, a
hardware device, or the processor itself, to suspend temporarily
what the program is doing, and to perform a routine that is stored
in the operating system. There are 256 such interrupt routines, with
many subservices stored in memory at locations, which are given in
the so called interrupt table. Turbo Pascal (somewhat like C) has a
special keyword Intr, and a predefined variable registers (in the
Dos unit) to access these interrupt routines. One way of looking at
them is as Turbo Pascal (complicated lowlevel) subroutines that are
already there ready for you to call.
   A detailed description of interrupt routines is way beyond a
single message with limited space. Instead, I shall give a simple
example, and good references to the subject. (For a somewhat more
comprehensive description of what an interrupt is, see INTERRUP.PRI
in Ralf Brown's ftp://garbo.uwasa.fi/pc/programming/inter48b.zip.)
     :
     uses Dos;
     (* This procedure turns on the border color for CGA and VGA *)
     procedure BORDER (color : byte);
     var regs : registers;  (* Predeclared in the Dos unit *)
     begin
       FillChar (regs, SizeOf(regs), 0);  (* A precaution *)
       regs.ax := $0B00;    (* Service number *)
       regs.bh := $00;      (* Subservice number *)
       regs.bl := color;
       Intr ($10, regs);    (* ROM BIOS video driver interrupt *)
     end;  (* border *)
   If you are new the subject and / or want ideas on the most useful
interrupts in Turbo Pascal programming, Ben Ezzel (1989),
Programming the IBM User Interface Using Turbo Pascal, is definitely
the best reference to look at. There are also many other good
references for a novice interrupt user, such as Jamsa & Nameroff,
Turbo Pascal Programmer's Library.
   If you are a more advanced interrupt user you'll find the
following references very useful. Michael Tischer (1990), Turbo
Pascal Internals; Norton & Wilton (1988), The New Peter Norton
Programmer's guide to the IBM PC & PS/2; Ray Duncan (1988), Advanced
MS-DOS Programming; Terry Dettmann (1989), Dos Programmer's
Reference, Second edition, Que. Furthermore, there is an impressive
list of interrupts collected and maintained by Ralf Brown. His
extensive ftp://garbo.uwasa.fi:/pc/programming/inter48a.zip,
inter48b.zip, inter48c.zip, inter48d.zip, inter48e.zip and
inter48f.zip (or whatever are the current versions when you read
this) is available by anonymous FTP or mail server from
garbo.uwasa.fi. A definite must for an advanced user. Also see the
reference to Brown's and Kyle's book in the bibliography at the end
of this FAQ. There is also a good hypertext advanced programmer's
quick reference ftp://garbo.uwasa.fi/pc/programming/helppc21.zip
which you might find useful.
   One more point for Turbo Pascal users. When Borland upgraded from
version 3 to 4.0 quite a number of tasks that needed to be done
using interrupts (such as getting the current time) were included as
normal TP routines. This means that while definitely useful,
interrupt programming is now relevant only in advanced Turbo Pascal
programming. Turbo Pascal 5.0 introduced a few more, but you can
find some of the missing TP 4.0 routines in the compatibility unit
in my ftp://garbo.uwasa.fi/pc/ts/tspa3440.zip TP units collection.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:08 1996
Subject: Borland's Turbo Pascal upgrades

8. *****
 Q: Should I upgrade my Turbo Pascal version?

 A1: Depends on what version you are using, and for what purposes.
If you are using version 3, the answer is a definite yes. There are
so many useful additions in the later version, including the concept
of units, and a great number of new useful keywords. The only reason
that I can think of for using TP 3 is that it makes .com files
(which reside in one memory segment only) instead of .exe files. As
an accounting and business finance teacher and researcher I've been
somewhat surprised to see postings stating that some users still
have to program in TP 3.0 because their employer doesn't want to
take the cost of upgrading. I find this cost argument ridiculous.
How about some consideration for cost effectiveness and
productivity?
   If you are currently using version 4.0, the most important point
in considering upgrading is the integrated debugger in the later
versions. It is really good, and useful if you write much code.
There are some minor considerations, as well. Later versions contain
some useful routines which 4.0 does not. I have programmed many of
them to be available also for 4.0 in my units collection
ftp://garbo.uwasa.fi/pc/ts/tspa3440.zip (or whatever is the latest
when you read this). Furthermore, I find somewhat annoying that the
executables will always end up in the default directory.
   If you are currently using version 5.0 the rational reasons for
upgrading are needing objects, and a better overlay manager. I have
also version 5.5 myself, but switched back to version 5.0 after I
had some problems with its linking of object files. (This is a false
statement from me, since it turned out that I had made a mistake
myself. My thanks are due to bj_stedm@gould2.bristol-poly.ac.uk
(Bruce Stedman) for questioning this item). Anyway, I don't use nor
need OOP objects (don't confuse linking object files and object
oriented programming here). One further point for 5.5. It has a
better help function than 5.0, and a few more procedures and
predefined constants. The TP 5.5 help includes examples, which can
be even pasted into your program. This is handy.
   The real snag in upgrading (waiving the reasonable cost) is the
fact that the units of the different versions are incompatible. If
you have a large library of units (as I do) you will have to
recompile the lot. This is something that has caused a fair amount
of justifiable flak against an otherwise excellent product.
   A tip. Don't throw away your Turbo Pascal version 3.0 manual, if
you have one. It is of use if you resort to the Turbo3 and Graph3
compatibility units. They give you access e.g. to turtle graphics.
   At the time of first writing this Turbo Pascal 6.0 version had
just been announced. I didn't have it yet myself, but I had been
(correctly) informed that its units are not compatible with the
earlier versions. I now have Turbo Pascal 6.0, and I must say that
my reactions have been disappointment and frustration. This is
probably partly (but not entirely) my own fault, since Turbo Pascal
seems to be headed from a common programming language into a full
professional's specialized tool, with many features I don't know how
to utilize. The only advancement from my point of view really is the
multiple file editing, but I have long had alternative programs for
that. If I used assembler (I don't) I am sure that I would find
useful TP 6.0's potential to include assembler code as such instead
of having to use the cumbersome Inline procedure of entering the
assembler code.
   There is also a Windows Turbo Pascal, as the latest addition to
the plethora. Since I don't use Windows at all, I have no further
information on it.
   I think a pattern is emerging here. Rather than being different
versions of the same product, the consecutive Turbo Pascals are
really different products for different purposes. Version 3.0 was a
simple programming language. Version 4.0 extended it into a full
scale programming modular platform. Version 5.0 introduced the
debugger. And there an advanced hobbyist's path ended. Version 5.5
introduced object oriented programming, which I'm sure is important
for the initiated, but personally I just don't need it even if I
write a lot of programs. And with the 6.0 we go completely out of
the realm of conventional programming into Turbo Pascal visions.
And Windows Turbo Pascal is for a different platform, altogether.
   I find the new integrated user interface of TP 6.0 awkward in
comparison to what was used in the 4.0, 5.0, and 5.5 versions. The
IDE of TP leaves less free memory than the previous versions.
Furthermore TP 6.0 IDE performs frequent disk accesses which cause
slowdowns  making it virtually unusable from a floppy. And I
wonder why Borland didn't at once go all the way to Windows, because
that is what 6.0 really is. An intermediate, incomplete step in that
direction. This means that we have a 5th upgrade in line with
incompatible units. This is aggravating even for a TP fan, isn't it?
   For information on Turbo Pascal version 7.0 and Borland email
contact numbers see ftp://garbo.uwasa.fi/pc/turbopa7/bp7-info.zip.
Also see ftp://garbo.uwasa.fi/pc/turbspec/bp7bugs2.zip by Duncan
Murdoch. Turbo Pascal 7.0 or more extensively Borland Pascal 7.0 is
a full professional's tool, and far beyond for example my moderate
programming needs. To list only a few of the features are protected
mode programming, handling of large programs, very fast compiling,
and a daunting amount of material elbowing its away on one's disk
space if one ever has the patience to look through it all. I would
use the word "overwhelming". But for a serious programmer this is an
impressive and a very worthwhile tool. One should not be misled
skipping it because of my comments which were written from a
hobbyist's point of view. As a general trend in programs, the
well-known columnist John C. Dvorak calls this increasing product
complexity trend "featurism" in PC Computing, May 1993. But TP 7.0
(7.01) has some important features also from a hobbyist's point of
view. So much so that I have finally succumbed to 7.01 myself. I
particularly like the color coding of the keywords, and the TPX
version enabling compiling very large programs (utilizing extended
memory). A very welcome addition are the new keywords break and
continue to exit or recycle a for, while or a repeat loop are.
Besides they make using the outcast goto statements virtually
unnecessary.

 A2: From: dmurdoch@watstat.waterloo.edu (Duncan Murdoch),
Newsgroups: comp.lang.pascal. Included with Duncan's kind
permission. [Duncan is one of the most knowledgeable and useful
contributors to the comp.lang.pascal UseNet newsgroup (later
replaced by comp.lang.pascal.borland for TP)].
   One other reason:  there's a bug in the code generator for 4.0
and 5.0 that makes it handle the Extended (10 byte) real type
poorly.  The code generated makes very poor use of the 8 element
internal stack on the coprocessor, so that expressions with lots of
operands like
  e1+e2+e3+e4+e5+e6+e7+e8+e9
always fail, if all the e's are of type extended.  (The generated
code pushes each operand onto the stack, then does all the adds.
It's smarter to push and add them one at a time.)
   This makes it a real pain translating numerical routines from
Fortran, especially since constants are taken to be of type
extended.
   The bug was fixed in 5.5.

 A3: From: Bengt Oehman (d92bo@efd.lth.se): A difference between
v4.0 and v5.5 is that you can calculate constants in tp55, but not
in 4.0. I see this as a big advantage. For example:
  CONST MaxW = 10;
        MaxH = 20;
        MaxSize = MaxW*MaxH;
        { or }
        MaxX = 100;
        HalfMaxX = MaxX DIV 2;
cannot be compiled with 4.0.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:09 1996
Subject: Shelling from a TP program

9. *****
 Q: How do I execute an MS-DOS command from within a TP program?

 A: The best way to answer this question is to give an example.
     {$M 2048, 0, 0}   (* <-- Important *)
     program outside;
     uses dos;
     begin
       write ('Directory call from within TP by Timo Salmi');
       SwapVectors;
       Exec (GetEnv('comspec'), '/c dir *.*');  (* Execution *)
       SwapVectors;
       (* Testing for errors is recommended *)
       if DosError <> 0 then
         writeln ('Dos error number ', DosError)
       else
         writeln ('Mission accomplished, exit code ', DosExitCode);
       (* For DosError and DosExitCode details see the TP manual *)
     end.
Alternatively, take a look at execdemo.pas from demos.arc which
should be on the disk accompanying Turbo Pascal.
   What the above Exec does is that it executes the command
processor. The /c specifies that the command interpreter is to
perform the command, and then stop (not halt).
   I have also seen it asked how one can swap the Turbo Pascal
program to the disk when shelling. It is unnecessary to program that
separately because there is an excellent program to do that for you.
It is ftp://garbo.uwasa.fi/pc/sysutil/shrom24b.zip.
   Somewhat surprisingly some users have had difficulties with
redirecting shelled output. It is straight-forward. In the above
code one would use, for example
  Exec (GetEnv('comspec'), '/c dir *.* > tmp');
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:10 1996
Subject: Millisecond timing

10. *****
 Q: How is millisecond timing done?

 A: A difficult task, but the facilities are readily available.
TurboPower Software's commercial Turbo Professional (don't confuse
with Borland's Turbo Professional) has a unit for this. (The usual
disclaimer applies). It is called tptimer and is part of the
ftp://garbo.uwasa.fi/pc/turbopas/bonus507.zip package. This one has
been released to the PD. I have also seen a SimTel upload
announcement of a ztimer11.zip for C and ASM, but I have no further
information on that. ftp://garbo.uwasa.fi/pc/turbopas/qwktimer.zip
is another option. It is not quite as accurate as tptimer.
   To test the tptimer unit in bonus507.zip you can use the
following example code
  uses Crt, tptimer;
  var time1, time2 : longint;
  begin
    InitializeTimer;
    time1 := ReadTimer;
    Delay (1356);    (* Or whatever code you wish to benchmark *)
    time2 := ReadTimer;
    RestoreTimer;
    writeln ('Elapsed = ', ElapsedTime (time1, time2)/1000.0 : 0 : 3);
  end.
   It is quite another question when you really need the millisecond
timing. The most common purpose for millisecond timing is testing
the efficiency of alternative procedures and functions, right? The
way I compare mine is simple. I call the procedures or functions I
want to compare for speed, say, a thousand times in a loop.  And
test this for elapsed time. This way the normal resolution (18.2
cycles per second) of the system clock becomes sufficient. This is
accurate enough for the comparisons.
     var elapsed : real; i : word;
     elapsed := TIMERFN;  (* e.g. from /pc/ts/tspa3455.zip *)
     for i := 1 to 1000 do YOURTEST;  (* Try out the alternatives *)
     elapsed := TIMERFN - elapsed;
     writeln ('Elapsed : ', elapsed : 0 : 2);
Incidentally, if you want to make more elaborate evaluations of the
efficiency of your code, Borland's Turbo Profiler is a useful tool.
(The usual disclaimer naturally applies.)
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:11 1996
Subject: Text font customizing

11. *****
 Q: How can I customize the text characters to my own liking?

 A: As far as I know, text-mode characters are hard-coded, and
cannot be customized at all unless you have an EGA or VGA adapter.
But you can always retrieve the bitmap information for the ascii
characters from your PC.
   The bitmap table for the lower part of the character set (0-127)
starts at memory position $F000 and ends at $FA6E. The upper part is
not at a fixed memory location. The pointer to the memory address of
upper part of the ascii table (provided that graftabl has been
loaded) is at an address $007C. One way of saying this is that the
segment address of the upper part's memory location is at $007E, and
its offset at $007C.
   Going into more details is beyond the scope of this posting. If
you want more information see Michael Tischer (1992), PC Intern
System Programming, "Selecting and Programming Fonts", pp. 197-210.
It also has information on a remotely related task of using sprites
(pp. 305-373), a concept familiar from the days of the Commodore 64
games programming. For another reference to customizing characters
see Kent Porter (1987), Stretching Turbo Pascal, Chapter 12, and
Kent Porter & Mike Floyd (1990), Stretching Turbo Pascal. Version
5.5. Revised Edition. Brady, Chapter 11.
   If you are interested in a demonstration of utilizing the
bitmapped character information (no source code available), take a
look at the demo in the garbo.uwasa.fi anonymous FTP archives file
ftp://garbo.uwasa.fi/pc/ts/tsdemo16.zip (or whatever version number
is current).
   Turbo Pascal also supports what is called stroked fonts (the
.chr) files which draw characters instead of bitmapping them. The
user should be able to write one's own .chr definitions, but I have
no experience nor information on how this can be done.
   There is something called bgikit10.zip which has facilities for
making fonts and adding graphics drivers. The problem is that I
cannot make it publicly available, since I think that it is not PD.
I am still missing the information. Unfortunately, it is not even
the only case where I encountered the fact that Borland does not
seem at all interested in the UseNet users' queries about the status
and distributability of their material.
   (From Leonard Erickson Leonard.Erickson@f51.n105.z1.fidonet.org
Well, you can *also* do it if you have a Hercules Graphics Card Plus
or Hercules InColor card (as far as I know, the only cards that
implemented Hercules RamFont 'standard'). And you can modify the
upper 128 characters on a CGA card. BTW, the RamFont cards are
*nice* pity it appeared too late to become a standard. It's a *lot*
more flexible than EGA/VGA fonts (I can have several *dozen* fonts
resident).)
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:12 1996
Subject: Finding files in TP

12. *****
 Q: How to find the files in a directory AND subdirectories?

 A: Writing a program that goes through the files of the directory,
and all the subdirectories below it, is based on Turbo Pascal's file
finding commands and recursion. This is universal whether you are
writing, for example, a directory listing program, or a program that
deletes, say, all the .bak files, or some other similar task.
   To find (for listing or other purposes) the files in a directory
you need above all the FindFirst and FindNext keywords, and testing
the predefined file attributes. You make these a procedure, and call
it recursively. If you want good examples with source code, please
see PC World, April 1989, p. 154; Kent Porter & Mike Floyd (1990),
Stretching Turbo Pascal. Version 5.5. Revised Edition, Chapter 23;
Michael Yester (1989), Using Turbo Pascal, p. 437; Michael Tischer
(1992), PC Intern System Programming, pp. 796-798.
   The simple (non-recursive) example listing all the read-only
files in the current directory shows the rudiments of the principle
of Using FindFirst, FindNext, and the file attributes, because some
users find it hard to use these keywords. Also see the code in the
item "How to establish if a name refers to a directory or not?" of
this same FAQ collection you are now reading.
    uses Dos;
    var FileInfo : SearchRec;
    begin
      FindFirst ('*.*', AnyFile, FileInfo);
      while DosError = 0 do
        begin
          if (FileInfo.Attr and ReadOnly) > 0 then
            writeln (FileInfo.Name);
          FindNext (FileInfo);
        end;
    end.  (* test *)

 A2: While we are on the subject related to FindFirst and FindNext,
here are two useful examples:

(* Number of files in a directory (not counting directories) *)
function DFILESFN (dirName : string) : word;
var nberOfFiles  : word;
    FileInfo     : searchRec;
begin
  if dirName[Length(dirName)] <> '\' then dirName := dirName + '\';
  dirName := dirName + '*.*';
  {}
  nberOfFiles := 0;
  FindFirst (dirName, AnyFile, FileInfo);
  while DosError = 0 do
    begin
      if ((FileInfo.Attr and VolumeId) = 0) then
        if (FileInfo.Attr and Directory) = 0 then
          Inc (nberOfFiles);
      FindNext (FileInfo);
    end; {while}
  dfilesfn := nberOfFiles;
end;  (* dfilesfn *)

(* Number of immediate subdirectories in a directory *)
function DDIRSFN (dirName : string) : word;
var nberOfDirs : word;
    FileInfo    : searchRec;
begin
  if dirName[Length(dirName)] <> '\' then dirName := dirName + '\';
  dirName := dirName + '*.*';
  {}
  nberOfDirs:= 0;
  FindFirst (dirName, AnyFile, FileInfo);
  while DosError = 0 do
    begin
      if ((FileInfo.Attr and VolumeId) = 0) then
        if (FileInfo.Attr and Directory) > 0 then
          if (FileInfo.Name <> '.') and (FileInfo.Name <> '..') then
            Inc (nberOfDirs);
      FindNext (FileInfo);
    end; {while}
  ddirsfn := nberOfDirs;
end;  (* ddirsfn *)
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:13 1996
Subject: A generic power function code for TP

13. *****
 Q: I need a power function but there is none in Turbo Pascal.

 A: Pascals do not have an inbuilt power function. You have to write
one yourself. The common, but non-general method is defining
   function POWERFN (number, exponent : real) : real;
     begin
       powerfn := Exp(exponent*Ln(number));
     end;
To make it general use:
   (* Generalized power function by Prof. Timo Salmi *)
   function GENPOWFN (number, exponent : real) : real;
   begin
     if (exponent = 0.0) then
       genpowfn := 1.0
     else if number = 0.0 then
       genpowfn := 0.0
     else if abs(exponent*Ln(abs(number))) > 87.498 then
       begin writeln ('Overflow in GENPOWFN expression'); halt; end
     else if number > 0.0 then
       genpowfn := Exp(exponent*Ln(number))
     else if (number < 0.0) and (Frac(exponent) = 0.0) then
       if Odd(Round(exponent)) then
         genpowfn := -GENPOWFN (-number, exponent)
       else
         genpowfn :=  GENPOWFN (-number, exponent)
     else
       begin writeln ('Invalid GENPOWFN expression'); halt; end;
   end;  (* genpowfn *)
On the lighter side of things an extract from an answer of mine in
the late comp.lang.pascal UseNet newsgroup:
 >anyone point out why X**Y is not allowed in Turbo Pascal?
   The situation in TP is a left-over from standard
   Pascal. You'll recall that Pascal was originally
   devised for teaching programming, not for
   something as silly and frivolous as actually
   writing programs.  :-)
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:14 1996
Subject: Arrays > 64K

14. *****
 Q: How can I create arrays that are larger than 64 kilobytes?

 A: Turbo Pascal does not directly support the so-called huge arrays
but you can get by this problem with a clever use of pointers as
presented in Kent Porter, "Handling Huge Arrays", Dr.Dobb's Journal,
March 1988. In this method you point to an element of a two
dimensional array using a^[row].col^[column]. The idea involves too
much code and explanation to be repeated here, so you'll have to see
the original reference. But I know from my own experience, that the
code works like magic. (The code is available from garbo.uwasa.fi
archives as ftp://garbo.uwasa.fi/pc/turbopas/ddj8803.zip). Kent
Porter, "Huge Arrays Revisited", Dr.Dobb's Journal, October 1988,
presents the extension of the idea to huge virtual arrays. (Virtual
arrays mean arrays that utilize disk space).
   Another possibility is using TurboPower Software's (the usual
disclaimer applies) commercial Turbo Professional (don't confuse
with Borland's Turbo Professional) package. It has facilities for
huge arrays, but they involve much more overhead than Kent Porter's
excellent method.

(* =================================================================
   My code below is based on a UseNet posting in the late
   comp.lang.pascal by Naji Mouawad nmouawad@watmath.waterloo.edu.
   Naji's idea was for a vector, my adaptation is for a
   two-dimensional matrix. The realization of the idea is simpler
   than the one presented by Kent Porter in Dr.Dobb's Journal, March
   1988. (Is something wrong, this is experimental.)
   ================================================================= *)
   {}
   const maxm = 150;
         maxn = 250;
   {}
   type BigVectorType = array [1..maxn] of real;
        BigMatrixType = array [1..maxm] of ^BigVectorType;
   {}
   var BigAPtr : BigMatrixType;
   {}
   (* Create the dynamic variables *)
   procedure MAKEBIG;
   var i          : word;
       heapNeeded : longint;
   begin
     heapNeeded := maxm * maxn * SizeOf(real) + maxm * 4 + 8196;
     if (MaxAvail <= heapNeeded) then
       begin writeln ('Out of memory'); halt; end;
     for i := 1 to maxm do New (BigAPtr[i]);
   end;  (* makebig *)
   {}
   (* Test that it works *)
   procedure TEST;
   var i, j : word;
   begin
     for i := 1 to maxm do
       for j := 1 to maxn do
         BigAPtr[i]^[j] := i * j;
     {}
     writeln (BigAPtr[5]^[7] : 0:0);
     writeln (BigAPtr[maxm]^[maxn] : 0:0);
   end;  (* test *)
   {}
   (* The main program *)
   begin
     writeln ('Big arrays test by Prof. Timo Salmi, Vaasa, Finland');
     writeln;
     MAKEBIG;
     TEST;
   end.
(For a better test of the heap than in MAKEBIG see Swan (1989), pp.
462-463.)
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:15 1996
Subject: Testing printer status

15. *****
 Q: How can I test that the printer is ready?

 A: Strictly speaking there is no guaranteed way to detect the
printer status on a PC. As Brian Key Brian@fantasia.demon.co.uk
wrote "Any book dealing with the PC BIOS support of a printer will
quickly show you that there is no hardware definition which deals
with the printer power status.  It simply wasn't designed (and I use
the word loosely!) into the IBM hardware specs."

   The usually advocated method in Turbo Pascal is to test the
status of regs.ah after a call to interrupt 17 Hex (the parallel
port driver interrupt), service 02:
      regs.dx := PrinterNumber;  (* LPT1 = 0 *)
      regs.ah := $02;            (* var regs : registers, uses DOS *)
      Intr ($17,regs);           (* Interrupt 17 Hex *)
      status := regs.ah          (* var status : byte *)
But this is not a good method since the combinations of the status
bits which indicate a ready state can vary from printer to printer
and PC to PC. If you want a list of the status bits, see e.g. Ray
Duncan (1988), Advanced MS-DOS Programming, p. 587. For an example
of a code using interrupt 17 Hex see Douglas Stivison (1986), Turbo
Pascal Library, pp. 118-120. Also see Michael Yester (1989), Using
Turbo Pascal, pp. 494-495.
   The more generic alternative is to try to write a #13 to the
printer having the i/o checking off, that is, while {$I-} is in
effect, and testing the IOResult. But then you must first alter the
printer retry times default (and restore it afterwards). Else the
method can take up to a minute instead of an immediate response.
Also, you must have set the FileMode for LPT1 appropriately (and
restore it afterwards). Sounds a bit complicated, but you don't have
to do all this yourself. There is a boolean function "LPTONLFN Get
the online status of the first parallel printer" for this purpose in
my ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip (or whatever version
number is the latest) Turbo Pascal units collection available by
anonymous FTP or mail server from garbo.uwasa.fi.

 A2: One potential, somewhat advanced solution is to use the Device
Driver Control (IOCTL) information. Here is the code.
  uses Dos;
  function PRNSTAFN : boolean;
  var regs   : registers;
      handle : ^word;
      f      : file;
  begin
    prnstafn := false;
    if swap(Dosversion) < $0200 then exit;  { At least MS-DOS 2.0 }
    Assign (f, 'prn');                 { Printer }
    Reset (f);
    FillChar (regs, SizeOf(regs), 0);  { Just to make sure }
    regs.ah := $44;                    { Function $44 }
    regs.al := $07;                    { Subfunction $07 }
    handle  := @f;                     { Establish a file handle }
    regs.bx := handle^;
    Msdos (regs);                      { Call interrupt $21 }
    Close (f);
    if regs.flags and FCarry <> 0 then exit;  { Is the carry flag set? }
    if regs.al <> $FF then exit;       { regs.al = $FF signals success}
    prnstafn := true;
  end;  (* prnstafn *)
  {}
  begin
    if PRNSTAFN then writeln ('Printer ready')
      else writeln ('Printer not ready');
    readln;
  end.

 A3: Another advanced method is using ports. This solution is based
on a posting by Joerg Kunze joerg@ang-physik.uni-kiel.de. A warning.
Do not experiment with the port parameters unless you know exactly
what you are doing. A serious loss of data might follow.
  function PRNON : boolean;
  var dr : word absolute $40:$08;
  begin
    prnon := port[dr+1] and $18=$18;
  end;
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:16 1996
Subject: Clearing the keyboard buffer

16. *****
 Q: How can I clear the keyboard type-ahead buffer?

 A: Three methods are usually suggested for solving this problem.
a) The first is to use something like
     uses Crt;
     while KeyPressed do ReadKey;
This kludge-type method has the disadvantage of requiring the Crt
unit. Also, in connection with procedures relying on ReadKey for
input, it may cause havoc on the programs logic.
b) The second method accesses directly the circular keyboard buffer
     var head : word absolute $0040:$001A;
         tail : word absolute $0040:$001C;
     procedure FLUSHKB; begin head := tail; end;
For a slightly different formulation of the same method see Michael
Tischer (1992), PC Intern System Programming, p. 462.
c) The third method is to call interrupt 21Hex (the MS-DOS
interrupt) with the ax register set as $0C00. This method has the
advantage of not being "hard-coded" like the second method, and thus
should be less prone to incompatibility.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:17 1996
Subject: Utilizing expanded memory

17. *****
 Q: How can I utilize expanded memory (EMS) in my programs?

 A: I have no experience (yet?) on this subject myself, but I can
give you a list of references: Michael Tischer (1990), Turbo Pascal
Internals, Abacus, Chapter 9; Michael Tischer (1992), PC Intern
System Programming, Chapter 12; Stephen O'Brien (1988), Turbo
Pascal, Advanced Programmer's Guide, Borland-Osborne, Chapter 4;
Chris Ohlsen & Gary Stoker (1989), Turbo Pascal Advanced Techniques,
Que, Chapter 11, Robert Jourdain (1992), Programmer's Problem
Solver, 2nd ed., Brady Publishing, pp. 68-87, and, maybe most
importantly, Dorfman & Neuberger, Turbo Pascal Memory Management
Techniques (with lots of code).
   Furthermore, Turbo Pascal delivery disks (at least 5.0) contain a
demos.arc archive which includes an ems.pas file.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:18 1996
Subject: Capturing the entire command line

18. *****
 Q: How can I obtain the entire command line (spaces and all)?

 A: ParamCount and ParamStr are for parsed parts of the command line
and cannot be used to get the command line exactly as it was. See
what happens if you try to capture
  "Hello.   I'm here"
you'll end up with a false number of blanks. For obtaining the
command line unaltered use
  type CommandLineType = string[127];
  var  CommandLinePtr  : ^CommandLineType;
  begin
    CommandLinePtr := Ptr(PrefixSeg, $80);
    writeln (CommandLinePtr^);
  end;
A warning. If you want to get this correct (the same goes for TP's
own ParamStr and ParamCount) apply them early in your program. At
least they must be used before any disk I/O takes place!
:
A related example demonstrating a function giving the number of
characters on the command line
  function CMDNBRFN : byte;
  var paramPtr : ^byte;
  begin
    paramPtr := Ptr (PrefixSeg, $80);
    cmdnbrfn := paramPtr^
  end;  (* cmdnbrfn *)
For the contents of the Program Segment Prefix (PSP) see Tischer,
Michael (1992), PC Intern System Programming, p. 753.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:19 1996
Subject: Redirecting from printer to file

19. *****
 Q: How do I redirect text from printer to file in my TP program?

 A: Simple. This is done in Turbo Pascal by using the assign command
(think what the word 'assign' implies). Here is a simple example of
the idea.
  uses Printer;
  begin
    assign (lst, 'printer.log');
    rewrite (lst);
    writeln (lst, 'Hello world');
    close (lst);
  end.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:20 1996
Subject: Turbo Pascal users are just wimps

20. *****
 Q: Turbo Pascal is for wimps. Why don't you use standard Pascal or
better still why don't you use C?

 A: These kinds of "real-programmers" statements often reflect what
is called self-over-others attitude, and they are a part of a kind
of a programming lore or cult. Basically, these attitudes waive the
simple fact that one should select one's tools according to the task
at hand, not vice versa. On the other hand one's productivity is
usually best when being able to use tools which one is familiar and
comfortable with. (Note however that the real-programmer's lore is
not really interested in producing results.)
   In very rough terms there are two attitudes to programming
languages. They can be seen as tools for writing applications, or
(by surprisingly many) as ends themselves.
   If we first look at standard Pascal (versus Turbo Pascal),
considering the language primary and its usage secondary is common.
This results from the history of Pascal, since as we all know it was
originally meant as a means for teaching programming concepts, not
at all for writing applications. But because Pascal turned out to be
useful also for writing applications, it has been extended for some
operating systems, most notably MS-DOS (Turbo Pascal) and VAX/VMS
(VAX Pascal). Both remedy a lot of flaws from the application
programmer's point of view. Most importantly they have a true file
I/O interface, and enhanced string handling. Turbo Pascal (the more
generic of these two) clearly draws from the structure and ideas of
advanced BASICs (and vice versa). While in standard Pascal the
language is an end by itself, for Turbo Pascal the only relevant
issue is its usefulness for writing applications.
   One problem that one encounters when moving away from standard
Pascal is the problem of portability. This is a truly serious
problem, since most often extensive rewriting is necessary from
converting say Turbo Pascal to, say, Unix Pascal. I have taken Unix
Pascal as the extreme example, since Unix Pascal is almost nothing
but the standard Pascal having no useful file I/O.
   If one considers C, its best aspect from applications point of
view is portability, and its strength for system programming. But it
is not an easy language to learn. Proponents of C also often have
the tendency discussed above, that is seeing the language as
primary, and its utilization as secondary. Now why this tendency,
not only for C, but in general? I've had the opportunity of writing
programs starting from the late 1960's, and one observation I have
made, and often propounded the view is that it is not writing code
that is the really difficult part. What is really difficult it is
coming up with good and original ideas for programs to write. I see
applications as primary, and the tools as secondary. As to Turbo
Pascal, I've written in many languages (including Cobol, Fortran,
several Basics and Pascals, and command languages) and I like Turbo
Pascal because it is one of the most convenient and flexible tools
for writing the kind of applications that I usually write and
distribute for the Public Domain. That is I use Turbo Pascal because
I'm comfortable with it in writing applications, and have thus
gathered a very useful modular library for it over the years, not
because of any inherent value attached to Turbo Pascal per se.

 A2: Another, a somewhat resembling line is made up by the arguments
about standards in Pascal which were recycled in the late
comp.lang.pascal time after time. Very often they end up with
purists vs pragmatists arguing about the true or imaginary viles of
using GOTOs. I find all this somewhat futile, although I understand
the academic nature of the background. As you'll recall, Pascal was
first developed for academic teaching programming concepts, not for
any practical programming. That came later, and the ensuing
popularity of Pascal in practical applications must have come as a
surprise way back then. I admit being biased in not sympathizing
with Pascal standard stalwarts. I am far more interested in getting
the job done than in defending a barren orthodoxy.
   Since Turbo Pascal version 7.0 introduced the "break" and
"continue" keywords to handle jumps in loops, GOTOs are much easier
to avoid without undue complications.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:21 1996
Subject: Turning off the cursor

21. *****
 Q: How do I turn the cursor off?

 A: The usually advocated trick for turning the cursor off is to
equate the lower and the upper scan line of the cursor as explained
e.g. in Stephen O'Brien (1988), Turbo Pascal, Advanced Programmer's
Guide.
     uses Dos;
     var regs : registers;
     begin
       regs.ax := $0100;   (* Service $01 *)
       regs.cl := $20;     (* Top scan line *)
       regs.ch := $20;     (* Bottom scan line *)
       Intr ($10, regs);   (* ROM BIOS video driver interrupt *)
     end;
To turn the cursor back on this (and many other) sources suggest
setting regs.ch and regs.cl as 12 and 13 for mono screen, and 6 and
7 for others.
   This is not a good solution since it is equipment dependent, and
may thus produce unexpected results. Better to store the current
scan line settings, and turn off the cursor bit. Below is the code
from ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip (or whatever version
number is the latest) available by anonymous FTP from garbo.uwasa.fi
archives. The general idea is that regs.ch bit 5 toggles the cursor
on / off state. Thus to set the cursor off, apply
  regs.ch := regs.ch or $20;    (* $20 = 00100000 *)
and to set it on, apply
  regs.ch := regs.ch and $DF;   (* $DF = 11011111 *)
(* From TSUNTE unit, which also has a CURSON procedure *)
procedure CURSOFF;
var regs : registers;
begin
  FillChar (regs, SizeOf(regs), 0);  (* Initialize, a precaution *)
  {... find out the current cursor size (regs.ch, regs.cl) ...}
  regs.ah := $03;
  regs.bh := $00;    (* page 1, superfluous because of FillChar *)
  Intr ($10, regs);  (* ROM BIOS video driver interrupt *)
  {... turn off the cursor without changing its size ...}
  regs.ah := $01;                   (* Below are bits 76543210 *)
  regs.ch := regs.ch or $20;  (* Turn on bit 5; $20 = 00100000 *)
  Intr ($10, regs);
end;  (* cursoff *)

 A2: A comment from Leonard Erickson leonard@qiclab.scn.rain.com.
Reprinted with permission. There's a *reason* those sources don't
suggest storing the current scan line settings. On IBM Monochrome
Display Adapters (MDA), Hercules Graphics Cards, and the various
clones of both, the "read cursor start and end scan lines" function
*always* returns the same values. And those values are almost never
the actual settings. Most cards return 6 & 7. Some return 12 & 13.
But they return these values even if the cursor has been set to
something else.
   So you are *still* stuck with checking the hardware type if the
screen is in mode 7.
   See the Interrupt list for details on this mess.

 A3: Another solution that has been suggested is putting the cursor
outside the screen.  But you can't do this with the Crt's GotoXY
procedure, since it ignores off screen positions, as observed by
Luiz Marques luiz.marques%mandic@ibase.org.br. You'll need to use
video interrupt, that is $10, function $02. Fair enough, but
somewhat complicated. Besides, how do you write on the screen if the
cursor position is off it?

 A4: This snippet of disabling the cursor at hardware level was
posted to comp.lang.pascal (now news:comp.lang.pascal.borland) by
JAB@ib.rl.ac.uk. Corrections due to John Stockton. John also points
out that this probably needs a VGA to work.
  procedure turn_off_cursor;
  var num : word;
  begin
    port[$03D4]:=$0A; num:=port[$03D5];
    port[$03D4]:=$0A; port[$03D5]:=num or 32;
  end;
  {}
  procedure turn_on_cursor;
  var num : word;
  begin
    port[$03D4]:=$0A; num:=port[$03D5];
    port[$03D4]:=$0A; port[$03D5]:=num and not 32;
  end;
  {}
  procedure toggle_cursor;
  var num : word;
  begin
    port[$03D4]:=$0A; num:=port[$03D5];
    port[$03D4]:=$0A; port[$03D5]:=num xor 32;
  end;

 A5: (Not to be taken seriously). Simple, turn off your computer and
the cursor stops showing :-).
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:22 1996
Subject: Finding the roots of a polynomial

22. *****
 Q: How to find all roots of a polynomial?

 A: If you need the code, see Turbo Pascal Numerical Toolbox and/or
Press & Flannery & Teukolsky & Vetterling (1986), Numerical Recipes,
The Art of Scientific Computing, Cambridge University Press. The
Numerical Recipes codes are available as /pc/turbopas/nrpas13.zip
(big, 404k!). If you just need to solve such a task (without code
available), get ftp://garbo.uwasa.fi/pc/ts/tsnum12.zip (or whatever
version number is the latest) from garbo.uwasa.fi archives by
anonymous FTP or mail server.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:23 1996
Subject: Pascal homework on the net

23. *****
 Q: What is all this talk about "Pascal homework on the net"?

 A: This is one of the subjects that seems to pop up at regular
intervals, cause some heated exchange for awhile, and then die down
again leaving some users harboring warranted or unwarranted grudges.
   Some posters to comp.lang.pascal (later comp.lang.pascal.borland)
have been very concerned of the possibility that the questions posed
on the net are related to students' homework assignments. I don't
have any unequivocal answers or a clear-cut stand on this question,
just some comments.
   The most important task of a newsgroup like comp.lang.pascal.borland
is the exchange of information between the users. If you think that
what you are going to post is interesting and useful to the group,
that should be your topmost criterion.
   If it is really a student that wants his/her work done on the net
(how do we know anyway?) also consider the following fact. Being
able to use a newsgroup amounts to having learned at least something
about using computers, and that is something per se.
   Even if the student may short-sightedly not realize it, providing
ALL the code for a student's homework is detrimental to the student,
since it is she/he that foregoes understanding what he/she is doing.
The group should not condone outright cheating. Being (partly) a
teacher myself, I understand also this view.
   If a student is stuck with a problem in his/her code, I don't see
any real harm in helping out, especially if the problem has general
interest. Instructing is what teaching is about, anyway, isn't it?
   But, on the other hand, I must admit that I find a it rather
flagrant if a posting asks for something of the kind "I have to
complete my term assignment to write a function plotter by the end
of this month. Send me the code, since I'm too busy with my other
exams to write it myself" (a true quote).
   Finally, let's not jump to premature conclusions about anyone's
questions.  That's what most often triggers off a vicious circle of
flaming.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:24 1996
Subject: Linking bgi drivers into executables

24. *****
 Q: How can I link graphics drivers directly into my executable?

 A: This is a complicated, yet a very useful task, because then you
won't need any separate graphics drivers (or fonts) to go separately
along with your program. Unfortunately, Turbo Pascal documentation
on this task is a bit confusing.
   1) The very first step is to get the necessary files from the
Turbo Pascal disks to your working directory. To start with, you'll
need binobj.exe and all the .bgi files.
   2) Run the following commands (best to place them in a batch,
call it e.g. makeobj.bat):
     binobj cga.bgi cga CGADriverProc
     binobj egavga.bgi egavga EGAVGADriverProc
     binobj herc.bgi herc HercDriverProc
     binobj pc3270.bgi pc3270 PC3270DriverProc
     binobj att.bgi att ATTDriverProc
     rem binobj ibm8514.bgi 8514 IBM8514DriverProc
   3) Get drivers.pas from the Turbo Pascal disk and compile it with
Turbo Pascal. Now you have a drivers.tpu unit which contains all the
graphics drivers.
   4) Now you won't need the .bgi and the .obj files any more. You
may delete them from your working directory.
   5) Write your graphics program in the usual manner. But before
putting your program in the graphics mode use the following
procedure if you want to link e.g. the EGAVGA graphics driver
directly into your executable. (Link just the driver(s) you'll need,
since the drivers take up a lot of space.)
     uses Graph, Drivers;
     :
     procedure EGAVGA2EXE;
     begin
       if RegisterBGIdriver(@EGAVGADriverProc) < 0 then
         begin
           writeln ('EGA/VGA: ', GraphErrorMsg(GraphResult));
           halt(1);
         end;
     end; (* egavga2exe *)
     :
   Linking the .bgi and .chr drivers is also covered in Swan (1989),
Mastering Turbo Pascal 5.5 pp. 355-359 and Mitchell (1993), Borland
Pascal Developer's Guide , pp. 221-229.
   If you have Turbo Pascal 7.0 its help function gives you an
example code. One way of getting at it is the following. In the
Turbo Pascal IDE (that is in the editor) type RegisterBGIdriver.
Then place the cursor on it and press alt-F1 for help of that
keyword. Press alt-F10 and select "Copy example". Press first <ESC>
then alt-F10 and select Paste. The example code is pasted within
your program for you to study.
   Incidentally, although this is a slightly different matter, you
can link any data material into your executable. See Stephen
O'Brien, (1988), Turbo Pascal, Advanced Programmer's Guide, pp. 31 -
35 for more details.
--------------------------------------------------------------------

From ts@uwasa.fi Sat Mar 30 00:00:25 1996
Subject: Trapping runtime errors

25. *****
 Q: How can I trap a runtime error?

 A: What you are probably asking for is a method writing a program
termination routine of your own. To do this, you have to replace
Turbo Pascal's ExitProc with your own customized exec procedure.
Several Turbo Pascal text books show ho to do this. See e.g. Tom
Swan (1989), Mastering Turbo Pascal 5.5, Third edition, Hayden
Books, pp. 440-454; Michael Yester (1989), Using Turbo Pascal, Que,
pp. 376-382; Stephen O'Brien (1988), Turbo Pascal, Advanced
Programmer's Guide, pp. 28-30; Tom Rugg & Phil Feldman (1989), Turbo
Pascal Programmer's Toolkit, Que, pp. 510-515. Here is an example
  var OldExitProcAddress : Pointer;
      x : real;
  {$F+} procedure MyExitProcedure; {$F-}
  begin
    if ErrorAddr <> nil then
      begin
        writeln ('Runtime error number ', ExitCode, ' has occurred');
        writeln ('The error address in decimal is ',
                  Seg(ErrorAddr^):5,':',Ofs(ErrorAddr^):5);
        writeln ('That''s all folks, bye bye');
        ErrorAddr := nil;
        ExitCode  := 0;
      end;
    {... Restore the pointer to the original exit procedure ...}
    ExitProc := OldExitProcAddress;
  end;  (* MyExitProcedure *)
  (* Main *)
  begin
    OldExitProcAddress := ExitProc;
    ExitProc := @MyExitProcedure;
    x := 7.0; writeln (1.0/x);
    x := 0.0; writeln (1.0/x);   {The trap}
    x := 7.0; writeln (4.0/x);   {We won't get this far}
  end.
:
Actually, I utilize this idea in my /pc/ts/tspa3470.zip Turbo Pascal
units collection, which includes a TSERR.TPU. If you put TSERR in
your program's uses statement, all the run time errors will be given
verbally besides the usual, cryptic error number. That's all there
is to it. That is, the inclusion to the uses statement to your main
program (if you have the program in several units) is all you have
to do to enable this handy feature.
:
Hans.Siemons@f149.n512.z2.fidonet.org notes "This line:
    ExitProc := OldExitProcAddress;
should IMHO never be placed at the end of your exit handler. If for
one reason or another your own handler should cause a runtime error,
it would go in an endless loop. If the first statement restores the
exit chain, this can never happen. I do agree that is not very
likely that your exit handler produces any runtime error, but it
performs I/O, and since it is located in a FAQ, people are bound to
use, and maybe extend it with more tricky stuff."
--------------------------------------------------------------------

