home *** CD-ROM | disk | FTP | other *** search
/ Delphi Developer's Kit 1996 / Delphi Developer's Kit 1996.iso / power / list / llist.pas next >
Encoding:
Pascal/Delphi Source File  |  1995-12-22  |  9.7 KB  |  271 lines

  1. { linked list demo.
  2.   requires a filename parameter on the command line. This file is
  3.   read into a doubly linked list of records and finally output to a second
  4.   file in reverse order of lines. If a second filename is given on the
  5.   command line, this file is used for output, otherwise output is send to
  6.   the console.
  7.  
  8.   Author: Peter Below, CIS 100113,1101
  9. }
  10. Program LList;
  11. {$I-}              (* we trap I/O error by hand *)
  12.  
  13. Uses WinCRT,       (* only required if made as a Windows program *)
  14. {$IFDEF VER80}   
  15.      SysUtils;     (* for Delphi *)
  16. {$ELSE}
  17.      WinDOS;       (* for BP 7.0, use DOS if you do not compile for Windows! *)
  18. {$ENDIF}
  19. Const 
  20.   Beep = #7;
  21.  
  22. Type
  23.   PLine = ^TLine;     (* pointer to a node of the list *)
  24.   TLine = Record      (* a node of the list *)
  25.     line: String;        (* a line of text *)
  26.     next, prev: PLine;   (* links to next and previous record in the list *)
  27.   End;
  28.  
  29. Var
  30.   F: System.Text;      (* text file to work on *)
  31.   fname: String[ 80 ]; (* name of the input file *)
  32.   root: PLine;         (* pointer to first node in the list *)
  33.  
  34. {************************************************************
  35.  * Procedure AddNode
  36.  *
  37.  * Parameters:
  38.  *  root: pointer to first node in list, may be Nil, if list
  39.  *        is empty!
  40.  *  pnode: pointer to node to add to the end of the list, must
  41.  *        never be Nil!
  42.  * Description:
  43.  *  The list we handle is a double-linked list that is logically
  44.  *  closed to a ring of nodes. Thus the last node in the list is
  45.  *  the one pointed to by root^.prev, which makes addition of 
  46.  *  a new node simple without needing a search thru the list to
  47.  *  find its end first!
  48.  * Error Conditions:
  49.  *  none
  50.  *
  51.  *Created: 09/27/95 18:14:48 by P. Below
  52.  ************************************************************}
  53. Procedure AddNode( Var root: PLine; pnode: PLine ); 
  54.   Begin
  55.     If root = Nil Then Begin
  56.       (* this is the first node we add, point both its next and
  57.          prev pointer to itself and assign it to root *)
  58.       With pnode^ Do Begin
  59.         prev := pnode;
  60.         next := pnode;
  61.       End; { With }
  62.       root := pnode;
  63.     End { If }
  64.     Else Begin
  65.       (* insert the node "in front" of root. This changes four pointers
  66.          in total: *)
  67.       pnode^.next := root;       (* next node after pnode is root *)
  68.       pnode^.prev := root^.prev; (* previous node before pnode is the
  69.                                     node previously in front of root *)
  70.       pnode^.prev^.next := pnode;(* that node now has pnode as the next node *)
  71.       root^.prev := pnode;       (* and root now has pnode as the previous
  72.                                     node *)
  73.     End; { Else }
  74.   End; { AddNode }
  75.   
  76. {************************************************************
  77.  * Function ReadInputFile
  78.  *
  79.  * Parameters:
  80.  *  F: file to read from, already open
  81.  *  root: pointer to first node of the list, Nil on entry
  82.  * Returns:
  83.  *  true if no errors on read, false otherwise
  84.  * Description:
  85.  *  Reads the file line by line, creating a new node for each line.
  86.  *  The node is added to the end of the list.
  87.  * Error Conditions:
  88.  *  file errors are trapped via IOResult. In case of error the list
  89.  *  is left in its current ( incomplete ) state. If we run out of memory
  90.  *  while building the list the same happens.
  91.  *
  92.  *Created: 09/27/95 17:58:20 by P. Below
  93.  ************************************************************}
  94. Function ReadInputFile( Var F: System.Text; Var root: PLine ): Boolean;
  95.   Var
  96.     err: Integer;
  97.     pnode: PLine;
  98.   Begin
  99.     err:= IOResult;
  100.     While not Eof( F ) and ( err = 0 ) Do Begin
  101.       (* alloc a new node *)
  102.       New( pnode );
  103.       If pnode = Nil Then Begin
  104.         (* blast! out of heap memory! Yell and then exit the loop by
  105.            settin err <> 0. *)
  106.         WriteLn( Beep+'Error: out of heap memory!' );
  107.         err := -1;
  108.       End { If }
  109.       Else Begin
  110.         (* read a line of text into the node *)
  111.         ReadLn( F, pnode^.line );
  112.         err := IOresult;
  113.         If err = 0 Then
  114.           AddNode( root, pnode )   (* add node to list, if read ok *)
  115.         Else Begin
  116.           Dispose( pnode );        (* else free it again and yell *)
  117.           WriteLn( Beep+'Error: read error on input file "'+
  118.                    TTextRec( F ).Name+'"!' );
  119.         End;
  120.       End; { Else }
  121.     End; { While }
  122.     ReadInputFile := err = 0;      (* return error status *)
  123.   End; { ReadInputFile }
  124.  
  125. {************************************************************
  126.  * Procedure WriteOutputFile
  127.  *
  128.  * Parameters:
  129.  *  F: file to write the inverted list to, already open
  130.  *  root: pointer to first node of the list
  131.  * Description:
  132.  *  This procedure walks the list backwards, writing the lines
  133.  *  out to the passed file.
  134.  * Error Conditions:
  135.  *  The procedure stops of it encounters a file error. The list
  136.  *  always remains unchanged.
  137.  *
  138.  *Created: 09/27/95 18:26:32 by P. Below
  139.  ************************************************************}
  140. Procedure WriteOutputFile( Var F: System.Text; root: PLine );
  141.   Var
  142.     pWalk: PLine;
  143.   Begin
  144.     If root <> Nil Then Begin (* do nothing for an empty list! *)
  145.       pWalk := root^.prev;    (* start at last node in list *)
  146.       Repeat
  147.         WriteLn( F, pWalk^.line );  (* write a line to output file *)
  148.         pWalk := pWalk^.prev;       (* backtrack one node *)
  149.       Until ( pWalk = root^.prev ) or ( IOresult <> 0 );
  150.       If pWalk <> root^.prev Then   (* if this is true we ran into an error *)
  151.         WriteLn( Beep+'Error: write error on output file "'+
  152.                  TTextRec( F ).Name+'"!' );
  153.     End; { If }
  154.   End; { WriteOutputFile }
  155.  
  156. {************************************************************
  157.  * Function DeleteNode
  158.  *
  159.  * Parameters:
  160.  *  root: pointer to the first node of the list
  161.  *  pnode: pointer to the node to delete from the list
  162.  * Returns:
  163.  *  pnode, the pointer to the node unhooked from the list
  164.  * Description:
  165.  *  This procedure cuts the requested node from the list but
  166.  *  it does not dispose of the nodes memory. 
  167.  * Error Conditions:
  168.  *  none
  169.  *
  170.  *Created: 09/27/95 18:43:24 by P. Below
  171.  ************************************************************}
  172. Function DeleteNode( Var root: PLine; pnode: PLine ): PLine;  
  173.   Begin
  174.     DeleteNode := pnode;
  175.     (* need to modify the next pointer of the node prior to pnode
  176.        and the prev pointer of the node following pnode *)
  177.     pnode^.prev^.next := pnode^.next;
  178.     pnode^.next^.prev := pnode^.prev;
  179.     If pnode = root Then
  180.       (* special case, deleting the root will make the next node the
  181.          new root, if there is more than one node left in the list *)
  182.       If root^.next = root Then
  183.         root := Nil         (* just deleted the last node *)
  184.       Else
  185.         root := root^.next;
  186.   End; { DeleteNode }
  187.   
  188. {************************************************************
  189.  * Procedure FreeList
  190.  *
  191.  * Parameters:
  192.  *  root: pointer to the first node in the list
  193.  * Description:
  194.  *  walks the list and disposes of every record in turn. This 
  195.  *  could be done simpler than here but i take the opportunity to
  196.  *  show how to delete a node from the list.
  197.  * Error Conditions:
  198.  *  none
  199.  *  The simple solution would be:
  200.  *  While root^.next <> root Do Begin
  201.  *    temp := root^.next;
  202.  *    root^.next := temp^.next;
  203.  *    Dispose( temp );
  204.  *  End;
  205.  *  Dispose( root );
  206.  *Created: 09/27/95 18:34:26 by P. Below
  207.  ************************************************************}
  208. Procedure FreeList( Var root: PLine ); 
  209.   Var
  210.     temp: PLine;
  211.   Begin
  212.     While root <> Nil Do Begin
  213.       temp := DeleteNode( root, root^.next );
  214.       Dispose( temp );
  215.     End; { While }
  216.   End; { FreeList }
  217.  
  218.  
  219. Function HeapErrorHandler( size: Word ): Integer; far;
  220.   Begin
  221.      HeapErrorHandler := 1;  (* return Nil from New/GetMem *)
  222.   End;
  223.  
  224. Begin
  225.   (* assign a new heap error handler so we do not get a run-time error
  226.      when New fails while building the list *)
  227.   HeapError := @HeapErrorHandler;
  228.  
  229.   (* set wincrt virtual window to max size, delete this line if this is
  230.      not compiled as a windows app! *)
  231.   ScreenSize.Y := $FFFF div Screensize.X;
  232.  
  233.   (* try to find the input file and open it *)
  234.   If ParamCount = 0 Then
  235.     WriteLn( Beep+'Error: filename required on command line!' )
  236.   Else Begin
  237.     fname := ParamStr( 1 );      (* get filename *)
  238.     System.Assign( F, fname );   (* assign to file *)
  239.     Reset( F );                  (* try to open file *)
  240.     If IOResult <> 0 Then
  241.       WriteLn( Beep+'Error: input file "'+fname+'" not found!' )
  242.     Else Begin                   (* open succeded, read file into list *)
  243.       root := nil;               (* start with no list node *)
  244.       If ReadInputFile( F, root ) Then Begin
  245.         System.Close( F );       (* read done, close input file *)
  246.         If IOresult=0 Then;                (* reset ioresult *)
  247.         If ParamCOunt > 1 Then Begin
  248.           fname := ParamStr( 2 ); (* look for a name for the output file *)
  249.           Assign( F, fname );
  250.           Rewrite( F );           (* try to open it *)
  251.           If IOResult <> 0 Then Begin
  252.             WriteLn( Beep+'Error: could not open output file "'+fname+'"!' );
  253.             WriteOutputFile( output, root );  (* failed, use stdout *)
  254.           End { If }
  255.           Else Begin
  256.             WriteOutputFile( F, root );  (* else use F *)
  257.             System.Close( F );           (* close it *)
  258.             If IOResult=0 Then;
  259.           End
  260.         End { If }
  261.         Else
  262.           WriteOutputFile( output, root ); (* no filename, use stdout *)
  263.       End
  264.       Else
  265.         System.Close( F );   (* close input file on error *)
  266.       FreeList( root );      (* release memory for the list *)
  267.     End; { Else }
  268.   End; { Else }
  269. End.
  270.  
  271.