home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / PASCAL / TCSEL002 / A2FAPQ.TXT next >
Text File  |  1992-09-25  |  32KB  |  637 lines

  1.         ANSWERS TO FREQUENTLY ASKED PASCAL QUESTIONS
  2.         ============================================
  3.  
  4. 1...
  5.                                                                               
  6.   Q. How do I pass an error level code when my program finishes?              
  7.                                                                               
  8.   A. The halt procedure takes an optional parameter of type word. Thus -      
  9.                                                                               
  10.          halt(1);                                                             
  11.                                                                               
  12.      terminates the program with an errorlevel of 1.  If halt is used without 
  13.      a parameter it is the same as -                                          
  14.                                                                               
  15.          halt(0);                                                             
  16.                                                                               
  17.      Note:  When a program is terminated using the halt procedure any exit    
  18.             procedure that has previously been set up is executed.            
  19.  
  20.  
  21. 2...
  22.                                                                           
  23.   Q. How do I empty the keyboard buffer?                                      
  24.                                                                               
  25.   A. There are several ways that this can be achieved.  However the safest    
  26.      is -                                                                     
  27.                                                                               
  28.         while Keypressed do ch := ReadKey;                                    
  29.                                                                               
  30.      This requires that a variable ch of type char is declared and the crt    
  31.      unit be used.  To do it without using a variable -                       
  32.                                                                               
  33.        while Keypressed do while ReadKey = #0 do;                             
  34.                                                                               
  35.      or if using TP6 with extended syntax enabled -                           
  36.                                                                               
  37.         while KeyPressed do ReadKey;                                          
  38.                                                                               
  39.      If you do not wish to incur the substantial overhead involved with the   
  40.      use of the CRT unit and there is no requirement for the program to run   
  41.      under a multi-tasker -                                                   
  42.                                                                               
  43.         var                                                                   
  44.           head : byte absolute $40:$1c;                                       
  45.           tail : byte absolute $40:$1e;                                       
  46.                                                                               
  47.         tail := head;                                                         
  48.  
  49. 3...
  50.  
  51.   Q. When I redirect the screen output of my programs to a file the file is   
  52.      empty and the output still appears on the screen. What am I doing        
  53.      wrong?                                                                   
  54.                                                                               
  55.   A. You are probably using the CRT unit and its default method of writing    
  56.      to stdout is by direct screen writes.  In order to enable output to be   
  57.      redirected all writes must be done by DOS.  Setting the variable         
  58.      DirectVideo to false has no effect on redirection as all it does is use  
  59.      the BIOS for screen writes - not DOS.                                    
  60.                                                                               
  61.      To enable redirection you must not use the CRT unit                      
  62.                                                                               
  63.      OR                                                                       
  64.                                                                               
  65.      assign(output,'');                                                       
  66.      rewrite(output);                                                         
  67.                                                                               
  68.      This will make all output go through DOS and thus can be redirected if   
  69.      desired.  To restore the default situation -                             
  70.                                                                               
  71.      AssignCRT(output); rewrite(output);                                      
  72.  
  73.  
  74. 4...
  75.  
  76.    Q. How do I make a string that is lower or mixed case all uppercase?
  77.                                                                               
  78.    A. There are several ways to convert lower case characters to upper case.  
  79.       Here are some of them.                                                  
  80.                                                                               
  81.       As a procedure (excluding asm code this is the fastest way)             
  82.                                                                               
  83.         procedure StrUpper(var st: string);                                   
  84.           var x : byte;                                                       
  85.           begin                                                               
  86.             for x := 1 to length(st) do                                       
  87.               st[x] := UpCase(st[x]);                                         
  88.           end;                                                                
  89.                                                                               
  90.       As a function (slower but sometimes more convenient) -                  
  91.                                                                               
  92.         function StrUpper(st: string): string;                                
  93.           var x : byte;                                                       
  94.           begin                                                               
  95.             StrUpper[0] := st[0];                                             
  96.             for x := 1 to length(st) do                                       
  97.               StrUpper[x] := UpCase(st[x]);                                   
  98.           end;                                                                
  99.                                                                               
  100.       Both the above are suitable for the English language .  However from    
  101.       version 4.0 onwards, DOS has had the facility to do this in a way that  
  102.       is country (language) specific.  I am indebted to Norbert Igl for the   
  103.       basic routine.  I have modified his code slightly.  For the anti-goto   
  104.       purists this is a good example of a goto that is convenient, efficient, 
  105.       self-documenting and structured.  The dos calls would make this method  
  106.       the slowest of all.                                                     
  107.                                                                               
  108.      function StrUpper(s: string): string;                                    
  109.        { Country specific string-to-uppercase conversion. Requires DOS unit } 
  110.        label                                                                  
  111.          fail;                                                                
  112.        var                                                                    
  113.          regs : registers;                                                    
  114.          x    : byte;                                                         
  115.        begin                                                                  
  116.          if lo(DosVersion) >= 4 then begin                                    
  117.            with regs do begin                                                 
  118.              ax := $6521;                                                     
  119.              ds := seg(s);                                                    
  120.              dx := ofs(s[1]);                                                 
  121.              cx := length(s);                                                 
  122.              msdos(regs);                                                     
  123.              if odd(flags) then { the attempted conversion failed so }        
  124.                goto fail;                                                     
  125.            end; { with }                                                      
  126.          end { if DOS >= 4.0 } else                                           
  127.        fail:                                                                  
  128.            for x := 1 to length(s) do                                         
  129.              s[x] := UpCase(s[x]);                                            
  130.          StrUpper := s;                                                       
  131.        end; { StrUpper }                                                      
  132.  
  133.  
  134.  
  135. 5...
  136.                                                                               
  137.    Q. When I include ANSI codes in a string and write that string to the      
  138.       screen the actual codes appear on the screen, rather than the results   
  139.       they are supposed to achieve.                                           
  140.                                                                               
  141.    A. In order for ANSI codes to be interpreted, screen writes must be        
  142.       directed through DOS and there must have been a suitable driver loaded  
  143.       via the config.sys file at boot time.  All output can be directed       
  144.       through DOS and the driver by -                                         
  145.                                                                               
  146.       Not using the crt unit                                                  
  147.                                                                               
  148.       OR -                                                                    
  149.                                                                               
  150.       assign(output,'');                                                      
  151.       rewrite(output);                                                        
  152.                                                                               
  153.       in which case ALL screen writes are "ANSI code sensitive"               
  154.                                                                               
  155.       OR -                                                                    
  156.                                                                               
  157.       You can set up write procedures that will be "ANSI code sensitive".     
  158.       (You will need an initialisation procedure to set this up.)             
  159.                                                                               
  160.       var                                                                     
  161.         ansi : text;                                                          
  162.                                                                               
  163.       procedure AssignANSI(var ansifile : text);                              
  164.         begin                                                                 
  165.           assign(ansifile,'CON');                                             
  166.           rewrite(ansifile);                                                  
  167.         end; { AssignANSI }                                                   
  168.                                                                               
  169.       procedure WriteANSI(var st: string);                                    
  170.         begin                                                                 
  171.           write(ansi,st)                                                      
  172.         end; { WriteANSI }                                                    
  173.                                                                               
  174.       procedure WriteLnANSI(var st: string);                                  
  175.         begin                                                                 
  176.           writeANSI(st);                                                      
  177.           writeln(ansi);                                                      
  178.         end; { WriteANSI }                                                    
  179.                                                                               
  180.       ObviousLy, if the ANSI.SYS driver (or an equivalent) is not installed   
  181.       none of the above can work.                                             
  182.                                                                               
  183.       Setting the variable DirectVideo in the CRT unit to false will not      
  184.       achieve the desired result as this merely turns off direct screen       
  185.       writes and uses the BIOS for all screen output.                         
  186.  
  187.  
  188. 6...
  189.                                                                               
  190.    Q. When I try to shell to DOS nothing happens. What am I doing wrong?      
  191.                                                                               
  192.    A. In order to be able to execute any child process there must be          
  193.       sufficient memory available for it to load and execute.  Unless you     
  194.       advise differently at compile time, a Turbo Pascal program grabs all    
  195.       available memory for itself when it is loaded.  To reserve memory for a 
  196.       child process use the compiler memory directive -                       
  197.                                                                               
  198.         {$M 16384,0,0)                                                        
  199.       the default is -                                                        
  200.         {$M 16384,0,655360}                                                   
  201.                                                                               
  202.       The first figure - StackMin - is the amount of memory to be allocated   
  203.       for the stack:                                                          
  204.                                                                               
  205.       Minimum is:    1024                                                     
  206.       Default is:   16384                                                     
  207.       Maximum is:   65520                                                     
  208.                                                                               
  209.       The next figure - HeapMin -is the minumum amount of memory to be        
  210.       allocated for the heap. If there is less memory available than this     
  211.       figure the program will not load.                                       
  212.                                                                               
  213.       Minimum is:          0                                                  
  214.       Default is:          0                                                  
  215.       Maximum is:     655360  In practice it will be the amount of free       
  216.                               memory less the space required for the stack,   
  217.                               less the code space of the program.  You should 
  218.                               set this to 0 unless your program uses the      
  219.                               heap.  In that case, set it to the lowest       
  220.                               possible figure to prevent heap allocation      
  221.                               errors.  In most cases it is best to leave it   
  222.                               at zero and do error checking within the        
  223.                               program for sufficient memory at allocation     
  224.                               time.                                           
  225.                                                                               
  226.       The last figure is the crucial on as regards child processes.  It       
  227.       should always be low enough to leave memory left over for a child       
  228.       process and high enough not to cause problems for the program when      
  229.       allocating heap memory.                                                 
  230.                                                                               
  231.       Minimum is:  HeapMin                                                    
  232.       Default is:  655360                                                     
  233.       Maximum is:  655360     If less than the requested amount is available  
  234.                               no error is reorted.  Instead all available     
  235.                               memory is allocated for heap use.               
  236.  
  237.  
  238.  
  239. 7...
  240.                                                                               
  241.    Q. How do I shell to DOS?                                                  
  242.                                                                               
  243.    A. SwapVectors;                                                            
  244.       exec(GetEnv('COMSPEC','');                                              
  245.       SwapVectors;                                                            
  246.                                                                               
  247.       Read previous section on memory allocation.                             
  248.                                                                               
  249.       I find that it is a good idea to write my own Exec function which will  
  250.       do everything that is needed for me.  I have it return an integer value 
  251.       that is the DosError code.                                              
  252.                                                                               
  253.       function Exec(p1,p2: string);                                           
  254.         begin                                                                 
  255.           SwapVectors;                                                        
  256.           Dos.Exec(p1,p2);                                                    
  257.           SwapVectors;                                                        
  258.           Exec := DosError;                                                   
  259.         end;                                                                  
  260.                                                                               
  261.       This enables me to have a statement such as -                           
  262.                                                                               
  263.       ReportError(Exec(GetEnv('COMPSEC'),''));                                
  264.                                                                               
  265.       Now you can have an empty ReportError procedure or you can make it      
  266.       report the error - whatever is suitable for you application.            
  267.  
  268.  
  269. 8...
  270.                                                                               
  271.    Q. When I execute a child process redirection does not work. Why?          
  272.                                                                               
  273.    A. Redirection of a child process's output only works if it is run under   
  274.       another copy of the command processor.  So -                            
  275.                                                                               
  276.       exec('YourProg.exe',' > nul');    will not work but                     
  277.       exec(GetEnv('COMSPEC'),'/c YourProg > nul'); will work.                 
  278.  
  279.  
  280. 9...
  281.  
  282.    Q. How do I read an errorlevel from a child process?
  283.  
  284.    A. After executing a child process the errorlevel returned can be read
  285.       by calling the DosExitCode function which returns a word.  The low
  286.       byte is the errorlevel.  A full description is in the manual.
  287.  
  288.       If the command interpreter is the child process and it in turn
  289.       executes a child process then the errorlevel of the second child
  290.       process cannot be read without resorting to some trickery.
  291.  
  292.  
  293. 10...
  294.  
  295.    Q. When I read a text file that has lines exceeding 255 characters I
  296.       lose all those characters from the 256th one on each time there is a
  297.       line that exceeds that length.  How can I prevent this?
  298.  
  299.    A. Turbo Pascal's readln procedure reads a line up to the 255th
  300.       character then skips to the next line.  To get around this you
  301.       should declare a buffer at least as large as the longest possible
  302.       line and then use the read procedure.  The best size for the buffer
  303.       is a multiple of 2048 bytes.
  304.  
  305.       const
  306.         BufferSize = 2048;
  307.         LineLength = 78;
  308.       type
  309.         textbuffer = array[1..BufferSize] of char;
  310.       var
  311.         st          : string;
  312.         f           : text;
  313.         buffer      : textbuffer;
  314.  
  315.       function ReadTxtLn(var tf: text; var s: string; max: byte): integer;
  316.         { Reads a string of a maximum length from a text file }
  317.         var
  318.           len         : byte absolute s;
  319.         begin
  320.           len := 0;
  321.           {$I-}
  322.           while (len < max) and not eoln(tf) do begin
  323.             inc(len);
  324.             read(tf);
  325.           end;
  326.           if eoln(tf) then
  327.             readln(tf);
  328.           ReadTxtLn := IOResult;
  329.           {$I+}
  330.         end; { ReadTxtLn }
  331.  
  332.       begin
  333.         assign(f,filename);
  334.         reset(f);
  335.         SetTextBuf(f,buffer);
  336.         while not eof(f) and (ReadTxtLn(f,st,LineLength) = 0) do
  337.           writeln(st);
  338.         close(f);
  339.       end.
  340.  
  341.  
  342. 11...
  343.  
  344.    Q. How do I convert nul terminated asciiz strings to Turbo Pascal
  345.       strings?
  346.  
  347.    A. Here is a function that will do that -
  348.  
  349.       function Asc2Str(var s; max: byte): string;
  350.         { Converts an ASCIIZ string to a Turbo Pascal string }
  351.         { with a maximum length of max.                      }
  352.         var starray  : array[1..255] of char absolute s;
  353.             len      : integer;
  354.         begin
  355.           len        := pos(#0,starray)-1;              { Get the length }
  356.           if (len > max) or (len < 0) then      { length exceeds maximum }
  357.             len      := max;                         { so set to maximum }
  358.           Asc2Str    := starray;
  359.           Asc2Str[0] := chr(len);                           { Set length }
  360.         end;  { Asc2Str }
  361.  
  362.  
  363. 12...
  364.  
  365.    Q. How can I tell if a particular bit of a variable is set or not? How can
  366.       I set it?  How can I turn it off? How can I make a large bit map and
  367.       then determine if a particular bit - say bit 10000 is on/of?
  368.  
  369.    A. This question, or a variation of it, is one of the most commonly asked
  370.       questions in the echo and there are several ways of doing what is
  371.       wanted.  None are necessarily right or wrong.  The way I will describe
  372.       is designed to take up as little code/data space as possible.  I do not
  373.       attempt to explain the theory behind these functions as this can be
  374.       obtained from any good book.
  375.  
  376.       The use of sets can be the best bit manipulation method if you have
  377.       control over the data being used. Here is an example of a byte variable
  378.       for a BBS program which sets various user access level flags.
  379.  
  380.          Bit 0 = Registered User
  381.              1 = Twit
  382.              2 = Normal
  383.              3 = Extra
  384.              4 = Privileged
  385.              5 = Visiting Sysop
  386.              6 = Assistant Sysop
  387.              7 = Sysop
  388.  
  389.        type
  390.          status_type  = (Registered,
  391.                          Twit,
  392.                          Normal,
  393.                          Extra,
  394.                          Privileged,
  395.                          VisitingSysop,
  396.                          AssistantSysop,
  397.                          Sysop);
  398.           status_level = set of status_type;
  399.  
  400.        var
  401.          access_flags  : status_level;
  402.  
  403.       Let us assume you have someone who logs on and you wish to determine
  404.       his user access level.  After reading access_flags from the user data
  405.       file -
  406.  
  407.            if Sysop in access_flags then ....
  408.  
  409.       To set the sysop flag -
  410.  
  411.            access_flags := access_flags + [Sysop];
  412.  
  413.       To reset the sysop flag -
  414.  
  415.            access_flags := access_flags - [Sysop];
  416.  
  417.       However on many occasions using a set may not be a suitable method.
  418.       You may simply need to know if bit 5 is set or not.  Here is the method
  419.       that I consider the best -
  420.  
  421.         function BitIsSet(var V,  bit: byte): boolean;
  422.           begin
  423.             BitIsSet := odd(V shr bit);
  424.           end;
  425.  
  426.       To set a bit -
  427.  
  428.          procedure SetBit(var V: byte; bit: byte);
  429.            begin
  430.              V := V or (1 shl bit);
  431.            end;
  432.  
  433.       To reset a bit -
  434.  
  435.          procedure ResetBit(var V: byte; bit: byte);
  436.            begin
  437.              V := V and not(1 shl bit);
  438.            end;
  439.  
  440.       To toggle (flip) a bit -
  441.  
  442.          procedure ToggleBit(var V: byte; bit: byte);
  443.            begin
  444.              V := V xor (1 shl bit);
  445.            end;
  446.  
  447.       Now a bit map can be made up from an array of bytes.  If stored on the
  448.       heap you can test any bit up to number 524159 (zero based).  Here's
  449.       how.
  450.  
  451.       type
  452.         map = array[0..maxsize] of byte;
  453.         { set maxsize to number of bits div 8 -1 needed in the bit map }
  454.  
  455.       function BitSetInBitMap(var x; numb : longint): boolean;
  456.         { Tests the numb bit in the bitmap array }
  457.         var m: map absolute x;
  458.         begin
  459.           BitSetInBitMap := odd(m[numb shr 3] shr (numb and 7));
  460.         end;
  461.  
  462.       procedure SetBitInBitMap(var x; numb: word);
  463.         { Sets the numb bit in the bitmap array }
  464.         var m: map absolute x;
  465.         begin
  466.           m[numb shr 3] := m[numb shr 3] or (1 shl (numb and 7))
  467.         end;
  468.  
  469.       procedure ResetBitInBitMap(var x; numb : longint);
  470.         { Resets the numb bit in the bitmap array }
  471.         var m: map absolute x;
  472.         begin
  473.          m[numb shr 3] := m[numb shr 3] and not(1 shl (numb and 7));
  474.         end;
  475.  
  476.       procedure ToggleBitInBitMap(var x; numb : longint);
  477.         { Toggles (flips) the numb bit in the bitmap array }
  478.         var m: map absolute x;
  479.         begin
  480.           m[numb shr 3] := m[numb shr 3] xor (1 shl (numb and 7));
  481.         end;
  482.  
  483.  
  484. 13...
  485.  
  486.    Q. How can I find a particular string in any file - text or binary?
  487.  
  488.    A. The Boyer-Moore string search algorithm is considered to be the fastest
  489.       method available.  However in a rare worst-case scenario it can be
  490.       slightly slower than a linear brute-force method.  The following
  491.       demonstration program will show how it works and could easily be
  492.       modified to allow for command line paramters etc.
  493.  
  494.  
  495.       program BMSearchDemo;
  496.  
  497.       type
  498.         bigarray = array[0..32767] of byte;
  499.         baptr    = ^bigarray;
  500.         BMTable  = array[0..255] of byte;
  501.  
  502.       const
  503.         KeyStr : string = 'Put whatever you want found here';
  504.         fname  : string = 'f:\Filename.txt';
  505.  
  506.       var
  507.         Btable : BMtable;
  508.         buffer : baptr;
  509.         f      : file;
  510.         result,
  511.         position : word;
  512.         offset : longint;
  513.         finished,
  514.         Strfound  : boolean;
  515.  
  516.       procedure MakeBMTable(var t : BMtable; var s);
  517.         { Makes a Boyer-Moore search table. s = the search string t = the table }
  518.         var
  519.           st  : BMtable absolute s;
  520.           slen: byte absolute s;
  521.           x   : byte;
  522.         begin
  523.           FillChar(t,sizeof(t),slen);
  524.           for x := slen downto 1 do
  525.             if (t[st[x]] = slen) then
  526.               t[st[x]] := slen - x
  527.         end;
  528.  
  529.       function BMSearch(var buff,st; size : word): word;
  530.         { Not quite a standard Boyer-Moore algorithm search routine }
  531.         { To use:  pass buff as a dereferenced pointer to the buffer}
  532.         {          st is the string being searched for              }
  533.         {          size is the size of the buffer                   }
  534.         { If st is not found, returns $ffff                         }
  535.         var
  536.           buffer : bigarray absolute buff;
  537.           s      : array[0..255] of byte absolute st;
  538.           len    : byte absolute st;
  539.           s1     : string absolute st;
  540.           s2     : string;
  541.           count,
  542.           x      : word;
  543.           found  : boolean;
  544.         begin
  545.           s2[0] := chr(len);       { sets the length to that of the search string }
  546.           found := false;
  547.           count := pred(len);
  548.           while (not found) and (count < (size - len)) do begin
  549.             if (buffer[count] = s[len]) then { there is a partial match } begin
  550.               if buffer[count-pred(len)] = s[1] then { less partial! } begin
  551.                 move(buffer[count-pred(len)],s2[1],len);
  552.                 found := s1 = s2;                   { if = it is a complete match }
  553.                 BMSearch := count - pred(len);      { will stick unless not found }
  554.               end;
  555.               inc(count);                { bump by one char - match is irrelevant }
  556.             end
  557.             else
  558.               inc(count,Btable[buffer[count]]);   { no match so increment maximum }
  559.           end;
  560.           if not found then
  561.             BMSearch := $ffff;
  562.         end;  { BMSearch }
  563.  
  564.  
  565.       begin
  566.         new(buffer);
  567.         assign(f,fname);
  568.         reset(f,1);
  569.         offset := 0;
  570.         MakeBMTable(Btable,KeyStr);
  571.         repeat
  572.           BlockRead(f,buffer^,sizeof(buffer^),result);
  573.           position := BMSearch(buffer^,KeyStr,result);
  574.           finished := (result < sizeof(buffer^)) or (position <> $ffff);
  575.           if position = $ffff then
  576.             inc(offset,result);
  577.           Strfound := position <> $ffff;
  578.         until finished;
  579.         close(f);
  580.         if Strfound then
  581.           writeln('Found at offset ',offset)
  582.         else
  583.           writeln('Not found');
  584.       end.
  585.  
  586. 14...
  587.  
  588.    Q. How can I put a apostrophe in a string?
  589.  
  590.    A. Just put in extra apostrophes.  If you want st to be equal to the
  591.       string -
  592.         The word 'quoted' is in quotes
  593.       do this -
  594.         st := 'The word ''quoted'' is in quotes';
  595.  
  596.       if you want the following to be written to screen -
  597.         'This is a quoted string'
  598.       do this -
  599.         writeln('''This is a quoted string''');
  600.  
  601.  
  602. 15...
  603.  
  604.    Q. What are the best books to purchase to help me learn Turbo Pascal?
  605.  
  606.    A. There are many good books for learners.  Here are a few -
  607.  
  608.       Complete Turbo Pascal - Third Edition - Jeff Duntemann
  609.       Mastering Turbo Pascal 6 - Tom Swann
  610.       Turbo Pascal - The Complete Reference - O'Brien.
  611.  
  612.       For advanced users there are also many good books.  Here are a few
  613.       that I have found useful - (Those marked with an asterisk are not
  614.       purely for Turbo Pascal)
  615.  
  616.       Turbo Pascal 6 - Techniques and Utilities - Rubenking
  617.       Turbo Pascal Internals - Tischer
  618.       * PC System Programming for Developers - Tischer
  619.       * Undocumented DOS - Schulman
  620.  
  621.       Any learner would be well advised to obtain a well known library
  622.       such as Technojock's Turbo Toolkit (TTT) which is shareware and
  623.       study the source code.
  624.  
  625.  
  626.  
  627.  
  628.  
  629.  
  630.  
  631.  
  632.  
  633.  
  634.  
  635.  
  636.  
  637.