

		     Late News on Turbo Professional 4.03
		     ------------------------------------

	  +-------------------------------------------------------+
	  |		      Table of Contents 		  |
	  +-------------------------------------------------------+
	  |  1. Missing and moved files 			  |
	  |  2. TPCRT compatibility issues			  |
	  |  3. TPCRT, DESQVIEW, and TASKVIEW			  |
	  |  4. Compaq and Zenith Detection in TPCRT		  |
	  |  5. MCGA and VGA Detection in TPCRT 		  |
	  |  6. FastWriteWindow moved to TPCRT			  |
	  |  7. Saving and restoring TPCRT window coordinates	  |
	  |  8. Changes to TPEDIT				  |
	  |  9. Horizontal scrolling in TPEDIT			  |
	  | 10. Change to the Critical Error Handlers		  |
	  | 11. New Demo Program: VBROWSE			  |
	  | 12. Unloading TSR's from the command line: SMACS -U   |
	  | 13. ExecDos and interrupt vectors			  |
	  | 14. When to use TPSCREEN				  |
	  | 15. Form and The Commas				  |
	  | 16. Exploding and Shadowed windows in TPWINDOW	  |
	  | 17. Other Changes to TPWINDOW			  |
	  | 18. Improved TPEXTMEM				  |
	  | 19. TPSORT's memory management                        |
	  | 20. Using TPTSR with TPWINDOW and/or TPMENU 	  |
	  | 21. TPTSR and SideKick				  |
	  | 22. Support for enhanced keyboards			  |
	  | 23. Clarification of the Purchase Agreement 	  |
	  | 24. Miscellaneous corrections/additions to the manual |
	  | 25. New Routines:					  |
	  |	  FastText	     (TPCRT)			  |
	  |	  ScrollWindow	     (TPCRT)			  |
	  |	  SearchUC	     (TPSTRING) 		  |
	  |	  Entab 	     (TPSTRING) 		  |
	  |	  Detab 	     (TPSTRING) 		  |
	  |	  BMMakeTable	     (TPSTRING) 		  |
	  |	  BMSearch	     (TPSTRING) 		  |
	  |	  BMSearchUC	     (TPSTRING) 		  |
	  |	  MakeLetterSet      (TPSTRING) 		  |
	  |	  CompareLetterSets  (TPSTRING) 		  |
	  |	  HexPtr	     (TPSTRING) 		  |
	  +-------------------------------------------------------+

1. Missing and moved files
--------------------------
Disk space has become a mounting problem for us, and we have had to move
things around a bit. PTRPT.EXE, STACKWIN.EXE, and WINEXMPL.EXE have all been
left off the DEMO disk. The source code for all three programs is still
included, however, in DEMOSRC.ARC (TPU disk). We have also had to move some
of the OBJ files from TPOBJ.ARC (SRC disk) into a second ARC file on the
DEMO disk, TPOBJ2.ARC.

2. TPCRT compatibility issues
-----------------------------
Although it is highly compatible with CRT, TPCRT is not interchangeable with
CRT as far as the standard units GRAPH3 and TURBO3 are concerned. Both these
units USE CRT, and consequently some conflicts can arise if you try to USE
either of them in a program that also USES TPCRT, since both CRT and TPCRT
would then be present in the same program. Although it is possible to resolve
the conflicts in some cases, in general we recommend that you not try to use
TPCRT in conjunction with either GRAPH3 or TURBO3.

Similar problems will arise if you try to use TPCRT in conjunction with any
non-standard unit that USES CRT. This is less of a problem than it is with the
standard units GRAPH3 and TURBO3, since you will typically have the source
code for the unit in question, and can simply replace CRT with TPCRT in the
USES statement. But you may encounter difficulties when using pre-compiled
units distributed in TPU form as shareware or commercial software. (Units
released into the public domain typically include source code.)

Important note for owners of early versions of Turbo Professional 4.0: TPCRT
is NOT incompatible with the standard GRAPH unit, as we originally reported.

3. TPCRT, DESQVIEW, and TASKVIEW
--------------------------------
Since the manual was printed, two new globals have been added to TPCRT:

  const DetectMultitasking : Boolean = False;
  var	MultitaskingOn : Boolean;

If DetectMultitasking is True, TPCRT will perform the checks necessary to
determine if the program is being run under a multitasking system such as
DesqView or TaskView. If it is, MultitaskingOn will be set to True, and all
screen writes (using Write/WriteLn, FastWrite, etc.) will be directed to the
virtual screen supplied by the system rather than to the physical screen.
Since the default setting for DetectMultitasking is False, you need to add
two lines to the start of your program if you want it to be able to run as a
background task:

   DetectMultitasking := True;
   ReinitCrt;

If the program uses TPSCREEN, you would call ReinitScreen rather than
ReinitCrt. Several of the example programs--including WINWOW.PAS,
STACKWIN.PAS, and MAKEMENU.PAS--demonstrate this.

