home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / UTILITY / DIR / DU113.ZIP / DU.MOD < prev    next >
Encoding:
Text File  |  1992-04-10  |  18.0 KB  |  814 lines

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