home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / FD.ZIP / FD.PAS
Encoding:
Pascal/Delphi Source File  |  1988-05-01  |  5.6 KB  |  174 lines

  1. program find_directory;   { TP 3.0 }
  2. {
  3.   Searches for and takes a user to the directory specified on command line.
  4.   User may specify 1 or more characters; program will change to first
  5.   matching directory (wildcards are not permitted).
  6.  
  7.   In addition to being a useful utility, I would like this program to serve
  8.   as an example of one of the more powerful and complex features of Pascal:
  9.   recursion.
  10.  
  11.   JEP 4/88
  12. }
  13.  
  14. {$p512}                       { Enable I/O redirection }
  15.  
  16. const
  17.    dtalength = 43;
  18.    filenamelength = 12;       { filename.ext -> 12 }
  19.    pathlength = 64;           { max characters DOS allows in a path specifier }
  20.    maxdirectories = 32;       { we'll allow this many directories per level }
  21.  
  22. type
  23.    registers = record
  24.                   case byte of
  25.                      0 : (ax,bx,cx,dx,bp,si,di,ds,es,flags : integer);
  26.                      1 : (al,ah,bl,bh,cl,ch,dl,dh : byte);
  27.                end;
  28.    filename = string[filenamelength];
  29.    pathname = string[pathlength];
  30.    disk_transfer_area = array[1..dtalength] of char;
  31.    directory = record
  32.                   numentries : integer;
  33.                   fname : array[1..maxdirectories] of filename;
  34.                end;
  35.  
  36. var
  37.    thedir : pathname;
  38.    destdir : filename;
  39.    dta : disk_transfer_area;
  40.    regs : registers;
  41.  
  42.  
  43. procedure set_dta_address(segment,offset : integer);
  44. begin
  45.    regs.ah:=$1a;
  46.    regs.ds:=segment;
  47.    regs.dx:=offset;
  48.    msdos(regs);
  49. end;
  50.  
  51. procedure load_first(var specifier : pathname; var rc : integer);
  52. begin
  53.    specifier:=specifier+chr(0);             { path must be ASCIIZ string }
  54.    regs.ah:=$4e;
  55.    regs.ds:=seg(specifier[1]);
  56.    regs.dx:=ofs(specifier[1]);
  57.    regs.cx:=$0010;       { search attribute: $0010 -> search for subdirs }
  58.    msdos(regs);
  59.    rc:=regs.ax;
  60. end;
  61.  
  62. procedure load_next(var rc : integer);
  63. begin
  64.    regs.ah:=$4f;
  65.    msdos(regs);
  66.    rc:=regs.ax;
  67. end;
  68.  
  69. procedure parse_dta(var fname : filename; var attribute : integer);
  70. var
  71.    i : integer;
  72. begin
  73.    i:=31;                                 { filename at offset 31 in dta }
  74.    repeat
  75.       fname[i-30]:=dta[i];
  76.       i:=i+1;
  77.    until (dta[i]=chr(0));                 { filename terminated by hex 0 }
  78.    fname[0]:=chr(i-31);                  { put string length in 0th byte }
  79.    attribute:=ord(dta[22]);
  80. end;
  81.  
  82. procedure get_directory(dirname : pathname; var dir : directory);
  83. var
  84.    rc,attribute : integer;
  85.    fname : filename;
  86. begin
  87.    dir.numentries:=0;
  88.    load_first(dirname,rc);
  89.    while (rc = 0) and (dir.numentries < maxdirectories) do begin
  90.       parse_dta(fname,attribute);
  91.       { avoid regular files and the current and root listings }
  92.       if ((attribute and $10)<>0) and (fname<>'.') and (fname<>'..') then begin
  93.          dir.numentries:=dir.numentries+1;
  94.          dir.fname[dir.numentries]:=fname;
  95.       end;
  96.       load_next(rc);
  97.    end;
  98. end;
  99.  
  100. procedure validate_parms(var parms : filename);
  101. { Returns parms capitalized if it is ok, '' otherwise }
  102. var
  103.    i : integer;
  104. begin
  105.    i:=1;
  106.    while (i<=length(parms)) do begin
  107.       { don't want illegal characters in the directory name }
  108.       if (parms[i] in ['?','*','.','"','/','\','[',']',':','|','<','>','+','=',';',',']) then
  109.          parms:='' { will terminate loop - crafty or kludgy, take your pick }
  110.       else
  111.          parms[i]:=upcase(parms[i]);
  112.       i:=i+1;
  113.    end;
  114. end;
  115.  
  116. procedure help;
  117. begin
  118.    writeln;
  119.    writeln('FD (Find Directory) - Subdirectory scan utility - JEP 4/88');
  120.    writeln;
  121.    writeln('Syntax: FD dest');
  122.    writeln;
  123.    writeln('        dest - 1 or more characters specifying the name of a directory ');
  124.    writeln('               for FD to locate and change to.  dest may not contain');
  125.    writeln('               multiple levels (or the "\" character), or an extension.');
  126.    writeln('               If more than one directory is a match, FD will change to');
  127.    writeln('               the first match it finds.  Wildcards may NOT be used.');
  128.    writeln;
  129. end;
  130.  
  131. procedure trace_directory(startdir,destdir : pathname; var thedir : pathname);
  132. {
  133.    Recursive procedure to check the immediate children of a directory.
  134.    Parameters are: startdir - a path specifying the directory to begin the
  135.                               search in (initial call passes '', signifying
  136.                               the root)
  137.                    destdir - the directory we are searching for; input
  138.                              from command line and passed in initial call;
  139.                              carried to all levels solely for comparison.
  140.                    thedir - the path specifier for the destination directory;
  141.                             has value of '' if no match found.
  142. }
  143. var
  144.    dir_list : directory;
  145.    i : integer;
  146.    curdir : pathname;
  147. begin
  148.    get_directory(startdir+'\*.',dir_list);   { get all children of startdir }
  149.    i:=1;
  150.    thedir:='';
  151.    while (i<=dir_list.numentries) and (thedir='') do begin
  152.       curdir:=startdir+'\'+dir_list.fname[i];
  153.       clreol;                                     { do the fancy output }
  154.       write('Tracing: ',curdir,chr(13));
  155.       if pos(destdir,dir_list.fname[i]) = 1 then { if it matches destdir }
  156.          thedir:=curdir                           { save it, ending the loop }
  157.       else                                        { otherwise }
  158.          trace_directory(curdir,destdir,thedir);  { search its children }
  159.       i:=i+1;
  160.    end;
  161. end;
  162.  
  163. begin { main }
  164.    destdir:=paramstr(1);
  165.    validate_parms(destdir);
  166.    if destdir<>'' then begin
  167.       set_dta_address(seg(dta),ofs(dta));
  168.       trace_directory('',destdir,thedir);
  169.       chdir(thedir);
  170.    end
  171.    else
  172.       help;
  173. end.
  174.