<> <> <> <> <> <> DIRECTORY BasicTime USING [GMT, nullGMT], DFOperations USING [BringOver], FS USING [Close, GetInfo, GetName, Error, Open, OpenFile, StreamOpen], FSExtras USING [DoInWDir, GetWDir], IO USING [BreakProc, Close, EndOfStream, Error, GetLineRope, GetTokenRope, PutF, RIS, STREAM, Value], PrinterNames USING [Get], Rope USING [Concat, Equal, ROPE, Translate, TranslatorType], SimpleTerminal USING [SetInputTimeout, TurnOff, TurnOn], SystemNames USING [LocalDir]; FontInstallerImpl: CEDAR PROGRAM IMPORTS DFOperations, FS, FSExtras, IO, PrinterNames, Rope, SimpleTerminal, SystemNames = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; in, out: STREAM _ NIL; <> <<>> PrintF: PROC [format: ROPE, v1, v2, v3, v4: IO.Value _ [null[]]] ~ { ENABLE IO.Error => IF ec=StreamClosed AND stream=out THEN CONTINUE; IO.PutF[out, format, v1, v2, v3, v4]; }; FileDesc: TYPE = RECORD [name: ROPE _ NIL, date: BasicTime.GMT _ BasicTime.nullGMT]; haveFonts: BOOL _ FALSE; fonts: FileDesc _ []; fontsDir: ROPE ~ SystemNames.LocalDir["Fonts"]; -- e.g., "[]<>7.0>Fonts>" FindBasicFonts: PROC = { <> name: ROPE = "BasicPrinter.fonts"; desc: FileDesc _ TryFile[name, topPath].desc; SELECT TRUE FROM desc.date ~= BasicTime.nullGMT => NULL; ENDCASE => {PrintF["The fonts can't be found. I give up.\N"]; Die[]; }; fonts _ desc; }; InstallBasicFonts: PROC [name: ROPE] = { FontAction: TYPE ~ PROC [prefix: ROPE, dfFile: ROPE]; ParseBasicFonts: PROC [stream: STREAM, action: FontAction] ~ { DO lineRope: ROPE ~ IO.GetLineRope[stream ! IO.EndOfStream => EXIT]; line: STREAM ~ IO.RIS[lineRope]; break: IO.BreakProc ~ { RETURN[SELECT char FROM <=' => sepr, '_ => break, ENDCASE => other] }; prefix: ROPE ~ line.GetTokenRope[break ! IO.EndOfStream => LOOP --empty--].token; arrow: ROPE ~ line.GetTokenRope[break ! IO.EndOfStream => EXIT].token; dfFile: ROPE ~ line.GetTokenRope[break ! IO.EndOfStream => EXIT].token; IF Rope.Equal[arrow, "_"] THEN action[prefix, dfFile]; ENDLOOP; }; GetFonts: FontAction ~ { ToBrackets: Rope.TranslatorType ~ { SELECT old FROM '/ => RETURN['>]; ENDCASE => RETURN[old]; }; wDir: ROPE ~ fontsDir.Concat[Rope.Translate[base: prefix, translator: ToBrackets]]; IF TryFile[dfFile, NIL].desc.date # BasicTime.nullGMT THEN { [] _ DFOperations.BringOver[dfFile: dfFile, action: [fetch: TRUE], workingDir: wDir] }; }; stream: STREAM ~ FS.StreamOpen[name]; ParseBasicFonts[stream, GetFonts]; IO.Close[stream]; }; <> topPath: ROPE _ NIL; -- "[Fonts]Top>" InitUserAndPaths: PROC = { topPath _ PrinterNames.Get[].currentFont; }; OpenInfo: PROC [name: ROPE, wDir: ROPE _ NIL] RETURNS [fullFName: ROPE, attachedTo: ROPE, created: BasicTime.GMT] = { <> file: FS.OpenFile _ FS.Open[name: name, wDir: wDir]; { ENABLE UNWIND => FS.Close[file]; [fullFName, attachedTo] _ FS.GetName[file]; created _ FS.GetInfo[file].created; FS.Close[file]; }; }; OpenTerminal: PROC = { IF in # NIL THEN RETURN; [in, out] _ SimpleTerminal.TurnOn[]; PrintF["\N"]; }; CloseTerminal: PROC = { IF in = NIL THEN RETURN; SimpleTerminal.TurnOff[]; in _ out _ NIL; }; TryFile: PROC [shortName, prefix: ROPE _ NIL] RETURNS [desc: FileDesc _ [], attachedTo: ROPE _ NIL] = { [fullFName: desc.name, attachedTo: attachedTo, created: desc.date] _ OpenInfo[name: shortName, wDir: prefix ! FS.Error => CONTINUE]; }; Die: PROC = {DO ENDLOOP}; <<>> <
> working: BOOL _ FALSE; installDir: ROPE ~ FSExtras.GetWDir[]; DoRealWork: PROC [] = { DoRealWorkInner: PROC ~ { haveFonts _ FALSE; InitUserAndPaths[]; FindBasicFonts[]; <> InstallBasicFonts[fonts.name]; SimpleTerminal.SetInputTimeout[0]; CloseTerminal[]; }; IF NOT working THEN { working _ TRUE; FSExtras.DoInWDir[installDir, DoRealWorkInner]; working _ FALSE; }; }; DoRealWork[ !FS.Error => {OpenTerminal[]; PrintF["\NFatal FS Error: %g\N", [rope[error.explanation]]]; Die[]}]; END.