DIRECTORY TextFind USING [CreateFromRope, SearchRope, MalformedPattern, Finder, NameLoc], Commander USING [CommandProc, Register, Handle, CommandObject], Convert USING [CardFromRope], Basics USING [LowHalf], FS USING [StreamOpen, Error, NameProc, EnumerateForNames, ComponentPositions, ExpandName], IO USING [STREAM, rope, int, PutF, EndOfStream, Close, PutChar, PutRope, GetLineRope], List USING [DReverse], Rope USING [ROPE, Size, Fetch, Concat, Find, Translate, Substr, Replace, FromChar], RopeFile USING [FromStream], Ascii USING [Upper, Lower], CommandTool USING [ParseToList]; TransImpl: CEDAR PROGRAM IMPORTS Commander, FS, IO, CommandTool, List, TextFind, Ascii, Rope, RopeFile, Convert, Basics = { ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; ReplacementRec: TYPE = RECORD [kind: {field, fieldLower, fieldUpper, text} _ text, text: ROPE]; Replacement: TYPE = LIST OF REF ReplacementRec; TransOp: TYPE = {delete, select, replace}; TransProgramContent: TYPE = RECORD [ pattern: TextFind.Finder, replacement: Replacement, patternText: ROPE, replacementText: ROPE, literal: BOOL, word: BOOL, ignoreCase: BOOL, transOp: TransOp ]; TransProgram: TYPE = REF TransProgramContent; Trans: Commander.CommandProc -- [cmd: Commander.Handle] -- = { stdout: STREAM _ cmd.out; stdin: STREAM _ cmd.in; stderr: STREAM _ cmd.err; cmdLine: LIST OF ROPE; whoCares: LIST OF ROPE; transPrograms: LIST OF TransProgram _ NIL; verbose: BOOL _ TRUE; outFile: STREAM _ NIL; UsageMessage: PROC [] = { IO.PutF[stderr, "Usage: trans [switches] [ ] \n"]; }; TransFile: FS.NameProc = { inFile: STREAM; cnt: INT; newR: ROPE; x: FS.ComponentPositions _ FS.ExpandName[fullFName].cp; continue _ TRUE; fullFName _ Rope.Substr[fullFName, 0, x.ver.start-1]; inFile _ FS.StreamOpen[fullFName, read ! FS.Error => { IO.PutF[stderr, "Could not open \"%g\" -- %g\n", IO.rope[fullFName], IO.rope[error.explanation]]; GOTO openFailed; }]; IF verbose THEN IO.PutF[stderr, "Transforming \"%g\"...", IO.rope[fullFName]]; [newR, cnt] _ TransStream[inFile]; IF cnt > 0 OR appendFile # NIL THEN { IF appendFile = NIL THEN outFile _ FS.StreamOpen[fileName: fullFName, accessOptions: create, keep: 2 ! FS.Error => { IO.PutF[stderr, "Could not open \"%g\" for write -- %g\n", IO.rope[fullFName], IO.rope[error.explanation]]; GOTO openFailed; }]; outFile.PutRope[newR]; IF appendFile = NIL THEN outFile.Close[]; stderr.PutF["%g changes\n", IO.int[cnt]]; } ELSE { IF verbose THEN IO.PutF[stderr, "no changes, file not rewritten.\n"]; }; inFile.Close[]; EXITS openFailed => NULL; }; TransStream: PROC [inFile: STREAM] RETURNS [newR: ROPE, cnt: INT] = { r: ROPE _ RopeFile.FromStream[inFile]; [newR, cnt] _ TransRope[r, transPrograms]; }; TransRope: PROC [r: ROPE, p: LIST OF TransProgram] RETURNS [newR: ROPE, cnt: INT _ 0] = { found: BOOL; ReplacementRope: PROC [r: ROPE, p: TransProgram] RETURNS [rep: ROPE _ NIL] = { FOR l: Replacement _ p.replacement, l.rest UNTIL l = NIL DO IF l.first.kind # text THEN { at, atEnd: INT; t: ROPE; [at, atEnd] _ p.pattern.NameLoc[l.first.text]; t _ r.Substr[at, atEnd-at]; SELECT l.first.kind FROM fieldUpper => t _ Upper[t]; fieldLower => t _ Lower[t]; ENDCASE; rep _ rep.Concat[t]; } ELSE rep _ rep.Concat[l.first.text]; ENDLOOP; }; newR _ r; FOR l: LIST OF TransProgram _ p, l.rest UNTIL l = NIL DO lastLoc, start, atEnd, before, after: INT _ 0; DO replRope: ROPE; [found, start, atEnd, before, after] _ TextFind.SearchRope[l.first.pattern, newR, start]; IF ~found THEN EXIT; IF atEnd=start THEN ERROR; replRope _ ReplacementRope[newR, l.first]; newR _ newR.Replace[start, atEnd-start, replRope]; IF l.first.transOp = select THEN { IF lastLoc < start THEN newR _ newR.Replace[lastLoc, start-lastLoc]; start _ start + Rope.Size[replRope]-(start-lastLoc); lastLoc _ start; } ELSE start _ start + Rope.Size[replRope]; cnt _ cnt + 1; ENDLOOP; IF l.first.transOp = select THEN newR _ newR.Replace[lastLoc, newR.Size[]-lastLoc]; IF verbose THEN stderr.PutChar['.]; ENDLOOP; }; MakeTransProgram: PROC [p, r: ROPE, literal, word, ignoreCase: BOOL, transOp: TransOp] RETURNS [ok: BOOL _ TRUE, t: TransProgram _ NEW[TransProgramContent]] = { t.patternText _ p; t.replacementText _ r; t.literal _ literal; t.word _ word; t.ignoreCase _ ignoreCase; t.transOp _ transOp; t.pattern _ TextFind.CreateFromRope[pattern: p, literal: literal, word: word, ignoreCase: ignoreCase ! TextFind.MalformedPattern => { stderr.PutF["Syntax error in pattern \"%g\"\n", IO.rope[p]]; GOTO prematureExit;}]; [ok, t.replacement] _ MakeReplacement[r, literal]; EXITS prematureExit => ok _ FALSE; }; MakeReplacement: PROC [r: ROPE, literal: BOOL] RETURNS [ok: BOOL _ TRUE, x: Replacement _ NIL] = { startPoint, endPoint: INT _ 0; len: INT _ r.Size[]; IF literal THEN { IF len > 0 THEN x _ CONS[NEW[ReplacementRec _ [text, r]], NIL]; RETURN; }; WHILE startPoint < len DO frag: REF ReplacementRec _ NEW[ReplacementRec]; endPoint _ startPoint; SELECT r.Fetch[startPoint] FROM '< => { colonPoint: INT _ startPoint; endPoint _ startPoint + 1; DO IF endPoint >= len THEN GOTO SyntaxError; SELECT r.Fetch[endPoint] FROM '' => { r _ r.Replace[endPoint, 1]; len _ len - 1; }; '> => { endPoint _ endPoint + 1; EXIT; }; ': => colonPoint _ endPoint; ENDCASE => NULL; endPoint _ endPoint + 1; ENDLOOP; IF colonPoint > startPoint THEN { frag.text _ r.Substr[startPoint+1, colonPoint-startPoint-1]; SELECT Ascii.Lower[r.Fetch[colonPoint+1]] FROM 'u => frag.kind _ fieldUpper; 'l => frag.kind _ fieldLower; ENDCASE => GOTO SyntaxError; } ELSE { frag.kind _ field; frag.text _ r.Substr[startPoint+1, endPoint-startPoint-2]; }; }; ENDCASE => { endPoint _ startPoint; DO IF endPoint > len THEN GOTO SyntaxError; IF endPoint = len THEN EXIT; SELECT r.Fetch[endPoint] FROM '' => { IF r.Fetch[endPoint+1] = '0 THEN { r _ r.Replace[endPoint, 5, Rope.FromChar[VAL[Basics.LowHalf[Convert.CardFromRope[r.Substr[endPoint+1, 4], 8]]]]]; len _ len - 4; } ELSE { r _ r.Replace[endPoint, 1]; len _ len - 1; }; }; '\\ => { SELECT Ascii.Lower[r.Fetch[endPoint+1]] FROM 'n => { r _ r.Replace[endPoint, 2, "\n"]; len _ len - 1; }; 't => { r _ r.Replace[endPoint, 2, "\t"]; len _ len - 1; }; 's => { r _ r.Replace[endPoint, 2, " "]; len _ len - 1; }; '\\ => { r _ r.Replace[endPoint, 2, "\\"]; len _ len - 1; }; ENDCASE => ERROR; }; '< => EXIT; ENDCASE => NULL; endPoint _ endPoint + 1; ENDLOOP; frag.kind _ text; frag.text _ r.Substr[startPoint, endPoint-startPoint]; }; x _ CONS[frag, x]; startPoint _ endPoint; ENDLOOP; TRUSTED {x _ LOOPHOLE[List.DReverse[LOOPHOLE[x]]];}; EXITS SyntaxError => { stderr.PutF["Syntax error in replacement expression: \"%g\"\n", IO.rope[r]]; ok _ FALSE; }; }; ParseCmdSwitches: PROC [handle: Commander.Handle, literal, ignoreCase, word: BOOL, transOp: TransOp, fileNamesOK: BOOL] RETURNS [ok: BOOL _ TRUE, cmdLine: LIST OF ROPE, appendFile: ROPE _ NIL] = { filePatternName: ROPE; present: BOOL; cmdLine _ CommandTool.ParseToList[handle, 040C].list; [present, cmdLine, whoCares] _ GetSwitch["-pattern", cmdLine]; IF present THEN literal _ FALSE; [present, cmdLine, whoCares] _ GetSwitch["-literal", cmdLine]; IF present THEN literal _ TRUE; [present, cmdLine, whoCares] _ GetSwitch["-caseSensitive", cmdLine]; IF present THEN ignoreCase _ FALSE; [present, cmdLine, whoCares] _ GetSwitch["-ignoreCase", cmdLine]; IF present THEN ignoreCase _ TRUE; [present, cmdLine, whoCares] _ GetSwitch["-wordMatch", cmdLine]; IF present THEN word _ FALSE; [present, cmdLine, whoCares] _ GetSwitch["-matchAnywhere", cmdLine]; IF present THEN word _ TRUE; [present, cmdLine, whoCares] _ GetSwitch["-deleteMatched", cmdLine]; IF present THEN transOp _ delete; [present, cmdLine, whoCares] _ GetSwitch["-selectMatched", cmdLine]; IF present THEN transOp _ select; [present, cmdLine, whoCares] _ GetSwitch["-replaceMatched", cmdLine]; IF present THEN transOp _ replace; [present, appendFile, cmdLine, whoCares] _ GetSwitchWithArg["-appendFile", cmdLine]; [present, filePatternName, cmdLine, whoCares] _ GetSwitchWithArg["-filePatterns", cmdLine]; IF SwitchesLeft[cmdLine, stderr] THEN GOTO SyntaxError; IF present THEN { h: Commander.Handle _ NEW[Commander.CommandObject]; -- Hacque. in: STREAM _ FS.StreamOpen[filePatternName ! FS.Error => { stderr.PutF["Could not open \"%g\"\n", IO.rope[filePatternName]]; GOTO SyntaxError}]; DO nc: LIST OF ROPE; h.commandLine _ in.GetLineRope[ ! IO.EndOfStream => EXIT]; IF h.commandLine.Size[] > 0 THEN [ok, nc, appendFile] _ ParseCmdSwitches[h, literal, ignoreCase, word, transOp, FALSE]; IF ~ok THEN GOTO SyntaxError; ENDLOOP; in.Close[]; } ELSE IF cmdLine = NIL THEN { stderr.PutF["Missing pattern and replacement in \"%g\"\n", IO.rope[handle.commandLine]]; GOTO SyntaxError; } ELSE IF transOp # delete AND cmdLine.rest = NIL THEN { stderr.PutF["Missing replacement expression in \"%g\"\n", IO.rope[handle.commandLine]]; GOTO SyntaxError; } ELSE IF transOp = delete AND cmdLine.rest # NIL THEN { stderr.PutF["Delete mode should not have replacement expression in \"%g\"\n", IO.rope[handle.commandLine]]; GOTO SyntaxError; } ELSE IF transOp = delete THEN { ok: BOOL; program: TransProgram; [ok, program] _ MakeTransProgram[cmdLine.first, "", literal, word, ignoreCase, transOp]; IF ~ok THEN GOTO SyntaxError; transPrograms _ CONS[program, transPrograms]; cmdLine _ cmdLine.rest; } ELSE { ok: BOOL; program: TransProgram; IF cmdLine.rest = NIL THEN GOTO SyntaxError; [ok, program] _ MakeTransProgram[cmdLine.first, cmdLine.rest.first, literal, word, ignoreCase, transOp]; IF ~ok THEN GOTO SyntaxError; transPrograms _ CONS[program, transPrograms]; cmdLine _ cmdLine.rest.rest; }; IF cmdLine # NIL AND ~fileNamesOK THEN { stderr.PutF["File names are not allowed in pattern files: \"%g\"\n", IO.rope[handle.commandLine]]; GOTO SyntaxError; }; EXITS SyntaxError => ok _ FALSE; }; ok: BOOL; appendFile: ROPE _ NIL; [ok, cmdLine, appendFile] _ ParseCmdSwitches[cmd, FALSE, TRUE, FALSE, replace, TRUE]; IF appendFile # NIL THEN outFile _ FS.StreamOpen[fileName: appendFile, accessOptions: create, keep: 2 ! FS.Error => { IO.PutF[stderr, "Could not open \"%g\" for write -- %g\n", IO.rope[appendFile], IO.rope[error.explanation]]; GOTO openFailed; }]; IF ~ok THEN RETURN; TRUSTED {transPrograms _ LOOPHOLE[List.DReverse[LOOPHOLE[transPrograms]]]}; IF cmdLine = NIL THEN { stdout.PutRope[TransStream[stdin].newR]; } ELSE FOR l: LIST OF ROPE _ cmdLine, l.rest UNTIL l = NIL DO FS.EnumerateForNames[DefaultToHighestGeneration[l.first], TransFile]; ENDLOOP; IF appendFile # NIL THEN outFile.Close[]; EXITS openFailed => NULL; }; GetSwitch: PROC [switch: ROPE, cmdLine: LIST OF ROPE, prefixLen: INT _ 2] RETURNS [present: BOOL _ FALSE, newCmdLine: LIST OF ROPE, previous: LIST OF ROPE _ NIL] = { IF cmdLine = NIL THEN RETURN; IF Prefix[switch, cmdLine.first, prefixLen] THEN { present _ TRUE; newCmdLine _ cmdLine.rest; } ELSE { newCmdLine _ cmdLine; FOR l: LIST OF ROPE _ cmdLine, l.rest UNTIL l.rest = NIL DO IF Prefix[switch, l.rest.first, prefixLen] THEN { l.rest _ l.rest.rest; present _ TRUE; previous _ l; RETURN; }; ENDLOOP; }; }; GetSwitchWithArg: PROC [switch: ROPE, cmdLine: LIST OF ROPE, prefixLen: INT _ 2] RETURNS [present: BOOL _ FALSE, arg: ROPE, newCmdLine: LIST OF ROPE, previous: LIST OF ROPE _ NIL] = { IF cmdLine = NIL THEN RETURN; IF Prefix[switch, cmdLine.first, prefixLen] THEN { present _ TRUE; arg _ cmdLine.rest.first; newCmdLine _ cmdLine.rest.rest; } ELSE { newCmdLine _ cmdLine; FOR l: LIST OF ROPE _ cmdLine, l.rest UNTIL l.rest = NIL DO IF Prefix[switch, l.rest.first, prefixLen] THEN { arg _ l.rest.rest.first; l.rest _ l.rest.rest.rest; present _ TRUE; previous _ l; RETURN; }; ENDLOOP; }; }; SwitchesLeft: PROC [cmdLine: LIST OF ROPE, stderr: STREAM, switchChar: CHAR _ '-] RETURNS [switchesLeft: BOOL _ FALSE] = { FOR l: LIST OF ROPE _ cmdLine, l.rest UNTIL l = NIL DO IF Rope.Size[l.first] >= 1 THEN IF Rope.Fetch[l.first] = switchChar THEN { IO.PutF[stderr, "Invalid switch: \"%g\"\n", IO.rope[l.first]]; switchesLeft _ TRUE; }; ENDLOOP; }; Prefix: PROC [r1, r2: ROPE, length: INT, ignoreCase: BOOL _ TRUE] RETURNS [BOOL] = { r2Len: INT _ r2.Size[]; r1Len: INT _ r1.Size[]; IF r1Len < length THEN ERROR; IF r2Len > r1Len OR r2Len < length THEN RETURN[FALSE]; IF ~ignoreCase THEN FOR i: INT IN [0..r2Len) DO IF r1.Fetch[i] # r2.Fetch[i] THEN RETURN[FALSE]; ENDLOOP ELSE FOR i: INT IN [0..r2Len) DO IF Ascii.Upper[r1.Fetch[i]] # Ascii.Upper[r2.Fetch[i]] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; Upper: PROC [r: ROPE] RETURNS [ROPE] = { UpIt: PROC[c: CHAR] RETURNS [CHAR] = { RETURN[Ascii.Upper[c]]; }; RETURN[Rope.Translate[base: r, translator: UpIt]]; }; Lower: PROC [r: ROPE] RETURNS [ROPE] = { LowerIt: PROC[c: CHAR] RETURNS [CHAR] = { RETURN[Ascii.Lower[c]]; }; RETURN[Rope.Translate[base: r, translator: LowerIt]]; }; DefaultToHighestGeneration: PROC [filePattern: ROPE] RETURNS [ROPE] = { IF Rope.Find[filePattern, "!"] = -1 THEN RETURN[Rope.Concat[filePattern,"!H"]] ELSE RETURN[filePattern]; }; Commander.Register[ key: "Trans", proc: Trans, doc: "Transforms files using regular expressions."]; }. TransImpl.mesa Last Edited by: Nix, April 5, 1984 4:40:03 pm PST Last Edited by: Swinehart, February 6, 1985 10:30:39 pm PST Callable from the command interpreter. Expects a list of file names as arguments, and counts the number of words in the indicated files. ΚΓ˜Jšœ™J™1J™;J˜šΟk ˜ Jšœ œA˜OIcodešœ œ0˜?Kšœœ˜Kšœœ ˜KšœœR˜ZKšœœœF˜VKšœœ ˜KšœœœC˜SKšœ œ˜Kšœœ˜Kšœ œ˜ K˜—KšΟb œœ˜Kšœ œœI˜bKšœœœ˜Kšœœœœ˜K˜K˜Kšœœœ<œ˜_Kš œ œœœœ˜/Kšœ œ˜*šœœœ˜$Kšœ˜Kšœ˜Kšœ œ˜Kšœœ˜Kšœ œ˜Kšœœ˜ Kšœ œ˜K˜Kšœ˜—Kšœœœ˜-unit•StartOfExpansion -- [cmd: Commander.Handle] -- šžœΠckœ˜?KšΟc‰™‰Kšœœ ˜Kšœœ ˜Kšœœ ˜Kšœ œœœ˜Kšœ œœœ˜Kšœœœœ˜*Kšœ œœ˜Kšœ œœ˜šΟn œœ˜KšœQ˜SK˜—šž œœ ˜Kšœœ˜Kšœœ˜ Kšœœ˜ Jšœœœ˜7Jšœ œ˜Jšœ5˜5šœ œœ ˜6Kšœ/œœ˜aKšœ ˜K˜—šœ ˜Kšœ(œ˜>—Kšœ"˜"šœœ˜%šœœ˜šœ œCœ ˜\Kšœ9œœ˜kKšœ ˜K˜——K˜šœœ˜K˜—Kšœœ ˜)K˜—šœ˜šœ ˜Kšœ3˜5—K˜—Kšœ˜š˜Kšœœ˜—K˜—š ‘ œœ œœœœ˜EKšœœ˜&K˜*K˜—šΠbn œœœœœœœœ ˜YKšœœ˜ š ‘œœœœœœ˜Nšœ(œœ˜;šœœ˜Kšœ œ˜Kšœœ˜K˜.K˜šœ˜K˜K˜Kšœ˜—K˜K˜—š˜K˜—Kšœ˜—K˜—K˜ š œœœœœ˜8Kšœ&œ˜.š˜Kšœ œ˜šœ'˜'Kšœ2˜2—Kšœœœ˜Kšœ œœ˜Kšœ*˜*Kšœ2˜2šœœ˜"šœ˜K˜-—K˜4K˜K˜—š˜K˜$—K˜Kšœ˜—šœ˜ K˜2—Kšœ œ˜#Kšœ˜—K˜—š‘œœœœœœœœ˜ K˜K˜K˜K˜K˜K˜šœ…˜…Kšœ0œ ˜˜>Kšœ œ œ˜ Kšœ>˜>Kšœ œ œ˜KšœD˜DKšœ œœ˜#KšœA˜AKšœ œœ˜"Kšœ@˜@Kšœ œœ˜KšœD˜DKšœ œœ˜KšœD˜DKšœ œ˜!KšœD˜DKšœ œ˜!KšœE˜EKšœ œ˜"KšœT˜TKšœ[˜[Kšœœœ ˜7šœ œ˜Kšœœ  ˜>šœœœœ ˜:Kšœ'œ˜AKšœ˜—š˜Kšœœœœ˜Kšœ"œœ˜:˜ KšœOœ˜V—Kšœœœ ˜Kšœ˜—K˜ K˜—šœœ œœ˜Kšœ;œ˜YKšœ ˜K˜—š œœœœœ˜6Kšœ:œ˜WKšœ ˜K˜—š œœœœœ˜6KšœNœ˜kKšœ ˜K˜—šœœœ˜Kšœœ˜ K˜K˜Xšœ˜ Kšœ ˜—Kšœœ˜-K˜K˜—šœ˜Kšœœ˜ K˜Kšœœœœ ˜,K˜hšœ˜ Kšœ ˜—Kšœœ˜-K˜K˜—šœ œœœ˜(KšœEœ˜bKšœ ˜K˜—š˜Kšœœ˜—Kšœ˜—Kšœœ˜ Kšœ œœ˜Kš œ2œœœ œ˜Ušœœ˜šœ œDœ ˜]Kšœ9œœ˜lKšœ ˜K˜——Kšœœœ˜Kšœœœ˜Kšœ œœ˜K˜(K˜—š˜š œœœœœœ˜6JšœC˜EJšœ˜——Jšœœœ˜)Jšœœ˜K˜J˜—š"‘ œœ œ œœœ œœ œœœœœ œœœœ˜₯Jšœ œœœ˜šœ*œ˜2Jšœ œ˜Jšœ˜Jšœ˜—šœ˜Jšœ˜š œœœœœ œ˜;šœ)œ˜1J˜Jšœ œ˜J˜ Jšœ˜J˜—Jšœ˜—J˜—J˜J˜J˜—š$‘œœ œ œœœ œœ œœœœœœ œœœœ˜·Jšœ œœœ˜šœ*œ˜2Jšœ œ˜J˜Jšœ˜Jšœ˜—šœ˜Jšœ˜š œœœœœ œ˜;šœ)œ˜1J˜J˜Jšœ œ˜J˜ Jšœ˜J˜—Jšœ˜—J˜—J˜J˜J˜—š‘ œœ œœœ œœœœœ˜zš œœœœœœ˜6šœ˜šœ"œ˜*Jšœ*œ˜>Jšœœ˜J˜——Jšœ˜—J˜J˜J˜—š‘œœ œ œœœœœ˜TJšœœ ˜Jšœœ ˜Jšœœœ˜Jš œœœœœ˜6šœ œ˜šœœœ ˜Jšœœœœ˜0Jš˜——š˜šœœœ ˜Jšœ5œœœ˜JJšœ˜——Jšœœ˜ J˜J˜—š ‘œœœœœ˜(š ‘œœœœœ˜&Jšœ˜J˜—Jšœ,˜2J˜J˜—š ‘œœœœœ˜(š ‘œœœœœ˜)Jšœ˜J˜—Jšœ/˜5J˜—J˜š ‘œœœœœ˜Gšœ"œ˜)Jšœ˜%—šœ˜Jšœ˜—J˜J˜—J˜šœd˜d˜K˜——˜J˜—K˜J˜—…—3Eλ