This feature allows most programs written with TPCRT and TPSCREEN (and hence
TPWINDOW, TPMENU, and TPEDIT) to be run as background tasks inside a window
(the only exceptions we know of are programs that use alternate video
pages). They can also be considered "TopView aware" under the definition
used by DesqView and TaskView. Note that TPCRT does not, however, support
TopView itself, nor does it support Microsoft Windows.

Important note: You should not set DetectMultitasking to True in TSR's. The
function call that is used to determine if a multitasker is in use can cause
problems if it is executed inside a partition that has been designated as
"writing directly to screen." This is why the default setting for
DetectMultitasking is False. If you know that you won't be writing TSR's,
you can change the default setting to True and recompile the TPCRT unit.

4. Compaq and Zenith Detection in TPCRT
---------------------------------------
The initialization code for TPCRT has been modified to automatically
recognize Compaqs and Zeniths, whose display adapters do not require snow
prevention, and to set the CheckSnow flag accordingly. This allows for
dramatically improved screen performance on these machines.

5. MCGA and VGA Detection in TPCRT
----------------------------------
Be forewarned that the EnhancedDisplay variable in TPCRT is not 100%
reliable when running on a dual-display system. At present we know of no
sure-fire method for detecting the presence of an MCGA or VGA adapter if it
is not the active display. For this reason EnhancedDisplay will differ from
CurrentDisplay only if the inactive display on a two-adapter system is an
EGA.

6. FastWriteWindow moved to TPCRT
---------------------------------
FastWriteWindow, originally a part of the TPWINDOW unit, is now a part of
TPCRT. The routine can still be used by programs that use TPWINDOW, but it
can also now be used by any program that USES TPCRT. The move does not
affect the behavior of the routine in any way; it simply makes the routine
more accessible.

7. Saving and restoring TPCRT window coordinates
------------------------------------------------
Many early users of Turbo Professional 4.0, we have found, were using the
TPSCREEN unit simply because they needed two simple routines,
StoreWindowCoordinates and RestoreWindowCoordinates. For this reason, we
have added these routines (as well as the type declaration for
WindowCoordinates) to TPCRT. These routines are identical in function to
those in TPSCREEN. See pages 2-53 and 2-56 for details.

8. Changes to TPEDIT
--------------------
A new parameter has been added to the ReadString routine, as has a new
command type. The declarations for RStype and ReadString should now read

RStype =
  (...
  RSchar,		 {A character to enter the string}
  RSctrlChar,		 {Accept control character}
  RSenter,		 {Accept current string and quit}
  ...);

procedure ReadString(Prompt : string; Row, Col, MaxLen : Byte;
		     PromptAttr, StringAttr, CtrlAttr : Byte;
		     var Escaped : Boolean; var S : string);

The RSctrlChar command is assigned by default to <CtrlP>. If you give this
command, the next character entered will be inserted into the string no
matter what. If it is a control character, it will be displayed as an
uppercase alphabetic character in the colors specified by CtrlAttr (the new
parameter), rather than StringAttr. For example, <CtrlP><CtrlC> would
display a 'C' in CtrlAttr. As a reminder that it is waiting for a control
character, ReadString will temporarily display a block cursor; after a key
is pressed, the cursor will resume its previous shape.

Two points worth noting: First, if CtrlAttr = StringAttr, the Accept control
character command will be ignored. This allows you to prevent control
characters from being accepted. Second, none of the other read commands
(ReadReal, ReadWord, etc.) take a CtrlAttr parameter, since control
characters would never be considered valid input when entering numbers.

A new typed constant has been added:

  ClearFirstChar : Boolean = True;

If ClearFirstChar is True, ReadString will clear the existing string if the
first key pressed is a character (as opposed to an editing command).

ReadCharacter can now be used to read function keys, cursor keys, etc. To make
this possible, we use the same bit-twiddling technique employed in TPMENU. See
the second paragraph on page 2-79 for details.

Finally, you can now examine the last character entered during a ReadString
operation (or any of numeric Reads). It is stored in a variable declared as

  var RsChWord : Word;

By checking the value of this variable, you can determine whether <Enter>,
<Escape>, or <^Break> was used to exit from the editor, for example.

9. Horizontal scrolling in TPEDIT
---------------------------------
The ReadString routine now allows entry of strings wider than the edit field.
It does so by horizontal scrolling, which works in much the same manner as it
does in TURBO.EXE. TPEDIT interfaces a new typed constant, EditSize, which
controls whether horizontal scrolling is active.

  EditSize : Byte = 0; {if NOT zero, overrides MaxLen as edit field width}

When EditSize is 0, ReadString operates just as described in the manual. That
is, the parameter MaxLen passed to ReadString determines both the maximum
length of the string and the screen width used for editing.

If you set EditSize to a non-zero value prior to calling ReadString, that
value is used to determine the screen width used for editing. The MaxLen
parameter passed to ReadString still specifies the maximum acceptable length
of the string being entered.

