(* Copyright (C) 1989, Digital Equipment Corporation *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* Last modified on Fri Jun 1 02:32:01 1990 by muller *) MODULE Filename; IMPORT Text, Rd, CoreOS, FileStream, Cstdlib, M3toC; PROCEDURE FileIsReadable (filename: Text.T): BOOLEAN = BEGIN RETURN CoreOS.access (M3toC.TtoS (filename), CoreOS.R_OK) = 0; END FileIsReadable; PROCEDURE Root (filename: Text.T): Text.T = BEGIN WITH dotpos=Text.FindCharR (filename, '.') DO IF (dotpos = -1) OR (Text.FindChar (filename, '/', dotpos + 1) # -1) THEN RETURN filename; ELSE RETURN (Text.Sub (filename, 0, dotpos)); END; END; END Root; PROCEDURE Extension (filename: Text.T): Text.T = BEGIN WITH dotpos=Text.FindCharR (filename, '.') DO IF (dotpos = -1) OR (Text.FindChar (filename, '/', dotpos + 1) # -1) THEN RETURN NIL; ELSE RETURN (Text.Sub (filename, dotpos + 1, Text.Length (filename) - (dotpos + 1))); END; END; END Extension; PROCEDURE Head (filename: Text.T): Text.T = BEGIN WITH slashpos=Text.FindCharR (filename, '/') DO IF slashpos = -1 THEN RETURN filename; ELSE RETURN (Text.Sub (filename, 0, slashpos)); END; END; END Head; PROCEDURE Tail (filename: Text.T): Text.T = BEGIN WITH slashpos=Text.FindCharR (filename, '/') DO IF slashpos = -1 THEN RETURN filename; ELSE RETURN (Text.Sub (filename, slashpos + 1, Text.Length (filename) - (slashpos + 1))); END; END; END Tail; (***************************************************************) (* DefaultExtension(filename, ".xxx") *) (* *) (* DefaultExtension adds an extension to filename *) (* if none already exists. Alternatively, if the extension *) (* field begins with a *, any old extension in the first *) (* filename is replaced with the given extension. Thus, *) (* *) (* DefaultExtension(filename, ".xxx") add .xxx if no ext *) (* DefaultExtension(filename, "*.xxx") force .xxx as ext *) (***************************************************************) PROCEDURE DefaultExtension (filename, ext: Text.T): Text.T = VAR force: BOOLEAN; dotpos: INTEGER; BEGIN force := (Text.GetChar (ext, 0) = '*'); IF force THEN ext := Text.Sub (ext, 1, Text.Length (ext)); END; dotpos := Text.FindCharR (filename, '.'); IF (dotpos = -1) OR (Text.FindChar (filename, '/', dotpos + 1) # -1) THEN force := TRUE; dotpos := Text.Length (filename); END; IF NOT force THEN RETURN filename; ELSE RETURN Text.Cat (Text.Sub (filename, 0, dotpos), ext); END; END DefaultExtension; (***************************************************************) (* ExpandTilde(filename) *) (* *) (* Expands the ~ character at the beginning of a file *) (* name to be the appropriate directory path. For ~/, this *) (* is taken from the HOME environment variable; ~user/ is *) (* converted by adding the /udir/ prefix. *) (***************************************************************) PROCEDURE ExpandTilde (filename: Text.T): Text.T = VAR len: INTEGER; home: Text.T; BEGIN len := Text.Length (filename); IF (len = 0) OR (Text.GetChar (filename, 0) # '~') THEN RETURN filename; END; IF (len = 1) OR (Text.GetChar (filename, 1) = '/') THEN home := M3toC.StoT (Cstdlib.getenv (M3toC.TtoS ("HOME"))); IF Text.Length (home) = 0 THEN RETURN filename; ELSE RETURN home & Text.Sub (filename, 1, Text.Length (filename)); END; ELSE RETURN "/udir/" & Text.Sub (filename, 1, Text.Length (filename)); END; END ExpandTilde; PROCEDURE SearchPath (path, filename: Text.T; pred: FilePredicate := FileIsReadable): Text.T RAISES {} = VAR start, finish: INTEGER; dirname, tempname: Text.T; BEGIN IF Text.Empty (filename) THEN RETURN NIL; END; IF Text.Empty (path) THEN path := "."; END; filename := ExpandTilde (filename); IF Text.GetChar (filename, 0) = '/' THEN IF pred (filename) THEN RETURN filename; ELSE RETURN NIL; END; ELSE start := 0; WITH path=path & ":" DO LOOP finish := Text.FindChar (path, ':', start); IF finish = -1 THEN RETURN NIL; END; dirname := ExpandTilde (Text.Sub (path, start, finish - start)); IF Text.Empty (dirname) THEN dirname := "."; END; IF Text.GetChar (dirname, Text.Length (dirname) - 1) = '/' THEN tempname := Text.Cat (dirname, filename); ELSE tempname := dirname & "/" & filename; END; IF pred (tempname) THEN RETURN tempname; END; start := finish + 1; END; END; RETURN NIL; END; END SearchPath; PROCEDURE RdFromPath ( (* dir: OS.Dir; *)path, filename: Text.T): Rd.T RAISES { (* OS.Error *)} = BEGIN WITH pathname=SearchPath (path, filename) DO IF pathname = NIL THEN RETURN NIL ELSE RETURN FileStream.OpenRead (pathname); END; END; END RdFromPath; BEGIN END Filename.