home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 24 / CD_ASCQ_24_0995.iso / vrac / tsfaqp26.zip / FAQPAS3.TXT < prev    next >
Internet Message Format  |  1995-07-23  |  45KB

  1. From ts@uwasa.fi Sun Jul 23 00:00:00 1995
  2. Subject: FAQPAS3.TXT contents
  3.  
  4.                              Copyright (c) 1993-1995 by Timo Salmi
  5.                                                All rights reserved
  6.  
  7. FAQPAS3.TXT The third set of frequently (and not so frequently)
  8. asked Turbo Pascal questions with Timo's answers. The items are in
  9. no particular order.
  10.  
  11. You are free to quote brief passages from this file provided you
  12. clearly indicate the source with a proper acknowledgment.
  13.  
  14. Comments and corrections are solicited. But if you wish to have
  15. individual Turbo Pascal consultation, please post your questions to
  16. a suitable Usenet newsgroup like news:comp.lang.pascal.borland. It
  17. is much more efficient than asking me by email. I'd like to help,
  18. but I am very pressed for time. I prefer to pick the questions I
  19. answer from the Usenet news. Thus I can answer publicly at one go if
  20. I happen to have an answer. Besides, newsgroups have a number of
  21. readers who might know a better or an alternative answer. Don't be
  22. discouraged, though, if you get a reply like this from me. I am
  23. always glad to hear from fellow Turbo Pascal users.
  24.  
  25. ....................................................................
  26. Prof. Timo Salmi   Co-moderator of news:comp.archives.msdos.announce
  27. Moderating at ftp:// & http://garbo.uwasa.fi archives  193.166.120.5
  28. Department of Accounting and Business Finance  ; University of Vaasa
  29. ts@uwasa.fi http://uwasa.fi/~ts BBS 961-3170972; FIN-65101,  Finland
  30.  
  31. --------------------------------------------------------------------
  32. 61) What are Binary Coded Decimals? How to convert them?
  33. 62) How can I copy a file in a Turbo Pascal program?
  34. 63) How can I use C code in my Turbo Pascal program?
  35. 64) How do I get started with the Turbo Profiler?
  36. 65) How can I detect if the shift/ctrl/alt etc key is pressed?
  37. 66) How do I get a base 10 logarithm in TP?
  38. 67) If Delay procedure does not work properly, how do I fix it?
  39. 68) How much memory will my TP program require?
  40. 69) How to detect if a drive is a CD-ROM drive?
  41. 70) How do I convert an array of characters into a string?
  42. 71) How do I get started with graphics programming?
  43. 72) Where to I find the different sorting source codes?
  44. 73) A beginner's how to write and compile units.
  45. 74) What are and how do I use pointers?
  46. 75) How can I read another program's errorlevel value in TP?
  47. 76) What are the current Pascal newsgroups on the Usenet news?
  48. 77) How do I detect the CapsLock status, how do I turn it on/off?
  49. 78) How do I detect if the F11 or F12 key has been pressed?
  50. 79) How do I extract (parse) substrings from an input string?
  51. 80) How do I find out the size of any kind of a file?
  52. 81) How do I format graphics output like in textmode writeln?
  53. --------------------------------------------------------------------
  54.  
  55. From ts@uwasa.fi Sun Jul 23 00:01:01 1995
  56. Subject: Binary Coded Decimals
  57.  
  58. 61. *****
  59.  Q: What are Binary Coded Decimals? How to convert them?
  60.  
  61.  A: Let us look at full integers only and skip the even more
  62. difficult question of BCD reals and BCD operations.
  63.      Decimal Hexa  BCD
  64.         1      $1    1
  65.         :      $9    9
  66.        10      $A   ..
  67.         :       :    :
  68.        12      $C   ..
  69.         :       :    :
  70.        16     $10   10
  71.        17     $11   11
  72.        18     $12   12
  73.         :       :    :
  74. Consider the last value, that is BCD presentation of 12. The
  75. corresponding hexadecimal is $12 (not $C as in normal decimal to
  76. hexadecimal conversion). The crucial question is how to convert
  77. 12BCD to $12 (or its normal decimal equivalent 18). Here is my
  78. sample code:
  79.   type BCDType = array [0..7] of char;
  80.   {}
  81.   procedure StrToBCD (s : string; var b : BCDType);
  82.   var i, p : byte;
  83.   begin
  84.     FillChar(b, SizeOf(b), '0');
  85.     p := Length (s);
  86.     if p > 8 then exit;
  87.     for i := p downto 1 do b[p-i] := s[i];
  88.   end;  (* strtobcd *)
  89.   {}
  90.   function BCDtoDec (b : BCDType; var ok : boolean) : longint;
  91.   const Digit : array [0..9] of char = '0123456789';
  92.   var i, k : byte;
  93.       y, d : longint;
  94.   begin
  95.     y := 0;
  96.     d := 1;
  97.     ok := false;
  98.     for i := 0 to 7 do begin
  99.       k := Pos (b[i], Digit);
  100.       if k = 0 then exit;
  101.       y := y + (k-1) * d;
  102.       if i < 7 then d := 16 * d;
  103.     end; { for }
  104.     ok := true;
  105.     BCDtoDec := y;
  106.   end;  (* bcdtodec *)
  107.   {}
  108.   {}
  109.   procedure TEST;
  110.   var i  : byte;
  111.       b  : BCDType;
  112.       x  : longint;
  113.       ok : boolean;
  114.       s  : string;
  115.   begin
  116.     s := '12';
  117.     StrToBCD (s, b);
  118.     write ('The BCD value : ');
  119.     for i := 7 downto 0 do write (b[i], ' ');
  120.     writeln;
  121.     x := BCDtoDec (b, ok);
  122.     if ok then writeln ('is ', x, ' as an ordinary decimal')
  123.       else writeln ('Error in BCD');
  124.   end;  (* test *)
  125.   {}
  126.   begin TEST; end.
  127.  
  128. Next we can ask, what if the BCD value is given as an integer.
  129. Simple, first convert the integer into a string. For example in
  130. the procedure TEST put
  131.   Str (12, s);
  132.  
  133. Finally, what about converting an ordinary decimal to the
  134. corresponding BCD but given also as a decimal variable.  For example
  135. 18 --> 12?
  136.   function LHEXFN (decimal : longint) : string;
  137.   const hexDigit : array [0..15] of char = '0123456789ABCDEF';
  138.   var i : byte;
  139.       s : string;
  140.   begin
  141.     FillChar (s, SizeOf(s), ' ');
  142.     s[0] := chr(8);
  143.     for i := 0 to 7 do
  144.       s[8-i] := HexDigit[(decimal shr (4*i)) and $0F];
  145.     lhexfn := s;
  146.   end;  (* lhexfn *)
  147.   {}
  148.   function DecToBCD (x : longint; var ok : boolean) : longint;
  149.   const Digit : array [0..9] of char = '0123456789';
  150.   var hexStr : string;
  151.   var i, k : byte;
  152.       y, d : longint;
  153.   begin
  154.     hexStr := LHEXFN(x);
  155.     y := 0;
  156.     d := 1;
  157.     ok := false;
  158.     for i := 7 downto 0 do begin
  159.       k := Pos (hexStr[i+1], Digit);
  160.       if k = 0 then exit;
  161.       y := y + (k-1) * d;
  162.       if i > 0 then d := 10 * d;
  163.     end; { for }
  164.     ok := true;
  165.     DecToBCD := y;
  166.   end;  (* dectobcd *)
  167.   {}
  168.   procedure TEST2;
  169.   var i    : byte;
  170.       x10  : longint;
  171.       xBCD : longint;
  172.       ok   : boolean;
  173.   begin
  174.     x10 := 18;
  175.     writeln ('The ordinary decimal value : ', x10);
  176.     xBCD := DecToBCD (x10, ok);
  177.     if ok then writeln ('is ', xBCD, ' as a binary coded decimal')
  178.       else writeln ('Error in BCD');
  179.   end;  (* test2 *)
  180.   {}
  181.   begin TEST; end.
  182. --------------------------------------------------------------------
  183.  
  184. From ts@uwasa.fi Sun Jul 23 00:01:02 1995
  185. Subject: Copying with TP
  186.  
  187. 62. *****
  188.  Q: How can I copy a file in a Turbo Pascal program?
  189.  
  190.  A: Here is the code. Take a close look. It has some instructive
  191. features besides the copying, like handling the filemode and using
  192. dynamic variables (using pointers).
  193.   procedure SAFECOPY (fromFile, toFile : string);
  194.   type bufferType = array [1..65535] of char;
  195.   type bufferTypePtr = ^bufferType;  { Use the heap }
  196.   var bufferPtr : bufferTypePtr;     { for the buffer }
  197.       f1, f2 : file;
  198.       bufferSize, readCount, writeCount : word;
  199.       fmSave : byte;              { To store the filemode }
  200.   begin
  201.     bufferSize := SizeOf(bufferType);
  202.     if MaxAvail < bufferSize then exit;  { Assure there is enough memory }
  203.     New (bufferPtr);              { Create the buffer }
  204.     fmSave := FileMode;           { Store the filemode }
  205.     FileMode := 0;                { To read also read-only files }
  206.     Assign (f1, fromFile);
  207.     {$I-} Reset (f1, 1); {$I+}    { Note the record size 1, important! }
  208.     if IOResult <> 0 then exit;   { Does the file exist? }
  209.     Assign (f2, toFile);
  210.     {$I-} Reset (f2, 1); {$I+}    { Don't copy on an existing file }
  211.     if IOResult = 0 then begin close (f2); exit; end;
  212.     {$I-} Rewrite (f2, 1); {$I+}  { Open the target }
  213.     if IOResult <> 0 then exit;
  214.     repeat                        { Do the copying }
  215.       BlockRead (f1, bufferPtr^, bufferSize, readCount);
  216.       {$I-} BlockWrite (f2, bufferPtr^, readCount, writeCount); {$I+}
  217.       if IOResult <> 0 then begin close (f1); exit; end;
  218.     until (readCount = 0) or (writeCount <> readCount);
  219.     writeln ('Copied ', fromFile, ' to ', toFile,
  220.              ' ', FileSize(f2), ' bytes');
  221.     close (f1); close (f2);
  222.     FileMode := fmSave;           { Restore the original filemode }
  223.     Dispose (bufferPtr);          { Release the buffer from the heap }
  224.   end;  (* safecopy *)
  225.  
  226. Of course a trivial solution would be to invoke the MS-DOS copy
  227. command using the Exec routine. (See the item "How do I execute an
  228. MS-DOS command from within a TP program?")
  229. --------------------------------------------------------------------
  230.  
  231. From ts@uwasa.fi Sun Jul 23 00:01:03 1995
  232. Subject: C modules in TP
  233.  
  234. 63. *****
  235.  Q: How can I use C code in my Turbo Pascal program?
  236.  
  237.  A: I have very little information on this question, since I do not
  238. program in C myself.  However in reading Turbo Pascal textbooks I
  239. have come across a couple of references I can give.  They are Edward
  240. Mitchell (1993), Borland Pascal Developer's Guide, pp. 60-64, and
  241. Stoker & Ohlsen (1989), Turbo Pascal Advanced Techniques, Ch 4.
  242. --------------------------------------------------------------------
  243.  
  244. From ts@uwasa.fi Sun Jul 23 00:01:04 1995
  245. Subject: Using Turbo Profiler
  246.  
  247. 64. *****
  248.  Q: How do I get started with the Turbo Profiler?
  249.  
  250.  A: Borland's separate Turbo Profiler is a powerful tool for
  251. improving program code and enhancing program performance, but far
  252. from an easy to use. It is an advanced tool. In fact setting it up
  253. the first time is almost a kind of detective work.
  254.    Let's walk through the steps with Turbo Profiler version 1.01 to
  255. see where a running Turbo Pascal program takes its time.
  256. Assume a working directory r:\
  257. 1. Copy the target .PAS file to r:\
  258. 2. Compile it with TURBO.EXE using the following Compiler and
  259.    Debugger options. The standalone debugging option is crucial.
  260.      Code generation
  261.       [ ] Force far calls        [X] Word align data
  262.       [ ] Overlays allowed       [ ] 286 instructions
  263.      Runtime errors             Syntax options
  264.       [ ] Range checking         [X] Strict var-strings
  265.       [X] Stack checking         [ ] Complete boolean eval
  266.       [ ] I/O checking           [X] Extended syntax
  267.       [ ] Overflow checking      [ ] Typed @ operator
  268.                                  [ ] Open parameters
  269.      Debugging
  270.       [X] Debug information     Numeric processing
  271.       [X] Local symbols          [ ] 8087/80287
  272.                                  [ ] Emulation
  273.      Debugging         Display swapping
  274.       [X] Integrated    ( ) None
  275.       [X] Standalone    () Smart
  276.                         ( ) Always
  277. 3) Call TPROF.EXE
  278. 4) Load the .EXE file produced by compilation in item 2.
  279. 5) Choose from the TPROF menus
  280.      Statistics
  281.        Profiling options...
  282.          Profile mode
  283.           () Active    ( ) Passive
  284.           Run count
  285.            1
  286.           Maximum areas
  287.            200
  288. 6) Choose from the TPROF menus
  289.       Options
  290.        Save options...
  291.       [X] Options
  292.       [ ] Layout
  293.       [ ] Macros
  294.      Save To
  295.       r:\tfconfig.tf
  296. 7) Press Alt-F10 for the Local Menu. Choose
  297.      Add areas
  298.        All routines
  299. and so on.
  300. 8) Choose Run from the TPROF menus (or F9)
  301. 9) Choose from the TPROF menus
  302.       Print
  303.        Options...
  304.      Width
  305.       80
  306.      Height
  307.       9999
  308.       ( ) Printer     ( ) Graphics
  309.       () File        () ASCII
  310.      Destination File
  311.       r:\report.lst
  312. 10) Print
  313.        Module...
  314.          All modules
  315.          Statistics
  316.            Overwrite
  317. Also see Edward Mitchell (1993), Borland Pascal Developer's Guide.
  318. It has a a very instructive chapter "Program Optimization" on the
  319. Turbo Profiler. The material in the Turbo Profiler manual is so
  320. complicated that additional guidance like Mitchell's is very much
  321. needed.
  322. --------------------------------------------------------------------
  323.  
  324. From ts@uwasa.fi Sun Jul 23 00:01:05 1995
  325. Subject: Detecting shift status
  326.  
  327. 65. *****
  328.  Q: How can I detect if the shift/ctrl/alt etc key is pressed? I
  329. know how to get the scan codes with the ReadKey function, but I
  330. can't find the procedure for detecting these keys.
  331.  
  332.  A: Detecting pressing the special keys or getting the toggle status
  333. cannot be done with ReadKey. You'll need to access the Keyboard
  334. Flags Byte at $0040:$0017. You can do this either by a direct "Mem"
  335. access, or using interrupt $16 function $02. For more details
  336. including the bitfields for the shift flags see in Ralf Brown's
  337. interrupt list ftp://garbo.uwasa.fi/pc/programming/inter46a.zip (or
  338. whatever is the current version). For example to see if the alt key
  339. is pressed you can use
  340.   uses Dos;
  341.   function ALTDOWN : boolean;
  342.   var regs : registers;
  343.   begin
  344.     FillChar (regs, SizeOf(regs), 0);
  345.     regs.ah := $02;
  346.     Intr ($16, regs);
  347.     altdown := (regs.al and $08) = $08;
  348.   end;
  349. For the enhanced keyboard flags see interrupt $16 function $12. It
  350. can distinguish also between the right and the left alt and ctlr
  351. keys.
  352.    A tip from Martijn Leisink martijnl@sci.kun.nl. Be careful [if
  353. you use the $0040:$0017 memory position to set a toggle]: On several
  354. computers you have to call int 16h after the new setting is shown by
  355. the LED's on the keyboard. Not doing so might give the user wrong
  356. information.
  357.    A tip from Dr John Stockton jrs@dclf.npl.co.uk. Going via a
  358. BytePointer set to Ptr(Seg0040, $0017) is almost as easy as "Mem",
  359. and also works in Protected mode.
  360. --------------------------------------------------------------------
  361.  
  362. From ts@uwasa.fi Sun Jul 23 00:01:06 1995
  363. Subject: Base 10 logarithm
  364.  
  365. 66. *****
  366.  Q: How do I get a base 10 logarithm in TP?
  367.  
  368.  A: Just define
  369.      function log (x : real) : real;
  370.      begin log := ln(x) / ln(10); end;
  371. This result is based on some elementary math. By definition
  372. y = log(x) in base 10 is equivalent to x = 10^y (where the ^
  373. indicates an exponent). Thus ln(x) = y ln(10) and hence
  374. y = ln(x) / ln(10).
  375. --------------------------------------------------------------------
  376.  
  377. From ts@uwasa.fi Sun Jul 23 00:01:07 1995
  378. Subject: Replacing Delay procedure
  379.  
  380. 67. *****
  381.  
  382.  Q: If Delay procedure does not work properly, how do I fix it?
  383.  
  384.  A: The Delay procedure in the Crt unit delays a specified number of
  385. milliseconds. It is declared as "procedure Delay(MS: Word);". There
  386. are two problems. The procedure requires using the Crt unit and
  387. there is a bug in it in TP 6.0, at least. The alternative is to use
  388. the procedure GetTime(var Hour, Minute, Second, Sec100: Word) as
  389. shown by the skeleton below
  390.   GetTime (...)
  391.   initialTime := ...
  392.   repeat
  393.     GetTime (...)
  394.     interval := ... - initialTime;
  395.   until interval >= YourDelay;
  396. There are two things you will have to see to. You will have to
  397. convert the time to sec100, and you will have to take care of the
  398. possibility of the interval spanning the midnight. If you do not
  399. wish to program the alternative Delay procedure yourself, you can
  400. use "DOSDELAY Delay without needing the Crt unit" from TSUNTD.TPU
  401. from ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip.
  402.  
  403.  A2: Dr John Stockton jrs@dclf.npl.co.uk suggested procedure that is
  404. expanded below. It has the advantage of being concise and working in
  405. the protected mode. The disadvantage is that it requires a later TP
  406. version. The solution is quite instructuve.
  407.   uses Dos;
  408.   {... John's procedure ...}
  409.   procedure WAIT (SecondsDelay : real) ;
  410.   Var Tptr : ^longint ; Finish : longint ;
  411.   begin
  412.     Tptr := Ptr(Seg0040, $006C) ;
  413.     Finish := Tptr^ + Round(18.2*SecondsDelay) ;
  414.     repeat until Tptr^ > Finish ;
  415.   end;
  416.   {... now let's test it ...}
  417.   var h1, m1, s1, sa100 : word;
  418.       h2, m2, s2, sb100 : word;
  419.   begin
  420.     GetTime (h1, m1, s1, sa100);
  421.     WAIT (3);
  422.     GetTime (h2, m2, s2, sb100);
  423.     writeln (h1, ':', m1, ':', s1, '.' ,sa100);
  424.     writeln (h2, ':', m2, ':', s2, '.' ,sb100);
  425.   end.
  426. --------------------------------------------------------------------
  427.  
  428. From ts@uwasa.fi Sun Jul 23 00:01:08 1995
  429. Subject: TP program memory requirement
  430.  
  431. 68. *****
  432.  
  433.  Q: How much memory will my TP program require?
  434.  
  435.  A: Get MAPMEM.EXE from ftp://garbo.uwasa.fi/pc/memutil/tsrcom35.zip
  436. and put the following code within your Turbo Pascal program:
  437.   Program faq;
  438.   uses Dos;
  439.   :
  440.   SwapVectors;
  441.   Exec (GetEnv('comspec'), '/c mapmem');
  442.   Swapvectors;
  443. Then you'll see a MAPMEM output something like this
  444.   Psp  Cnt   Size Name       Command Line        Hooked Vectors
  445.   ---- --- ------ ---------- ------------------- --------------
  446.         2  26,896 DOS
  447.   0694  2   3,392 COMMAND                        2E
  448.         1      64 ---free---
  449.   0776  2   1,488 MARK       scrollit
  450.   07D6  2  70,816 FAQ                            FF
  451.   1923  3   2,752 command                        22 23 24
  452.   19D2  2 549,712 ---free---
  453.           655,344 ---total--
  454. The memory requirement of your program FAQ.PAS is 70,816. Do not
  455. confuse this figure with the physica size of your program. The
  456. memory requirement affected among other things by the Memory
  457. Allocation Sizes Directive. For example you might have
  458. {$M 16384,0,50000}
  459.  
  460. -Date: Sun, 12 Jun 1994 10:22:18
  461. -From: dmurdoch@mast.queensu.ca (Duncan Murdoch)
  462. -Newsgroups: comp.lang.pascal
  463. -Subject: Re: How much memory will my TP program require?
  464.  
  465.    I think this is a hard question, and probably needs a longer
  466. answer than you gave.  Yours isn't quite right, because TP will
  467. allocate memory that it doesn't need if you set the heapmax
  468. parameter too high.  Your program will run in less memory than
  469. MAPMEM reports. Here's a quick attempt at it:
  470.    TP DOS programs use memory in 4 or 5 blocks:  fixed code, static
  471. data, the stack, sometimes overlaid code, and the heap.  TP Windows
  472. programs add a local heap to this list, but don't use overlays.  The
  473. discussion below deals with real mode DOS programs.
  474.    The size of the code is determined by which procedures and
  475. functions you use in your program.  In DOS, if you don't use
  476. overlays, this is all fixed code, and the size is reported as "Code
  477. size" in the Compile| Information listing in the IDE.  The ways to
  478. reduce it are to use fewer procedures or make them smaller, or move
  479. them to overlays.
  480.    Static data consists of all the global variables and typed
  481. constants in every unit.  It is reported as "Data size" in the
  482. Compile|Information listing.  You can reduce it by declaring fewer
  483. or smaller variables.
  484.    If you use the $O directive to move code to overlays, then those
  485. units won't count as part of your fixed code needs.  You will need
  486. an overlay buffer at run-time; by default, it's the size of the
  487. largest unit you use, but normally you'll change the size with
  488. OvrSetBuf.  It's difficult to work out the best size of this block
  489. except by trial and error:  if your program spends too much time
  490. swapping, then make it larger; if you run out of memory, make it
  491. smaller.  You'll need to use the .MAP file (see the Options| Linker
  492. dialog to create one) to find the size of each unit.  Remember to
  493. subtract the size of overlaid units from the reported "Code size"
  494. when working out the size of fixed code.
  495.   The stack is used for local variables in procedures.  Its size is
  496. controlled by the first parameter to the $M directive; the default
  497. size is 16K.  It's hard to predict exactly how much stack space your
  498. program will use.  One way is to keep reducing the value until your
  499. program aborts with a stack overflow, then use a slightly larger
  500. value.  Another way is to fill the stack with a fixed value at the
  501. start of your program, and at the end, see how many values were
  502. changed.  Again, it's a good idea to allow for a margin of safety,
  503. because hardware interrupts will use this space, and their size is
  504. hard to predict.
  505.    The heap is where New and Getmem get their allocated memory.  The
  506. size is controlled by the 2nd and 3rd parameters to the $M
  507. directive.  The heapmin value will always be allocated; if extra
  508. memory is available, your program will ask for as much as possible,
  509. up to heapmax.  If not enough memory is available to load all your
  510. fixed code, data, stack and heapmin, DOS will refuse to load your
  511. program.  You have nearly complete control over the size of the heap
  512. that you need, determined by how much you use New and Getmem. The
  513. only exception is that some of the standard units use heap space;
  514. GRAPH and all the TurboVision units are examples.  To find how much
  515. your program actually uses, you can reduce Heapmax until it fails,
  516. fill the heap with a special value and look for changes, or monitor
  517. the value of HeapPtr as your program progresses.
  518. --------------------------------------------------------------------
  519.  
  520. From ts@uwasa.fi Sun Jul 23 00:01:09 1995
  521. Subject: Detecting a CD-ROM drive?
  522.  
  523. 69. *****
  524.  
  525.  Q: How to detect if a drive is a CD-ROM drive?
  526.  
  527.  A: There are several methods to do this. Here is one option.
  528.   (* Is a drive a CD-ROM with MSCDEX driver installed *)
  529.   function CDROMFN (drive : char) : boolean;
  530.   var regs : registers;
  531.   begin
  532.     cdromfn := false;
  533.     if swap(DosVersion) < $0200 then exit;
  534.     drive := UpCase(drive);
  535.     if (drive < 'A') or (drive > 'Z') then exit;
  536.     FillChar (regs, SizeOf(regs), 0);
  537.     regs.cx := ord(drive) - ord('A');
  538.     regs.ax := $150B;
  539.     Intr ($2F, regs);
  540.     cdromfn := (regs.ax <> 0) and (regs.bx = $ADAD);
  541.   end;  (* cdromfn *)
  542. The other relevant $2F interrupt functions you can use are $1500,
  543. $1501, and in particular $150D.
  544. --------------------------------------------------------------------
  545.  
  546. From ts@uwasa.fi Sun Jul 23 00:01:10 1995
  547. Subject: Array of chars into string
  548.  
  549. 70. *****
  550.  
  551.  Q: How do I convert an array of characters to a string? More
  552. specifically, I haven't been able to convert an array of characters
  553. into a string, so that I can write it to a file. The only way I have
  554. been able to do it, is writing 1 char at a time.
  555.  
  556.  A: Carefully study these two simple test examples.  Note the
  557. difference in the array's dimensions in the tests.
  558.  
  559.   type atype = array [0..20] of char;
  560.   type stype = string[20];
  561.   var s : stype;
  562.       a : atype absolute s;
  563.   begin
  564.     FillChar (a, SizeOf(a), '*');
  565.     s[0] := chr(20);
  566.     writeln (s);
  567.   end.
  568.  
  569.   type atype = array [1..20] of char;
  570.   var s : string;
  571.       a : atype;
  572.   begin
  573.     FillChar (a, Sizeof(a), '*');
  574.     Move (a, s[1], 20);
  575.     s[0] := chr(20);
  576.     writeln (s);
  577.   end.
  578.  
  579. Of course, you could also assign the array's characters one by one
  580. to the string using a simple for loop (left as an exercise), but the
  581. above methods are more efficient.
  582. --------------------------------------------------------------------
  583.  
  584. From ts@uwasa.fi Sun Jul 23 00:01:11 1995
  585. Subject: Graphics programming primer
  586.  
  587. 71. *****
  588.  
  589.  Q: How do I get started with graphics programming?
  590.  
  591.  A:
  592.   (* This simple test shows the rudiments of getting started with Turbo
  593.      Pascal graphics programming *)
  594.   uses Crt, Graph;
  595.   var grDriver : integer;
  596.       grMode   : integer;
  597.       ErrCode  : integer;
  598.       i, j     : integer;
  599.       xm, ym   : integer;
  600.   const CharSize : integer = 3;
  601.   begin
  602.     { Request graphics driver autodetection }
  603.     grDriver := Detect;
  604.     { Initialize graphics system and put hardware into graphics mode }
  605.     { The relevant .bgi driver is needed in the current directory
  606.       for example egavga.bgi }
  607.     InitGraph (grDriver, grMode, ' ');
  608.     { Return an error code for the previous graphic operation }
  609.     ErrCode := GraphResult;
  610.     { Test for initialialization success }
  611.     if ErrCode <> grOk then begin
  612.       Writeln ('Graphics error:', GraphErrorMsg(ErrCode)); halt; end;
  613.     { Clear the output device and home the current pointer }
  614.     ClearDevice;
  615.     {}
  616.     { Use your own coordinates }
  617.     xm := Round (GetMaxX / 100.0);
  618.     ym := Round (GetMaxY / 100.0);
  619.     {}
  620.     { Set the current line width and style, optional }
  621.     SetLineStyle (SolidLn, 0, ThickWidth);
  622.     { Set the drawing color }
  623.     SetColor (Yellow);
  624.     { Draw a line }
  625.     Line (70*xm, 50*ym, 90*xm, 80*ym);
  626.     {}
  627.     { Drawing bars }
  628.     { Set the fill pattern and color }
  629.     SetFillStyle (SolidFill, Red);
  630.     Bar (0, 0, 25*xm, 25*ym);
  631.     {}
  632.     SetColor (Magenta);
  633.     SetFillStyle (SolidFill, Blue);
  634.     Bar3D (30*xm, 20*ym, 50*xm, 60*ym, 8*xm, TopOn);
  635.     {}
  636.     { Writing text in the graphics mode }
  637.     { Set the drawing color }
  638.     SetColor (LightCyan);
  639.     { Set the current background color }
  640.     SetBkColor (Black);
  641.     { Set style for text output in graphics mode }
  642.     SetTextStyle(DefaultFont, HorizDir, CharSize);
  643.     OutTextXY (0, 80*ym, 'Press any key');
  644.     {}
  645.     repeat until KeyPressed;
  646.     {}
  647.     { Restore the original screen mode before graphics was initialized }
  648.     RestoreCrtMode;
  649.     writeln ('That''s all folks');
  650.     { Shut down the graphics system }
  651.     CloseGraph;
  652.   end.
  653. For an example what you can do with graphics, see
  654.  111673 Oct 8 1993 ftp://garbo.uwasa.fi/pc/ts/tsdemo16.zip
  655.  tsdemo16.zip Assorted graphics demonstrations of functions etc
  656. (or whatever is the current version).
  657. --------------------------------------------------------------------
  658.  
  659. From ts@uwasa.fi Sun Jul 23 00:01:12 1995
  660. Subject: Sorting it out
  661.  
  662. 72. *****
  663.  
  664.  Q: Where to I find the different sorting source codes?
  665.  
  666.  A: I'll answer very briefly by giving two references:
  667.  303771 May 2 1991 ftp://garbo.uwasa.fi/pc/turbopas/nrpas13.zip
  668.  nrpas13.zip Numerical Recipes Pascal shareware version
  669. and
  670.  Gary Martin (1992), Turbo Pascal, Theory and Practice of Good
  671. Programming, Chapter 15.
  672. --------------------------------------------------------------------
  673.  
  674. From ts@uwasa.fi Sun Jul 23 00:01:13 1995
  675. Subject: TP units
  676.  
  677. 73. *****
  678.  
  679.  Q: A beginner's how to write and compile units.
  680.  
  681.  A1: Many of the text-books in the bibliography section of this FAQ
  682. discuss using units in Turbo Pascal. For example see Tom Swan
  683. (1989), Mastering Turbo Pascal 5.5, Chapters 9 and 10 for a more
  684. detailed discussion than the rudiments given in the current item.
  685. Likewise see your Turbo Pascal (7.0) User's Guide Chapter 6, "Turbo
  686. Pascal units".
  687.    You can and need to write your own units if you need recurring or
  688. common routines in your programs and/or your program becomes so big
  689. that it cannot be handled as a single entity.
  690.    A Turbo Pascal unit is a separate file which you compile. The
  691. following trivial example to calculate the sum of two reals
  692. illustrates the basic structure of a unit.
  693.   { The name of this file must be faq73.pas to correspond. }
  694.   unit faq73;
  695.   {}
  696.   { The interface section lists definitions and routines that are }
  697.   { available to the other programs or units. }
  698.   interface
  699.   function SUMFN (a, b : real) : real;
  700.   {}
  701.   { The implementation section contains the actual unit program }
  702.   implementation
  703.   function SUMFN (a, b : real) : real;
  704.   begin
  705.     sumfn := a + b;
  706.   end;
  707.   {}
  708.   end.
  709. When you compile the file FAQ73.PAS a unit FAQ73.TPU results. Next
  710. an example utilizing the faq73 unit in the main program.
  711.   uses faq73;
  712.   {}
  713.   procedure TEST;
  714.   var x, y, z : real;
  715.   begin
  716.      x := 12.34;
  717.      y := 56.78;
  718.      z := SUMFN (x, y);
  719.      writeln (z);
  720.   end;
  721.   {}
  722.   begin
  723.     TEST;
  724.   end.
  725.  
  726.  A2: Most often you would be compiling a Turbo Pascal program
  727. using the IDE (Integrated Development Environment). If you have
  728. precompiled units you must see to it that you have informed the IDE
  729. of the path to them.
  730.    Press F10 and invoke the "Options" menu (or press alt-O). Select
  731. "Directories...". Press tab two times to get to "Unit directories"
  732. and edit the path accordingly. Here is what I have entered myself
  733.   EXE & TPU directory  r:\
  734.   Include directories  r:\
  735.   Unit directories     f:\progs\turbo70\tpu70
  736.   Object directories   f:\progs\turbo70\tpu70
  737. As you see I keep all my precompiled Turbo Pascal 7.0 units in the
  738. f:\progs\turbo70\tpu70 directory.
  739. --------------------------------------------------------------------
  740.  
  741. From ts@uwasa.fi Sun Jul 23 00:01:14 1995
  742. Subject: Beginners' pointers
  743.  
  744. 74. *****
  745.  
  746.  Q: What are and how do I use pointers?
  747.  
  748.  A: This is a beginner's simplified introduction. A pointer is a
  749. variable type used to hold the address of another variable, that is
  750. to point to it. Pointers are used to
  751.  1) To refer to and manipulate variables indirectly.
  752.  2) In Turbo Pascal to obtain access to the heap storage area, which
  753.     is not restricted to 64Kbytes.
  754. Consider the following example
  755.   {$M 16384,0,80000}
  756.   var yPtr : ^real;
  757.   begin
  758.     New(yPtr);
  759.     yPtr^ := 3.14159;
  760.     writeln ('2 times pi = ',  2.0 * yPtr^);
  761.     Dispose(yPtr);
  762.     yPtr := nil;
  763.   end.
  764. Before we can discuss pointers we have to consider some rudiments of
  765. what a kind of a memory model a compiled Turbo Pascal program uses.
  766. This is a highly simplified presentation. For a more detailed
  767. presentation of the TP memory model see for example Tischer (1990b).
  768.   +-------------------------+
  769.   | Heap                    |
  770.   |-------------------------|
  771.   | Data Segment            |
  772.   |-------------------------|
  773.   | Code                    |
  774.   |-------------------------|
  775.   | Program Segment Prefix  |
  776.   +-------------------------+
  777. When you write and compile a Turbo Pascal program it usually
  778. consists of (this is a simplification!) of the three lowest parts.
  779. When you define a global variable, it goes to the Data Segment. For
  780. example defining at the beginning of your program
  781.  var x : real;
  782. requires 6 bytes from the data segment. (Local variables are placed
  783. on the stack.)
  784.    Now, the catch is that because of the underlying 16-bit nature of
  785. MS-DOS, the size of the data segment cannot exceed 64Kb. On occasion
  786. the 64Kb is insufficient. However, if you use pointers, the
  787. corresponding variable values are held on the heap instead of the
  788. data segment or the stack. Before you can use the heap, you have to
  789. reserve it for your program. The following compiler directive makes
  790. a heap of 80000 bytes available to your program {$M 16384,0,80000}.
  791. (The syntax is {$M Stack size, Low heap limit, High heap limit}).
  792.    With pointers you do not refer to a variable directly, but you
  793. point to it. For example, define
  794.   var yPtr : ^real;
  795. Before you can use this pointer, you have to create this new dynamic
  796. variable as follows:
  797.   New(yPtr);
  798. The New(yPtr) statement "Creates a new dynamic variable and sets a
  799. pointer variable to point to it." This pointer, yPtr, will point to
  800. the actual value, which the program puts on the heap. In your
  801. program you can write, for example
  802.   yPtr^ := 3.14159;
  803. Think about the difference between yPtr and yPtr^. The former
  804. contains the value of the memory address where you now have put the
  805. value 3.14159. The latter gives that value. Hence yPtr^ can be used
  806. like any ordinary real variable. The difference is that it is on the
  807. heap, not on the data segment (or stack). Thus you can now use this
  808. pointer. For example you n write
  809.  writeln ('2 times pi = ',  2.0 * yPtr^);
  810. When you do not need the pointer any more in your program you can
  811. dispose of it to release the memory allocated for other purposes:
  812.   Dispose(yPtr);
  813.   yPtr := nil;
  814. "After a call to Dispose, the value of yPtr is undefined and it is
  815. an error to reference yPtr. The reserved word nil denotes a pointer
  816. type constant that does not point to anything." Setting yPtr := nil
  817. is just good programming practice, because then you can later easily
  818. test whether the pointer is available or not. Disposing of a pointer
  819. within your program is not necessary unless the amount of memory is
  820. a critical consideration in your program. The heap will be released
  821. when your program terminates.
  822.   To recount. What yPtr actually contains is the memory address of
  823. the value on the heap. When you write yPtr^, the caret indicates
  824. that you do not mean the pointer itself, but the pointed memory
  825. location in the heap. In this example that memory location in the
  826. heap was made to contain 3.14159.
  827.    You can also define the pointer types. Our second example
  828. illustrates. It displays the squares from one to ten.
  829.   {$M 16384,0,80000}
  830.   type arrayType = array [1..10] of real;
  831.   type arrayPtrType = ^arrayType;
  832.   var A : arrayPtrType;
  833.       i : integer;
  834.   begin
  835.     if SizeOf(arrayType) > MaxAvail then begin
  836.       writeln ('Out of memory');
  837.       halt;
  838.     end;
  839.     New(A);
  840.     for i := 1 to 10 do A^[i] := i*i;
  841.     writeln (A^[9]);
  842.   end.
  843. For an actual application using pointers, see the item "How can I
  844. copy a file in a Turbo Pascal program?"
  845. --------------------------------------------------------------------
  846.  
  847. From ts@uwasa.fi Sun Jul 23 00:01:15 1995
  848. Subject: Reading errorlevel
  849.  
  850. 75. *****
  851.  
  852.  Q: How can I read another program's errorlevel value in TP?
  853.  
  854.  A: This question is best answered by an example. Here is a very
  855. elementary program that returns errorlevel 14 on exiting.
  856.   program faq2;
  857.   begin
  858.     writeln ('Hello world...');
  859.     halt(14);
  860.   end.
  861. Below is the program that calls FAQ2.EXE and detects its errorlevel.
  862.   {$M 2000,0,0}
  863.   uses Dos;
  864.   begin
  865.     SwapVectors;
  866.     Exec ('r:\faq2.exe', '');  (* Execution *)
  867.     SwapVectors;
  868.     WriteLn('...back from Exec');
  869.     if DosError <> 0 then
  870.       WriteLn('Dos error #', DosError)
  871.       else
  872.       WriteLn('Success; child process errorlevel = ', lo(DosExitCode));
  873.   end.
  874. The output should be
  875.   Hello world...
  876.   ...back from Exec
  877.   Success; child process errorlevel = 14
  878. --------------------------------------------------------------------
  879.  
  880. From ts@uwasa.fi Sun Jul 23 00:01:16 1995
  881. Subject: Usenet Pascal newsgroups
  882.  
  883. 76. *****
  884.  
  885.  Q: What are the current Pascal newsgroups on the Usenet news?
  886.  
  887.  A: The following new Pascal newsgroups were created June 12, 1995
  888. to replace the old comp.lang.pascal. The following new Delphi
  889. newsgroups were created around July 10, 1995.
  890.  
  891. A special note about Delphi postings. Please use the new delphi
  892. newsgroups for the Delphi related postings. In particular, don't let
  893. the names mislead you. The newsgroup comp.lang.pascal.borland does
  894. NOT cover Delphi.
  895.  
  896. A second special note. Please avoid crossposting between the Pascal
  897. newsgroups. In particular do not crosspost between the old
  898. comp.lang.pascal and the new Pascal newsgroups. It is slows the
  899. transition to the new system. (This automatic posting breaches the
  900. non-crossposting tenet only because it is relevant information about
  901. the arrangements of all the Pascal newsgroups.)
  902.  
  903. NEW:
  904.  comp.lang.pascal.ansi-iso Pascal according to ANSI and ISO standards.
  905.  comp.lang.pascal.borland  Borland's Pascal incl. Turbo Pascal (not Delphi!)
  906.  comp.lang.pascal.mac      Macintosh based Pascals.
  907.  comp.lang.pascal.misc     Pascal in general and ungrouped Pascals.
  908.  
  909.  comp.lang.pascal.delphi.databases     Database aspects of Borland Delphi.
  910.  comp.lang.pascal.delphi.components    Writing components in Borland Delphi.
  911.  comp.lang.pascal.delphi.misc          General issues with Borland Delphi.
  912.  
  913. RELATED of potential interest:
  914. comp.os.msdos.programmer.turbovision Borland's text application libraries
  915.  
  916. OLD:
  917.  comp.lang.pascal          Discussion about Pascal. (Please cease using!)
  918.  
  919. For more information about the new Pascal newsgroups please see
  920.  
  921.  52703 Jun 14 21:37 ftp://garbo.uwasa.fi/pc/doc-net/pasgroup.zip
  922.  pasgroup.zip Information about the comp.lang.pascal.* newsgroups
  923.  
  924.  18086 Jul 11 08:18 ftp://garbo.uwasa.fi/pc/doc-net/delphi.zip
  925.  delphi.zip Vote results of the comp.lang.pascal.delphi.* newsgroups
  926.  
  927. If your site is not getting the new Pascal newsgroups, please
  928. contact your own site's newsmaster about the situation.
  929. --------------------------------------------------------------------
  930.  
  931. From ts@uwasa.fi Sun Jul 23 00:01:17 1995
  932. Subject: Capslock status and toggling
  933.  
  934. 77. *****
  935.  
  936.  Q: How do I detect the CapsLock status, how do I turn it on/off?
  937.  
  938.  A: Here are the relevant Turbo Pascal routines in answer to these
  939. questions.
  940.   {}
  941.   Uses Dos;  { The Dos unit is needed }
  942.   {}
  943.   (* Is CapsLock on *)
  944.   function CAPSONFN : boolean;
  945.   var regs      : registers;
  946.       KeyStatus : byte;
  947.   begin
  948.     FillChar (regs, SizeOf(regs), 0);
  949.     regs.ax := $0200;      { Get shift flags }
  950.     Intr ($16, regs);      { The keyboard interrupt }
  951.     KeyStatus := regs.al;  { AL = shift status bits }
  952.     if (KeyStatus and $40) > 0 then         { bit 6 }
  953.       capsonfn := true
  954.     else
  955.       capsonfn := false;
  956.   end;  (* capsonfn *)
  957.   {}
  958.   (* Set CapsLock. Use true to turn on, false to turn off *)
  959.   procedure CAPS (TurnOn : boolean);
  960.   var keyboardStatus : byte absolute $0040:$0017;
  961.       regs           : registers;
  962.   begin
  963.     if TurnOn then
  964.        keyboardStatus := keyboardStatus or $40
  965.      else
  966.        keyboardStatus := keyboardStatus and $BF;
  967.     { Interrrupt "check for keystroke" to ensure the LED status }
  968.     FillChar (regs, SizeOf(regs), 0);
  969.     regs.ah := $01;
  970.     Intr ($16, regs);
  971.   end;  (* caps *)
  972.   {}
  973. As you see, CapsLock is indicated by bit 6. The other toggles can be
  974. handled in an equivalent way using this information about the memory
  975. location Mem[$0040:$0017]:
  976.   ScrollLock = bit 4      $10  $EF
  977.   NumLock    = bit 5      $20  $DF
  978.   CapsLock   = bit 6      $40  $BF
  979. --------------------------------------------------------------------
  980.  
  981. From ts@uwasa.fi Sun Jul 23 00:01:18 1995
  982. Subject: Detecting F11 and F12
  983.  
  984. 78. *****
  985.  
  986.  Q: How do I detect if the F11 or F12 key has been pressed?
  987.  
  988.  A: Here is a sample program
  989.   uses Dos;
  990.   (* Enhanced keyboard ReadKey, no Crt unit needed. Detects also F11
  991.      and F12, and distinguishes between the numeric keypad and the
  992.      gray keys. Lower part of the word returns the first scan code,
  993.      the higher part the second *)
  994.   function RDENKEFN : word;
  995.   var regs     : registers;
  996.       keyboard : byte absolute $40:$96;
  997.   begin
  998.     rdenkefn := 0;
  999.     if ((keyboard shr 4) and 1) = 0 then exit;
  1000.     FillChar (regs, SizeOf(regs), 0);
  1001.     regs.ah := $10;
  1002.     Intr ($16, regs);
  1003.     rdenkefn := regs.ax;
  1004.   end;  (* rdenkefn *)
  1005.   {}
  1006.   procedure TEST;
  1007.   var key : word;
  1008.   begin
  1009.     while Lo(key) <> 27 do  { esc exits }
  1010.       begin
  1011.         key := RDENKEFN;
  1012.         if (Lo(key) = 0) and (Hi(key) = 133) then
  1013.           writeln ('F11 was pressed');
  1014.         if (Lo(key) = 0) and (Hi(key) = 134) then
  1015.           writeln ('F12 was pressed');
  1016.       end;
  1017.   end;
  1018.   {}
  1019.   begin TEST; end.
  1020. --------------------------------------------------------------------
  1021.  
  1022. From ts@uwasa.fi Sun Jul 23 00:01:19 1995
  1023. Subject: Substrings from a string
  1024.  
  1025. 79. *****
  1026.  
  1027.  Q: How do I extract (parse) substrings from an input string?
  1028.  
  1029.  A: Carefully study these two routines which I have included in
  1030.  19593 Jun 1 12:12 ftp://garbo.uwasa.fi/pc/research/simirr10.zip
  1031.  simirr10.zip Deriving IRR from ARR: A Simulation Testbench, TS+IV
  1032. They use space (and anything in ascii below it) as the separator.
  1033. Change the while tests if you wish to have a different set of
  1034. separators.
  1035.   (* Number of substrings in a string *)
  1036.   function PARSENFN (sj : string) : integer;
  1037.   var i, n, p : integer;
  1038.   begin
  1039.     p := Length(sj);
  1040.     n := 0;
  1041.     i := 1;
  1042.     repeat
  1043.       while (sj[i] <= #32) and (i <= p) do Inc(i);
  1044.       if i > p then begin parsenfn := n; exit; end;
  1045.       while (sj[i] > #32) and (i <= p) do Inc(i);
  1046.       Inc(n);
  1047.       if i > p then begin parsenfn := n; exit; end;
  1048.     until false;
  1049.   end;  (* parsenfn *)
  1050.   {}
  1051.   (* Get substrings from a string *)
  1052.   function PARSERFN (sj : string; PartNumber : integer) : string;
  1053.   var i, j, n, p : integer;
  1054.       stash      : string;
  1055.   begin
  1056.     if (PartNumber < 1) or (PartNumber > PARSENFN(sj)) then
  1057.       begin PARSERFN := ''; exit; end;
  1058.     p := Length(sj);
  1059.     n := 0;
  1060.     i := 1;
  1061.     repeat
  1062.       while (sj[i] <= #32) and (i <= p) do Inc(i);
  1063.       Inc(n);
  1064.       if n = PartNumber then
  1065.         begin
  1066.           j := 0;
  1067.           while (sj[i] > #32) and (i <= p) do
  1068.             begin
  1069.               Inc(j);
  1070.               stash[0] := chr(j);
  1071.               stash[j] := sj[i];
  1072.               Inc(i);
  1073.             end;
  1074.           PARSERFN := stash;
  1075.           exit;
  1076.         end
  1077.        else
  1078.          while (sj[i] > #32) and (i <= p) do Inc(i);
  1079.     until false;
  1080.   end;  (* parserfn *)
  1081.   {}
  1082.   {... A separate, but useful function from the same package ...}
  1083.   (* Delete trailing white spaces etc rubble from a string *)
  1084.   function TRAILFN (sj : string) : string;
  1085.   var i : byte;
  1086.   begin
  1087.     i := Length (sj);
  1088.     while (i > 0) and (sj[i] <= #32) do i := i - 1;
  1089.     sj[0] := chr(i); trailfn := sj;
  1090.   end;  (* trailfn *)
  1091.   {}
  1092.   {... Another separate, but useful function from the same package ...}
  1093.   (* Delete leading white spaces etc subble from a string *)
  1094.   function LEADFN (sj : string) : string;
  1095.   var i, p : byte;
  1096.   begin
  1097.     p := Length (sj); i := 1;
  1098.     while (i <= p) and (sj[i] <= #32) do i := i + 1;
  1099.     leadfn := Copy (sj, i, p-i+1);
  1100.   end;  (* leadfn *)
  1101. --------------------------------------------------------------------
  1102.  
  1103. From ts@uwasa.fi Sun Jul 23 00:01:20 1995
  1104. Subject: Size of a file
  1105.  
  1106. 80. *****
  1107.  
  1108.  Q: How do I find out the size of any kind of a file?
  1109.  
  1110.  A: Well, to begin with the FileSize keyword and an example code are
  1111. given in the manual (and help function of later TP versions) so
  1112. those, as usual, are the first places to look at. But the example
  1113. solution can be somewhat improved, and there is also an alternative
  1114. solution. The FSIZEFN should never be applied on an open file.
  1115.   function FSIZEFN (filename : string) : longint;
  1116.   var fle    : file of byte;  { declare as a file of byte }
  1117.       fmSave : byte;
  1118.   begin
  1119.     fmSave := FileMode;       { save the current filemode }
  1120.     FileMode := 0;            { to handle also read-only files }
  1121.     assign (fle, filename);
  1122.     {$I-} reset (fle); {$I+}  { to do your own error detection }
  1123.     if IOResult <> 0 then begin
  1124.       fsizefn := -1; FileMode := fmSave; exit;
  1125.     end;
  1126.     fsizefn := FileSize(fle);
  1127.     close (fle);
  1128.     FileMode := fmSave;       { restore the original filemode }
  1129.   end; (* fsizefn *)
  1130. The second, general alternative is
  1131.   uses Dos;
  1132.   function FSIZE2FN (FileName : string) : longint;
  1133.   var FileInfo : SearchRec;   { SearchRec is declared in the Dos unit }
  1134.   begin
  1135.     fsize2fn := -1;           { return -1 if anything goes wrong }
  1136.     FindFirst (filename, AnyFile, FileInfo);
  1137.     if DosError <> 0 then exit;
  1138.     if (FileInfo.Attr and VolumeId = 0) and
  1139.        (FileInfo.Attr and Directory = 0) then
  1140.          fsize2fn := FileInfo.Size;
  1141.   end;  (* fsize2fn *)
  1142. --------------------------------------------------------------------
  1143.  
  1144. From ts@uwasa.fi Sun Jul 23 00:01:21 1995
  1145. Subject: Formatting graphics output
  1146.  
  1147. 81. *****
  1148.  
  1149.  Q: How do I format graphics output like in textmode writeln?
  1150.  
  1151.  A: In the graphics mode the positioned text output procedure is
  1152. OutTextXY (X ,Y : integer; TextString : string); It does not have
  1153. the same output formatting capabilities as the write procedure. It
  1154. only accepts the one TextString. Therefore all the output formatting
  1155. must be done previously on the string. The Str procedure has such
  1156. capabilities. The example below gives the rudiments.
  1157.   uses Crt, Graph;
  1158.   var grDriver : integer;
  1159.       grMode   : integer;
  1160.       ErrCode  : integer;
  1161.       s, s1    : string;
  1162.       v1       : real;
  1163.   begin
  1164.     grDriver := Detect;
  1165.     InitGraph (grDriver, grMode, ' ');
  1166.     ErrCode := GraphResult;
  1167.     if ErrCode <> grOk then begin
  1168.       Writeln ('Graphics error:', GraphErrorMsg(ErrCode)); halt; end;
  1169.     ClearDevice;
  1170.     {}
  1171.     { Writing text in the graphics mode }
  1172.     { Set the drawing color }
  1173.     SetColor (Yellow);
  1174.     { Set the current background color }
  1175.     SetBkColor (Black);
  1176.     { Set style for text output in graphics mode }
  1177.     SetTextStyle (DefaultFont, HorizDir, 2);
  1178.     { Preprocess the text }
  1179.     v1 := 2.345;
  1180.     Str (v1 : 10:2, s1);
  1181.     s := 'The first value is' + s1 + '.';
  1182.     { Output the text }
  1183.     OutTextXY (100, 30, s);
  1184.     OutTextXY (100, 50, 'Press any key');
  1185.     {}
  1186.     repeat until KeyPressed;
  1187.     {}
  1188.     RestoreCrtMode;
  1189.     writeln ('That''s all folks');
  1190.     CloseGraph;
  1191.   end.
  1192. Besides not having the same output formatting capabilities OutTextXY
  1193. and OutText procedures do not scroll the screen. If you wish to
  1194. achieve such an effect, you will have to code it yourself step by
  1195. step. You can see the effect in
  1196.  111673 Oct 8 1993 ftp://garbo.uwasa.fi/pc/ts/tsdemo16.zip
  1197.  tsdemo16.zip Assorted graphics demonstrations of functions etc
  1198. Coding the scrolling is a straight-forward but a laborious task.
  1199. Hence it is beyond this FAQ. The outline, however, is that you must
  1200. keep track where on the screen you are. When you come to the bottom
  1201. of your window you have to move the above region upwards before you
  1202. output new text. You can move graphics regions using the ImageSize,
  1203. GetImage and PutImage procedures.
  1204.   As for readln-type input in a graphics mode, that is a complicated
  1205. issue. You will have to build the input routine reading a character
  1206. at a time with ReadKey. The rudiments of using ReadKey are shown in
  1207. the first question of FAQPAS.TXT. The demo, referred to a few lines
  1208. back, will show the effect.
  1209. --------------------------------------------------------------------
  1210.  
  1211.