For example, if you wanted to allow a 128 character string, but only had
40 columns of screen space for the edit field, you might call ReadString as
follows:

  TpEdit.EditSize := 40;
  ReadString(Prompt, Row, Col, 128, Attr, Attr, Attr, Escaped, S);


10. Change to the Critical Error Handlers
-----------------------------------------
If DOS 3.x or higher is being used, the critical error handlers in TPTSR and
TPINT24 will now return a failure flag to DOS, rather than telling it to
ignore the error. The error handlers still, however, return the IGNORE
signal to DOS 2.x, which does not provide the FAIL option.

11. New Demo Program: VBROWSE
-----------------------------
Since the manual was printed, a new demo program has been added to give an
example of how to use big arrays. VBROWSE is a file browsing utility that
uses TPVARRAY to allow files of almost any size to be viewed (provided you
have lots of disk space). VBROWSE also demonstrates the use of various
routines in the TPSTRING, TPDOS, TPCRT, TPEDIT, and TPWINDOW units. Like
PTRPT, VBROWSE is provided in source form only, and can be found in
DEMOSRC.ARC (TPU disk).

VBROWSE is not, we should emphasize, intended to "compete" with more
efficient file browsers, such as LIST.COM. It reads entire files into memory
before allowing you to browse through them, and it can create _very_ large
"swap files" in some cases. For these reasons, you will probably not want to
use it if you don't have a hard disk with lots of disk space available. The
primary purpose of the program is simply to illustrate the use of the big
array routines.

VBROWSE is invoked as follows:

   VBROWSE FileName [d:\path]

"FileName" is the file to be browsed. (VBROWSE will search DOS's PATH to
find it, if necessary.) If no filename is specified, you will be prompted
for one. "d:\path" is an optional drive and directory for TPVARRAY's swap
file. This option allows you to use another drive (a RAM disk, perhaps) for
temporary storage. For example,

   VBROWSE vbrowse.pas d:

would instruct VBROWSE to load VBROWSE.PAS into memory, and to write its
swap file to D:.

The following commands are available in VBROWSE:

Scroll up	 <Up>	     <CtrlE>   <CtrlW>
Scroll down	 <Down>      <CtrlX>   <CtrlZ>
Scroll left	 <Left>      <CtrlS>
Scroll right	 <Right>     <CtrlD>
Scroll left 20	 <CtrlLeft>  <CtrlA>
Scroll right 20  <CtrlRight> <CtrlF>
Page up 	 <PgUp>      <CtrlR>
Page down	 <PgDn>      <CtrlC>
Top of file	 <^PgUp>     <CtrlQ>R  <Home>
Bottom of file	 <^PgDn>     <CtrlQ>C  <End>
Find string	 <CtrlQ>F
Repeat find	 <CtrlL>
Goto line	 <CtrlQ>L
Set marker 0..9  <CtrlK>n
Goto marker 0..9 <CtrlQ>n
Print lines	 <AltP>      <CtrlK>P
Toggle ruler	 <AltR>
New file	 <F3>	     <CtrlK>D  <AltF>
Exit		 <CtrlBreak> <Esc>

Inside VBROWSE, you can see a list of the available commands by pressing
<F1>, the help key.

12. Unloading TSR's from the command line: SMACS -U
---------------------------------------------------
SMACS has been modified to allow it to be unloaded from the DOS command
line as well as from its main menu, so you may now do so by entering

  SMACS -U

Case ('-u', '-U') is not significant.

13. ExecDos and interrupt vectors
---------------------------------
ExecDos now automatically restores the original vectors (those stored by the
runtime library in SaveInt23 and SaveInt24) for interrupts $23 (DOS control
break) and $24 (DOS critical error) before making the Exec call. On return
from the Exec call, the vectors are reset to what they were.

14. When to use TPSCREEN
------------------------
A number of users have experienced problems caused by using the TPSCREEN
unit when they don't need to. A couple of rules of thumb:

   - don't use TPSCREEN if you don't need virtual screens
   - don't use TPSCREEN if you are using TPWINDOW or TPMENU

To explain: Like TPWINDOW and TPMENU, TPSCREEN "sits on top of" TPCRT,
adding advanced functions and capabilities. Unlike the other two units,
however, it also takes control of basic screen I/O away from TPCRT. When
used, TPSCREEN handles all Write and WriteLn statements, as well as basic
functions such as cursor movement and, most notably, windowing. TPWINDOW and
TPMENU both expect and demand TPCRT to be in control of these functions, and
for this reason they should generally not be used with TPSCREEN.

If this restriction causes a problem for you, you can probably get around it
by making special versions of TPWINDOW and/or TPMENU. The changes required
should be minimal, perhaps involving nothing more than adding TPSCREEN to
their USES statements.

15. Form and The Commas
-----------------------
Several unsuspecting users have reported what they thought was a bug in the
Form function (TPSTRING/TPBCD). Consider the following statement:

   WriteLn( Form('###,###,###', 1000.0) );

