MODULE---------------------------------------------------------------------------; IMPORT Pathname, TextSeq, FS, OSError, Wr, TextWr, Thread, Text; IMPORT FSUtils, SMsg AS Msg, RegEx, PathRepr, TextUtils; IMPORT FSFindError, FindExpr, FindExprSeq, FileClassification; FSFind
PROCEDURE---------------------------------------------------------------------------SimplifyPN (p : Pathname.T; stripPrefix := TRUE) : Pathname.T = VAR start := Pathname.Current & PathRepr.PathSep; BEGIN IF stripPrefix AND TextUtils.Pos(p, start) = 0 THEN RETURN Text.Sub(p, Text.Length(start)); ELSE RETURN p; END; END SimplifyPN;
PROCEDURE---------------------------------------------------------------------------List (root : Pathname.T; expr : FindExpr.T; ignoreDirs : FindExpr.T; stripPrefix := TRUE) : TextSeq.T RAISES {FSFindError.E} = VAR res := NEW(TextSeq.T).init(); (*-------------------------------------------------------------------------*) PROCEDURE ListRec(current : Pathname.T) RAISES {FSFindError.E} = VAR fn : Pathname.T; BEGIN TRY IF FSUtils.IsFile(current) THEN IF expr.test(Pathname.Last(current)) THEN res.addhi(SimplifyPN(current, stripPrefix)); END; ELSIF FSUtils.IsDir(current) AND NOT (ignoreDirs # NIL AND ignoreDirs.test(Pathname.Last(current))) THEN TRY WITH it = FS.Iterate(current) DO TRY WHILE it.next(fn) DO ListRec(Pathname.Join(current, fn, NIL)); END; EXCEPT ELSE Msg.Error("cannot get status of file " & fn & " in directory " & current & ", iteration aborted"); END; END; EXCEPT ELSE Msg.Error("cannot iterate directory" & current); END; END; EXCEPT RegEx.Error(e) => RAISE FSFindError.E("regex error: " & e); END; END ListRec; BEGIN (* List *) ListRec(root); RETURN res; END List;
PROCEDURE---------------------------------------------------------------------------SimpleClassify ( root : Pathname.T; (* root of tree traversal *) patterns : FindExprSeq.T; (* list of expressions to select files *) ignoreDirs : FindExpr.T := NIL; (* selects which directories to ignore *) recursive := TRUE; stripPrefix := TRUE; ) : REF ARRAY OF TextSeq.T RAISES {FSFindError.E} = (*-------------------------------------------------------------------------*) PROCEDURE ClassifyRec(current : Pathname.T; level := 0) RAISES {FSFindError.E} = VAR fn : Pathname.T; BEGIN TRY IF FSUtils.IsFile(current) THEN FOR i := 0 TO rules - 1 DO WITH expr = patterns.get(i) DO IF expr.test(Pathname.Last(current)) THEN res[i].addhi(SimplifyPN(current, stripPrefix)); END; END; END; ELSIF (recursive OR level = 0) AND FSUtils.IsDir(current) AND NOT (ignoreDirs # NIL AND ignoreDirs.test(Pathname.Last(current))) THEN TRY WITH it = FS.Iterate(current) DO TRY WHILE it.next(fn) DO ClassifyRec(Pathname.Join(current, fn, NIL), level + 1); END; EXCEPT ELSE Msg.Error("cannot get status of file " & fn & " in directory " & current & ", iteration aborted"); END; END; EXCEPT ELSE Msg.Error("cannot iterate directory" & current); END; END; EXCEPT RegEx.Error(e) => RAISE FSFindError.E("regex error: " & e); END; END ClassifyRec; (*-------------------------------------------------------------------------*) VAR (* SimpleClassify *) rules := patterns.size(); res := NEW(REF ARRAY OF TextSeq.T, rules); BEGIN FOR i := 0 TO rules - 1 DO res[i] := NEW(TextSeq.T).init(); END; ClassifyRec(root); RETURN res; END SimpleClassify;
PROCEDURE---------------------------------------------------------------------------ClassifyToWr ( root : Pathname.T; (* root of tree traversal *) fc : FileClassification.T; (* file classification rules *) wr : Wr.T; recursive := TRUE; flush := FALSE; stripPrefix := TRUE; ) RAISES {FSFindError.E} = (*-------------------------------------------------------------------------*) PROCEDURE ClassifyRec(current : Pathname.T; level := 0) RAISES {FSFindError.E} = VAR fn : Pathname.T; BEGIN IF FSUtils.IsFile(current) THEN TRY WITH line = fc.match(SimplifyPN(current, stripPrefix)) DO IF line # NIL THEN TRY Wr.PutText(wr, line & "\n"); IF flush THEN Wr.Flush(wr); END; EXCEPT Thread.Alerted => RAISE FSFindError.E("interrupted"); | Wr.Failure => RAISE FSFindError.E("write error"); END; END; END; EXCEPT FileClassification.E(e) => RAISE FSFindError.E("classification error: " & e); END; ELSIF (recursive OR level = 0) AND FSUtils.IsDir(current) AND NOT fc.ignoreDir(current) THEN TRY WITH it = FS.Iterate(current) DO WHILE it.next(fn) DO ClassifyRec(Pathname.Join(current, fn, NIL), level + 1); END; END; EXCEPT OSError.E => Msg.Error("cannot iterate directory" & current); END; END; END ClassifyRec; (*-------------------------------------------------------------------------*) BEGIN (* ClassifyToWr *) ClassifyRec(root); END ClassifyToWr;
PROCEDUREClassify ( root : Pathname.T; (* root of tree traversal *) fc : FileClassification.T; (* file classification rules *) recursive := TRUE; stripPrefix := TRUE; ) : TEXT RAISES {FSFindError.E} = VAR wr := TextWr.New(); BEGIN ClassifyToWr(root, fc, wr, recursive, FALSE, stripPrefix); RETURN TextWr.ToText(wr); END Classify; BEGIN END FSFind.