MODULE; IMPORT AtomList, FileWr, Fmt, OS, OSError, Process, Rd, Stdio; IMPORT Text, Text2, TextSeq, TextWr, Thread, Wr; CONST SupportMsg = "Please feel free to contact m3-support@elego.de to troubleshoot this problem."; VAR log_wr: Wr.T := TextWr.New (); got_drain: BOOLEAN := FALSE; PROCEDURE Msg AskBool (question, default: TEXT): BOOLEAN = VAR txt := Ask (question, default); BEGIN LOOP IF txt = NIL THEN (* huh? *) ELSIF Text.Equal (txt, "y") OR Text.Equal (txt, "Y") OR Text.Equal (txt, "yes") OR Text.Equal (txt, "YES") THEN RETURN TRUE; ELSIF Text.Equal (txt, "n") OR Text.Equal (txt, "N") OR Text.Equal (txt, "no") OR Text.Equal (txt, "NO") THEN RETURN FALSE; END; Out (""); Out ("Please enter Y (yes) or N (no)."); txt := Ask (question, default); END; END AskBool; PROCEDUREAsk (question, default: TEXT; suf : TEXT := NIL): TEXT = VAR txt: TEXT; q_len := Text.Length (question); s_len := 0; BEGIN OutX (question); IF suf # NIL THEN s_len := Text.Length(suf) END; IF Text.GetChar (question, q_len - 1) # ' ' THEN OutX (" "); END; IF default # NIL THEN IF q_len + Text.Length (default) + s_len >= 70 THEN OutX (Wr.EOL); OutX (" "); END; OutX ("["); OutX (default); OutX ("]"); END; IF suf # NIL THEN OutX (suf); END; OutX(" "); FlushX (); TRY txt := Rd.GetLine (Stdio.stdin); EXCEPT Rd.EndOfFile, Rd.Failure, Thread.Alerted => (* ignore *) END; IF (txt # NIL) THEN txt := Text2.Trim (txt); END; IF (txt = NIL) OR Text.Length (txt) <= 0 THEN OutLog (""); txt := default; ELSE OutLog (txt); END; RETURN txt; END Ask; PROCEDUREAskChoice (question: TEXT; choices : TextSeq.T): TEXT = VAR i := 0; result : TEXT := NIL; item : TEXT; BEGIN IF choices.size() = 0 THEN RETURN Ask(question, NIL); END; FOR i := 0 TO choices.size() - 1 DO WITH c = choices.get(i) DO Out(Fmt.Int(i + 1), ": ", c); END; END; WHILE result = NIL OR Text.Equal(result, ".") OR Text.Equal(result, "+") OR Text.Equal(result, "-") DO IF result # NIL THEN IF Text.Equal(result, "+") OR Text.Equal(result, ".") THEN INC(i); IF i >= choices.size() THEN i := 0 END; ELSIF Text.Equal(result, "-") THEN DEC(i); IF i < 0 THEN i := choices.size() - 1 END; END; END; item := "(" & Fmt.Int(i + 1) & " of " & Fmt.Int(choices.size()) & ")"; result := Ask(question, choices.get(i), item); END; RETURN result; END AskChoice; PROCEDUREDebug (a, b, c, d: TEXT := NIL) = BEGIN IF Debugging THEN Out (a, b, c, d); END; END Debug; PROCEDUREWarn (a, b, c, d: TEXT := NIL) = BEGIN OutI (Wr.EOL, "Warning: ", a, b, c, d); OutI (Wr.EOL, SupportMsg, Wr.EOL); END Warn; PROCEDUREError (ec: AtomList.T; a, b, c, d: TEXT := NIL) = VAR e: TEXT := NIL; BEGIN IF (ec # NIL) THEN e := OS.Err (ec); END; OutI (Wr.EOL & "Unexpected problem: ", a, b, c, d, e); OutI (Wr.EOL, SupportMsg, Wr.EOL); Process.Exit (1); END Error; PROCEDUREOut (a, b, c, d, e, f: TEXT := NIL) = BEGIN IF Quiet THEN RETURN END; OutI (a, b, c, d, e, f); END Out; PROCEDUREOutI (a, b, c, d, e, f: TEXT := NIL) = BEGIN OutX (a); OutX (b); OutX (c); OutX (d); OutX (e); OutX (f); OutX (Wr.EOL); FlushX (); END OutI; PROCEDUREOutS (a, b, c, d, e, f: TEXT := NIL) = BEGIN IF Quiet THEN RETURN END; OutX (a); OutX (b); OutX (c); OutX (d); OutX (e); OutX (f); FlushX (); END OutS; PROCEDUREOutX (a: TEXT) = <*FATAL Wr.Failure, Thread.Alerted *> BEGIN IF (a # NIL) THEN Wr.PutText (log_wr, a); Wr.PutText (Stdio.stdout, a); END; END OutX; PROCEDUREOutLog (a: TEXT) = <*FATAL Wr.Failure, Thread.Alerted *> BEGIN Wr.PutText (log_wr, a); Wr.PutText (log_wr, Wr.EOL); END OutLog; PROCEDUREFlushX () = <*FATAL Wr.Failure, Thread.Alerted *> BEGIN Wr.Flush (log_wr); Wr.Flush (Stdio.stdout); END FlushX; PROCEDUREAttachDrain (filename: TEXT) = VAR txt: TEXT; drain: Wr.T; BEGIN (* open the log file *) TRY drain := FileWr.Open (filename); EXCEPT | OSError.E (ec) => Error (ec, "Unable to open the log file: ", filename); RETURN; END; (* dump everything we've got so far *) txt := TextWr.ToText (log_wr); TRY Wr.PutText (drain, txt); Wr.Flush (drain); EXCEPT | Wr.Failure (ec) => OutLog (txt); (* restore the in-memory log *) Error (ec, "Unable to write the log file: ", filename); drain := NIL; RETURN; | Thread.Alerted => OutLog (txt); (* restore the in-memory log *) Error (NIL, "Interrupted while writing the log file: ", filename); drain := NIL; RETURN; END; (* ok, we successfully converted *) log_wr := drain; got_drain := TRUE; END AttachDrain; PROCEDUREFinishLog (filename: TEXT) = BEGIN IF NOT got_drain THEN OS.WriteFile (filename, TextWr.ToText (log_wr)); END; END FinishLog; BEGIN END Msg.