What they expected was '      1,000'. What they got was '  1,000,000'. This is
_not_ a bug (see p. 3-14 of the Turbo Professional manual). It is consistent
with the behavior of the Form function in TURBOBCD 3.0, which treated the last
period _or_ _comma_ in the mask as marking the decimal point. This allows the
same function to be used in countries that use commas where we Yanks use
periods. If you want Form to treat commas and periods differently, you can
easily modify Form to suit you. We consider it important for us to maintain as
much compatibility as possible with the original Form routine.

16. Exploding and Shadowed windows in TPWINDOW
----------------------------------------------
TPWINDOW has received several enhancements. The most visible improvement is
its new support for "exploding" windows. When exploding windows are first
displayed, they smoothly grow from a minimum size box to their final size.
When removed from the screen, they shrink to a "dot" and disappear.

When enabled, exploding windows operate automatically -- your application
calls DisplayWindow and EraseTopWindow as usual. TPWINDOW interfaces three new
typed constants that allow you to enable and control exploding windows. Here
are the declarations:

const
  Explode : Boolean = False; {True to make exploding windows}
  ExplodeDelay : Word = 15;  {Milliseconds per stage of explosion}
  SoundFlagW : Boolean = False; {True to make sound during explosions}

Set Explode to True to enable exploding windows. The value in ExplodeDelay
determines how many milliseconds delay is inserted after each stage of the
explosion. The default value of 15 looks good to us; you may prefer a
different value. By setting SoundFlagW to true, you enable sound effects
during explosions. You'll have to try it and see if it makes sense for your
application. The state of these three constants at the time when MakeWindow is
called determines whether and how a particular window will explode.

The example programs WINWOW.PAS and VBROWSE.PAS both enable exploding windows
so you can see how they look.

Should you decide that you don't want to use exploding windows, you can save
about 2200 bytes of code space in the TPWINDOW unit. Edit TPWINDOW.PAS and
delete the directive

{$DEFINE ExplodingWindows}

When you next recompile TPWINDOW, the compiler will leave out all of the
explosion-related code.

A second enhancement to TPWINDOW is support for "shadowed" windows. These
windows use an additional row below the window and two columns to the right of
the window for a shadow zone. The shadow zone shows any underlying characters,
but changes their video attributes to a specified value (usually dim white on
black) to give the window a three-dimensional appearance.

Like exploding windows, shadowed windows operate automatically once enabled.
TPWINDOW interfaces two typed constants you use to enable shadowing.

const
  Shadow : Boolean = False;	  {True to make shadowed windows}
  ShadowAttr : Byte = $07;	  {Attribute to apply to shadow}

Set Shadow to True to enable shadows. ShadowAttr determines the attribute to
apply to the shadowed region. Whatever value you specify here is color mapped
before use for optimum appearance on monochrome displays. The state of these
two constants at the time when MakeWindow is called determines whether and how
a particular window will be shadowed.

Should you decide that you don't want to use shadowed windows, you can save
about 800 bytes of code space in the TPWINDOW unit. Edit TPWINDOW.PAS and
delete the directive

{$DEFINE ShadowedWindows}

When you next recompile TPWINDOW, the compiler will leave out all of the
shadow-related code.

For an example of how to use shadowed windows in your programs, see the
demonstration program VBROWSE.PAS.

17. Other Changes to TPWINDOW
-----------------------------
The WindowRec type descriptor in TPWINDOW has been interfaced. As a result,
other units that build upon TPWINDOW can refer to the internal window
descriptor without needing to redeclare this type.

Three new functions have been added to TPWINDOW:

function SelectTopWindow(W : WindowPtr) : Boolean;
  {-Make an already active, tiled window the current one}

function MoveWindow(XDelta, YDelta : Integer) : Boolean;
  {-Move current window by specified distance. Positive means right or down.}

function SelectTiledWindow(W : WindowPtr) : Boolean;
  {-Display or select tiled window}

SelectTopWindow operates like SetTopWindow, but is optimized for tiled rather
than overlapping windows. SelectTopWindow simply repositions the cursor and
sets the appropriate window coordinates and default attributes. For tiled
windows this operation is faster and uses less code than SetTopWindow.
Attempting to use SelectTopWindow for overlapping windows will result in a
corrupted display.

The SetTopWindow function for stacked windows now uses virtual screen
techniques so that intermediate steps of unstacking and restacking are not
visible.

MoveWindow lets you move the currently selected window in any direction for
any distance (as long as the window stays on the screen). Like SetTopWindow,
it uses virtual screen techniques to move the window cleanly without flashing.
Run WINWOW.EXE to see the clean visual effect of SetTopWindow and MoveWindow.

SelectTiledWindow is a small shell around DisplayWindow and SelectTopWindow.
If the specified window is not currently active, SelectTiledWindow displays
it. Otherwise it simply selects it.

All three of these new functions -- SelectTopWindow, MoveWindow, and
SelectTiledWindow -- return True if the operation was successful, or False if
not. Reasons for failure include insufficient heap space to support a
virtual screen, a request to select an inactive window, and a request to move
a window off the current screen.

