home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / TRAVER.ZIP / TRAVERSE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-09-04  |  41.7 KB  |  1,256 lines

  1. PROGRAM TRAVERSE;
  2.  
  3. {$B-,D+,R-,S-,T+,V-}
  4. {$DEFINE nSelfConfigure}               { Set to "SelfConfigure" to make   }
  5.                                        { self-configuring EXE file        }
  6. USES Crt, Dos;
  7.  
  8. {  ┌────────────────────────────────────────────────────┐
  9.    │ Define data types                                  │
  10.    └────────────────────────────────────────────────────┘
  11. }
  12.  
  13. TYPE
  14.  
  15.   Fptr      = ^Dir_Rec;
  16.  
  17.   Dir_Rec   = RECORD                   { Dble ptr. record for dir. entries }
  18.                 DirChr  : char;
  19.                 DirName : string[12];
  20.                 Next    : Fptr;
  21.                 Prev    : Fptr;
  22.               END;
  23.  
  24.   str_type  = string[12];
  25.  
  26.   panel     = array [1..4000] of byte;           { For saving screen image }
  27.  
  28.   DriveList = 'A'..'Z';
  29.  
  30.   ConfigType =
  31.     RECORD
  32.       Cnt_CurFlag : boolean;
  33.       LoopDirFlag : boolean;
  34.       AutoSize    : boolean;
  35.       Row_BEGIN   : integer;          { Absolute screen Row/Col for        }
  36.       Col_BEGIN   : integer;          { Location of Upper Left Corner      }
  37.                                       { of dir. selection window           }
  38.                                       { Absolute screen Col for            }
  39.       Act_Attr    : integer;          { Active (highlighted) dir. vid attr }
  40.       IAct_Attr   : integer;          { Inactive dir. video attribute      }
  41.       Wndw_Bdr    : integer;          { Dir. selection window border type  }
  42.     END;
  43.  
  44. {
  45.    ┌────────────────────────────────────────────────────┐
  46.    │ Define Global Constants                            │
  47.    └────────────────────────────────────────────────────┘
  48. }
  49.  
  50. CONST
  51.   NL   = #13#10;
  52.   Bell = #7;
  53.  
  54.   Alphabet : string[26]
  55.            = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';       { Set up alphabet string    }
  56.  
  57.   Config   : ConfigType
  58.             = (Cnt_CurFlag : False;              { Don't cnt current dir.    }
  59.                LoopDirFlag : False;              { No looping is default     }
  60.                AutoSize    : True;               { Flag re autosizing wndw   }
  61.                Row_BEGIN   : 5;                  { Row to place window       }
  62.                Col_BEGIN   : 22;                 { Col to place window       }
  63.                Act_Attr    : 112;                { Normal color of window    }
  64.                IAct_Attr   : 31;                 { Highlight color           }
  65.                Wndw_Bdr    : 1);                 { Deflt border = sngle line }
  66.                                                  { Border types are:
  67.                                                      0  = No Border
  68.                                                      1  = Single line
  69.                                                      2  = Double Line        }
  70.  
  71.  
  72. {
  73.    ┌────────────────────────────────────────────────────┐
  74.    │ Define Global Variables                            │
  75.    └────────────────────────────────────────────────────┘
  76. }
  77.  
  78. VAR
  79.   LoopDirs    : boolean;              { Looping flag                       }
  80.   Cnt_Cur     : boolean;              { Flag for cnt'g curr. dir. or not   }
  81.   DirName     : str_type;             { Found directory name               }
  82.   Dir_Ptr     : Fptr;                 { Ptr. to directory name list        }
  83.   Num_Dirs    : integer;              { Total # of dirs. found             }
  84.  
  85.   Cur_Dir     : string[65];           { Current directory                  }
  86.   Orig_Dir    : string[65];           { Dir. you started in                }
  87.   Drive       : DriveList;            { Contains drive designation         }
  88.   To_A_Drv    : Boolean;              { Shows direction of drive changes   }
  89.  
  90.   ColBEGIN    : integer;
  91.   Row_Quan    : integer;              { Number of rows                     }
  92.   Col_Quan    : integer;              { Number of cols                     }
  93.  
  94.   Save_Attr   : integer;              { Save current text attribute        }
  95.  
  96.   Col_Max     : integer;              { Max Col to put dir. name at        }
  97.   Row_Max     : integer;              { Max Row to put dir. name at        }
  98.   Cur_Col     : integer;              { Current column                     }
  99.   Cur_Row     : integer;              { Current Row                        }
  100.   Row_Beg     : integer;              { Beginning row of window            }
  101.   Col_Beg     : integer;              { Beginning col of window            }
  102.  
  103.   Save_WMin   : word;                 { Save area for WindMin & WindMax    }
  104.   Save_WMax   : word;
  105.   Save_X      : integer;              { Cursor x,y save area               }
  106.   Save_Y      : integer;
  107.  
  108.   OrigMode    : byte;                        { Original video mode         }
  109.   Vidcolor    : panel absolute $B800:0000;   { Storage for color video mem }
  110.   Vidmono     : panel absolute $B000:0000;   { Storage for b/w video mem   }
  111.   Screen      : panel;
  112.  
  113.   HeapPtr     : pointer;              { Pointer to heap for mark/release   }
  114.   ExitSave    : pointer;              { Pointer for exit procedure         }
  115.  
  116. {
  117.  ┌────────────────────────────────────────────────────┐
  118.  │ BEGIN TRAVERSE Procedures                          │
  119.  └────────────────────────────────────────────────────┘
  120. }
  121.  
  122. {
  123.    ┌────────────────────────────────────────────────────┐
  124.    │ PROCEDURE Usage                                    │
  125.    └────────────────────────────────────────────────────┘
  126. }
  127.  
  128. PROCEDURE Usage;
  129.  
  130. VAR
  131.   Ch : char;
  132.  
  133. BEGIN
  134.   WRITELN (Bell,
  135. 'A directory tree traverser.  If only one child directory exists, then',NL,
  136. 'TRAVERSE automatically changes to that subdirectory.  If you are at the',NL,
  137. '"bottom" level of a directory tree, TRAVERSE will automatically "bounce"',NL,
  138. 'you up to the parent directory level.  Otherwise, TRAVERSE gives you a 1',NL,
  139. 'character choice (A-Z) to change to one of up to 26 displayed',NL,
  140. 'subdirectories.  You can also use the arrow keys to traverse the displayed',NL,
  141. 'list, then press ENTER.  ESC drops you back in the directory you started',NL,
  142. 'from; / or \ take you to the root directory; PgUp takes your to the',NL,
  143. 'PREVIOUS DRIVE, and PgDn takes you to the NEXT DRIVE.  ',NL,
  144. '',NL,
  145. 'USAGE:     TRAVERSE {U} {D} {O} {L} {N} {X}',NL,
  146. 'U -- UP: Immediately moves up one level.',NL,
  147. 'D -- DOWN: Immediately moves down one level if only one subdirectory',NL,
  148. '     exists, otherwise displays directory list.',NL,
  149. 'O -- OVER: Immediately moves up one level AND displays directory list',NL,
  150. '     (useful to move Over to a sibling directory).',NL,
  151. 'L -- LOOP: Loops through the program, displaying each list of directories',NL,
  152. '     until you hit either (1) the RETURN key while highlighting a directory',NL,
  153. '     entry, or (2) select the current directory (.) while in a sub-',NL,
  154. '     directory, or (3) press ESC.  / or \ takes you to the root directory',NL,
  155. 'N -- NO LOOPING: used when configured to loop as the default. ',NL,
  156. 'X -- XCHANGE: self-configuration, to select colors, options.',NL,
  157. '                      (press any key to continue)');
  158.   Ch := Readkey;
  159.   Halt;
  160. END;
  161.  
  162.  
  163. {
  164.    ┌────────────────────────────────────────────────────┐
  165.    │ PROCEDURE Beepit                                   │
  166.    └────────────────────────────────────────────────────┘
  167. }
  168.  
  169. PROCEDURE Beepit (Tone : integer; Duration : integer);
  170.  
  171. BEGIN
  172.   SOUND (Tone);                                         { Beep the speaker }
  173.   DELAY (Duration);
  174.   NOSOUND;
  175. END;
  176.  
  177. {
  178.    ┌────────────────────────────────────────────────────┐
  179.    │ FUNCTION VideoMode                                 │
  180.    └────────────────────────────────────────────────────┘
  181. }
  182.  
  183. FUNCTION VideoMode : Byte;
  184.  
  185. VAR
  186.   reg        : registers;
  187.  
  188. BEGIN
  189.   reg.ah     := 15;                                 { Determine video type }
  190.   INTR ($10,reg);                                   { by polling BIOS int. }
  191.   VideoMode  := reg.al;                             { 10                   }
  192. END;
  193.  
  194. {
  195.    ┌────────────────────────────────────────────────────┐
  196.    │ FUNCTION ISColor                                   │
  197.    └────────────────────────────────────────────────────┘
  198. }
  199.  
  200. FUNCTION ISColor : Boolean;
  201.   BEGIN;
  202.     IF VideoMode = 7 THEN
  203.       ISColor  := False
  204.     ELSE
  205.       ISColor  := True;
  206.   END;
  207.  
  208. {
  209.    ┌────────────────────────────────────────────────────┐
  210.    │ PROCEDURE Highlight                                │
  211.    └────────────────────────────────────────────────────┘
  212. }
  213.  
  214. PROCEDURE Highlight (ptr : Fptr);
  215.  
  216. BEGIN
  217.   TextAttr := Config.Act_Attr;                  { Highlight a dir. name    }
  218.   GOTOXY (Cur_Col,Cur_Row);
  219.   WRITE ('',ptr^.DirChr,' ',ptr^.DirName,'');
  220.   TextAttr := Config.IAct_Attr;
  221. END;
  222.  
  223. {
  224.    ┌────────────────────────────────────────────────────┐
  225.    │ PROCEDURE Un_Highlight                             │
  226.    └────────────────────────────────────────────────────┘
  227. }
  228.  
  229. PROCEDURE Un_Highlight (ptr : Fptr);
  230.  
  231. BEGIN
  232.   TextAttr := Config.IAct_Attr;                 { Un─Highlight a dir. name }
  233.   GOTOXY (Cur_Col,Cur_Row);
  234.   WRITE (' ',ptr^.DirChr,' ',ptr^.DirName,' ');
  235. END;
  236.  
  237. {
  238.    ┌────────────────────────────────────────────────────┐
  239.    │ PROCEDURE Save_Screen                              │
  240.    └────────────────────────────────────────────────────┘
  241. }
  242.  
  243. PROCEDURE Save_Screen;
  244.  
  245. BEGIN
  246.   Save_X    := WhereX;                           { Save current cursor     }
  247.   Save_Y    := WhereY;                           { x,y coordinates         }
  248.   Save_WMin := WindMin;                          { Save the current window }
  249.   Save_WMax := WindMax;                          { min/max coordinates     }
  250.   Save_Attr := TextAttr;
  251.  
  252.   IF (ISColor) THEN                              { Move screen image to    }
  253.     Screen  := Vidcolor                          { storage depending on    }
  254.   ELSE                                           { video card type         }
  255.     Screen  := Vidmono;
  256. END;
  257.  
  258. {
  259.    ┌────────────────────────────────────────────────────┐
  260.    │ PROCEDURE Restore_Screen                           │
  261.    └────────────────────────────────────────────────────┘
  262. }
  263.  
  264. PROCEDURE Restore_Screen;
  265.  
  266. BEGIN
  267.   IF (ISColor) THEN                              { Restore original screen }
  268.     Vidcolor := Screen                           { image                   }
  269.   ELSE
  270.     Vidmono  := Screen;
  271.  
  272.   TextAttr   := Save_Attr;
  273.  
  274.   WINDOW (LO(Save_WMin)+1,HI(Save_WMin)+1,
  275.           LO(Save_WMax)+1,HI(Save_WMax)+1);
  276.                                                  { Restore original window }
  277.   GOTOXY (Save_X,Save_Y);                        { min/max coord.'s & cur. }
  278.  
  279. END;
  280.  
  281. {
  282.    ┌────────────────────────────────────────────────────┐
  283.    │ PROCEDURE Cursor                                   │
  284.    └────────────────────────────────────────────────────┘
  285. }
  286.  
  287. PROCEDURE Cursor (Cur_Off : Boolean);
  288.  
  289. VAR
  290.   reg  : registers;
  291.  
  292. BEGIN
  293.   IF (NOT Cur_Off) THEN
  294.     BEGIN                                                { Turn cursor off }
  295.       reg.ah := 1;
  296.       reg.cl := 7;
  297.       reg.ch := 32;
  298.       INTR ($10,reg);
  299.     END
  300.   ELSE
  301.     BEGIN                                                { Turn cursor on  }
  302.       INTR ($11,reg);
  303.       IF ((reg.al AND $10) <> 0) THEN
  304.         reg.cx := $0B0C
  305.       ELSE
  306.         reg.cx := $0607;
  307.       reg.ah := 1;
  308.       INTR ($10,reg);
  309.     END;
  310. END;
  311.  
  312. {
  313.    ┌────────────────────────────────────────────────────┐
  314.    │ PROCEDURE Draw_Border                              │
  315.    └────────────────────────────────────────────────────┘
  316. }
  317.  
  318. PROCEDURE Draw_Border;
  319.  
  320. VAR
  321.   TLC, TRC   : char;
  322.   BLC, BRC   : char;
  323.   HLINE      : char;
  324.   VLINE      : char;
  325.   TLFT, TRHT : char;
  326.   i          : integer;
  327.  
  328. BEGIN
  329.   CASE (Config.Wndw_Bdr) OF                     { Define border elements   }
  330.                                                 { based on global Wndw_Bdr }
  331.     1  :  BEGIN
  332.             TRC   := '┐';
  333.             BRC   := '┘';
  334.             TLC   := '┌';
  335.             BLC   := '└';
  336.             HLINE := '─';
  337.             VLINE := '│';
  338.             TLFT  := '┤';
  339.             TRHT  := '├';
  340.           END;
  341.  
  342.     2  :  BEGIN
  343.             TRC   := '╗';
  344.             BRC   := '╝';
  345.             TLC   := '╔';
  346.             BLC   := '╚';
  347.             HLINE := '═';
  348.             VLINE := '║';
  349.             TLFT  := '╡';
  350.             TRHT  := '╞';
  351.           END;
  352.  
  353.   END; {case}
  354.  
  355.   GOTOXY (1,1);                                 { Start to draw the border }
  356.  
  357.   WRITE (TLC);                                  { Top line with corners    }
  358.   FOR i := 1 to (Col_Quan*16 + 2) DO WRITE (HLINE);
  359.   WRITE (TRC);
  360.  
  361.   FOR i := 2 to Row_Quan - 1 DO                 { Vertical lines           }
  362.     BEGIN
  363.       GOTOXY (1,i);
  364.       WRITE (VLINE);
  365.       GOTOXY ((Col_Quan*16 + 4),i);
  366.       WRITE (VLINE);
  367.     END;
  368.  
  369.   GOTOXY (1,Row_Quan);                          { Bottom line with corners }
  370.   WRITE (BLC);
  371.   FOR i:=1 to (Col_Quan*16 + 2) DO WRITE (HLINE);
  372.   WRITE (BRC);                                  { End draw of border       }
  373.  
  374.   IF ((LENGTH (Cur_Dir) + 2) < (Col_Quan*16 + 1)) THEN
  375.     BEGIN
  376.       GOTOXY (2,1);                             { If dir. name fits,       }
  377.       WRITE (TLFT,' ',Cur_Dir,' ',TRHT);        { insert it in the top row }
  378.     END;
  379. END;
  380.  
  381. {
  382.    ┌────────────────────────────────────────────────────┐
  383.    │ PROCEDURE WindowX                                  │
  384.    └────────────────────────────────────────────────────┘
  385. }
  386.  
  387. PROCEDURE WindowX;
  388.  
  389. VAR
  390.   x1,y1,x2,y2 : byte;
  391.  
  392. BEGIN
  393.   TextAttr := Config.IAct_Attr;               { Define text color          }
  394.  
  395.   x1 := ColBEGIN;                             { Define dirs. window        }
  396.   y1 := Config.Row_BEGIN;
  397.   x2 := ColBEGIN + (Col_Quan * 16) + 3;       { Width = 20 or 36 cols.     }
  398.   y2 := Config.Row_BEGIN + Row_Quan;
  399.   WINDOW (x1,y1,x2,y2);                       { Activate the window        }
  400.   ClrScr;                                     { Clear window               }
  401.  
  402.   IF (Config.Wndw_Bdr <> 0) THEN
  403.     BEGIN
  404.       Draw_Border;                            { Draw the window border     }
  405.       INC (x1);                               { Redefine window so don't   }
  406.       INC (y1);                               { scroll the border if there }
  407.       DEC (x2);                               { is one.                    }
  408.       DEC (y2,2);                             { Wndw 2 rows < than border  }
  409.       WINDOW (x1,y1,x2,y2);                   { Activate new window        }
  410.       ClrScr;                                 { Clear window               }
  411.     END;
  412. END;
  413.  
  414. {
  415.    ┌────────────────────────────────────────────────────┐
  416.    │ PROCEDURE SizeWindow                               │
  417.    └────────────────────────────────────────────────────┘
  418. }
  419.  
  420. PROCEDURE SizeWindow;
  421.  
  422. BEGIN
  423.   IF (Num_Dirs < 14) AND (NOT LoopDirs) THEN
  424.     BEGIN                                      { Calc. small window size   }
  425.       Row_Quan  := Num_Dirs + 2;
  426.       Col_Quan  := 1;
  427.       ColBEGIN  := Config.Col_BEGIN + 8;       { Col to place window       }
  428.     END
  429.   ELSE
  430.     BEGIN                                      { Calc. large window size   }
  431.       IF (Num_Dirs > 26) OR (LoopDirs) OR (NOT Config.AutoSize) THEN
  432.         Row_Quan := 13 + 2                     { 1/2 dir. entries + 2 for  }
  433.       ELSE                                     { border                    }
  434.         Row_Quan := (((Num_Dirs+1) DIV 2)+2);  { Balance dirs. betw 2 cols }
  435.  
  436.       Col_Quan := 2;
  437.       ColBEGIN := Config.Col_BEGIN;             { Col to place window       }
  438.     END;
  439. END;
  440.  
  441. {
  442.    ┌────────────────────────────────────────────────────┐
  443.    │ FUNCTION Get_Dirs                                  │
  444.    └────────────────────────────────────────────────────┘
  445. }
  446.  
  447. FUNCTION Get_Dirs (VAR First : Fptr) : integer;
  448.  
  449. VAR
  450.   p1, p2   : Fptr;
  451.   numdirs  : integer;
  452.   DirInfo  : SearchRec;
  453.   Placed   : boolean;
  454.   FirstDir : boolean;
  455.  
  456. BEGIN
  457.   Get_Dirs := 0;
  458.   numdirs  := 0;
  459.   FirstDir := True;
  460.   First    := nil;
  461.  
  462.   FindFirst ('*.*',Directory,DirInfo);       { Find 1st matching file/dir. }
  463.  
  464.   IF DosError = 0 THEN                       { If found file/dir., cont.   }
  465.     BEGIN
  466.       IF (DirInfo.name = '.') AND (Cnt_Cur = False) THEN FindNext (DirInfo);
  467.  
  468.       WHILE DosError = 0 DO
  469.         BEGIN
  470.           IF (DirInfo.attr = Directory) THEN
  471.             BEGIN                            { If there are more, continue }
  472.               INC (numdirs);                 { Incr. number dirs. counter  }
  473.               NEW (p1);                      { Allocate new pointer        }
  474.               p1^.DirName := DirInfo.name;               { Copy dir. name  }
  475.  
  476.               IF FirstDir = True THEN
  477.                 BEGIN
  478.                   First    := p1;
  479.                   p1^.Prev := nil;
  480.                   p1^.Next := nil;
  481.                   FirstDir := False;
  482.                 END
  483.               ELSE
  484.                 BEGIN
  485.                   IF (p1^.DirName < First^.DirName) THEN { Sort dir. names }
  486.                     BEGIN
  487.                       p1^.Next    := First;
  488.                       p1^.Prev    := nil;
  489.                       First^.Prev := p1;
  490.                       First       := p1;
  491.                     END
  492.                   ELSE
  493.                     BEGIN
  494.                       p2     := First;
  495.                       Placed := False;
  496.                       WHILE ((p2^.Next <> nil) AND (Placed = False)) DO
  497.                         BEGIN
  498.                           IF (p1^.DirName >= p2^.Next^.DirName) THEN
  499.                             p2 := p2^.Next
  500.                           ELSE
  501.                            Placed := True;
  502.                         END;
  503.                       p1^.Next := p2^.Next;
  504.                       p1^.Prev := p2;
  505.                       p2^.Next^.Prev := p1;
  506.                       p2^.Next := p1;
  507.                     END;
  508.                 END;
  509.             END;                                        { End sort       }
  510.  
  511.           FindNext (DirInfo);              { Find next matching dir.     }
  512.  
  513.         END;
  514.  
  515.       IF LENGTH (Cur_Dir) = 3 THEN         { If at root, add record      }
  516.         BEGIN
  517.           NEW (p1);
  518.           p1^.DirName := '>ROOT';          { Copy in dir.name            }
  519.           p1^.Prev    := nil;              { Set up prev pointer         }
  520.  
  521.           IF First <> nil THEN
  522.             BEGIN
  523.               p1^.Next    := First;
  524.               First^.Prev := p1;
  525.             END
  526.           ELSE
  527.             p1^.Next    := nil;
  528.  
  529.           First       := p1;
  530.           INC (numdirs);
  531.         END;
  532.  
  533.       Get_Dirs := numdirs;                 { Return num. of dirs. found  }
  534.     END;
  535. END;
  536.  
  537. {
  538.    ┌────────────────────────────────────────────────────┐
  539.    │ PROCEDURE Put_Dirs                                 │
  540.    └────────────────────────────────────────────────────┘
  541. }
  542.  
  543. PROCEDURE Put_Dirs (var_ptr : Fptr; Maxdirs : integer);
  544.  
  545. VAR
  546.   i,irow,icol : integer;
  547.  
  548. BEGIN                                           { Put the dirs. found into }
  549.   irow := Row_Beg;                              { the dirs. window by      }
  550.   icol := Col_Beg;                              { traversing the dir. ptr  }
  551.                                                 { linked list              }
  552.   FOR i := 1 to Maxdirs DO
  553.     BEGIN
  554.       GOTOXY (icol,irow);
  555.       var_ptr^.DirChr := Alphabet[i];
  556.       WRITE (' ',var_ptr^.DirChr,' ',var_ptr^.DirName,' ');
  557.       INC (irow);
  558.       IF (irow > Row_Max) THEN
  559.         BEGIN
  560.           irow := Row_Beg;
  561.           icol := Col_Beg + 16;
  562.         END;
  563.       IF (var_ptr^.Next <> nil) THEN
  564.         var_ptr := var_ptr^.Next
  565.       ELSE
  566.         i := Maxdirs;
  567.     END;
  568. END;
  569.  
  570. {
  571.    ┌────────────────────────────────────────────────────┐
  572.    │ FUNCTION Srch_Dir                                  │
  573.    └────────────────────────────────────────────────────┘
  574. }
  575.  
  576. FUNCTION Srch_Dir (var_ptr : Fptr; var_str : char) : Fptr;
  577.  
  578. VAR
  579.   Found      :  boolean;
  580.   var_str2   :  char;
  581.  
  582. BEGIN
  583.   Found    := False;
  584.   Srch_Dir := nil;
  585.  
  586.   WHILE ((var_ptr <> nil) AND (NOT Found)) DO       { Search list for list }
  587.     BEGIN                                           { entry that matches   }
  588.       var_str2 := var_ptr^.DirChr;                  { keyboard entry       }
  589.       IF var_str = var_str2 THEN
  590.         BEGIN
  591.           Srch_Dir := var_ptr;
  592.           Found    := True;
  593.         END
  594.       ELSE
  595.         var_ptr := var_ptr^.Next;
  596.         IF (var_ptr = nil) THEN
  597.           BEGIN
  598.             Srch_Dir := nil;                    { If key entry not on list }
  599.             Beepit (760, 80);                   { set Srch_Dir to nil &    }
  600.             Found    := True;                   { beep                     }
  601.           END;
  602.      END;
  603. END;
  604.  
  605. {
  606.    ┌────────────────────────────────────────────────────┐
  607.    │ FUNCTION Next_Dir                                  │
  608.    └────────────────────────────────────────────────────┘
  609. }
  610.  
  611. FUNCTION Next_Dir (var_ptr : Fptr; count : integer) : Fptr;
  612.  
  613. VAR
  614.   i    : integer;
  615.  
  616. BEGIN
  617.   IF (var_ptr^.Next <> nil) THEN                { Move up one dir.         }
  618.     BEGIN                                       { Is there a next dir.?    }
  619.       Un_Highlight(var_ptr);                    { Unhighlight current dir. }
  620.       FOR i := 1 to count DO                    { Traverse dir. list while }
  621.         BEGIN                                   { updating the current row }
  622.           IF (var_ptr^.Next <> nil) THEN        { and col location         }
  623.             BEGIN
  624.               var_ptr := var_ptr^.Next;
  625.               INC (Cur_row);
  626.               IF (Cur_row > Row_Max) THEN
  627.                 BEGIN
  628.                   Cur_Row := Row_Beg;
  629.                   INC (Cur_Col,16);
  630.                   IF (Cur_Col > Col_Max) THEN   { If off edge, stay put,   }
  631.                     BEGIN                       { beep, and stop           }
  632.                       var_ptr := var_ptr^.Prev;
  633.                       Cur_Col := Col_Beg - 16;
  634.                       Beepit (760, 80);
  635.                       i := count;
  636.                     END;
  637.                 END;
  638.             END
  639.          ELSE
  640.             i := count;
  641.         END;
  642.  
  643.       Highlight(var_ptr);                        { All done, highlight     }
  644.     END                                          { new current dir. name   }
  645.   ELSE
  646.     Beepit (760, 80);
  647.     Next_Dir := var_ptr;
  648. END;
  649.  
  650. {
  651.    ┌────────────────────────────────────────────────────┐
  652.    │ FUNCTION Prev_Dir                                  │
  653.    └────────────────────────────────────────────────────┘
  654. }
  655.  
  656. FUNCTION Prev_Dir (var_ptr : Fptr; count : integer) : Fptr;
  657.  
  658. VAR
  659.   i    : integer;
  660.  
  661. BEGIN
  662.   IF (var_ptr^.Prev <> nil) THEN                { Back up one dir.         }
  663.     BEGIN                                       { Is there a prev dir.?    }
  664.       Un_Highlight(var_ptr);                    { Unhighlight current dir. }
  665.       FOR i := 1 to count DO                    { Traverse dir. list while }
  666.         BEGIN                                   { updating the current row }
  667.           IF (var_ptr^.Prev <> nil) THEN        { and col location         }
  668.             BEGIN
  669.               var_ptr := var_ptr^.Prev;
  670.               DEC (Cur_Row);
  671.               IF (Cur_Row < Row_Beg) THEN
  672.                 BEGIN
  673.                   Cur_Row := Row_Max;
  674.                   DEC (Cur_Col,16);
  675.                   IF (Cur_Col < Col_Beg) THEN
  676.                     BEGIN
  677.                       var_ptr := var_ptr^.Next; { If off edge, stay put,   }
  678.                       Cur_Col := Col_Beg + 16;  { beep, and stop           }
  679.                       Beepit (760, 80);
  680.                       i := count;
  681.                     END;
  682.                 END;
  683.             END
  684.           ELSE
  685.             i := count;
  686.         END;
  687.  
  688.       Highlight(var_ptr);                       { All done, highlight      }
  689.     END                                         { new current dir. name    }
  690.   ELSE
  691.     Beepit (760, 80);
  692.     Prev_Dir := var_ptr;
  693. END;
  694.  
  695. {
  696.    ┌────────────────────────────────────────────────────┐
  697.    │ PROCEDURE Sel_Dir                                  │
  698.    └────────────────────────────────────────────────────┘
  699. }
  700.  
  701. PROCEDURE Sel_Dir (VAR Dir_Name : str_type;
  702.                    NumDirs : integer; var_ptr : Fptr;
  703.                    VAR To_A_Drv : Boolean);
  704.  
  705. VAR
  706.   ptr1, ptr2  : Fptr;
  707.   Max_Scrn    : integer;
  708.   Ch          : char;
  709.   done        : boolean;
  710.  
  711. BEGIN
  712.   Dir_Name  := '';                         { Init. Dir_Name                }
  713.   To_A_Drv  := False;                      { Init. direction of drv changes}
  714.  
  715.   IF (NumDirs <> 0) THEN                   { Proceed if dirs. found        }
  716.     BEGIN
  717.       ptr1 := var_ptr;
  718.  
  719.       Col_Beg := 2;                        { Define some window limits     }
  720.       Row_Beg := 1;
  721.       Col_Max := (Col_Beg + ((Col_Quan - 1) * 16));
  722.  
  723.       IF (Config.Wndw_Bdr = 0) THEN        { Compute Max rows of dirs.     }
  724.         Row_Max := Row_Quan
  725.       ELSE
  726.         Row_Max := Row_Quan - 2;
  727.  
  728.       Max_Scrn := Col_Quan * Row_Max;      { Compute Max dirs. w/in window }
  729.       IF (Max_Scrn > NumDirs) THEN Max_Scrn := NumDirs;
  730.  
  731.       WindowX;                             { Draw the dirs. window         }
  732.  
  733.       Put_Dirs (ptr1, Max_Scrn);           { Fill window w/ avail dirs.    }
  734.  
  735.       Cur_Row := Row_Beg;                  { Initialize cur row/col        }
  736.       Cur_Col := Col_Beg;
  737.       Highlight (ptr1);                    { Highlight first dir.          }
  738.  
  739.       Done := False;                       { Continue till user selects a  }
  740.       WHILE (Done = False) DO              { dir. or quits                 }
  741.         BEGIN
  742.           Ch := ReadKey;
  743.           IF (Ch = #0) THEN
  744.             BEGIN
  745.               Ch := ReadKey;
  746.               CASE Ch OF
  747.                 #75 : ptr1 := Prev_Dir(ptr1,13);      { Left Arrow         }
  748.                 #77 : ptr1 := Next_Dir(ptr1,13);      { Right Arrow        }
  749.                 #72 : ptr1 := Prev_Dir(ptr1,1);       { Up Arrow           }
  750.                 #80 : ptr1 := Next_Dir(ptr1,1);       { Down Arrow         }
  751.  
  752.                 #73: BEGIN
  753.                        Drive    := PRED (Drive);      { If PgUp, go to     }
  754.                        Dir_Name := Drive + ':\';      { prev. drive;       }
  755.                        Done     := True;              { redraw scrn.       }
  756.                        To_A_Drv := True;              { Towards A:         }
  757.                       END;
  758.                 #81: BEGIN
  759.                        Drive    := SUCC (Drive);      { If PgDn, go to     }
  760.                        Dir_Name := Drive + ':\';      { next drive;        }
  761.                        Done     := True;              { redraw scrn.       }
  762.                        To_A_Drv := False;             { Away from A:       }
  763.                       END;
  764.               END;  {case}
  765.             END
  766.  
  767.           ELSE
  768.             BEGIN
  769.               CASE Ch OF
  770.  
  771.                 #13 : BEGIN                           { Return Key;        }
  772.                         Dir_Name := ptr1^.DirName;    { Return highlighted }
  773.                                                       { dir. to caller     }
  774.                         IF Dir_Name = '>ROOT' THEN Dir_Name := '.';
  775.                         LoopDirs := False;
  776.                         Done     := True;
  777.                       END;
  778.  
  779.                 #27 : BEGIN                           { Escape Key         }
  780.                         Dir_Name := Orig_Dir;         { Retrn to orig. dir }
  781.                         LoopDirs := False;
  782.                         Done     := True;
  783.                       END;
  784.  
  785.                '\','/' : BEGIN
  786.                            Dir_Name := '\';           { If \ or /, go to   }
  787.                            Done     := True;          { root; redraw scrn  }
  788.                          END;                         { if looping         }
  789.  
  790.               ELSE
  791.                 BEGIN
  792.                   Ch := UPCASE (Ch);                  { Cap letter inputs  }
  793.                   IF ((Ch >= 'A') and (Ch <= 'Z')) THEN
  794.                     BEGIN
  795.                       ptr2 := ptr1;
  796.                       ptr1 := Srch_Dir (Dir_Ptr,Ch);  { See if input is on }
  797.                       IF ptr1 <> nil THEN             { dir. listing       }
  798.                         BEGIN
  799.                           Dir_Name := ptr1^.DirName;  { If so, return      }
  800.                                                       { selected dir. name }
  801.  
  802.                           IF (Dir_Name = '.') OR (Dir_Name = '>ROOT') THEN
  803.                             BEGIN                     { If sel. cur. dir., }
  804.                               Dir_Name := '.';        { or root, then      }
  805.                               LoopDirs := False;
  806.                             END;
  807.                           Done     := True;           { all done           }
  808.                         END
  809.                       ELSE
  810.                         ptr1 := ptr2;                 { Else, set ptr1 to  }
  811.                     END                               { prev. value        }
  812.                   ELSE
  813.                    Beepit (760, 80);
  814.                 END;
  815.               END; {case}
  816.  
  817.             END;
  818.         END;
  819.  
  820.     END
  821.   ELSE
  822.     BEGIN
  823.       Dir_Name := '.';                      { No dirs. found - return cur. }
  824.     END;
  825.  
  826. END;
  827.  
  828. {
  829.    ┌────────────────────────────────────────────────────┐
  830.    │ PROCEDURE ChangeDir                                │
  831.    └────────────────────────────────────────────────────┘
  832. }
  833.  
  834. PROCEDURE ChangeDir (To_A_Drv : Boolean);
  835.  
  836. BEGIN
  837.  
  838. {$I-}
  839.   CHDIR (DirName);                             { Go to selected dir.       }
  840. {$I+}
  841.   IF IOResult = 0 THEN
  842.     BEEPIT (1000, 5)                           { Chirp on change of dir.   }
  843.   ELSE
  844.     BEGIN                                      { If error, such as disk not}
  845.       ClrScr;                                  { in drive, show error mess.}
  846.       WRITELN ('I/O Error -- cannot change');  { and try next drive        }
  847.       WRITELN ('to drive or directory specified');
  848.       BEEPIT (760,80);
  849.       BEGIN
  850.         CASE Drive OF
  851.           'A' : BEGIN
  852.                   Drive    := SUCC (Drive);
  853.                   To_A_Drv := false;
  854.                 END;
  855.           'B' : BEGIN
  856.                   IF To_A_Drv THEN
  857.                     BEGIN
  858.                       Drive    := 'A';
  859.                       To_A_Drv := false;
  860.                     END
  861.                   ELSE
  862.                     Drive      := SUCC (Drive);
  863.                 END
  864.         ELSE                                 { change back to prev. valid  }
  865.           Drive   := PRED (Drive);           { drive otherwise             }
  866.         END {case};
  867.         WRITELN;
  868.         WRITELN ('Trying drive ', Drive,':');
  869.         DELAY (1000);
  870.         DirName := Drive + ':\';
  871.         ChangeDir (To_A_Drv);                { Try to change to new drv.   }
  872.       END;
  873.       EXIT;
  874.     END;
  875.  
  876. END;
  877.  
  878. {$IFDEF SelfConfigure}                      {******************************}
  879.  
  880. {
  881.    ┌────────────────────────────────────────────────────┐
  882.    │ PROCEDURE Configure                                │
  883.    └────────────────────────────────────────────────────┘
  884. }
  885.  
  886. PROCEDURE Configure;
  887.  
  888.    {
  889.       ┌────────────────────────────────────────────────────┐
  890.       │ SUBPROCEDURE InputError                            │
  891.       └────────────────────────────────────────────────────┘
  892.    }
  893.  
  894.    PROCEDURE InputError;
  895.  
  896.    BEGIN
  897.      WRITELN (NL,NL,'INPUT VALUE INCORRECT -- MUST START OVER');
  898.      Beepit (560,80);
  899.      DELAY (2500);
  900.      HALT;
  901.    END;
  902.  
  903.    {
  904.       ┌────────────────────────────────────────────────────┐
  905.       │ SUBPROCEDURE Yes_No                                │
  906.       └────────────────────────────────────────────────────┘
  907.    }
  908.  
  909.    PROCEDURE Yes_No (message : string; VAR ReturnVar : Boolean);
  910.  
  911.    VAR
  912.     in_char : char;
  913.  
  914.    BEGIN
  915.      WRITE (message);
  916.      in_char := ReadKey;
  917.      WRITELN (in_char);
  918.      CASE in_char OF
  919.        'Y','y' : ReturnVar := true;
  920.        'N','n' : ReturnVar := false;
  921.        #13     : ;
  922.      ELSE
  923.        InputError;
  924.      END; {case}
  925.    END;
  926.  
  927.    {
  928.       ┌────────────────────────────────────────────────────┐
  929.       │ SUBPROCEDURE Ask_for_input                         │
  930.       └────────────────────────────────────────────────────┘
  931.    }
  932.  
  933.    PROCEDURE Ask_for_input (message : string;
  934.                             VAR ReturnVar : integer;
  935.                             error : integer);
  936.  
  937.    VAR
  938.      in_string : string;
  939.      in_char   : char;
  940.      code      : integer;
  941.  
  942.    BEGIN
  943.      in_string := '';
  944.      WRITE (message);
  945.      REPEAT
  946.        in_char := ReadKey;
  947.        WRITE (in_char);
  948.        in_string := in_string + in_char;
  949.      UNTIL in_char = #13;
  950.      IF LENGTH (in_string) > 1 THEN
  951.        VAL (COPY(in_string,1,LENGTH(in_string)-1), ReturnVar, code);
  952.      IF (ReturnVar > error) THEN InputError;
  953.      WRITELN;
  954.    END;
  955.  
  956.    {
  957.       ┌────────────────────────────────────────────────────┐
  958.       │ SUBFUNCTION DosVersion                             │
  959.       └────────────────────────────────────────────────────┘
  960.    }
  961.  
  962.  
  963.    FUNCTION DosVersion : REAL;                { Return DOS version number }
  964.  
  965.    VAR
  966.      Regs : registers;
  967.  
  968.    BEGIN
  969.      WITH Regs DO
  970.        BEGIN
  971.          AX := $3000;
  972.          MSDOS(Regs);
  973.          IF AL <> 0 THEN
  974.            DosVersion := AL + AH/100
  975.          ELSE
  976.            DosVersion := 1.0;
  977.        END;
  978.    END;
  979.  
  980.    {
  981.       ┌────────────────────────────────────────────────────┐
  982.       │ SUBFUNCTION PgmName                                │
  983.       └────────────────────────────────────────────────────┘
  984.    }
  985.  
  986.    FUNCTION PgmName : STRING;               { Returns name & path of pgm.  }
  987.                                             { A null string is returned if }
  988.    VAR                                      { DOS version is < 3.00.       }
  989.      EnvSeg : word;
  990.      i      : integer;
  991.      Temp   : string;
  992.  
  993.    BEGIN
  994.      IF TRUNC (DosVersion) > 2.0 THEN
  995.        BEGIN
  996.          EnvSeg := MEMW[PREFIXSEG : $2C];   {Start loc of the environ. str }
  997.          i      := 0;
  998.          Temp   := '';
  999.  
  1000.          WHILE MEMW[EnvSeg:i] <> 0 DO
  1001.            INC(i);
  1002.          INC(i,4);
  1003.  
  1004.          WHILE MEM[EnvSeg:i] <> 0 DO
  1005.            BEGIN
  1006.              Temp := Temp + UPCASE(CHR(MEM[EnvSeg:i]));
  1007.              INC(i);
  1008.            END;  {while}
  1009.          PgmName := Temp;
  1010.        END  {if}
  1011.      ELSE
  1012.        PgmName := '';                       { Null string if DOS < 3.00    }
  1013.    END;
  1014.  
  1015. {────────────────────────────────────────────────────}
  1016.  
  1017. VAR
  1018.   ExeFile    : file;
  1019.   FileAttr   : word;
  1020.   HeaderSize : word;
  1021.  
  1022. BEGIN
  1023.  
  1024.   ASSIGN (ExeFile, PgmName);                    { Test for existence of   }
  1025.   GetFAttr (ExeFile, FileAttr);                 { file w/ PGMNAME func.   }
  1026.  
  1027.   IF (FileAttr = 0) THEN
  1028.     BEGIN
  1029.       WRITELN (PgmName, ' missing -- aborting configure routine');
  1030.       Beepit (560,80);
  1031.       DELAY (5000);
  1032.       HALT;
  1033.     END;
  1034.  
  1035.   WITH Config DO
  1036.     BEGIN
  1037.       Yes_No ('DEFAULT = LOOP? (y or N) ', LoopDirFlag);
  1038.  
  1039.       Yes_No ('COUNT CURRENT DIRECTORY? (y or N) ', Cnt_CurFlag);
  1040.  
  1041.       Yes_No ('AUTOMATICALLY SIZE WINDOW? (Y or n) ', AutoSize);
  1042.  
  1043.       Ask_for_input ('TOP ROW FOR WINDOW? (1 to 10 -- preset to 5) ',
  1044.         Row_BEGIN, 10);
  1045.  
  1046.       Ask_for_input ('COLUMN FOR WINDOW? (1 to 44 -- preset to 22) ',
  1047.         Col_BEGIN, 44);
  1048.  
  1049.       Ask_for_input ('HIGHLIGHT COLOR? (1 to 256 -- preset to 112) ',
  1050.         Act_Attr, 256);
  1051.  
  1052.       Ask_for_input ('BACKGROUND COLOR? (1 to 256 -- preset to 31) ',
  1053.         IAct_Attr, 256);
  1054.  
  1055.       Ask_for_input ('BORDER TYPE? (0 for none, 1 for single [preset], 2 for double) ',
  1056.          Wndw_Bdr, 2);
  1057.     END;
  1058.  
  1059.   RESET (ExeFile, 1);                           { change Typed Constant   }
  1060.   SEEK (ExeFile, 8);
  1061.   BLOCKREAD (ExeFile, HeaderSize, SIZEOF (HeaderSize));
  1062.   SEEK (ExeFile, 16 * (SEG (Config) - PREFIXSEG + HeaderSize)
  1063.                     + OFS (Config) - 256);
  1064.   BLOCKWRITE (ExeFile, Config, SIZEOF (Config));
  1065.   CLOSE (ExeFile);
  1066.  
  1067.   WRITELN;
  1068.   WRITELN ('CONFIGURATION CHANGES MADE -- RE-START ', PgmName);
  1069.   Beepit (1000,80);
  1070.   DELAY (2000);
  1071.   HALT;
  1072. END;
  1073.  
  1074. {$ENDIF}                                    {******************************}
  1075.  
  1076. {
  1077.    ┌────────────────────────────────────────────────────┐
  1078.    │ PROCEDURE Read_Parm                                │
  1079.    └────────────────────────────────────────────────────┘
  1080. }
  1081.  
  1082. PROCEDURE Read_Parm;
  1083.  
  1084. VAR
  1085.   Param : String[1];
  1086.  
  1087. BEGIN
  1088.   Param := ParamStr(1);
  1089.  
  1090.   CASE (Param[1]) OF
  1091.  
  1092.     'U','u': BEGIN
  1093.                IF LENGTH (Cur_Dir) > 3 THEN CHDIR ('..');
  1094.                HALT;                           { If "u" for "up", go up    }
  1095.              END;                              { and stop, unless at root  }
  1096.  
  1097.     'D','d': CHDIR ('.');                      { Just to be symetric:      }
  1098.                                                { If "d" for "down",        }
  1099.                                                { just continue             }
  1100.  
  1101.     'L','l': LoopDirs := True;                 { Set flag if looping       }
  1102.  
  1103.     'N','n': LoopDirs := False;                { Set flag if NOT looping   }
  1104.  
  1105.     'O','o': IF LENGTH (Cur_Dir) > 3 THEN      { If "o" for "over", go up  }
  1106.                BEGIN                           { 1 dir., (unless at root)  }
  1107.                  CHDIR ('..');                 { disp. lst, & continue     }
  1108.                  GETDIR (0,Cur_Dir);
  1109.                END;
  1110.  
  1111.      '?'   : Usage;
  1112.  
  1113. {$IFDEF SelfConfigure}                         {***************************}
  1114.     'X','x': Configure                         { Go to configuration proc. }
  1115. {$ELSE}
  1116.     'X','x': BEGIN
  1117.                WRITELN ('THIS VERSION NOT SELF-CONFIGURING');
  1118.                BEEPIT (760,80);
  1119.                DELAY (3000);
  1120.                HALT;
  1121.              END
  1122. {$ENDIF}                                       {***************************}
  1123.  
  1124.   ELSE
  1125.     BEEPIT (760,80);                           { If improper parameter,    }
  1126.     Usage;                                     { beep & show usage         }
  1127.   END; {case}
  1128.  
  1129. END;
  1130.  
  1131. {
  1132.    ┌────────────────────────────────────────────────────┐
  1133.    │ PROCEDURE Go_Direct                                │
  1134.    └────────────────────────────────────────────────────┘
  1135. }
  1136.  
  1137. PROCEDURE Go_Direct (Ptr1 : Fptr);
  1138.  
  1139. BEGIN
  1140.   IF (Ptr1^.DirName = '>ROOT') AND (Ptr1^.Next = nil) THEN
  1141.     CHDIR ('\')
  1142.   ELSE
  1143.     BEGIN
  1144.       WHILE (Ptr1^.Next <> nil) DO
  1145.         Ptr1 := Ptr1^.Next;
  1146.       CHDIR (Ptr1^.DirName);
  1147.     END;
  1148.  
  1149.   BEEPIT (1000,5);                           { Chirp on change of dir.   }
  1150.   HALT;
  1151. END;
  1152.  
  1153. {
  1154.    ┌────────────────────────────────────────────────────┐
  1155.    │ PROCEDURE TestDirect                               │
  1156.    └────────────────────────────────────────────────────┘
  1157. }
  1158.  
  1159. PROCEDURE TestDirect;
  1160.  
  1161. BEGIN
  1162.   IF LoopDirs = False THEN                     { Do if NOT looping         }
  1163.     CASE Num_Dirs OF                           { Test for direct movement  }
  1164.                                                { to single subdir. or to   }
  1165.       1 : Go_Direct (Dir_Ptr);                 { parent dir.               }
  1166.       2 : Go_Direct (Dir_Ptr);
  1167.       3 : IF ((LENGTH (Cur_Dir) > 3) AND (Cnt_Cur = True)) THEN
  1168.           Go_Direct (Dir_Ptr);
  1169.     END;  {case}
  1170. END;
  1171.  
  1172. {
  1173.    ┌────────────────────────────────────────────────────┐
  1174.    │ PROCEDURE Program Exit                             │
  1175.    └────────────────────────────────────────────────────┘
  1176. }
  1177.  
  1178. {$F+}
  1179. PROCEDURE PgmExit;
  1180.  
  1181. BEGIN
  1182.   TextMode (OrigMode);                         { Return to orig. vid. mode }
  1183.   Restore_Screen;
  1184.   Cursor (True);                               { Turn cursor back on       }
  1185.   Release (HeapPtr);                           { Restore all mem allocated }
  1186.   ExitProc := ExitSave;                        { Restore orig. exit proc.  }
  1187. END;
  1188. {$F-}
  1189.  
  1190. {
  1191.    ┌────────────────────────────────────────────────────┐
  1192.    │ BEGIN MAIN PROGRAM                                 │
  1193.    └────────────────────────────────────────────────────┘
  1194. }
  1195.  
  1196. VAR
  1197.   Version : string;
  1198.  
  1199. BEGIN
  1200.  
  1201.   ExitSave := ExitProc;                    { Save last exit proc. in chain }
  1202.   ExitProc := @PgmExit;                    { Install PgmExit in exit proc. }
  1203.                                            { chain.                        }
  1204.  
  1205.   Version  := 'Version 1.9 -- 6-19-88 -- Public Domain by John Land';
  1206.                                                { Version; sticks in .EXE   }
  1207.  
  1208.   Cnt_Cur  := Config.Cnt_CurFlag;              { False means don't cnt cur.}
  1209.                                                { dir., True means cnt. it  }
  1210.  
  1211.   LoopDirs := Config.LoopDirFlag;              { Init. looping flag        }
  1212.  
  1213.                        { START DIR. PROCESSING }
  1214.  
  1215.   NEW  (HeapPtr);                              { Save the current heap ptr }
  1216.   MARK (HeapPtr);
  1217.  
  1218.   OrigMode := VideoMode;                       { Save video mode           }
  1219.  
  1220.   Save_Screen;                                 { Save the current screen   }
  1221.  
  1222.   Cursor (False);                              { Turn off the cursor       }
  1223.  
  1224.   GETDIR (0,Cur_Dir);                          { Get current directory     }
  1225.   Orig_Dir := Cur_Dir;                         { Save copy of cur. dir.    }
  1226.   Drive    := Cur_Dir[1];                      { Save drive designation    }
  1227.  
  1228.   IF ParamCount > 0 THEN Read_Parm;            { Do command line parms     }
  1229.   IF LoopDirs THEN Cnt_Cur := True;            { Cnt. cur. dir if looping  }
  1230.  
  1231.  
  1232.                        {    LOOPING ROUTINE    }
  1233.  
  1234.   REPEAT                                       { Do routines at least once }
  1235.  
  1236.     Num_Dirs := Get_Dirs (Dir_Ptr);            { Get matching dirs. & cnt  }
  1237.  
  1238.     TestDirect;                                { Test if can CD directly   }
  1239.  
  1240.              { Windowed list of directories procedures and routines follows}
  1241.  
  1242.     ClrScr;                                    { Use if want clr. scrn     }
  1243.                                                { while disp'g dir. list    }
  1244.  
  1245.     SizeWindow;                                { Auto. sizing of window    }
  1246.  
  1247.     Sel_Dir (DirName,Num_Dirs,Dir_Ptr,To_A_Drv); { Select directory        }
  1248.  
  1249.     ChangeDir (To_A_Drv);                      { Change to selected dir.   }
  1250.  
  1251.     GETDIR (0,Cur_Dir)                         { Get current directory     }
  1252.  
  1253.   UNTIL LoopDirs = False;                      { Looping test              }
  1254.  
  1255. END.
  1256.