MODULE----------------------------------------------------------- internal ---; IMPORT Env, Params, Pathname, M3File, M3ID, Quake, RTIO, Text, Thread; IMPORT QMachine; VAR mu : MUTEX := NEW (MUTEX); found : BOOLEAN := FALSE; config : TEXT := NIL; mach : Quake.Machine := NIL; trace : BOOLEAN := FALSE; PROCEDURE MxConfig FindFile (): TEXT = BEGIN IF NOT found THEN LOCK mu DO FindConfig (); END; END; RETURN config; END FindFile; PROCEDUREGet (param: TEXT): TEXT = BEGIN LOCK mu DO EvalConfig (); TRY RETURN Quake.LookUp (mach, param); EXCEPT Quake.Error => RETURN NIL; END; END; END Get; PROCEDUREEnableQuakeTrace () = BEGIN trace := TRUE; END EnableQuakeTrace;
PROCEDUREFindConfig () = (* LL = mu *) VAR txt: TEXT; BEGIN IF (found) THEN RETURN END; (* try the current directory *) IF TryConfig (".", Filename) THEN RETURN END; (* try the immediate source directory *) IF TryConfig ("src", Filename) THEN RETURN END; (* try the sibling source directory *) IF TryConfig ("..", "src", Filename) THEN RETURN END; (* try the M3CONFIG environment variable *) txt := QMachine.GetEnv (NIL, "M3CONFIG"); IF (txt # NIL) THEN IF TryConfig (txt) THEN RETURN END; IF TryConfig (txt, Filename) THEN RETURN END; END; (* try the directory containing the current executable *) txt := Pathname.Prefix (Params.Get (0)); IF Text.Length (txt) > 0 THEN IF TryConfig (txt, Filename) THEN RETURN END; END; (* try the directories named by the PATH environment variable. *) txt := Env.Get ("PATH"); FindConfigInPath (txt); IF found THEN RETURN END; (* try the etc directories *) IF TryConfig("/usr/local/cm3/etc", Filename) THEN RETURN END; IF TryConfig("/usr/cm3/etc", Filename) THEN RETURN END; IF TryConfig("/cm3/etc", Filename) THEN RETURN END; IF TryConfig("/usr/contrib/etc", Filename) THEN RETURN END; IF TryConfig("/usr/local/etc", Filename) THEN RETURN END; IF TryConfig("/usr/etc", Filename) THEN RETURN END; IF TryConfig("/opt/etc", Filename) THEN RETURN END; IF TryConfig("/sw/etc", Filename) THEN RETURN END; IF TryConfig("/etc", Filename) THEN RETURN END; (* oh well, make sure we don't try this silly exercise again... *) config := NIL; found := TRUE; END FindConfig; PROCEDUREFindConfigInPath (txt: TEXT) = VAR s0, s1: INTEGER; sep: CHAR; BEGIN (* what's the convention for search paths? Unix or Win32 *) CONST XX = ARRAY BOOLEAN OF CHAR { ';', ':' }; BEGIN sep := XX [Text.Equal (Pathname.Join ("a", "b", NIL), "a/b")]; END; IF (txt # NIL) THEN s0 := 0; WHILE (s0 < Text.Length (txt)) DO s1 := Text.FindChar (txt, sep, s0); IF (s1 < 0) THEN s1 := Text.Length (txt); END; IF (s0 < s1) THEN IF TryConfig (Text.Sub (txt, s0, s1-s0), Filename) THEN RETURN END; END; s0 := s1 + 1; END; END; END FindConfigInPath; PROCEDURETryConfig (a, b, c: TEXT := NIL): BOOLEAN = BEGIN config := a; IF (b # NIL) THEN config := Pathname.Join (config, b, NIL); END; IF (c # NIL) THEN config := Pathname.Join (config, c, NIL); END; found := M3File.IsReadable (config); RETURN found; END TryConfig; PROCEDUREEvalConfig () = (* LL = mu *) BEGIN IF (mach # NIL) THEN RETURN END; FindConfig (); mach := Quake.NewMachine (Quake.NewIDMap (Str2ID, Txt2ID, ID2Txt)); mach.trace (trace); TRY IF (config # NIL) THEN Quake.Run (mach, config); END; EXCEPT Quake.Error(e) => RTIO.PutText ("quake runtime error: " & e); RTIO.Flush (); | Thread.Alerted => RTIO.PutText ("interrupted"); RTIO.Flush (); END; END EvalConfig; PROCEDUREStr2ID (READONLY x: ARRAY OF CHAR): Quake.ID = BEGIN RETURN M3ID.FromStr (x); END Str2ID; PROCEDURETxt2ID (t: TEXT): Quake.ID = BEGIN RETURN M3ID.Add (t); END Txt2ID; PROCEDUREID2Txt (i: Quake.ID): TEXT = BEGIN RETURN M3ID.ToText (i); END ID2Txt; BEGIN END MxConfig.