18. Improved TPEXTMEM
---------------------
TPEXTMEM now supports the extended memory management scheme used by
MicroSoft's RAMDRIVE.SYS ram disk program, as well as the one employed by
VDISK.SYS. Although this represents a significant improvement in terms of
compatibility, there are a couple of side effects that you should be aware of.

First, MicroSoft's memory manager can handle only 95 blocks of memory, at
least 1 of which will always be in use as a ram disk. If all 95 blocks are in
use, ExtMemAvail will return 0, and GetExtMem will return a nil pointer if you
try to allocate memory. Practically speaking, all this means that you should
probably not count on being able to allocate a large number of small blocks of
extended memory, at least not if you want your programs to run on systems that
have RAMDRIVE.SYS installed.

Second, in order to accomodate RAMDRIVE.SYS, most of the routines in TPEXTMEM
now require a little over 1K of stack space to be available at the time they
are called. You should keep this fact in mind if you are using the routines in
programs with small stacks.

19. TPSORT's memory management
------------------------------
Normally TPSORT uses a special kind of Mark/Release technique to allow rapid
deallocation of heap space without destroying the Turbo memory manager's free
list. This technique works fine so long as the caller of the TPSORT routines
does not need to perform heap allocation or deallocation while the sort is in
progress, that is, within the user-defined procedures of the sort. If you do
need to do so, you will have to modify the source code for TPSORT. We have
made this change a simple one, however: all you need to do is un-define the
conditional compilation directive FastDispose.

20. Using TPTSR with TPWINDOW and/or TPMENU
-------------------------------------------
When using either TPWINDOW or TPMENU in memory resident programs written with
TPTSR, you need to keep in mind that both TPWINDOW and TPMENU make liberal use
of the heap. They do most of their memory allocation when windows and menus
are first defined, but they also allocate/deallocate some smaller blocks of
memory as menus and windows are displayed on/removed from the screen.

In general, this means that you should (1) make all of your calls to
MakeWindow, SubMenu, and MenuItem _before_ going resident, and (2) set aside
at least a few hundred extra bytes of heap space at the time you go resident.
For example,

   if not TerminateAndStayResident(ParagraphsToKeep+25, 0) then {};

This would insure that at least 400 (25*16) bytes will be available on the
heap after going resident. See pages 5-20 and 5-21 of the manual for a
discussion of issues related to the allocation of heap space while resident.

Of course, the same basic guidelines described here apply to the use of _any_
unit or routine that needs to allocate heap space, such as TPSORT.

21. TPTSR and SideKick
----------------------
Many users have expressed a desire to be able to load their TSR's after
SideKick. (See page 5-24 of the manual.) We now have what appears to be a
reliable means of doing so. First some background:

The main compatibility problem with SideKick is and always has been that it
insists on having control of the keyboard interrupt (INT $9). To insure
that, its INT $8 (clock tick) handler constantly checks to see if another
program has grabbed INT $9; if it has, SideKick grabs it back. This would be
fine, but the code that does this assumes that it will only have to do it
once. If it has to do it twice, it can lock the machine. That's why Borland
says "load SideKick last," and why we have said "don't load your TSR after
SideKick."

Fortunately, our tests have shown that, if you can prevent SideKick from
regrabbing INT $9, you can load pretty much any TSR you want after it,
including those written with TPTSR. So we have added some code that does
exactly that: if it finds that SideKick's INT $8 handler is installed, it
tries to patch the interrupt handler so that the current TSR can be loaded
safely. If it succeeds, it will reset the 'SideKickLoaded' flag to False.

Although this patch has been tested only with SideKick version 1.56A, it
should be effective with earlier versions as well. Note that if TPTSR cannot
find the proper patch point, it will leave the SideKickLoaded flag set and
do nothing to SideKick. The only known disadvantage to patching SideKick and
then loading your TSR above it is that SideKick will then no longer be able
to keep itself from being loaded twice.

We recognize that this is a sneaky trick, and if you'd prefer that your
memory resident programs be mild mannered participants in the TSR wars, you
can simply unDEFINE the conditional compilation directive 'ThwartSideKick',
found near the top of TPTSR.PAS.

22. Support for enhanced keyboards
----------------------------------
Enhanced keyboards (the ones with the <F11> and <F12> keys) pose a multitude
of problems that cannot be explained fully here. Suffice it to say that, if
you want your programs to be able to take advantage of these keyboards, we
strongly recommend that you use our ENHKBD unit, which can be found on the
BONUS disk. This unit makes it as easy as possible for you to write programs
that behave identically on both kinds of keyboards.

In order to demonstrate the use of ENHKBD, we have included it in the
demonstration program SMACS. The use of ENHKBD in SMACS is optional in two
senses. You can prevent it from being included in the compiled program by
omitting the conditional compilation directive 'UseEnhKbd', found at the top
of SMACS.PAS. While SMACS is running, you can also disable the keyboard
remapping performed by ENHKBD's interrupt handlers using the configuration
menu. Simply toggle the setting for 'Remap keyboard' to 'OFF'.

