<<>> <> <> <> <> DIRECTORY Ascii, CedarProcess, Commander, CommanderOps, FileNames, FS, IO, Rope, TiogaAccess; TransTiogaImpl: CEDAR PROGRAM IMPORTS Ascii, CedarProcess, Commander, CommanderOps, FileNames, FS, IO, Rope, TiogaAccess ~ BEGIN ROPE: TYPE ~ Rope.ROPE; Reader: TYPE ~ TiogaAccess.Reader; TiogaChar: TYPE ~ TiogaAccess.TiogaChar; CharSequence: TYPE ~ RECORD [seq: SEQUENCE maxLength: CARDINAL OF CHAR]; TiogaCharSequence: TYPE ~ RECORD [seq: SEQUENCE maxLength: CARDINAL OF TiogaChar]; <> TransTiogaCommand: Commander.CommandProc ~ { out: IO.STREAM ¬ cmd.out; argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd]; IF argv.argc < 4 THEN RETURN[$Failure, usage]; FOR i: NAT IN [3..argv.argc) DO Reverse: PROC [list: LIST OF ROPE] RETURNS [rev: LIST OF ROPE] ~ { FOR l: LIST OF ROPE ¬ list, l.rest WHILE l # NIL DO rev ¬ CONS[l.first, rev]; ENDLOOP; }; Each: PROC [name: ROPE] RETURNS [BOOL ¬ TRUE] ~ {names ¬ CONS[name, names]}; names: LIST OF ROPE ¬ NIL; pattern: ROPE ¬ IF Rope.Equal[FileNames.StripVersionNumber[argv[i]], argv[i]] THEN Rope.Concat[argv[i], "!H"] ELSE argv[i]; FS.EnumerateForNames[pattern, Each ! FS.Error => LOOP]; IF names = NIL THEN IO.PutRope[out, Rope.Cat["No such files: ", argv[i], "\n"]] ELSE FOR l: LIST OF ROPE ¬ Reverse[names], l.rest WHILE l # NIL DO nSubs: NAT; reader: Reader ¬ TiogaAccess.FromFile[l.first ! FS.Error => LOOP]; IO.PutRope[out, Rope.Cat["Translating ", FileNames.GetShortName[l.first, FALSE], ": "]]; nSubs ¬ TransTioga[reader, l.first, argv[1], argv[2]]; IO.PutF[out, "%g substitution%g\n", IO.int[nSubs], IO.rope[IF nSubs = 1 THEN NIL ELSE "s"]]; ENDLOOP; ENDLOOP; }; TransTioga: PROC [reader: Reader, fileName, key, sub: ROPE] RETURNS [nSubs: NAT ¬ 0] ~ { IF NOT Rope.IsEmpty[key] AND NOT Rope.IsEmpty[sub] THEN { writer: TiogaAccess.Writer ¬ TiogaAccess.Create[]; firstKeyChar: CHAR ¬ Ascii.Lower[Rope.Fetch[key]]; keyLen: NAT ¬ Rope.Length[key]; subLen: NAT ¬ Rope.Length[sub]; keyChars: REF CharSequence ¬ NEW[CharSequence[keyLen]]; subChars: REF CharSequence ¬ NEW[CharSequence[subLen]]; tiogaChars: REF TiogaCharSequence ¬ NEW[TiogaCharSequence[keyLen]]; FOR n: NAT IN [0..keyLen) DO keyChars[n] ¬ Ascii.Lower[Rope.Fetch[key, n]]; ENDLOOP; FOR n: NAT IN [0..subLen) DO subChars[n] ¬ Rope.Fetch[sub, n]; ENDLOOP; DO tiogaChar: TiogaChar; CedarProcess.CheckAbort[]; IF TiogaAccess.EndOf[reader] THEN { IF nSubs > 0 THEN TiogaAccess.WriteFile[writer, fileName]; EXIT; }; tiogaChar ¬ tiogaChars[0] ¬ TiogaAccess.Get[reader]; IF Ascii.Lower[tiogaChar.char] = firstKeyChar THEN { FOR n: NAT IN [1..keyLen) DO IF TiogaAccess.EndOf[reader] THEN EXIT; tiogaChars[n] ¬ TiogaAccess.Get[reader]; IF Ascii.Lower[tiogaChars[n].char] # keyChars[n] THEN { FOR i: INT IN [0..n] DO TiogaAccess.Put[writer, tiogaChars[i]]; ENDLOOP; EXIT; }; REPEAT FINISHED => { nSubs ¬ nSubs+1; subChars[0] ¬ SELECT tiogaChar.char FROM IN ['A..'Z] => Ascii.Upper[subChars[0]], IN ['a..'z] => Ascii.Lower[subChars[0]], ENDCASE => subChars[0]; FOR n: NAT IN [0..subLen) DO tiogaChar.char ¬ subChars[n]; TiogaAccess.Put[writer, tiogaChar]; ENDLOOP; }; ENDLOOP; } ELSE TiogaAccess.Put[writer, tiogaChar]; ENDLOOP; }; }; <> usage: ROPE ¬ "TransTioga . . . "; Commander.Register["TransTioga", TransTiogaCommand, usage]; END.