1113 lines
45 KiB
Plaintext
1113 lines
45 KiB
Plaintext
From ts@uwasa.fi Thu Mar 7 00:00:00 1996
|
|
Subject: FAQPAS2.TXT contents
|
|
|
|
Copyright (c) 1993-1996 by Timo Salmi
|
|
All rights reserved
|
|
|
|
FAQPAS2.TXT More frequently (and not so frequently) asked Turbo
|
|
Pascal questions with Timo's answers. The items are in no particular
|
|
order.
|
|
|
|
You are free to quote brief passages from this file provided you
|
|
clearly indicate the source with a proper acknowledgment.
|
|
|
|
Comments and corrections are solicited. But if you wish to have
|
|
individual Turbo Pascal consultation, please post your questions to
|
|
a suitable Usenet newsgroup like news:comp.lang.pascal.borland. It
|
|
is much more efficient than asking me by email. I'd like to help,
|
|
but I am very pressed for time. I prefer to pick the questions I
|
|
answer from the Usenet news. Thus I can answer publicly at one go if
|
|
I happen to have an answer. Besides, newsgroups have a number of
|
|
readers who might know a better or an alternative answer. Don't be
|
|
discouraged, though, if you get a reply like this from me. I am
|
|
always glad to hear from fellow Turbo Pascal users.
|
|
|
|
....................................................................
|
|
Prof. Timo Salmi Co-moderator of news:comp.archives.msdos.announce
|
|
Moderating at ftp:// & http://garbo.uwasa.fi archives 193.166.120.5
|
|
Department of Accounting and Business Finance ; University of Vaasa
|
|
ts@uwasa.fi http://uwasa.fi/~ts BBS 961-3170972; FIN-65101, Finland
|
|
|
|
--------------------------------------------------------------------
|
|
26) How to get ansi control codes working in Turbo Pascal writes?
|
|
27) How to evaluate a function given as a string to the program?
|
|
28) How does one detect whether input (or output) is redirected?
|
|
29) How does one set the 43/50 line text mode?
|
|
30) How can I assign a value to an environment variable in TP?
|
|
31) How does one store, and then restore the original screen?
|
|
32) How can I convert a TPU unit of one TP version to another?
|
|
33) Which error is e.g. Runtime error 205, etc
|
|
34) Why can't I open read-only files? I get "File access denied".
|
|
35) How do I obtain high and low parts of a byte variable?
|
|
36) How can I set a hi-intensity color background in the text mode?
|
|
37) Where can I find a program to convert (Turbo) Pascal to C?
|
|
38) How can I read input without echoing to the screen?
|
|
39) How can I edit the readln input stream?
|
|
40) How can I write (brand) something into my executables?
|
|
41) What is wrong with my program? It hangs without a clear pattern?
|
|
42) How do I convert a decimal word into a hexadecimal string, etc?
|
|
43) How to determine the last drive?
|
|
44) How can I put a running clock into my Turbo Pascal program?
|
|
45) How to establish if a name refers to a directory or not?
|
|
46) How does one disable alt-ctrl-del?
|
|
47) How can I test whether a file exists?
|
|
48) What is the name of the current Turbo Pascal program?
|
|
49) How is the code for rebooting the PC written in Turbo Pascal?
|
|
50) How can I write inline code?
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:26 1996
|
|
Subject: Using ansi codes in a TP program
|
|
|
|
26. *****
|
|
Q: How to get ansi control codes working in Turbo Pascal writes?
|
|
|
|
A: It is very simple, but one has to be aware of the pitfalls.
|
|
Let's start from the assumption that ansi.sys or a corresponding
|
|
driver has been loaded, and that you know ansi codes. If you don't,
|
|
you'll find that information in the standard MS-DOS manual. To apply
|
|
ansi codes you just include the ansi codes in your write statements.
|
|
For example the following first clears the screen and then puts the
|
|
text at location 10,10:
|
|
write (#27, '[2J'); (* the ascii code for ESC is 27 *)
|
|
write (#27, '[10;10HUsing ansi codes can be fun');
|
|
If you want to test (as you should) whether ansi.sys or some some
|
|
replacement driver has been loaded, you can use the ISANSIFN
|
|
function from my ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip.
|
|
Now the catches. If you have a
|
|
uses Crt;
|
|
statement in your program, direct screen writes will be used, and
|
|
the ansi codes won't work. You have either to leave out the Crt
|
|
unit, or include
|
|
assign (output, '');
|
|
rewrite (output);
|
|
:
|
|
close (output);
|
|
Occasionally I have seen it suggested that one should just set
|
|
DirectVideo := false;
|
|
This is a popular misconception. It won't produce the desired
|
|
result. I'm not claiming to know the reason for this quirk of Turbo
|
|
Pascal. Rather it is an observation I've made.
|
|
|
|
-From: Bengt Oehman d92bo@efd.lth.se with a later dicussion with Bob
|
|
Peck bpeck@prairienet.org and help from Duncan Murdoch
|
|
dmurdoch@mast.queensu.ca. The `DirectVideo:=False' statement only
|
|
tells the Crt unit to use BIOS calls instead of using direct
|
|
video-memory writes. A demo program to illustrate the screen writing
|
|
modes follows:
|
|
|
|
Program ScreenWriteDemo;
|
|
USES Crt;
|
|
BEGIN
|
|
Writeln('This is written directly to the video memory');
|
|
DirectVideo:=False;
|
|
Writeln('This is written via BIOS interrupt calls (int 10h)');
|
|
Assign(Output,'');
|
|
Append(Output);
|
|
Writeln('This is written via DOS calls (int 21h)');
|
|
END.
|
|
|
|
A note: The latter could be also written as
|
|
Writeln(Output, 'This is written via DOS calls (int 21h)');
|
|
since the writeln default is the standard output.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:27 1996
|
|
Subject: Writing an expression parser
|
|
|
|
27. *****
|
|
Q: How to evaluate a function given as a string to the program?
|
|
|
|
A: To do this you have to have a routine for parsing and evaluating
|
|
your expression. This is a complicated task requiring a clever use
|
|
of recursion. You can find such code in Stephen O'Brien (1988),
|
|
Turbo Pascal, The Complete Reference. Borland-Osborne/McGraw-Hill,
|
|
Chapter 10. Another, simpler piece of code can be found in Michael
|
|
Yester (1989), Using Turbo Pascal, Que, Chapter 5.
|
|
I've also written such a function evaluation program myself, and
|
|
much of it is based on the ideas in O'Brien with my own corrections
|
|
and enhancements. The resulting program is available as fn.exe
|
|
function evaluator in the ftp://garbo.uwasa.fi/pc/ts/tsfunc13.zip
|
|
package (or whatever version number is the latest). Note however,
|
|
that the source code is not included, nor available.
|
|
Tips from Justin Lee (ossm1jl@rex.uokhsc.edu):
|
|
67666 Sep 22 03:00 ftp://garbo.uwasa.fi/pc/turboobj/parstp30.zip
|
|
parstp30.zip Recursive expression TP7.0/BP/VB/C++ parser, R.Loewy
|
|
An excellent parser is included with all the Turbo Pascal versions
|
|
since TP4.0 as part of the MCALC or TCALC spreadsheet example
|
|
program. See mcparse.pas or tcparse.pas.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:28 1996
|
|
Subject: Detecting redirection
|
|
|
|
28. *****
|
|
Q: How does one detect whether input (or output) is redirected?
|
|
|
|
A: As we know input to a program can come from a file, from the
|
|
console, or from a pipe or redirection. Examples of the latter are
|
|
type text.dat | program
|
|
program < text.dat
|
|
A Turbo Pascal program can be made to detect the redirections using
|
|
Interrupt 21Hex, function 44Hex, subfunction 00Hex. See PC Magazine
|
|
April 16, 1991, p. 374 for the code, and Duncan (1988), Advanced
|
|
MS-DOS Programming, pp. 412-413 for more information. Alternatively,
|
|
you can utilize the preprogrammed routines
|
|
PIPEDIFN Is the standard input from redirection
|
|
PIPEDNFN Is the standard output redirected to nul
|
|
PIPEDOFN Is the standard output redirected
|
|
from my ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip units.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:29 1996
|
|
Subject: Setting the 43/50 line text mode
|
|
|
|
29. *****
|
|
Q: How does one set the 43/50 line text mode?
|
|
|
|
A: Quite simple. Just apply TextMode (C80 + font8x8). Requires a
|
|
"uses Crt;". First, however, you should test that you have a at
|
|
least an EGA video adapter. (See DetectGraph in your TP manual).
|
|
Also see TSUTLE.NWS in ftp://garbo.uwasa.fi/pc/ts/tsutle22.zip (or
|
|
whichever version number is the current) for the non-standard wide
|
|
text modes like 132x43.
|
|
{ An example }
|
|
uses Crt;
|
|
var InitialMode : integer;
|
|
begin
|
|
InitialMode := LastMode;
|
|
TextMode (CO80 + Font8x8);
|
|
TextColor (LightCyan);
|
|
writeln ('Test1');
|
|
readln;
|
|
{}
|
|
TextMode (CO40);
|
|
writeln ('Test2');
|
|
readln;
|
|
{}
|
|
TextMode (InitialMode);
|
|
TextColor (Yellow);
|
|
writeln ('Test3');
|
|
readln;
|
|
end.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:30 1996
|
|
Subject: Assigning environment variable values
|
|
|
|
30. *****
|
|
Q: How can I assign a value to an environment variable in TP?
|
|
|
|
A: For assigning a value to (a parent process's) environment value
|
|
you have to access and manipulate the Program Segment Prefix and
|
|
Memory Control Blocks. This is a rather complicated undertaking. A
|
|
source code with an accompanying article by Trudy Neuhaus can be
|
|
found in PC Magazine Volume 11 Number 1 pages 425-427.
|
|
The budding TP programmers should note that the elementary trick
|
|
of Exec (GetEnv('comspec'), '/c set key=whatever') will achieve only
|
|
a transient result for the duration of the exec shell. When you exit
|
|
the shell after this endeavor, the environment will be as it was.
|
|
Here is about the why. When the above command is executed, MS-DOS
|
|
makes a copy of the environment, and uses the copy. When the above
|
|
shelling terminates, the copy of the environment is deleted, and the
|
|
original is restored. Hence the above trick cannot be used to change
|
|
the parent environment.
|
|
If you don't want to try to go through this rather complicated
|
|
task yourself, the routines
|
|
"SETEVN Set a parent environment variable (variable=value)"
|
|
"SETENVSH Set an environment variable for the duration of shelling"
|
|
can be found in my TP TPU collection ftp://garbo.uwasa.fi/pc/ts/
|
|
tspa34*.zip (* = 40,50,55,60,70). No source code is included, nor
|
|
available for tspa34. However, there is a TPENV section within
|
|
ftp://garbo.uwasa.fi/pc/turbopas/bonus507.zip. From zeta@tcscs.com
|
|
Gregory Youngblood: For a source code see /pc/source/setenv.zoo at
|
|
Garbo.
|
|
One further detail. Users sometimes ask how one can change the
|
|
prompt or the path from within a Turbo Pascal program. This is in no
|
|
way different from changing the value of any other environment
|
|
variable. Both PATH and PROMPT are environment variables that can be
|
|
set with the MS-DOS SET command in the fashion described in the
|
|
above. This is not changed in any way by the fact that you can apply
|
|
PROMPT and PATH also in an alternative format not requiring the SET
|
|
command.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:31 1996
|
|
Subject: Saving the screen
|
|
|
|
31. *****
|
|
Q: How does one store, and then restore the original screen?
|
|
|
|
A: Here is a simple outline for storing and restoring a text mode
|
|
screen in the standard 80 x 25 mode. Note that the code below is
|
|
incomplete in a sense that it works for a color monitor only,
|
|
because the monochrome screen address is $B000:$0000.
|
|
For storing and restoring the graphics screen see Ohlsen & Stoker
|
|
(1989), Turbo Pascal Advanced Techniques, Que, pp 333-337.
|
|
uses Crt;
|
|
type ScreenType = array [1..4000] of byte; (* 2 x 80 x 25 *)
|
|
var ColorScreen : ScreenType Absolute $B800:$0000;
|
|
SavedScreen : ScreenType;
|
|
posx, posy : byte;
|
|
begin
|
|
SavedScreen := ColorScreen; (* Save the screen *)
|
|
posx := WhereX; posy := WhereY; (* Save the cursor position *)
|
|
writeln ('A simple demo storing and restoring the color text screen');
|
|
writeln ('By Prof. Timo Salmi, ts@uwasa.fi');
|
|
writeln; write ('Press <-'''); readln;
|
|
ColorScreen := SavedScreen; (* Restore the screen *)
|
|
GotoXY(posx,posy); (* Go to the stored cursor position *)
|
|
end.
|
|
If you would prefer not using the Crt unit, you can apply WHEREXFN,
|
|
WHEREYFN, and GOATXY from TSUNTG.TPU from my units collection
|
|
ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip.
|
|
If you wish to test for the monitor type, that is choose between
|
|
$B800:$0000 and $B000:$0000 bases, you can use the following
|
|
function to test for the monochrome adapter.
|
|
function MONOFN : boolean;
|
|
var regs : registers;
|
|
begin
|
|
FillChar (regs, SizeOf(regs), 0);
|
|
regs.ah := $0F;
|
|
Intr ($10, regs);
|
|
monofn := (regs.al = 7);
|
|
end; (* monofn *)
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:32 1996
|
|
Subject: Converting TPUs
|
|
|
|
32. *****
|
|
Q: How can I convert a TPU unit of one TP version to another?
|
|
|
|
A: Forget it. In practical terms such a conversion is not on. The
|
|
Turbo Pascal TPU units are strictly version dependent. If there were
|
|
a working solution I assume we would have heard of it long since.
|
|
The hacks that have been tried won't solve this dilemma. For all
|
|
practical purposes you need the source code and the relevant
|
|
compiler version.
|
|
You may nevertheless wish to ascertain for which version a TPU
|
|
unit has been compiled. This is very simple. Just look at the first
|
|
four character of a TPU file. The codes are
|
|
TPU0 for 4.0
|
|
TPU5 for 5.0
|
|
TPU6 for 5.5
|
|
TPU9 for 6.0
|
|
TPUQ for 7.0 real mode
|
|
But don't go editing these. It will not get you anywhere.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:33 1996
|
|
Subject: Finding about runtime errors
|
|
|
|
33. *****
|
|
Q: Which error is e.g. Runtime error 205
|
|
|
|
A: Basically this is a case of RTFM (read the f*ing manual). But it
|
|
is very easy to find out even without resorting to the manual. Put
|
|
temporarily the statement RunError (205); as the first statement of
|
|
your program. Then run your program from the Turbo Pascal IDE, that
|
|
is from within the TP editor. The description of the error will
|
|
appear.
|
|
If you run a program from within a Turbo Pascal IDE, it is
|
|
advisable to turn on the debug options on. You'll get both the error
|
|
number and the description. Furthermore by pressing F1 after the
|
|
error you get its description in a more verbal format.
|
|
One further trick is to put "uses TSERR"; (Include verbal
|
|
run-time error messages) into your program. If you do that, the
|
|
run-time errors will be given with a verbal description not just as
|
|
a number. TSERR.TPU is part of my TPU collection at Garbo
|
|
ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip.
|
|
In TP 7.0 the run time errors can also be found by invoking
|
|
"Help" from the main manu (Alt-H) and selecting "Error messages".
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:34 1996
|
|
Subject: Opening read-only files
|
|
|
|
34. *****
|
|
Q: Why can't I open read-only files? I get "File access denied".
|
|
|
|
A: The answer is rather simple, but it is not well displayed in the
|
|
manuals. In order to read a read-only file you have to set the
|
|
FileMode as 0 like below. Else you'll get runtime error 005 "File
|
|
access denied".
|
|
var f : text; (* Can be any file type *)
|
|
savefm : byte;
|
|
begin
|
|
savefm := FileMode; (* Save the current FileMode status *)
|
|
FileMode := 0; (* The default is 2 *)
|
|
assign (f, 'readonly.txt');
|
|
reset (f);
|
|
{ have your wicked ways }
|
|
close (f);
|
|
FileMode := savefm; (* Restore the original FileMode *)
|
|
end.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:35 1996
|
|
Subject: Getting a nybble from a byte
|
|
|
|
35. *****
|
|
Q: I have a variable of type BYTE and would like to extract two
|
|
numbers from it. (The first 4 bits making up number A, the second 4
|
|
bits making up number B). How can I extract these two numbers?
|
|
|
|
A: Ah, this question brings back the good bad old days of the
|
|
Commodore C64 programming when bit operations were rather a rule
|
|
than an exception. Here is the solution.
|
|
function HIBYTEFN (x : byte) : byte;
|
|
begin
|
|
hibytefn := x Shr 4; (* Shift right by four bits *)
|
|
end;
|
|
{}
|
|
function LOBYTEFN (x : byte) : byte;
|
|
begin
|
|
lobytefn := x and 15; (* x and 00001111 *)
|
|
end;
|
|
From Patrick Taylor (exuptr@exu.ericsson.se): Ah, leave it to Timo
|
|
to come up with a different way! An other is (n div 16)
|
|
(n mod 16).
|
|
Patrick is right. But unless the compiler is optimized, the
|
|
former produces more efficient code. Not that it really makes any
|
|
practical difference whatsoever.
|
|
Of course the fastest code is produced using assembler as pointed
|
|
out by Maarten Pennings (maarten@cs.ruu.nl) who provided the
|
|
following inline example:
|
|
function high(b:byte):byte;
|
|
inline($58 { POP AX | AH=?, AL=b }
|
|
/$30/$e4 { XOR AH,AH | AH=0, AL=b }
|
|
/$b9/$04/$00 { MOV CX,0004 | AH=0, AL=b, CL=4 }
|
|
/$d3/$e8 { SHR AX,CL | AX=b shr 4 }
|
|
);
|
|
|
|
A2: Getting a word from a longint can alternatively be achieved
|
|
without any calculations by using a kind of typecasting. Below is
|
|
the code I have utilized in ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip.
|
|
(* Get the high-order word of the longint argument *)
|
|
function HIWORDFN (x : longint) : word;
|
|
type type1 = record
|
|
low : word;
|
|
high : word;
|
|
end;
|
|
var m1 : type1 absolute x;
|
|
begin
|
|
hiwordfn := m1.high;
|
|
end; (* hiwordfn *)
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:36 1996
|
|
Subject: Setting hi-intensity background
|
|
|
|
36. *****
|
|
Q: How can I set a hi-intensity color background in the text mode?
|
|
|
|
A: As you should know, the you can test for a blinking text for
|
|
example as follows.
|
|
uses Crt;
|
|
begin
|
|
TextColor (11 + 128); (* or LightCyan + Blink *)
|
|
TextBackground (Blue);
|
|
writeln ('What''s the catch?'); (* An aside, note the '' pair *)
|
|
end.
|
|
In the above, bit 7 (the 128) controls the blinking. If you have at
|
|
least an EGA, you can alter the interpretation of the highest text
|
|
color bit to denote a hi-intensity background, but then you lose the
|
|
the blinking. The following piece of code disables blinking,
|
|
enabling a hi-intensity background.
|
|
uses Dos;
|
|
var regs : registers;
|
|
begin
|
|
FillChar (regs, SizeOf(regs), 0); (* An initialization precaution *)
|
|
regs.ah := $10; (* Function $10 *)
|
|
regs.al := $03; (* Subfunction $03 *)
|
|
regs.bl := $00;
|
|
Intr ($10, regs); (* ROM BIOS video driver interrupt *)
|
|
end.
|
|
To enable blinking again, set regs.bl := $01; Any high-intensity
|
|
background you may have currently on the screen, will instantly
|
|
change into a blinking text a a low-intensity background.
|
|
|
|
A2: The previous answer assumes at least an EGA. Otherwise ports
|
|
must be accessed. This is both advanced and dangerous programming,
|
|
because errors in handling posts can do real harm. Besides it is
|
|
fair to require at least an EGA in writing modern programs, at least
|
|
for non-laptops, and on the latter the colors don't really matter
|
|
for CGA and below. Let's take a look, nevertheless, how this is done
|
|
for a CGA. Note that this won't work an an EGA and beyond, not at
|
|
least in my tests. For detecting the video adapter you have, see the
|
|
DetectGraph procedure in you Turbo Pascal manual.
|
|
First we need some basics from MEMORY.LST in Ralf Brown's
|
|
ftp://garbo.uwasa.fi/pc/programming/inter48b.zip (or whatever
|
|
version is current):
|
|
Format of BIOS Data Segment at segment 40h:
|
|
63h WORD Video CRT controller base address: color=03D4h, mono=03B4h
|
|
65h BYTE Video current setting of mode select register 03D8h/03B8h
|
|
From David Jurgens's ftp://garbo.uwasa.fi/pc/programming/helppc21.zip
|
|
we see
|
|
3D0-3DF Color Graphics Monitor Adapter (ports 3D0-3DB are
|
|
write only, see 6845)
|
|
3D8 6845 Mode control register (CGA, EGA, VGA, except PCjr)
|
|
From Darryl Friesen's (friesend@jester.usask.ca) in the late
|
|
comp.lang.pascal we have, the following procedure, with my own added
|
|
comments (* *).
|
|
procedure SetBlinkState (state : boolean);
|
|
var ModeRegPort : word;
|
|
ModeReg : byte;
|
|
begin
|
|
Inline($FA); { CLI } (* Interrupts off *)
|
|
ModeRegPort := MemW[$0040:$0063]+4; (* Typically $03D4+4 = $03D8 *)
|
|
ModeReg := Mem[$0040:$0065]; (* Typically 1001 *)
|
|
if state then (* Bit 5 controls blink enable *)
|
|
ModeReg := ModeReg or $20 (* $20 = 00100000 (base2) *)
|
|
else
|
|
ModeReg := ModeReg and $DF; (* $DF = 11011111 disable *)
|
|
Port[ModeRegPort] := ModeReg; (* Typically $9 = 00001001 *)
|
|
Mem[$0040:$0065] := ModeReg; (* or $29 = 00101001 *)
|
|
Inline($FB) { STI } (* Interrupts on *)
|
|
end;
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:37 1996
|
|
Subject: Pascal to C
|
|
|
|
37. *****
|
|
Q: Where can I find a program to convert (Turbo) Pascal to C?
|
|
|
|
A: This is a relevant question, but I have placed elsewhere the
|
|
tips on the "looking for a program" questions. Here are the
|
|
pointers to further pointers :-). (The FAQ versions might have been
|
|
updated since I wrote this.)
|
|
ftp://garbo.uwasa.fi/pc/pd2/camfaq.zip
|
|
camfaq.zip comp.archives.msdos.(d/announce) FAQ (general finding)
|
|
:
|
|
ftp://garbo.uwasa.fi/pc/ts/tsfaqn43.zip
|
|
tsfaqn43.zip Questions from UseNet and Timo's answers
|
|
:
|
|
ftp://garbo.uwasa.fi/pc/pd2/faquote.zip
|
|
faquote.zip Old information from tsfaq Frequently Asked Questions
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:38 1996
|
|
Subject: Turning off the input echo
|
|
|
|
38. *****
|
|
Q: How can I read input without echoing to the screen?
|
|
|
|
A: It is fairly simple. Study this example source code, with the
|
|
manual, if need be.
|
|
uses Crt;
|
|
var password : string;
|
|
{}
|
|
(* Read without echoing *)
|
|
procedure GETPASS (var s : string);
|
|
var key : integer;
|
|
ch : char;
|
|
begin
|
|
s := '';
|
|
repeat
|
|
ch := ReadKey; key := ord (ch);
|
|
case key of
|
|
0 : ch := ReadKey; (* Discard two-character keys, like F1 *)
|
|
13 : exit; (* Enter has been pressed *)
|
|
1..12,13..31,255 :; (* Discard the special characters *)
|
|
else s := s + ch;
|
|
end;
|
|
until false;
|
|
end; (* getpass *)
|
|
{}
|
|
(* The main program *)
|
|
begin
|
|
write ('Password: ');
|
|
GETPASS (password);
|
|
writeln;
|
|
writeln (password);
|
|
end.
|
|
{}
|
|
If you wish to be able to edit the input stream, like having the
|
|
BackSpace functional, that is more complicated, and is left as an
|
|
exercise after these basics. A hint: 8 : Delete (s, Length(s), 1);
|
|
There is another approach to this problem pointed out by Colin
|
|
Lamond colin@sound.demon.co.uk. Quite innovative in its simplicity
|
|
once one comes to think of it. "Set the textcolor, and the
|
|
textbackground to the same color, and so the typed text can not be
|
|
seen on the screen."
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:39 1996
|
|
Subject: Input line-editing
|
|
|
|
39. *****
|
|
Q: How can I edit the readln input stream?
|
|
|
|
A: In practice, if you wish to use anything beyond simple the
|
|
BackSpace deleting, you'll have to build your own line editing
|
|
routines expanding on the code in the previous item. It is quite a
|
|
task, and you can alternatively find the preprogrammed routines in
|
|
my Turbo Pascal units ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip (or
|
|
whatever version number is current).
|
|
EDRDEBLN Editable Readln with ctrl-c, break trapping, pre-fill etc
|
|
EDRDEFLN Editable Readln with recall, pre-fill, and insert toggle
|
|
EDRDLN Readln with line-editing potential (the simplest)
|
|
EDREABLN Edreadln with ctrl-c and break trapping
|
|
EDREADLN Editable Readln with recall, and insert toggle
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:40 1996
|
|
Subject: Executable branding
|
|
|
|
40. *****
|
|
Q: How can I write (brand) something into my executables?
|
|
Here is the actual question that led me to writing this item: 'I
|
|
am very interested in the .EXE "branding" techniques you use in
|
|
your TSUNTI unit. Would it be possible to get hold of the source
|
|
code for that unit, as it would save me from having to re-invent
|
|
the wheel?'
|
|
|
|
A: What you are referring to is
|
|
BRANDEXE Store information within your program's .exe file (MS-DOS 3.0+)
|
|
CHKSUMFN Checksum self-test to detect any tampering (MS-DOS 3.0+)
|
|
USECOUNT Get the number of times the program has been used
|
|
Sorry no, I don't want to distribute my source codes from
|
|
ftp://garbo.uwasa.fi/pc/turbopas/ts/tspa3470.zip. Besides they would
|
|
be less useful to you than you may think because internally my
|
|
programs are in Finnish, comments, variable and procedure names, and
|
|
all. But I can hopefully help you by giving a reference to a similar
|
|
code. Please see Ohlsen & Stoker, Turbo Pascal Advanced Techniques,
|
|
Que, 1989, p. 420.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:41 1996
|
|
Subject: Elusive, inconsistent errors
|
|
|
|
41. *****
|
|
Q: What is wrong with my program? It hangs without a clear pattern?
|
|
|
|
A: With experience one learns that some programming errors are very
|
|
elusive. I have many times seen users declaring that they have found
|
|
a bug in Turbo Pascal, but in the overwhelming majority of cases it
|
|
still is just a programming error, which just is more difficult to
|
|
find than the more clear-cut cases. When you have symptoms like your
|
|
program crashing from within the IDE, but working seemingly all
|
|
right when called as stand-alone, or something equally strange, you
|
|
might have one of the following problems.
|
|
- A variable or some variables in your code are uninitialized thus
|
|
getting random values, which differ depending on your environment.
|
|
- Your indexes are overflowing. Set on the range check {$R+}
|
|
directive for testing.
|
|
- An error in the pointer logic.
|
|
Normal debugging does not necessarily help in locating these errors
|
|
because one is easily led to debugging the wrong parts of one's
|
|
program. Especially the latter two reasons can cause errors which
|
|
seemingly have nothing to do with the actual cause. This results
|
|
from the fact that indexing and pointer errors can overwrite parts
|
|
of memory causing strange quirks in your program. If you have used
|
|
indexing with {$R-} or if you use pointer operations, sooner or
|
|
later you are bound to have these problems in developing your
|
|
applications.
|
|
See Edward Mitchell (1993), Borland Pascal Developer's Guide,
|
|
275-288 for common programming errors and especially the information
|
|
on memory clobbering, in a useful chapter on debugging Turbo Pascal
|
|
programs. You might also take a look at your Turbo Pascal User's
|
|
Guide. At least version 7.0 has an instructive general
|
|
categorization of errors on pages 76-77.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:42 1996
|
|
Subject: Converting the number base
|
|
|
|
42. *****
|
|
Q: How do I convert a decimal word into a hexadecimal string, etc?
|
|
|
|
A: Here is one possibility
|
|
function HEXFN (decimal : word) : string;
|
|
const hexDigit : array [0..15] of char = '0123456789ABCDEF';
|
|
begin
|
|
hexfn := hexDigit[(decimal shr 12)]
|
|
+ hexDigit[(decimal shr 8) and $0F]
|
|
+ hexDigit[(decimal shr 4) and $0F]
|
|
+ hexDigit[(decimal and $0F)];
|
|
end; (* hexfn *)
|
|
Here is another conversion example (from longint to binary string)
|
|
function LBINFN (decimal : longint) : string;
|
|
const BinDigit : array [0..1] of char = '01';
|
|
var i : byte;
|
|
binar : string;
|
|
begin
|
|
FillChar (binar, SizeOf(binar), ' ');
|
|
binar[0] := chr(32);
|
|
for i := 0 to 31 do
|
|
binar[32-i] := BinDigit[(decimal shr i) and 1];
|
|
lbinfn := binar;
|
|
end; (* lbinfn *)
|
|
For a full set of conversions, both from and to decimal, apply
|
|
TSUTNTB.TPU from ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:43 1996
|
|
Subject: Identifying the last drive
|
|
|
|
43. *****
|
|
Q: How to determine the last drive?
|
|
|
|
A: One way of doing that is utilizing the information in DPB, that
|
|
is the Drive Parameter Block, but that is rather complicated, so you
|
|
can find that without source code in the TSUNTH unit in
|
|
ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip .
|
|
Another way is using interrupt 21H, function 36H to detect if a
|
|
drive exists starting from the first drive letter. The code is given
|
|
below. The disadvantage of this method is that it does not
|
|
distinguish between real and substituted drives.
|
|
uses Dos;
|
|
function LASTDFN : char; (* Detect last harddisk letter *)
|
|
var regs : registers;
|
|
i : byte;
|
|
begin
|
|
i := 2;
|
|
repeat
|
|
Inc(i);
|
|
FillChar (regs, SizeOf(regs), 0);
|
|
regs.ah := $36;
|
|
regs.dl := i;
|
|
MsDos(regs);
|
|
until (regs.ax = $FFFF);
|
|
lastdfn := chr(i+63);
|
|
end; (* lastdfn *)
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:44 1996
|
|
Subject: Clock display in a TP program
|
|
|
|
44. *****
|
|
Q: How can I put a running clock into my Turbo Pascal program?
|
|
|
|
A: We are not speaking of a stand-alone TSR-clock (which is a
|
|
different task), but considering a clock that continuously displays
|
|
the time in some part of the output screen of your Turbo Pascal
|
|
program.
|
|
You might first want to read the earlier items about ReadKey
|
|
usages if you are not familiar with it (you probably are, because
|
|
you would not pose this advanced question if you were a novice). The
|
|
items are the unlikely "How do I disable or capture the break key in
|
|
Turbo Pascal?" and "How can I read input without echoing to the
|
|
screen?"
|
|
The general idea is to make the body of the program a repeat
|
|
until loop using ReadKey for input and updating the clock display
|
|
at suitable junctions within the loop. The scheme is thus something
|
|
like the following.
|
|
procedure showtime;
|
|
begin
|
|
{ if the second has changed, write the time }
|
|
end;
|
|
:
|
|
repeat
|
|
{ do whatever }
|
|
showtime;
|
|
if KeyPressed then
|
|
case ReadKey of
|
|
{ whatever }
|
|
{ exit rules }
|
|
end;
|
|
showtime;
|
|
:
|
|
showtime;
|
|
until false;
|
|
One trick of the trade is that you must not update your clock
|
|
each time the clock routine is encountered. You should test if the
|
|
second has changed, and update only then. Else you are liable to get
|
|
an annoying flicker in your clock.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:45 1996
|
|
Subject: Is a name a directory
|
|
|
|
45. *****
|
|
Q: How to establish if a name refers to a directory or not?
|
|
|
|
A: This question has turned out a bit more complicated than I first
|
|
thought. There are several methods, each with some catch. The first
|
|
is trying to open the name as a file and observing the IOResult. The
|
|
ISDIRFN function in ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip TPU unit
|
|
TSUNTJ.TPU is based on this method. Unfortunately it is not always
|
|
stable. I have been reported problems in connection with DRDOS by
|
|
Richard Breuer (ricki@pool.informatik.rwth-aachen.de) who has
|
|
tested these routines.
|
|
The second method (ISDIR2FN) is based on the fact that the file
|
|
NUL exists in a directory if the directory exists.
|
|
The thrid method (ISDIR3FN) is a brute force method. It is given
|
|
below, since it is quite an instructive little exercise of Turbo
|
|
Pascal programming.
|
|
(* Search recursively through a drive's directories.
|
|
Auxiliary, recursive procedure for ISDIR3FN *)
|
|
procedure SEARCHDR (Path, FileSpec : string;
|
|
name : string;
|
|
var found : boolean);
|
|
var FileInfo : SearchRec;
|
|
begin
|
|
FindFirst (Path + '*.*', Directory, FileInfo);
|
|
while DosError = 0 do
|
|
begin
|
|
if ((FileInfo.Attr and Directory) > 0) and
|
|
(FileInfo.Name <> '.') and
|
|
(FileInfo.Name <> '..') then
|
|
begin
|
|
SEARCHDR (Path + FileInfo.Name + '\',
|
|
FileSpec,
|
|
name,
|
|
found);
|
|
if Path + FileInfo.Name + '\' = name then
|
|
found := true;
|
|
end;
|
|
FindNext (FileInfo);
|
|
end; {while}
|
|
end; (* searchdr *)
|
|
|
|
(* Does a name refer to a directory *)
|
|
function ISDIR3FN (name : string) : boolean;
|
|
var drive : char;
|
|
found : boolean;
|
|
begin
|
|
{... Default value ...}
|
|
isdir3fn := false;
|
|
{... Discard empty names ...}
|
|
if name = '' then exit;
|
|
{... Expand into a fully qualified name, makes it uppercase ...}
|
|
name := FExpand (name);
|
|
if name[Length(name)] <> '\' then name := name + '\';
|
|
{... Extract the drive letter from the name ...}
|
|
drive := UpCase (name[1]);
|
|
{... Check first for the root ...}
|
|
if drive + ':\' = name then
|
|
begin isdir3fn := true; exit; end;
|
|
{... Check the rest of the directories recursively ...}
|
|
found := false;
|
|
SEARCHDR (drive + ':\', '*.*', name, found);
|
|
isdir3fn := found;
|
|
end; (* isdir3fn *)
|
|
|
|
-Date: Mon, 13 Jun 1994 00:13:05 +0000 (GMT)
|
|
-From: JEROEN SCHIPPER <JSCHIPPER@HUT.NL>
|
|
-To: ts@uwasa.fi (Timo Salmi)
|
|
-Subject: Is a name a directory in TP
|
|
|
|
The method I use is simply checking the attribute bit, as this small
|
|
program will demonstrate:
|
|
program isdir;
|
|
uses dos;
|
|
var s:string;
|
|
attr:word;
|
|
f:file;
|
|
begin
|
|
repeat
|
|
readln(s);
|
|
if s = '' then break;
|
|
assign(f,s);
|
|
getfattr(f,attr);
|
|
if doserror <> 0 then
|
|
writeln('DOS error code = ', doserror)
|
|
else
|
|
begin
|
|
if attr and directory <> 0 then
|
|
writeln(S,' is a directory')
|
|
else
|
|
writeln(S,' is a not directory')
|
|
end;
|
|
until false;
|
|
end.
|
|
The methods you mention in your faq are far more complicated, but
|
|
why? Is there are catch why the method above won't work? I guess
|
|
don't really understand the problem here.
|
|
Jeroen.
|
|
|
|
A2: This has turned out to be a tricky FAQ. There are some
|
|
additional suggestions and comments from the gentle readers. You can
|
|
track them from ftp://garbo.uwasa.fi/pc/ts/tspost00.zip index.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:46 1996
|
|
Subject: Disabling alt-ctrl-del
|
|
|
|
46. *****
|
|
Q: How does one disable alt-ctrl-del?
|
|
|
|
A: I can only give a pointer to source code. Take a look at
|
|
4067 Jul 1 1993 ftp://garbo.uwasa.fi/pc/turbopa7/cadthf10.zip
|
|
cadthf10.zip CadThief TP6+ unit for trapping ctrl+alt+del, M.Hanninen
|
|
and
|
|
30673 Oct 13 1987 ftp://garbo.uwasa.fi/pc/turbopas/keyint.zip
|
|
keyint.zip Disable alt-ctrl-del + other int09h TP tricks, N.Rubenking
|
|
and
|
|
7105 Apr 19 10:51 ftp://garbo.uwasa.fi/pc/turbopa7/cad_int9.zip
|
|
cad_int9.zip Disable Ctrl-Alt-Del via new TP kb interrupt, J.Robertson
|
|
Also see Lou Duchez's source code in 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.
|
|
I have utilized alt-ctrl-del disabling at least in one of my own
|
|
programs (PESTIKID.EXE). The code is not available, but the general
|
|
idea is replacing the old keyboard interrupt ($09) with a handler of
|
|
one's own. If the handler detects alt-ctrl-del, the keyboard is
|
|
reset, else the handler is chained back to the original interrupt.
|
|
The chaining requires a rather complicated inline procedure provided
|
|
in TurboPower Software's kit. An additional complication is that the
|
|
del keypress must be intercepted already at the relevant port $60,
|
|
and the alt and ctrl status must be tested, so that the rebooting
|
|
will not be invoked. Resetting the keyboard requires accessing the
|
|
$20 and $61 ports.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:47 1996
|
|
Subject: Does a file exist
|
|
|
|
47. *****
|
|
Q: How can I test whether a file exists?
|
|
|
|
A: There are several alternatives. Here is the most common with
|
|
example code. It recognizes also read-only, hidden and system files.
|
|
function FILEXIST (name : string) : boolean;
|
|
var fm : byte;
|
|
f : file;
|
|
b : boolean;
|
|
begin
|
|
fm := FileMode;
|
|
FileMode := 0;
|
|
assign (f, name);
|
|
{$I-} reset(f); {$I+}
|
|
b := IOResult = 0;
|
|
if b then close(f);
|
|
filexist := b;
|
|
FileMode := fm;
|
|
end;
|
|
|
|
A second alternative is
|
|
Uses Dos;
|
|
function FILEXIST (name : string) : boolean;
|
|
var f : file;
|
|
a : word;
|
|
begin
|
|
assign (f, name);
|
|
GetFAttr (f, a);
|
|
filexist := false;
|
|
if DosError = 0 then
|
|
if ((a and Directory) = 0) and ((a and VolumeId) = 0) then
|
|
filexist := true;
|
|
end;
|
|
|
|
A third alternative is
|
|
Uses Dos;
|
|
function FILEXIST (name : PathStr) : boolean;
|
|
begin
|
|
filexist := FSearch (name, '') <> '';
|
|
end;
|
|
|
|
A fourth alternative is the following. Be careful with this option,
|
|
since it works a bit differently from the others. It accepts wild
|
|
cards. Thus, for example FILEXIST('c:\autoexec.*') would be TRUE in
|
|
this method, while FALSE in all the above.
|
|
Uses Dos;
|
|
function FILEXIST (name : string) : boolean;
|
|
var f : SearchRec;
|
|
begin
|
|
filexist := false;
|
|
FindFirst (name, AnyFile, f);
|
|
if DosError = 0 then
|
|
if (f.attr <> Directory) and (f.attr <> VolumeId) then
|
|
filexist := true;
|
|
end;
|
|
A good variation from KDT@newton.national-physical-lab.co.uk of this
|
|
theme, disallowing wildcards:
|
|
function file_exists (fname :string) :boolean;
|
|
var f :searchrec;
|
|
begin
|
|
findfirst (fname, anyfile - directory - volumeid, f);
|
|
file_exists := (doserror + pos('*',fname) + pos('?',fname) = 0);
|
|
end;
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:48 1996
|
|
Subject: The current program name
|
|
|
|
48. *****
|
|
Q: What is the name of the current Turbo Pascal program?
|
|
|
|
A: The name of the currently executing Turbo Pascal program is in
|
|
ParamStr(0).
|
|
This was introduced in TP version 5.0, and as far as I recall at
|
|
least MS-DOS version 3.0 is required. For TP 4.0 you can use
|
|
"ParamStr0 The name of the program" from TSUNT45 in
|
|
ftp://garbo.uwasa.fi/pc/ts/tspa3440.zip (or whatever the version
|
|
number is the latest).
|
|
It is advisable to put the value into a string variable at be
|
|
beginning of the program before eny I/O takes place. Thus you might
|
|
wish to use:
|
|
var progname : string;
|
|
begin { the main program }
|
|
progname := ParamStr(0);
|
|
:
|
|
A bonus of this method is that you can access the individual
|
|
characters of progname (e.g. progname[1] for the drive) while that
|
|
is not possible to do for the ParamStr keyword.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:49 1996
|
|
Subject: How can a program reboot my PC?
|
|
|
|
49. *****
|
|
Q: How is the code for rebooting the PC written in Turbo Pascal?
|
|
|
|
A: This item draws from the information and the C-code example in
|
|
Stan Brown's, later J.Carlyle's comp.os.msdos.programmer FAQ,
|
|
ftp://garbo.uwasa.fi/pc/doc-net/dosfv204.zip (at the time of
|
|
updating this), from memory.lst and interrup.b in
|
|
ftp://garbo.uwasa.fi/pc/programming/inter48b.zip, and from
|
|
ftp://garbo.uwasa.fi/pc/programming/helppc21.zip. The Turbo Pascal
|
|
code is my adaptation of the C-code. It is not a one-to-one port.
|
|
The usually advocated warm-boot method is storing $1234 in the
|
|
word at $0040:$0072 and jumping to address $FFFF:$0000. The problem
|
|
with this approach is that files must first be closed, potential
|
|
caches flushed. This is how to do this
|
|
procedure REBOOT;
|
|
label next;
|
|
var regs : registers;
|
|
i : byte;
|
|
ticks : longint;
|
|
begin
|
|
{... "press" alt-ctrl ...}
|
|
mem[$0040:$0017] := mem[$0040:$0017] or $0C; { 00001100 }
|
|
{... "press" del, try a few times ...}
|
|
for i := 1 to 10 do
|
|
begin
|
|
FillChar (regs, sizeOf(regs), 0); { initialize }
|
|
regs.ah := $4F; { service number }
|
|
regs.al := $53; { del key's scan code }
|
|
regs.flags := FCarry; { "sentinel for ignoring key" }
|
|
Intr ($15, regs);
|
|
{... check if the del key registered, if not retry ...}
|
|
if regs.flags and Fcarry > 0 then goto next;
|
|
{... waste some time, watch out for midnight ...}
|
|
ticks := MemL [$0040:$006C];
|
|
repeat until (MemL[$0040:$006C] - ticks > 3) or
|
|
(MemL[$0040:$006C] - ticks < 0)
|
|
end; {for}
|
|
exit;
|
|
next:
|
|
{... disk reset: writes all modified disk buffers to disk ...}
|
|
FillChar (regs, sizeOf(regs), 0);
|
|
regs.ah := $0D;
|
|
MsDos (regs);
|
|
{... set post-reset flag, use $0000 instead of $1234 for coldboot ...}
|
|
memW[$0040:$0072] := $1234;
|
|
{... jump to $FFFF:0000 BIOS reset ...}
|
|
Inline($EA/$00/$00/$FF/$FF);
|
|
end; (* reboot *)
|
|
One slight problem with this approach is that the keyboard intercept
|
|
interrupt $15 service $4F requires at least an AT according to
|
|
ftp://garbo.uwasa.fi/pc/programming/inter48b.zip. A simple test
|
|
based on "FFFF:E byte ROM machine id" (the previous definition is
|
|
from ftp://garbo.uwasa.fi/pc/programming/helppc21.zip) is:
|
|
function ISATFN : boolean;
|
|
begin
|
|
case Mem[$F000:$FFFE] of
|
|
$FC, $FA, $F8 : isatfn := true;
|
|
else isatfn := false;
|
|
end; {case}
|
|
end; (* isatfn *)
|
|
For a more comprehensive test use CPUFN "Get the type of the
|
|
processor chip" from TSUNTH in ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip
|
|
or see the TP + ASM code in Michael Ticher (1992), PC Intern System
|
|
Programming, pp. 725-727.
|
|
|
|
An addition by Per Bergland (d6caps@dtek.chalmers.se): I recently
|
|
downloaded the FAQ for this newsgroup, and studied the code for
|
|
rebooting a PC. The problem with that code (calling FFFF:0000) is
|
|
that it will not work in protected mode programs such as those
|
|
compiled for Windows or BP7 DPMI, or even in a DOS program run in a
|
|
Windows DOS session. The solution provided has been tested on
|
|
various COMPAQ PC:s, but I think it will work on any AT-class
|
|
machine. It involves using the 8042 keyboard controller chip output
|
|
pin 0, which is physically connected to the reset pin of the CPU.
|
|
There is unfortunately no way to perform a "warm" reboot this way,
|
|
and the warnings about disk caches etc apply to this code, too (see
|
|
FAQ). The code is written in BP7 assembly lingo, because that's what
|
|
I normally write code in, but anyone could rewrite it in C or high
|
|
level Pascal.
|
|
UNIT Reboot;
|
|
INTERFACE
|
|
procedure DoReboot;
|
|
IMPLEMENTATION
|
|
procedure DoReboot;assembler;
|
|
asm
|
|
cli
|
|
@@WaitOutReady: { Busy-wait until 8042 is ready for new command}
|
|
in al,64h { read 8042 status byte}
|
|
test al,00000010b { Bit 1 of status indicates input buffer full }
|
|
jnz @@WaitOutReady
|
|
mov al,0FEh { Pulse "reset" = 8042 pin 0 }
|
|
out 64h,al
|
|
{ The PC will reboot now }
|
|
end;
|
|
END.
|
|
--------------------------------------------------------------------
|
|
|
|
From ts@uwasa.fi Thu Mar 7 00:00:50 1996
|
|
Subject: Writing inline code
|
|
|
|
50. *****
|
|
Q: How can I write inline code?
|
|
|
|
A: In Turbo Pascal versions prior 6.0 assembler code could not be
|
|
directly included in the code. Instead one had to assemble the code
|
|
into inline statements. Consider the task of rebooting the PC
|
|
(without disk closing and cache flushing). The assembler code for
|
|
this is
|
|
mov ax,$40
|
|
mov ds,ax
|
|
mov wo [$72],$1234
|
|
jmp $FFFF:$0000
|
|
To assemble this code into an inline statement write the following
|
|
file calling it e.g. debug.in. The empty line is important. Also
|
|
carefully note that debug assumes hexadecimal notation. Do not use
|
|
the $ designator in debug.in.
|
|
.... begin debug.in, cut here ....
|
|
a 100
|
|
mov ax,40
|
|
mov ds,ax
|
|
mov wo [72],1234
|
|
jmp FFFF:0000
|
|
|
|
u 100
|
|
q
|
|
.... end debug.in, cut here ....
|
|
Give the following command
|
|
debug < debug.in
|
|
You'll get
|
|
0E9E:0100 B84000 MOV AX,0040
|
|
0E9E:0103 8ED8 MOV DS,AX
|
|
0E9E:0105 C70672003412 MOV WORD PTR [0072],1234
|
|
0E9E:010B EA0000FFFF JMP FFFF:0000
|
|
This translates into
|
|
Inline ($B8/$40/$00/
|
|
$8E/$D8/
|
|
$C7/$06/$72/$00/$34/$12/
|
|
$EA/$00/$00/$FF/$FF);
|
|
|
|
A2: You can also utilize an inline <--> asm converter called
|
|
ftp://garbo.uwasa.fi/pub/pc/turbopas/inlin219.zip
|
|
inlin219.zip Inline assembler for Turbo Pascal, w/src, D.Baldwin
|
|
It has two sources, inline.pas and uninline.pas which you can
|
|
compile to do the conversions in both directions for you. For
|
|
example, if you have a file test.asm containing the
|
|
mov ax,$0040
|
|
mov ds,ax
|
|
mov word ptr [$72],$1234
|
|
jmp far $FFFF:$0000
|
|
then "inline test.asm" will produce test.obj with the following,
|
|
expected contents
|
|
Inline(
|
|
$B8/$40/$00/ {mov ax,$0040}
|
|
$8E/$D8/ {mov ds,ax}
|
|
$C7/$06/$72/$00/$34/$12/ {mov word ptr [$72],$1234}
|
|
$EA/$00/$00/$FF/$FF); {jmp far $FFFF:$0000}
|
|
--------------------------------------------------------------------
|
|
|