In addition, we have modified several other units to support enhanced
keyboards in general and the ENHKBD unit in particular. TPMACRO and TPMACED
both now recognize all of the special keys listed at the top of ENHKBD.PAS
(<F11>, <F12>, <AltUp>, <AltTab>, etc.). We also changed the TPTSR unit to
allow TSR's to pop up while waiting for input on an enhanced keyboard, and
it now allows you to use <F11> and <F12> as hotkeys. All of these changes
will be evident if you run some experiments with SMACS on a machine with an
enhanced keyboard.

23. Clarification of the Purchase Agreement
-------------------------------------------
This section will clarify our Purchase Agreement for Turbo Professional 4.0.
Consider it an addendum to section 1.D of the manual.

You may distribute, without runtime fees or further licenses, your own
compiled programs based on any of the source code and precompiled units of
Turbo Professional. You may not distribute any of the Turbo Professional
source code, precompiled units (TPU files), or example programs without
written permission from TurboPower Software.

Note that the previous restrictions do not prohibit you from distributing your
own units that depend on Turbo Professional units. However, others who
received your units would need their own copies of Turbo Professional in order
to write programs using your units.

24. Miscellaneous corrections/additions to the manual
-----------------------------------------------------
   1-2: The discussion of your legal rights as an owner of Turbo Professional
	is in section 1.D of the manual, not 1.E.
   2-5: The following constants in TPCRT should also be listed:
	CO40 = 1;
	CO80 = 3;
   2-5: The value of the constant Blink is 128, not 16.
   2-8: The following variable in TPCRT should also be listed:
	  OneMS : Word;
	This variable is used internally by Delay. It indicates the number
	of times that an empty loop needs to be executed in order to delay
	for one millisecond.
  2-99: It should be noted that Row and Col are absolute screen coordinates,
	and not relative to the current window.
   5-4: The parameters to MyIsr are shown in reverse order. They should read
	  MyIsr(Flags, CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP : Word);
  5-18: The scan code for <Z> should be $2C, not $2D.
  5-23: The declaration for Regs in MyCmdEntryRoutine should read
	"Regs : IntRegisters absolute BP;".


25. New Routines
----------------

FastText    (TPCRT)
-------------------------------------------------------------------------------
Declaration
  procedure FastText(St : string; Row, Col : Byte);
Purpose
  Write St at Row,Col without changing the underlying video attribute.
Comments
  FastText is identical to FastWrite, except that it does not take an
  attribute parameter. Just as ChangeAttribute changes the colors on the
  screen without affecting the text, FastText changes the text without
  affecting the screen colors.


ScrollWindow (TPCRT)
-------------------------------------------------------------------------------
Declaration
  procedure ScrollWindow(Up : Boolean; Lines : Byte);
Purpose
  Scroll current window Up or down (Up = False) the designated number of
  Lines.
Comments
  ScrollWindow simply passes the coordinates for the active window, along
  with the Lines parameter, to either ScrollWindowUp (if Up is True) or
  ScrollWindowDown (if Up is False).
Example
  ScrollWindow(True);
is equivalent to
  GotoXY(1,1);
  DelLine;
See Also
  ScrollWindowDown (TPCRT)	ScrollWindowUp(TPCRT)


SearchUC    (TPSTRING)
-------------------------------------------------------------------------------
Declaration
  function SearchUC(var Buffer; BufLength : Word;
		    var Match; MatLength : Word) : Word;
Purpose
  Case-insensitive search through Buffer for a Match.
Comments
  The function works in a manner identical to Search (TPSTRING) except that
  the comparison is made in a case-insensitive manner. Characters in both
  the Buffer and the Match strings are raised to uppercase prior to
  comparison. The uppercasing does not change the actual parameters.

  If the Match string is not found, SearchUC returns $FFFF. Otherwise it
  returns the number of characters searched to find the start of the match
  string.

  SearchUC runs 2-4 times slower than Search, due to the uppercasing
  operation.

  See the Search function in TPSTRING for further information and examples.


Entab	 (TPSTRING)
-------------------------------------------------------------------------------
Declaration
  function Entab(S : string; TabSize : Byte) : string;
Purpose
  Convert blanks in string S to tabs on spacing TabSize.
Comments
  Entab compresses a string by converting runs of spaces to appropriate
  sequences of tabs and spaces.

  Entab recognizes literal strings delimited by single quotes or double
  quotes, and does not convert spaces to tabs within these strings. It also
  recognizes the C "escape" character '\' to allow quotes embedded within
  strings.

  A TabSize of 8 is the normal size used by most text editors. If TabSize is
  zero, Entab will always return an empty string.
Example
  var
    s:string;
  begin
    while not Eof do begin
      ReadLn(s);
      WriteLn(Entab(s, 8));
    end;
  end.
