home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / PASCAL / DU111 / DU.MOD < prev    next >
Text File  |  1991-10-29  |  14KB  |  662 lines

  1. MODULE du;
  2.  
  3. IMPORT FIO,IO,Lib,Str,SYSTEM;
  4.  
  5. TYPE
  6.   String = ARRAY [0..255] OF CHAR;
  7.   FileSpec = RECORD
  8.     i : BOOLEAN;
  9.     n : String;
  10.   END;
  11.   bs = SET OF [0..31];
  12.  
  13. CONST
  14.   FileAttr = FIO.FileAttr{FIO.archive,FIO.hidden,FIO.system,FIO.directory};
  15.  
  16.   eol =
  17.     CHAR(13)+CHAR(10);
  18.   helptext =
  19.     'du v1.11 (c) 1991 Arnt Gulbrandsen'+eol+eol+
  20.     'du {options|filespec} {directory {options|filespecs}} '+eol+
  21.     '/a -a  List individual file sizes'+eol+
  22.     '/d -d  Debug'+eol+
  23.     '/i -i  Include following filespecs'+eol+
  24.     "/n -n  Don't include subdirectories in directory size"+eol+
  25.     '/s -s  Sum only (like -0)'+eol+
  26.     '/x -x  Exclude following filespecs'+eol+
  27.     "/w -w  Show wasted space (in percent)"+eol+
  28.     "/z -z  Don't show 0k directories / files"+eol+
  29.     '/0...  Show only the top 0..65535 levels of the directory tree'+eol+
  30.     '/? /h  Help'+eol+eol+
  31.     'Filespecs may contain ? (any single character except /), * (0 or more'+eol+
  32.     'chars), and [list] (matches any single character in the list).  The full'+eol+
  33.     'stop is not special, *[a-cx]* will match any file containing A,B,C or'+eol+
  34.     'X anywhere in the file name or extension.';
  35.  
  36. VAR
  37.   opt_a,
  38.   opt_d,
  39.   opt_h,
  40.   opt_n,
  41.   opt_w,
  42.   opt_z:BOOLEAN;
  43.   max_depth,
  44.   cur_depth:CARDINAL;
  45.   IncludeAll,
  46.   include:BOOLEAN;
  47.  
  48.   Specs : ARRAY [0..99] OF FileSpec;
  49.   FileSpecs : CARDINAL;
  50.  
  51.   stepup ,
  52.   granularity : LONGCARD;
  53.  
  54.  
  55.  
  56.  
  57. PROCEDURE Match(VAR a,b: String):BOOLEAN;
  58.  
  59.   PROCEDURE Test(p,q:CARDINAL):BOOLEAN;
  60.   VAR
  61.     f:BOOLEAN;
  62.     r:CARDINAL;
  63.   BEGIN
  64.     IF (p=0) AND (q=0) THEN
  65.       RETURN(TRUE);
  66.     ELSIF (p=0) AND (b[q-1]='/') THEN
  67.       RETURN(TRUE);
  68.     ELSIF (p=0) OR (q=0) THEN
  69.       RETURN(FALSE);
  70.     ELSE
  71.       DEC(p);
  72.       DEC(q);
  73.       CASE a[p] OF
  74.         |'?':
  75.           RETURN(Test(p,q));
  76.         |'*':
  77.           r:=q;
  78.           REPEAT
  79.             IF b[r]='/' THEN
  80.               f:=(p=0);
  81.             ELSE
  82.               f:=Test(p,r);
  83.             END;
  84.             IF r>0 THEN
  85.               DEC(r);
  86.             END;
  87.           UNTIL f OR (r=0);
  88.           RETURN(f);
  89.         |']':
  90.           r:=p;
  91.           WHILE (a[r]#'[') AND (r>0) DO
  92.             DEC(r);
  93.           END;
  94.           INC(r);
  95.           f:=FALSE;
  96.           WHILE NOT(f) AND (r<p) DO
  97.             IF a[r+1]='-' THEN
  98.               f:=(a[r]<=b[q]) AND (a[r+2]>=b[q]);
  99.             ELSE
  100.               f:=(a[r]=b[q]);
  101.             END;
  102.             INC(r);
  103.           END;
  104.           RETURN(f);
  105.       ELSE
  106.         RETURN((a[p]=b[q]) AND Test(p,q));
  107.       END;
  108.     END;
  109.   END Test;
  110.  
  111. BEGIN
  112.   RETURN(Test(Str.Length(a),Str.Length(b)));
  113. END Match;
  114.  
  115.  
  116.  
  117. PROCEDURE Print(TrueSize,NominalSize:LONGCARD;VAR name:String;dir:BOOLEAN);
  118.  
  119.   PROCEDURE PrintWasted;
  120.   BEGIN
  121.     IF opt_w THEN
  122.       IF TrueSize>0 THEN
  123.         IO.WrLngCard(LONGCARD(LONGREAL(TrueSize-NominalSize)*100.0/LONGREAL(TrueSize)),2);
  124.         IO.WrStr('.');
  125.         IO.WrLngCard(LONGCARD(LONGREAL(TrueSize-NominalSize)*10005.0/LONGREAL(TrueSize)/10.0) MOD 10,1);
  126.       ELSE
  127.         IO.WrStr(' 0.0');
  128.       END;
  129.       IO.WrStr('%  ');
  130.     END;
  131.   END PrintWasted;
  132.  
  133. BEGIN
  134.   IF dir THEN
  135.     IF (cur_depth<=max_depth) AND (NOT(opt_z) OR (TrueSize>0)) THEN
  136.       IO.WrLn;
  137.       IO.WrLngCard(TrueSize DIV 1024,7);
  138.       IO.WrStr('k  ');
  139.       PrintWasted;
  140.       IO.WrStr(name);
  141.     END;
  142.   ELSE
  143.     IF opt_a AND (NOT(opt_z) OR (TrueSize>0)) THEN
  144.       IO.WrLn;
  145.       IO.WrLngCard(TrueSize DIV 1024,7);
  146.       IO.WrStr('k  ');
  147.       PrintWasted;
  148.       IO.WrStr(name);
  149.     END;
  150.   END;
  151. END Print;
  152.  
  153.  
  154.  
  155. PROCEDURE ScanDirectory(dir:String;VAR TrueSize,NominalSize:LONGCARD);
  156. VAR
  157.   filedata:FIO.DirEntry;
  158.   NominalFileSize,
  159.   TrueFileSize : LONGCARD;
  160.   file : String;
  161.   foo : BOOLEAN;
  162.   bar : CARDINAL;
  163. BEGIN
  164.   INC(cur_depth);
  165.   Str.Concat(file,dir,'*.*');
  166.   NominalSize:=0;
  167.   TrueSize:=0;
  168.   IF FIO.ReadFirstEntry(file,FileAttr,filedata) THEN
  169.     REPEAT
  170.       Str.Lows(filedata.Name);
  171.       IF IncludeAll THEN
  172.         INC(NominalSize,32);
  173.         INC(TrueSize,32);
  174.       END;
  175.       TrueFileSize:=0;
  176.       NominalFileSize:=0;
  177.       IF
  178.         (Str.Compare(filedata.Name,'.')#0)
  179.       AND
  180.         (Str.Compare(filedata.Name,'..')#0)
  181.       THEN
  182.         Str.Concat(file,dir,filedata.Name);
  183.         IF FIO.directory IN filedata.attr THEN
  184.           Str.Append(file,'/');
  185.           ScanDirectory(file,TrueFileSize,NominalFileSize);
  186.           Print(TrueFileSize,NominalFileSize,file,TRUE);
  187.           IF opt_n THEN
  188.             TrueFileSize:=0;
  189.             NominalFileSize:=0;
  190.           END;
  191.         ELSE
  192.           foo:=IncludeAll;
  193.           FOR bar:=1 TO FileSpecs DO
  194.             IF Specs[bar].i THEN
  195.               foo:=foo OR Match(Specs[bar].n,file);
  196.             ELSE
  197.               foo:=foo AND NOT(Match(Specs[bar].n,file));
  198.             END;
  199.           END;
  200.           IF foo THEN
  201.             NominalFileSize:=filedata.size;
  202.             TrueFileSize:=LONGCARD(bs(filedata.size+stepup)*bs(granularity));
  203.             Print(TrueFileSize,NominalFileSize,file,FALSE);
  204.           END;
  205.         END;
  206.       END;
  207.       INC(TrueSize,TrueFileSize);
  208.       INC(NominalSize,NominalFileSize);
  209.     UNTIL NOT(FIO.ReadNextEntry(filedata));
  210.   END;
  211.   DEC(cur_depth);
  212.   TrueSize:=LONGCARD(bs(TrueSize+stepup)*bs(granularity));
  213. END ScanDirectory;
  214.  
  215.  
  216.  
  217.  
  218. PROCEDURE IsFilespec(VAR a:String):BOOLEAN;
  219. VAR
  220.   p:CARDINAL;
  221.   f:BOOLEAN;
  222. BEGIN
  223.   p:=0;
  224.   f:=(a[0]#CHAR(0)) AND (a[0]#'/');
  225.   WHILE f AND (a[p]#CHAR(0)) DO
  226.     IF a[p]='\' THEN
  227.       a[p]:='/';
  228.     END;
  229.     f:=f AND (a[p] IN Str.CHARSET{'0'..'9','a'..'z','.','/','[','?','*'});
  230.     IF a[p]='[' THEN
  231.       REPEAT
  232.         INC(p);
  233.         f:=f AND (a[p]#CHAR(0)) AND (a[p]#'[') AND (a[p]#'-');
  234.         IF f AND (a[p+1]='-') AND (a[p+2]#']') THEN
  235.           INC(p);
  236.         END;
  237.         INC(p);
  238.       UNTIL NOT(f) OR (a[p]=']');
  239.     END;
  240.     INC(p);
  241.   END;
  242.   RETURN(f);
  243. END IsFilespec;
  244.  
  245.  
  246.  
  247. PROCEDURE IsDirectory(a:String):BOOLEAN;
  248.  
  249.   (*
  250.    * I copied the FIO ReadFirstEntry / ReadNextEntry
  251.    * and deleted some error checking so ReadFirstEntry
  252.    * doesn't burp on being given a nonsense path
  253.    * like -a or *.zip
  254.    *)
  255.  
  256.   PROCEDURE ReadFirstEntry ( DirName : ARRAY OF CHAR;
  257.                              Attr    : FIO.FileAttr;
  258.                              VAR D   : FIO.DirEntry) : BOOLEAN;
  259.   VAR
  260.     r  : SYSTEM.Registers;
  261.   BEGIN
  262.     WITH r DO
  263.       AH := 1AH;
  264.       DS := Seg(D);
  265.       DX := Ofs(D);
  266.       Lib.Dos(r);    (* set DTA *)
  267.       AH := 4EH;
  268.       DS := Seg(DirName);
  269.       DX := Ofs(DirName);
  270.       CL := SHORTCARD(Attr);
  271.       CH := SHORTCARD(0);
  272.       Lib.Dos(r);
  273.       IF (BITSET{SYSTEM.CarryFlag} * Flags) # BITSET{} THEN
  274.         RETURN FALSE;
  275.       END;
  276.     END;
  277.     RETURN TRUE;
  278.   END ReadFirstEntry;
  279.  
  280.   PROCEDURE ReadNextEntry(VAR D: FIO.DirEntry) : BOOLEAN;
  281.   VAR
  282.     r : SYSTEM.Registers;
  283.   BEGIN
  284.     WITH r DO
  285.       AH := 1AH;
  286.       DS := Seg(D);
  287.       DX := Ofs(D);
  288.       Lib.Dos(r);    (* set DTA *)
  289.       AH := 4FH;
  290.       Lib.Dos(r);
  291.       IF (BITSET{SYSTEM.CarryFlag} * Flags) # BITSET{} THEN
  292.         RETURN FALSE;
  293.       END;
  294.     END;
  295.     RETURN TRUE;
  296.   END ReadNextEntry;
  297.  
  298.  
  299. VAR
  300.   d:FIO.DirEntry;
  301.   foo:String;
  302. BEGIN
  303.   IF (Str.CharPos(a,'*')<65535) THEN
  304.     RETURN(FALSE);
  305.   END;
  306.   IF (Str.CharPos(a,'[')<65535) THEN
  307.     RETURN(FALSE);
  308.   END;
  309.   IF (Str.CharPos(a,'?')<65535) THEN
  310.     RETURN(FALSE);
  311.   END;
  312.   IF ReadFirstEntry(a,FileAttr,d) AND (FIO.directory IN d.attr) THEN
  313.     RETURN(TRUE);
  314.   ELSE
  315.     IF (a[Str.Length(a)-1] IN Str.CHARSET{'/','\'}) THEN
  316.       Str.Concat(foo,a,'*.*');
  317.     ELSE
  318.       Str.Concat(foo,a,'/*.*');
  319.     END;
  320.     RETURN(ReadFirstEntry(foo,FileAttr,d));
  321.   END;
  322. END IsDirectory;
  323.  
  324.  
  325. PROCEDURE IsSwitch(a:String):BOOLEAN;
  326. VAR
  327.   foo,
  328.   bar:CARDINAL;
  329.   valid:BOOLEAN;
  330. BEGIN
  331.   IF Str.Length(a)>1 THEN
  332.     IF (a[0]='-') OR (a[0]='/') THEN
  333.       valid:=TRUE;
  334.       bar:=0;
  335.       FOR foo:=1 TO Str.Length(a)-1 DO
  336.         IF (a[foo]>='0') AND (a[foo]<='9') THEN
  337.           IF (bar>6553) OR ( (bar=6553) AND (a[foo]>'5') ) THEN
  338.             valid:=FALSE;
  339.           ELSE
  340.             bar:=bar*10+(CARDINAL(a[foo])-48);
  341.           END;
  342.         ELSIF a[foo] IN Str.CHARSET{'a','s','d','h','?','w','z','i','x','n'} THEN
  343.           bar:=0;
  344.         ELSE
  345.           valid:=FALSE;
  346.         END;
  347.       END;
  348.     ELSE
  349.       valid:=FALSE;
  350.     END;
  351.   ELSE
  352.     valid:=FALSE;
  353.   END;
  354.   RETURN(valid);
  355. END IsSwitch;
  356.  
  357.  
  358.  
  359. PROCEDURE CheckArgs();
  360. VAR
  361.   argno,
  362.   argv:CARDINAL;
  363.   arg:String;
  364. BEGIN
  365.   opt_d:=FALSE;
  366.   opt_h:=FALSE;
  367.   argv:=Lib.ParamCount();
  368.   FOR argno:=1 TO argv DO
  369.     Lib.ParamStr(arg,argno);
  370.     IF IsSwitch(arg) THEN
  371.       IF IsDirectory(arg) THEN
  372.         IO.WrLn;
  373.         IO.WrStr(arg);
  374.         IO.WrStr(' is valid both as switch and base directory.');
  375.         Lib.SetReturnCode(2);
  376.         HALT;
  377.       ELSIF IsFilespec(arg) THEN
  378.         IO.WrLn;
  379.         IO.WrStr(arg);
  380.         IO.WrStr(' is valid both as switch and file specification.');
  381.         Lib.SetReturnCode(2);
  382.         HALT;
  383.       ELSE
  384.         IF Str.CharPos(arg,'d')<MAX(CARDINAL) THEN
  385.           opt_d:=TRUE;
  386.         END;
  387.         IF Str.CharPos(arg,'h')<MAX(CARDINAL) THEN
  388.           opt_h:=TRUE;
  389.         END;
  390.       END;
  391.     ELSIF IsDirectory(arg) THEN
  392.       (* all dirs are filespecs also so don't try IsFilespec *)
  393.     ELSIF IsFilespec(arg) THEN
  394.       (* no action necessary *)
  395.     ELSE
  396.       IO.WrLn;
  397.       IO.WrStr(arg);
  398.       IO.WrStr(" isn't a valid argument.");
  399.       Lib.SetReturnCode(2);
  400.       HALT;
  401.     END;
  402.   END;
  403.   IF opt_d THEN
  404.     IO.WrLn;
  405.     IO.WrStr('Command line arguments:');
  406.     FOR argno:=1 TO argv DO
  407.       Lib.ParamStr(arg,argno);
  408.       IO.WrLn;
  409.       IO.WrStr('  "');
  410.       IO.WrStr(arg);
  411.       IF IsDirectory(arg) THEN
  412.         IO.WrStr('" is a base directory');
  413.       ELSIF IsSwitch(arg) THEN
  414.         IO.WrStr('" is a switch');
  415.       ELSE
  416.         IO.WrStr('" is a file specification');
  417.       END;
  418.     END;
  419.   END;
  420. END CheckArgs;
  421.  
  422.  
  423.  
  424.  
  425. PROCEDURE SetFlags(a:String);
  426. VAR
  427.   foo:CARDINAL;
  428.   bar:BOOLEAN;
  429. BEGIN
  430.   bar:=FALSE;
  431.   FOR foo:=1 TO Str.Length(a) DO
  432.     CASE a[foo] OF
  433.       |'a':
  434.         opt_a:=TRUE;
  435.         bar:=FALSE;
  436.       |'s':
  437.         max_depth:=0;
  438.         bar:=FALSE;
  439.       |'d':
  440.         bar:=FALSE;
  441.       |'h','?':
  442.         bar:=FALSE;
  443.       |'w':
  444.         opt_w:=TRUE;
  445.         bar:=FALSE;
  446.       |'z':
  447.         opt_z:=TRUE;
  448.         bar:=FALSE;
  449.       |'x':
  450.         include:=FALSE;
  451.         bar:=FALSE;
  452.       |'i':
  453.         include:=TRUE;
  454.         bar:=FALSE;
  455.       |'n':
  456.         opt_n:=TRUE;
  457.         bar:=FALSE;
  458.       |'0'..'9':
  459.         IF NOT(bar) THEN
  460.           max_depth:=0;
  461.         END;
  462.         max_depth:=max_depth*10+(CARDINAL(a[foo])-48);
  463.         bar:=TRUE;
  464.     END;
  465.   END;
  466. END SetFlags;
  467.  
  468.  
  469.  
  470. PROCEDURE FindClusterSize(dir:String);
  471. VAR
  472.   r : SYSTEM.Registers;
  473. BEGIN
  474.   IF (Str.Length(dir)>2) AND (dir[1]=':') THEN
  475.     r.DL:=SHORTCARD(dir[0])-96;
  476.   ELSE
  477.     r.DL:=0;
  478.   END;
  479.   r.AH:=36H;
  480.   Lib.Dos(r);
  481.   IF r.AX=0FFFFH THEN
  482.     stepup:=1023;
  483.   ELSE
  484.     stepup:=LONGCARD(r.AX*r.CX-1);
  485.   END;
  486.   granularity:=MAX(LONGCARD)-stepup;
  487. END FindClusterSize;
  488.  
  489.  
  490.  
  491.  
  492. PROCEDURE ParseArgs();
  493. VAR
  494.   argv,
  495.   argno : CARDINAL;
  496.   arg : String;
  497.  
  498.   s_depth : CARDINAL;
  499.   s_a,
  500.   s_n,
  501.   s_w,
  502.   s_z,
  503.   s_inc : BOOLEAN;
  504.  
  505.   base : String;
  506.  
  507.   lastglobalfs : CARDINAL;
  508.  
  509.   PROCEDURE DoScan();
  510.   VAR
  511.     TrueSize,
  512.     NominalSize : LONGCARD;
  513.  
  514.     foo:CARDINAL;
  515.     bar:LONGCARD;
  516.   BEGIN
  517.     IncludeAll:=TRUE;
  518.     FOR foo:=1 TO FileSpecs DO
  519.       IF Specs[foo].i THEN
  520.         IncludeAll:=FALSE;
  521.       END;
  522.     END;
  523.     IF base[Str.Length(base)-1]#'/' THEN
  524.       Str.Append(base,'/');
  525.     END;
  526.     IF opt_d THEN
  527.       IO.WrLn;
  528.       IO.WrLn;
  529.       IO.WrStr('Base directory: ');
  530.       IO.WrStr(base);
  531.       IO.WrLn;
  532.       IO.WrStr('  Switches: ');
  533.       IF opt_a THEN
  534.         IO.WrStr('a ');
  535.       END;
  536.       IF opt_n THEN
  537.         IO.WrStr('n ');
  538.       END;
  539.       IF opt_w THEN
  540.         IO.WrStr('w ');
  541.       END;
  542.       IF opt_z THEN
  543.         IO.WrStr('z ');
  544.       END;
  545.       IO.WrLn;
  546.       IO.WrStr('  List depth:');
  547.       IO.WrCard(max_depth,6);
  548.       IF IncludeAll THEN
  549.         IO.WrLn;
  550.         IO.WrStr('  Include all files');
  551.       END;
  552.       FOR foo:=1 TO FileSpecs DO
  553.         IO.WrLn;
  554.         IF Specs[foo].i THEN
  555.           IO.WrStr('  Include: ');
  556.         ELSE
  557.           IO.WrStr('  Exclude: ');
  558.         END;
  559.         IO.WrStr(Specs[foo].n);
  560.       END;
  561.     ELSE
  562.       FindClusterSize(base);
  563.       ScanDirectory(base,TrueSize,NominalSize);
  564.       Print(TrueSize,NominalSize,base,TRUE);
  565.     END;
  566.   END DoScan;
  567.  
  568.   PROCEDURE FixAppearance();
  569.   VAR
  570.     foo:CARDINAL;
  571.   BEGIN
  572.     foo:=0;
  573.     WHILE arg[foo]#CHAR(0) DO
  574.       IF arg[foo]='\' THEN
  575.         arg[foo]:='/';
  576.       ELSIF (arg[foo]>='A') AND (arg[foo]<='Z') THEN
  577.         arg[foo]:=CHAR(CARDINAL(arg[foo])+32);
  578.       END;
  579.       INC(foo);
  580.     END;
  581.   END FixAppearance;
  582.  
  583. BEGIN
  584.   opt_a:=FALSE;
  585.   opt_n:=FALSE;
  586.   opt_w:=FALSE;
  587.   opt_z:=FALSE;
  588.   include:=TRUE;
  589.   max_depth:=65535;
  590.   base:='.';
  591.   FileSpecs:=0;
  592.   argv:=Lib.ParamCount();
  593.   argno:=0;
  594.   WHILE argno<argv DO
  595.     INC(argno);
  596.     Lib.ParamStr(arg,argno);
  597.     IF IsSwitch(arg) THEN
  598.       SetFlags(arg);
  599.     ELSE
  600.       FixAppearance;
  601.       IF IsDirectory(arg) THEN
  602.         IF Str.Compare(base,'.')#0 THEN
  603.           DoScan;
  604.           opt_a:=s_a;
  605.           opt_n:=s_n;
  606.           opt_w:=s_w;
  607.           opt_z:=s_z;
  608.           include:=s_inc;
  609.           max_depth:=s_depth;
  610.           FileSpecs:=lastglobalfs;
  611.         END;
  612.         base:=arg;
  613.         s_a:=opt_a;
  614.         s_n:=opt_n;
  615.         s_w:=opt_w;
  616.         s_z:=opt_z;
  617.         s_inc:=include;
  618.         s_depth:=max_depth;
  619.         lastglobalfs:=FileSpecs;
  620.       ELSE
  621.         INC(FileSpecs);
  622.         Specs[FileSpecs].i:=include;
  623.         Specs[FileSpecs].n:=arg;
  624.       END;
  625.     END;
  626.   END;
  627.   DoScan;
  628. END ParseArgs;
  629.  
  630.  
  631.  
  632. BEGIN
  633.   CheckArgs;
  634.   IF opt_h THEN
  635.     IO.WrLn;
  636.     IO.WrStr(helptext);
  637.     Lib.SetReturnCode(1);
  638.   ELSE
  639.     ParseArgs;
  640.     Lib.SetReturnCode(0);
  641.   END;
  642.   IO.WrLn;
  643. END du.
  644.  
  645.  
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.  
  655.  
  656.  
  657.  
  658.  
  659.  
  660.  
  661.  
  662.