Implements a complete filter for compressing text files by tab conversion.


Detab	 (TPSTRING)
-------------------------------------------------------------------------------
Declaration
  function Detab(S : string; TabSize : Byte) : string;
Purpose
  Expand tabs in string S to blanks on spacing TabSize.
Comments
  Detab removes tabs from a string, converting them into appropriate strings
  of blanks.

  Unlike Entab, Detab will apply its conversion to all parts of a string,
  whether or not the string contains quoted literals.

  A TabSize of 8 is the normal size used by most text editors. If TabSize is
  zero, Detab will always return an empty string.
Example
  var
    s:string;
  begin
    while not Eof do begin
      ReadLn(s);
      WriteLn(Detab(s, 8));
    end;
  end.
Implements a complete filter for expanding tabs in a text file.


BMMakeTable    (TPSTRING)
-------------------------------------------------------------------------------
Declaration
  procedure BMMakeTable(MatchString : string; var BT : BTable);
Purpose
  Build Boyer-Moore link table.
Comments
  The Boyer-Moore algorithm is a very fast string search method. It gains
  this speed from the fact that it need not compare many elements of the
  string. The elements it can skip are determined by a link table that must
  be initialized before the search itself begins.

  The link table is an array[0..255] of byte. For each character in the
  ASCII set (0..255) the table contains the number of positions the search
  can safely skip. BMMakeTable takes the string to be matched, MatchString,
  and returns a properly initialized link table. The link table will be
  passed to the Boyer-Moore search routine itself to aid in the search.

  The BMMakeTable operation may dominate the performance of B-M if the
  region to be searched is short. In general, you should minimize the number
  of calls to BMMakeTable. If you find the need to call it very often, you
  will probably get better performance using the brute force function
  Search.

  See the BMSearch function for an example.


BMSearch    (TPSTRING)
-------------------------------------------------------------------------------
Declaration
  function BMSearch(var Buffer; BufLength : Word;
		    BT : BTable; MatchString : string) : Word;
Purpose
  Search Buffer for MatchString using the Boyer-Moore algorithm.
Comments
  This string search routine returns results consistent with the Search
  function also in TPSTRING. However, BMSearch uses the Boyer-Moore
  algorithm, which in some cases leads to significantly improved performance
  compared to Search.

  BMSearch differs from Search in the parameters that it requires. Like
  Search, it will search any Buffer region, with a BufLength of up to 65534
  bytes. Unlike Search, it requires a special table BT previously
  initialized by BMMakeTable, and the search string is a normal Turbo
  string.

  BMSearch returns the number of bytes searched to find the target string.
  If the string is not found, BMSearch returns $FFFF. If the target string
  is found at the very start of Buffer, BMSearch returns 0.

  The performance of Boyer-Moore searching is dependent on many factors. If
  the buffer region is the size of a normal Turbo string (255 bytes or
  less), and the link table BT must be regenerated for each search, BMSearch
  will always be slower than the simpler Search routine. On the other hand,
  if the buffer is large, or if the same link table can be used many times,
  BMSearch's performance ranges from about the same as Search's to twice as
  fast depending on the length of the MatchString. Typically, the longer the
  MatchString, the more advantage BMSearch will gain.

  Special thanks to Don Strenczewilk for providing the initial version of
  the Boyer-Moore search routines.
Example
  function BMS(var Buffer; BufLength : Word; MatchSt : string) : Word;
  var
    LocalTable : BTable;
  begin
    BMMakeTable(MatchSt, LocalTable);
    BMS := BMSearch(Buffer, BufLength, LocalTable, MatchSt);
  end;
This function hides the link table from the calling program. Unfortunately,
it also updates the link table at every call, thus minimizing the
performance of the B-M search. This function will provide good performance
only if the Buffer region is large. Otherwise, an application should call
BMMakeTable explicitly and use the returned link table as many times as
possible before discarding it.


BMSearchUC    (TPSTRING)
-------------------------------------------------------------------------------
Declaration
  function BMSearchUC(var Buffer; BufLength : Word;
		      BT : BTable; MatchString : string) : Word;
Purpose
  Case-insensitive search of Buffer for MatchString using the Boyer-Moore
  algorithm.
Comments
  This function operates just like BMSearch, except that searching is not
  case sensitive. See BMSearch for more details.

  Important requirement: it is the application's responsibility to assure
  that MatchString is raised to uppercase prior to calling either
  BMMakeTable or BMSearchUC.

  BMSearchUC almost always outperforms SearchUC, even if the link table BT
  must be built for each search. The speed of BMSearchUC ranges from
  slightly slower than SearchUC to about four times faster depending on how
  often the link table is rebuilt, the length of the MatchString, and the
  data contents.
Example
  function UCBMS(var Buffer; BufLength : Word; MatchSt : string) : Word;
  var
    LocalTable : BTable;
  begin
    MatchSt := StUpcase(MatchSt);     {Guarantee that MatchSt is uppercase}
    BMMakeTable(MatchSt, LocalTable); {Build the link table}
    UCBMS := BMSearchUC(Buffer, BufLength, LocalTable, MatchSt);
  end;
This function hides from the calling program all operations preparatory to a
case-insensitive Boyer-Moore search. If the link table could be used more
than once, this function will waste performance, although it will still be
faster than most alternative approaches.


MakeLetterSet  (TPSTRING)
-------------------------------------------------------------------------------
Declaration
  function MakeLetterSet(S : string) : LongInt;
Purpose
  Returns a bit-mapped longint storing the individual letters contained in S.
Comments
  MakeLetterSet creates a bit-mapped set (in the form of LongInt) indicating
  which letters of the alphabet are in S. For example, if the string were
  'A' (or 'a'), MakeLetterSet would return $00000001; if it were 'ABC', the
  result would be $00000007, and so on. The maximum possible value of the
  result is $003FFFFF (first 26 bits set). See the discussion of
  CompareLetterSets, below, for more details.


CompareLetterSets  (TPSTRING)
-------------------------------------------------------------------------------
Declaration
  function CompareLetterSets(Set1, Set2 : LongInt) : Word;
Purpose
  Returns the sum of the values of the letters common to Set1 and Set2.
Comments
  When used in conjunction with MakeLetterSet, CompareLetterSets provides an
  alternative to the Soundex algorithm for judging the similarity of two
  words or strings of words. The algorithm was developed by Michael Bickel,
  and it is discussed at length in Jim Howell's "An Alternative to Soundex"
  (Dr. Dobb's Journal, November 1987).

  Before calling CompareLetterSets, you must use MakeLetterSet to create a
  bit-mapped long integer (or "letter set") indicating what letters are used
  in a particular string; this process should be repeated for each string to
  be compared. Given two such sets, CompareLetterSets will then find the
  union of the two sets (the letters shared in common) and return a value
  that indicates how closely the two strings match. In calculating this
  value, it relies on the LetterValues table (declared in TPSTRING.PAS),
  which assigns relatively high values to rarely used letters ('J', 'Q',
  'X', 'Z') and low ones to the most frequently used letters ('A', 'E', 'N',
  'S', 'T'). The return value is simply the sum of the values for each set
  in the union. To determine the maximum possible value that could be
  returned in any given situation, you would compare the letter set for a
  string to itself:

    PossibleValue := CompareLetterSets(LetterSet1, LetterSet1);

  Comparisons to the letter sets for other strings will yield a result in
  the range 0..PossibleValue. The higher the value, the higher the degree of
  similarity.

  Unfortunately, there is no definitive method for deciding whether or not
  the value returned by CompareLetterSets indicates a close similarity, so
  you'll probably need to run some experiments to determine how best to use
  these two functions. One way to make its results more informative would be
  to use a function such as DissimilarityIndex, shown in the example below,
  which returns a value between 0.0 (high degree of similarity) and 130.0
  (first string is empty). (Similar strings will usually have an index of
  0.3 or less.) You might also wish to modify the function to take into
  account factors that Bickel's algorithm ignores (are the lengths of the
  two strings the same? are the first characters the same? etc.). For a more
  complete discussion of the algorithm, see Howell's article in Dr. Dobb's.
Example
    function DissimilarityIndex(S1, S2 : string) : real;
    var Set1, Set2 : LongInt;
	Possible, Actual, Delta : Integer;
    begin
      Set1 := MakeLetterSet(S1);
      Set2 := MakeLetterSet(S2);
      Possible := CompareLetterSets(Set1, Set1);
      Actual := CompareLetterSets(Set1, Set2);
      Delta := Possible - Actual;
      if Possible = 0 then
	DissimilarityIndex := 130
      else
	DissimilarityIndex := Abs(Delta / Possible);
    end;

  var S1, S2 : string;
  begin
    repeat
      {get first string}
      Write('String 1: '); ReadLn(S1);
      {get second string}
      Write('String 2: '); ReadLn(S2); Set2 := MakeLetterSet(S2);
      {show result}
      WriteLn('Index:  ', DissimilarityIndex(S1, S2):1:3);
    until False; {press ^C to stop}
  end.


HexPtr	 (TPSTRING)
-------------------------------------------------------------------------------
Declaration
  function HexPtr(P : Pointer) : string;
Purpose
  Return hex string for pointer.
Comments
  Given a pointer. HexPtr returns a string of the form 'ssss:oooo', where
  'ssss' is the segment portion of the address, and 'oooo' is the offset.
Example
    if (ErrorAddr <> nil) or (ExitCode <> 0) then begin
      {don't report ^Break as an error}
      if ExitCode <> $FF then
	WriteLn('Error ', HexW(ExitCode), ' at ', HexPtr(ErrorAddr));
      {prevent runtime library from reporting error again}
      ErrorAddr := nil;
      ExitCode := 0;
    end;
  Code such as the above might be included in a user-defined exit handler to
  report runtime errors. HexPtr is used to turn the address of the error
  into a string.

